(()=>{var __webpack_modules__={848:(__unused_webpack_module,__unused_webpack___webpack_exports__,__webpack_require__)=>{"use strict";eval("\n// EXTERNAL MODULE: ./node_modules/lazysizes/lazysizes.js\nvar lazysizes = __webpack_require__(879);\n;// CONCATENATED MODULE: ./node_modules/gsap/gsap-core.js\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }\n\n/*!\n * GSAP 3.12.5\n * https://gsap.com\n *\n * @license Copyright 2008-2024, GreenSock. All rights reserved.\n * Subject to the terms at https://gsap.com/standard-license or for\n * Club GSAP members, the agreement issued with that membership.\n * @author: Jack Doyle, jack@greensock.com\n*/\n\n/* eslint-disable */\nvar _config = {\n autoSleep: 120,\n force3D: \"auto\",\n nullTargetWarn: 1,\n units: {\n lineHeight: \"\"\n }\n},\n _defaults = {\n duration: .5,\n overwrite: false,\n delay: 0\n},\n _suppressOverwrites,\n _reverting,\n _context,\n _bigNum = 1e8,\n _tinyNum = 1 / _bigNum,\n _2PI = Math.PI * 2,\n _HALF_PI = _2PI / 4,\n _gsID = 0,\n _sqrt = Math.sqrt,\n _cos = Math.cos,\n _sin = Math.sin,\n _isString = function _isString(value) {\n return typeof value === \"string\";\n},\n _isFunction = function _isFunction(value) {\n return typeof value === \"function\";\n},\n _isNumber = function _isNumber(value) {\n return typeof value === \"number\";\n},\n _isUndefined = function _isUndefined(value) {\n return typeof value === \"undefined\";\n},\n _isObject = function _isObject(value) {\n return typeof value === \"object\";\n},\n _isNotFalse = function _isNotFalse(value) {\n return value !== false;\n},\n _windowExists = function _windowExists() {\n return typeof window !== \"undefined\";\n},\n _isFuncOrString = function _isFuncOrString(value) {\n return _isFunction(value) || _isString(value);\n},\n _isTypedArray = typeof ArrayBuffer === \"function\" && ArrayBuffer.isView || function () {},\n // note: IE10 has ArrayBuffer, but NOT ArrayBuffer.isView().\n_isArray = Array.isArray,\n _strictNumExp = /(?:-?\\.?\\d|\\.)+/gi,\n //only numbers (including negatives and decimals) but NOT relative values.\n_numExp = /[-+=.]*\\d+[.e\\-+]*\\d*[e\\-+]*\\d*/g,\n //finds any numbers, including ones that start with += or -=, negative numbers, and ones in scientific notation like 1e-8.\n_numWithUnitExp = /[-+=.]*\\d+[.e-]*\\d*[a-z%]*/g,\n _complexStringNumExp = /[-+=.]*\\d+\\.?\\d*(?:e-|e\\+)?\\d*/gi,\n //duplicate so that while we're looping through matches from exec(), it doesn't contaminate the lastIndex of _numExp which we use to search for colors too.\n_relExp = /[+-]=-?[.\\d]+/,\n _delimitedValueExp = /[^,'\"\\[\\]\\s]+/gi,\n // previously /[#\\-+.]*\\b[a-z\\d\\-=+%.]+/gi but didn't catch special characters.\n_unitExp = /^[+\\-=e\\s\\d]*\\d+[.\\d]*([a-z]*|%)\\s*$/i,\n _globalTimeline,\n _win,\n _coreInitted,\n _doc,\n _globals = {},\n _installScope = {},\n _coreReady,\n _install = function _install(scope) {\n return (_installScope = _merge(scope, _globals)) && gsap;\n},\n _missingPlugin = function _missingPlugin(property, value) {\n return console.warn(\"Invalid property\", property, \"set to\", value, \"Missing plugin? gsap.registerPlugin()\");\n},\n _warn = function _warn(message, suppress) {\n return !suppress && console.warn(message);\n},\n _addGlobal = function _addGlobal(name, obj) {\n return name && (_globals[name] = obj) && _installScope && (_installScope[name] = obj) || _globals;\n},\n _emptyFunc = function _emptyFunc() {\n return 0;\n},\n _startAtRevertConfig = {\n suppressEvents: true,\n isStart: true,\n kill: false\n},\n _revertConfigNoKill = {\n suppressEvents: true,\n kill: false\n},\n _revertConfig = {\n suppressEvents: true\n},\n _reservedProps = {},\n _lazyTweens = [],\n _lazyLookup = {},\n _lastRenderedFrame,\n _plugins = {},\n _effects = {},\n _nextGCFrame = 30,\n _harnessPlugins = [],\n _callbackNames = \"\",\n _harness = function _harness(targets) {\n var target = targets[0],\n harnessPlugin,\n i;\n _isObject(target) || _isFunction(target) || (targets = [targets]);\n\n if (!(harnessPlugin = (target._gsap || {}).harness)) {\n // find the first target with a harness. We assume targets passed into an animation will be of similar type, meaning the same kind of harness can be used for them all (performance optimization)\n i = _harnessPlugins.length;\n\n while (i-- && !_harnessPlugins[i].targetTest(target)) {}\n\n harnessPlugin = _harnessPlugins[i];\n }\n\n i = targets.length;\n\n while (i--) {\n targets[i] && (targets[i]._gsap || (targets[i]._gsap = new GSCache(targets[i], harnessPlugin))) || targets.splice(i, 1);\n }\n\n return targets;\n},\n _getCache = function _getCache(target) {\n return target._gsap || _harness(toArray(target))[0]._gsap;\n},\n _getProperty = function _getProperty(target, property, v) {\n return (v = target[property]) && _isFunction(v) ? target[property]() : _isUndefined(v) && target.getAttribute && target.getAttribute(property) || v;\n},\n _forEachName = function _forEachName(names, func) {\n return (names = names.split(\",\")).forEach(func) || names;\n},\n //split a comma-delimited list of names into an array, then run a forEach() function and return the split array (this is just a way to consolidate/shorten some code).\n_round = function _round(value) {\n return Math.round(value * 100000) / 100000 || 0;\n},\n _roundPrecise = function _roundPrecise(value) {\n return Math.round(value * 10000000) / 10000000 || 0;\n},\n // increased precision mostly for timing values.\n_parseRelative = function _parseRelative(start, value) {\n var operator = value.charAt(0),\n end = parseFloat(value.substr(2));\n start = parseFloat(start);\n return operator === \"+\" ? start + end : operator === \"-\" ? start - end : operator === \"*\" ? start * end : start / end;\n},\n _arrayContainsAny = function _arrayContainsAny(toSearch, toFind) {\n //searches one array to find matches for any of the items in the toFind array. As soon as one is found, it returns true. It does NOT return all the matches; it's simply a boolean search.\n var l = toFind.length,\n i = 0;\n\n for (; toSearch.indexOf(toFind[i]) < 0 && ++i < l;) {}\n\n return i < l;\n},\n _lazyRender = function _lazyRender() {\n var l = _lazyTweens.length,\n a = _lazyTweens.slice(0),\n i,\n tween;\n\n _lazyLookup = {};\n _lazyTweens.length = 0;\n\n for (i = 0; i < l; i++) {\n tween = a[i];\n tween && tween._lazy && (tween.render(tween._lazy[0], tween._lazy[1], true)._lazy = 0);\n }\n},\n _lazySafeRender = function _lazySafeRender(animation, time, suppressEvents, force) {\n _lazyTweens.length && !_reverting && _lazyRender();\n animation.render(time, suppressEvents, force || _reverting && time < 0 && (animation._initted || animation._startAt));\n _lazyTweens.length && !_reverting && _lazyRender(); //in case rendering caused any tweens to lazy-init, we should render them because typically when someone calls seek() or time() or progress(), they expect an immediate render.\n},\n _numericIfPossible = function _numericIfPossible(value) {\n var n = parseFloat(value);\n return (n || n === 0) && (value + \"\").match(_delimitedValueExp).length < 2 ? n : _isString(value) ? value.trim() : value;\n},\n _passThrough = function _passThrough(p) {\n return p;\n},\n _setDefaults = function _setDefaults(obj, defaults) {\n for (var p in defaults) {\n p in obj || (obj[p] = defaults[p]);\n }\n\n return obj;\n},\n _setKeyframeDefaults = function _setKeyframeDefaults(excludeDuration) {\n return function (obj, defaults) {\n for (var p in defaults) {\n p in obj || p === \"duration\" && excludeDuration || p === \"ease\" || (obj[p] = defaults[p]);\n }\n };\n},\n _merge = function _merge(base, toMerge) {\n for (var p in toMerge) {\n base[p] = toMerge[p];\n }\n\n return base;\n},\n _mergeDeep = function _mergeDeep(base, toMerge) {\n for (var p in toMerge) {\n p !== \"__proto__\" && p !== \"constructor\" && p !== \"prototype\" && (base[p] = _isObject(toMerge[p]) ? _mergeDeep(base[p] || (base[p] = {}), toMerge[p]) : toMerge[p]);\n }\n\n return base;\n},\n _copyExcluding = function _copyExcluding(obj, excluding) {\n var copy = {},\n p;\n\n for (p in obj) {\n p in excluding || (copy[p] = obj[p]);\n }\n\n return copy;\n},\n _inheritDefaults = function _inheritDefaults(vars) {\n var parent = vars.parent || _globalTimeline,\n func = vars.keyframes ? _setKeyframeDefaults(_isArray(vars.keyframes)) : _setDefaults;\n\n if (_isNotFalse(vars.inherit)) {\n while (parent) {\n func(vars, parent.vars.defaults);\n parent = parent.parent || parent._dp;\n }\n }\n\n return vars;\n},\n _arraysMatch = function _arraysMatch(a1, a2) {\n var i = a1.length,\n match = i === a2.length;\n\n while (match && i-- && a1[i] === a2[i]) {}\n\n return i < 0;\n},\n _addLinkedListItem = function _addLinkedListItem(parent, child, firstProp, lastProp, sortBy) {\n if (firstProp === void 0) {\n firstProp = \"_first\";\n }\n\n if (lastProp === void 0) {\n lastProp = \"_last\";\n }\n\n var prev = parent[lastProp],\n t;\n\n if (sortBy) {\n t = child[sortBy];\n\n while (prev && prev[sortBy] > t) {\n prev = prev._prev;\n }\n }\n\n if (prev) {\n child._next = prev._next;\n prev._next = child;\n } else {\n child._next = parent[firstProp];\n parent[firstProp] = child;\n }\n\n if (child._next) {\n child._next._prev = child;\n } else {\n parent[lastProp] = child;\n }\n\n child._prev = prev;\n child.parent = child._dp = parent;\n return child;\n},\n _removeLinkedListItem = function _removeLinkedListItem(parent, child, firstProp, lastProp) {\n if (firstProp === void 0) {\n firstProp = \"_first\";\n }\n\n if (lastProp === void 0) {\n lastProp = \"_last\";\n }\n\n var prev = child._prev,\n next = child._next;\n\n if (prev) {\n prev._next = next;\n } else if (parent[firstProp] === child) {\n parent[firstProp] = next;\n }\n\n if (next) {\n next._prev = prev;\n } else if (parent[lastProp] === child) {\n parent[lastProp] = prev;\n }\n\n child._next = child._prev = child.parent = null; // don't delete the _dp just so we can revert if necessary. But parent should be null to indicate the item isn't in a linked list.\n},\n _removeFromParent = function _removeFromParent(child, onlyIfParentHasAutoRemove) {\n child.parent && (!onlyIfParentHasAutoRemove || child.parent.autoRemoveChildren) && child.parent.remove && child.parent.remove(child);\n child._act = 0;\n},\n _uncache = function _uncache(animation, child) {\n if (animation && (!child || child._end > animation._dur || child._start < 0)) {\n // performance optimization: if a child animation is passed in we should only uncache if that child EXTENDS the animation (its end time is beyond the end)\n var a = animation;\n\n while (a) {\n a._dirty = 1;\n a = a.parent;\n }\n }\n\n return animation;\n},\n _recacheAncestors = function _recacheAncestors(animation) {\n var parent = animation.parent;\n\n while (parent && parent.parent) {\n //sometimes we must force a re-sort of all children and update the duration/totalDuration of all ancestor timelines immediately in case, for example, in the middle of a render loop, one tween alters another tween's timeScale which shoves its startTime before 0, forcing the parent timeline to shift around and shiftChildren() which could affect that next tween's render (startTime). Doesn't matter for the root timeline though.\n parent._dirty = 1;\n parent.totalDuration();\n parent = parent.parent;\n }\n\n return animation;\n},\n _rewindStartAt = function _rewindStartAt(tween, totalTime, suppressEvents, force) {\n return tween._startAt && (_reverting ? tween._startAt.revert(_revertConfigNoKill) : tween.vars.immediateRender && !tween.vars.autoRevert || tween._startAt.render(totalTime, true, force));\n},\n _hasNoPausedAncestors = function _hasNoPausedAncestors(animation) {\n return !animation || animation._ts && _hasNoPausedAncestors(animation.parent);\n},\n _elapsedCycleDuration = function _elapsedCycleDuration(animation) {\n return animation._repeat ? _animationCycle(animation._tTime, animation = animation.duration() + animation._rDelay) * animation : 0;\n},\n // feed in the totalTime and cycleDuration and it'll return the cycle (iteration minus 1) and if the playhead is exactly at the very END, it will NOT bump up to the next cycle.\n_animationCycle = function _animationCycle(tTime, cycleDuration) {\n var whole = Math.floor(tTime /= cycleDuration);\n return tTime && whole === tTime ? whole - 1 : whole;\n},\n _parentToChildTotalTime = function _parentToChildTotalTime(parentTime, child) {\n return (parentTime - child._start) * child._ts + (child._ts >= 0 ? 0 : child._dirty ? child.totalDuration() : child._tDur);\n},\n _setEnd = function _setEnd(animation) {\n return animation._end = _roundPrecise(animation._start + (animation._tDur / Math.abs(animation._ts || animation._rts || _tinyNum) || 0));\n},\n _alignPlayhead = function _alignPlayhead(animation, totalTime) {\n // adjusts the animation's _start and _end according to the provided totalTime (only if the parent's smoothChildTiming is true and the animation isn't paused). It doesn't do any rendering or forcing things back into parent timelines, etc. - that's what totalTime() is for.\n var parent = animation._dp;\n\n if (parent && parent.smoothChildTiming && animation._ts) {\n animation._start = _roundPrecise(parent._time - (animation._ts > 0 ? totalTime / animation._ts : ((animation._dirty ? animation.totalDuration() : animation._tDur) - totalTime) / -animation._ts));\n\n _setEnd(animation);\n\n parent._dirty || _uncache(parent, animation); //for performance improvement. If the parent's cache is already dirty, it already took care of marking the ancestors as dirty too, so skip the function call here.\n }\n\n return animation;\n},\n\n/*\n_totalTimeToTime = (clampedTotalTime, duration, repeat, repeatDelay, yoyo) => {\n\tlet cycleDuration = duration + repeatDelay,\n\t\ttime = _round(clampedTotalTime % cycleDuration);\n\tif (time > duration) {\n\t\ttime = duration;\n\t}\n\treturn (yoyo && (~~(clampedTotalTime / cycleDuration) & 1)) ? duration - time : time;\n},\n*/\n_postAddChecks = function _postAddChecks(timeline, child) {\n var t;\n\n if (child._time || !child._dur && child._initted || child._start < timeline._time && (child._dur || !child.add)) {\n // in case, for example, the _start is moved on a tween that has already rendered, or if it's being inserted into a timeline BEFORE where the playhead is currently. Imagine it's at its end state, then the startTime is moved WAY later (after the end of this timeline), it should render at its beginning. Special case: if it's a timeline (has .add() method) and no duration, we can skip rendering because the user may be populating it AFTER adding it to a parent timeline (unconventional, but possible, and we wouldn't want it to get removed if the parent's autoRemoveChildren is true).\n t = _parentToChildTotalTime(timeline.rawTime(), child);\n\n if (!child._dur || _clamp(0, child.totalDuration(), t) - child._tTime > _tinyNum) {\n child.render(t, true);\n }\n } //if the timeline has already ended but the inserted tween/timeline extends the duration, we should enable this timeline again so that it renders properly. We should also align the playhead with the parent timeline's when appropriate.\n\n\n if (_uncache(timeline, child)._dp && timeline._initted && timeline._time >= timeline._dur && timeline._ts) {\n //in case any of the ancestors had completed but should now be enabled...\n if (timeline._dur < timeline.duration()) {\n t = timeline;\n\n while (t._dp) {\n t.rawTime() >= 0 && t.totalTime(t._tTime); //moves the timeline (shifts its startTime) if necessary, and also enables it. If it's currently zero, though, it may not be scheduled to render until later so there's no need to force it to align with the current playhead position. Only move to catch up with the playhead.\n\n t = t._dp;\n }\n }\n\n timeline._zTime = -_tinyNum; // helps ensure that the next render() will be forced (crossingStart = true in render()), even if the duration hasn't changed (we're adding a child which would need to get rendered). Definitely an edge case. Note: we MUST do this AFTER the loop above where the totalTime() might trigger a render() because this _addToTimeline() method gets called from the Animation constructor, BEFORE tweens even record their targets, etc. so we wouldn't want things to get triggered in the wrong order.\n }\n},\n _addToTimeline = function _addToTimeline(timeline, child, position, skipChecks) {\n child.parent && _removeFromParent(child);\n child._start = _roundPrecise((_isNumber(position) ? position : position || timeline !== _globalTimeline ? _parsePosition(timeline, position, child) : timeline._time) + child._delay);\n child._end = _roundPrecise(child._start + (child.totalDuration() / Math.abs(child.timeScale()) || 0));\n\n _addLinkedListItem(timeline, child, \"_first\", \"_last\", timeline._sort ? \"_start\" : 0);\n\n _isFromOrFromStart(child) || (timeline._recent = child);\n skipChecks || _postAddChecks(timeline, child);\n timeline._ts < 0 && _alignPlayhead(timeline, timeline._tTime); // if the timeline is reversed and the new child makes it longer, we may need to adjust the parent's _start (push it back)\n\n return timeline;\n},\n _scrollTrigger = function _scrollTrigger(animation, trigger) {\n return (_globals.ScrollTrigger || _missingPlugin(\"scrollTrigger\", trigger)) && _globals.ScrollTrigger.create(trigger, animation);\n},\n _attemptInitTween = function _attemptInitTween(tween, time, force, suppressEvents, tTime) {\n _initTween(tween, time, tTime);\n\n if (!tween._initted) {\n return 1;\n }\n\n if (!force && tween._pt && !_reverting && (tween._dur && tween.vars.lazy !== false || !tween._dur && tween.vars.lazy) && _lastRenderedFrame !== _ticker.frame) {\n _lazyTweens.push(tween);\n\n tween._lazy = [tTime, suppressEvents];\n return 1;\n }\n},\n _parentPlayheadIsBeforeStart = function _parentPlayheadIsBeforeStart(_ref) {\n var parent = _ref.parent;\n return parent && parent._ts && parent._initted && !parent._lock && (parent.rawTime() < 0 || _parentPlayheadIsBeforeStart(parent));\n},\n // check parent's _lock because when a timeline repeats/yoyos and does its artificial wrapping, we shouldn't force the ratio back to 0\n_isFromOrFromStart = function _isFromOrFromStart(_ref2) {\n var data = _ref2.data;\n return data === \"isFromStart\" || data === \"isStart\";\n},\n _renderZeroDurationTween = function _renderZeroDurationTween(tween, totalTime, suppressEvents, force) {\n var prevRatio = tween.ratio,\n ratio = totalTime < 0 || !totalTime && (!tween._start && _parentPlayheadIsBeforeStart(tween) && !(!tween._initted && _isFromOrFromStart(tween)) || (tween._ts < 0 || tween._dp._ts < 0) && !_isFromOrFromStart(tween)) ? 0 : 1,\n // if the tween or its parent is reversed and the totalTime is 0, we should go to a ratio of 0. Edge case: if a from() or fromTo() stagger tween is placed later in a timeline, the \"startAt\" zero-duration tween could initially render at a time when the parent timeline's playhead is technically BEFORE where this tween is, so make sure that any \"from\" and \"fromTo\" startAt tweens are rendered the first time at a ratio of 1.\n repeatDelay = tween._rDelay,\n tTime = 0,\n pt,\n iteration,\n prevIteration;\n\n if (repeatDelay && tween._repeat) {\n // in case there's a zero-duration tween that has a repeat with a repeatDelay\n tTime = _clamp(0, tween._tDur, totalTime);\n iteration = _animationCycle(tTime, repeatDelay);\n tween._yoyo && iteration & 1 && (ratio = 1 - ratio);\n\n if (iteration !== _animationCycle(tween._tTime, repeatDelay)) {\n // if iteration changed\n prevRatio = 1 - ratio;\n tween.vars.repeatRefresh && tween._initted && tween.invalidate();\n }\n }\n\n if (ratio !== prevRatio || _reverting || force || tween._zTime === _tinyNum || !totalTime && tween._zTime) {\n if (!tween._initted && _attemptInitTween(tween, totalTime, force, suppressEvents, tTime)) {\n // if we render the very beginning (time == 0) of a fromTo(), we must force the render (normal tweens wouldn't need to render at a time of 0 when the prevTime was also 0). This is also mandatory to make sure overwriting kicks in immediately.\n return;\n }\n\n prevIteration = tween._zTime;\n tween._zTime = totalTime || (suppressEvents ? _tinyNum : 0); // when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect.\n\n suppressEvents || (suppressEvents = totalTime && !prevIteration); // if it was rendered previously at exactly 0 (_zTime) and now the playhead is moving away, DON'T fire callbacks otherwise they'll seem like duplicates.\n\n tween.ratio = ratio;\n tween._from && (ratio = 1 - ratio);\n tween._time = 0;\n tween._tTime = tTime;\n pt = tween._pt;\n\n while (pt) {\n pt.r(ratio, pt.d);\n pt = pt._next;\n }\n\n totalTime < 0 && _rewindStartAt(tween, totalTime, suppressEvents, true);\n tween._onUpdate && !suppressEvents && _callback(tween, \"onUpdate\");\n tTime && tween._repeat && !suppressEvents && tween.parent && _callback(tween, \"onRepeat\");\n\n if ((totalTime >= tween._tDur || totalTime < 0) && tween.ratio === ratio) {\n ratio && _removeFromParent(tween, 1);\n\n if (!suppressEvents && !_reverting) {\n _callback(tween, ratio ? \"onComplete\" : \"onReverseComplete\", true);\n\n tween._prom && tween._prom();\n }\n }\n } else if (!tween._zTime) {\n tween._zTime = totalTime;\n }\n},\n _findNextPauseTween = function _findNextPauseTween(animation, prevTime, time) {\n var child;\n\n if (time > prevTime) {\n child = animation._first;\n\n while (child && child._start <= time) {\n if (child.data === \"isPause\" && child._start > prevTime) {\n return child;\n }\n\n child = child._next;\n }\n } else {\n child = animation._last;\n\n while (child && child._start >= time) {\n if (child.data === \"isPause\" && child._start < prevTime) {\n return child;\n }\n\n child = child._prev;\n }\n }\n},\n _setDuration = function _setDuration(animation, duration, skipUncache, leavePlayhead) {\n var repeat = animation._repeat,\n dur = _roundPrecise(duration) || 0,\n totalProgress = animation._tTime / animation._tDur;\n totalProgress && !leavePlayhead && (animation._time *= dur / animation._dur);\n animation._dur = dur;\n animation._tDur = !repeat ? dur : repeat < 0 ? 1e10 : _roundPrecise(dur * (repeat + 1) + animation._rDelay * repeat);\n totalProgress > 0 && !leavePlayhead && _alignPlayhead(animation, animation._tTime = animation._tDur * totalProgress);\n animation.parent && _setEnd(animation);\n skipUncache || _uncache(animation.parent, animation);\n return animation;\n},\n _onUpdateTotalDuration = function _onUpdateTotalDuration(animation) {\n return animation instanceof Timeline ? _uncache(animation) : _setDuration(animation, animation._dur);\n},\n _zeroPosition = {\n _start: 0,\n endTime: _emptyFunc,\n totalDuration: _emptyFunc\n},\n _parsePosition = function _parsePosition(animation, position, percentAnimation) {\n var labels = animation.labels,\n recent = animation._recent || _zeroPosition,\n clippedDuration = animation.duration() >= _bigNum ? recent.endTime(false) : animation._dur,\n //in case there's a child that infinitely repeats, users almost never intend for the insertion point of a new child to be based on a SUPER long value like that so we clip it and assume the most recently-added child's endTime should be used instead.\n i,\n offset,\n isPercent;\n\n if (_isString(position) && (isNaN(position) || position in labels)) {\n //if the string is a number like \"1\", check to see if there's a label with that name, otherwise interpret it as a number (absolute value).\n offset = position.charAt(0);\n isPercent = position.substr(-1) === \"%\";\n i = position.indexOf(\"=\");\n\n if (offset === \"<\" || offset === \">\") {\n i >= 0 && (position = position.replace(/=/, \"\"));\n return (offset === \"<\" ? recent._start : recent.endTime(recent._repeat >= 0)) + (parseFloat(position.substr(1)) || 0) * (isPercent ? (i < 0 ? recent : percentAnimation).totalDuration() / 100 : 1);\n }\n\n if (i < 0) {\n position in labels || (labels[position] = clippedDuration);\n return labels[position];\n }\n\n offset = parseFloat(position.charAt(i - 1) + position.substr(i + 1));\n\n if (isPercent && percentAnimation) {\n offset = offset / 100 * (_isArray(percentAnimation) ? percentAnimation[0] : percentAnimation).totalDuration();\n }\n\n return i > 1 ? _parsePosition(animation, position.substr(0, i - 1), percentAnimation) + offset : clippedDuration + offset;\n }\n\n return position == null ? clippedDuration : +position;\n},\n _createTweenType = function _createTweenType(type, params, timeline) {\n var isLegacy = _isNumber(params[1]),\n varsIndex = (isLegacy ? 2 : 1) + (type < 2 ? 0 : 1),\n vars = params[varsIndex],\n irVars,\n parent;\n\n isLegacy && (vars.duration = params[1]);\n vars.parent = timeline;\n\n if (type) {\n irVars = vars;\n parent = timeline;\n\n while (parent && !(\"immediateRender\" in irVars)) {\n // inheritance hasn't happened yet, but someone may have set a default in an ancestor timeline. We could do vars.immediateRender = _isNotFalse(_inheritDefaults(vars).immediateRender) but that'd exact a slight performance penalty because _inheritDefaults() also runs in the Tween constructor. We're paying a small kb price here to gain speed.\n irVars = parent.vars.defaults || {};\n parent = _isNotFalse(parent.vars.inherit) && parent.parent;\n }\n\n vars.immediateRender = _isNotFalse(irVars.immediateRender);\n type < 2 ? vars.runBackwards = 1 : vars.startAt = params[varsIndex - 1]; // \"from\" vars\n }\n\n return new Tween(params[0], vars, params[varsIndex + 1]);\n},\n _conditionalReturn = function _conditionalReturn(value, func) {\n return value || value === 0 ? func(value) : func;\n},\n _clamp = function _clamp(min, max, value) {\n return value < min ? min : value > max ? max : value;\n},\n getUnit = function getUnit(value, v) {\n return !_isString(value) || !(v = _unitExp.exec(value)) ? \"\" : v[1];\n},\n // note: protect against padded numbers as strings, like \"100.100\". That shouldn't return \"00\" as the unit. If it's numeric, return no unit.\nclamp = function clamp(min, max, value) {\n return _conditionalReturn(value, function (v) {\n return _clamp(min, max, v);\n });\n},\n _slice = [].slice,\n _isArrayLike = function _isArrayLike(value, nonEmpty) {\n return value && _isObject(value) && \"length\" in value && (!nonEmpty && !value.length || value.length - 1 in value && _isObject(value[0])) && !value.nodeType && value !== _win;\n},\n _flatten = function _flatten(ar, leaveStrings, accumulator) {\n if (accumulator === void 0) {\n accumulator = [];\n }\n\n return ar.forEach(function (value) {\n var _accumulator;\n\n return _isString(value) && !leaveStrings || _isArrayLike(value, 1) ? (_accumulator = accumulator).push.apply(_accumulator, toArray(value)) : accumulator.push(value);\n }) || accumulator;\n},\n //takes any value and returns an array. If it's a string (and leaveStrings isn't true), it'll use document.querySelectorAll() and convert that to an array. It'll also accept iterables like jQuery objects.\ntoArray = function toArray(value, scope, leaveStrings) {\n return _context && !scope && _context.selector ? _context.selector(value) : _isString(value) && !leaveStrings && (_coreInitted || !_wake()) ? _slice.call((scope || _doc).querySelectorAll(value), 0) : _isArray(value) ? _flatten(value, leaveStrings) : _isArrayLike(value) ? _slice.call(value, 0) : value ? [value] : [];\n},\n selector = function selector(value) {\n value = toArray(value)[0] || _warn(\"Invalid scope\") || {};\n return function (v) {\n var el = value.current || value.nativeElement || value;\n return toArray(v, el.querySelectorAll ? el : el === value ? _warn(\"Invalid scope\") || _doc.createElement(\"div\") : value);\n };\n},\n shuffle = function shuffle(a) {\n return a.sort(function () {\n return .5 - Math.random();\n });\n},\n // alternative that's a bit faster and more reliably diverse but bigger: for (let j, v, i = a.length; i; j = Math.floor(Math.random() * i), v = a[--i], a[i] = a[j], a[j] = v); return a;\n//for distributing values across an array. Can accept a number, a function or (most commonly) a function which can contain the following properties: {base, amount, from, ease, grid, axis, length, each}. Returns a function that expects the following parameters: index, target, array. Recognizes the following\ndistribute = function distribute(v) {\n if (_isFunction(v)) {\n return v;\n }\n\n var vars = _isObject(v) ? v : {\n each: v\n },\n //n:1 is just to indicate v was a number; we leverage that later to set v according to the length we get. If a number is passed in, we treat it like the old stagger value where 0.1, for example, would mean that things would be distributed with 0.1 between each element in the array rather than a total \"amount\" that's chunked out among them all.\n ease = _parseEase(vars.ease),\n from = vars.from || 0,\n base = parseFloat(vars.base) || 0,\n cache = {},\n isDecimal = from > 0 && from < 1,\n ratios = isNaN(from) || isDecimal,\n axis = vars.axis,\n ratioX = from,\n ratioY = from;\n\n if (_isString(from)) {\n ratioX = ratioY = {\n center: .5,\n edges: .5,\n end: 1\n }[from] || 0;\n } else if (!isDecimal && ratios) {\n ratioX = from[0];\n ratioY = from[1];\n }\n\n return function (i, target, a) {\n var l = (a || vars).length,\n distances = cache[l],\n originX,\n originY,\n x,\n y,\n d,\n j,\n max,\n min,\n wrapAt;\n\n if (!distances) {\n wrapAt = vars.grid === \"auto\" ? 0 : (vars.grid || [1, _bigNum])[1];\n\n if (!wrapAt) {\n max = -_bigNum;\n\n while (max < (max = a[wrapAt++].getBoundingClientRect().left) && wrapAt < l) {}\n\n wrapAt < l && wrapAt--;\n }\n\n distances = cache[l] = [];\n originX = ratios ? Math.min(wrapAt, l) * ratioX - .5 : from % wrapAt;\n originY = wrapAt === _bigNum ? 0 : ratios ? l * ratioY / wrapAt - .5 : from / wrapAt | 0;\n max = 0;\n min = _bigNum;\n\n for (j = 0; j < l; j++) {\n x = j % wrapAt - originX;\n y = originY - (j / wrapAt | 0);\n distances[j] = d = !axis ? _sqrt(x * x + y * y) : Math.abs(axis === \"y\" ? y : x);\n d > max && (max = d);\n d < min && (min = d);\n }\n\n from === \"random\" && shuffle(distances);\n distances.max = max - min;\n distances.min = min;\n 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);\n distances.b = l < 0 ? base - l : base;\n distances.u = getUnit(vars.amount || vars.each) || 0; //unit\n\n ease = ease && l < 0 ? _invertEase(ease) : ease;\n }\n\n l = (distances[i] - distances.min) / distances.max || 0;\n return _roundPrecise(distances.b + (ease ? ease(l) : l) * distances.v) + distances.u; //round in order to work around floating point errors\n };\n},\n _roundModifier = function _roundModifier(v) {\n //pass in 0.1 get a function that'll round to the nearest tenth, or 5 to round to the closest 5, or 0.001 to the closest 1000th, etc.\n var p = Math.pow(10, ((v + \"\").split(\".\")[1] || \"\").length); //to avoid floating point math errors (like 24 * 0.1 == 2.4000000000000004), we chop off at a specific number of decimal places (much faster than toFixed())\n\n return function (raw) {\n var n = _roundPrecise(Math.round(parseFloat(raw) / v) * v * p);\n\n return (n - n % 1) / p + (_isNumber(raw) ? 0 : getUnit(raw)); // n - n % 1 replaces Math.floor() in order to handle negative values properly. For example, Math.floor(-150.00000000000003) is 151!\n };\n},\n snap = function snap(snapTo, value) {\n var isArray = _isArray(snapTo),\n radius,\n is2D;\n\n if (!isArray && _isObject(snapTo)) {\n radius = isArray = snapTo.radius || _bigNum;\n\n if (snapTo.values) {\n snapTo = toArray(snapTo.values);\n\n if (is2D = !_isNumber(snapTo[0])) {\n radius *= radius; //performance optimization so we don't have to Math.sqrt() in the loop.\n }\n } else {\n snapTo = _roundModifier(snapTo.increment);\n }\n }\n\n return _conditionalReturn(value, !isArray ? _roundModifier(snapTo) : _isFunction(snapTo) ? function (raw) {\n is2D = snapTo(raw);\n return Math.abs(is2D - raw) <= radius ? is2D : raw;\n } : function (raw) {\n var x = parseFloat(is2D ? raw.x : raw),\n y = parseFloat(is2D ? raw.y : 0),\n min = _bigNum,\n closest = 0,\n i = snapTo.length,\n dx,\n dy;\n\n while (i--) {\n if (is2D) {\n dx = snapTo[i].x - x;\n dy = snapTo[i].y - y;\n dx = dx * dx + dy * dy;\n } else {\n dx = Math.abs(snapTo[i] - x);\n }\n\n if (dx < min) {\n min = dx;\n closest = i;\n }\n }\n\n closest = !radius || min <= radius ? snapTo[closest] : raw;\n return is2D || closest === raw || _isNumber(raw) ? closest : closest + getUnit(raw);\n });\n},\n random = function random(min, max, roundingIncrement, returnFunction) {\n return _conditionalReturn(_isArray(min) ? !max : roundingIncrement === true ? !!(roundingIncrement = 0) : !returnFunction, function () {\n return _isArray(min) ? min[~~(Math.random() * min.length)] : (roundingIncrement = roundingIncrement || 1e-5) && (returnFunction = roundingIncrement < 1 ? Math.pow(10, (roundingIncrement + \"\").length - 2) : 1) && Math.floor(Math.round((min - roundingIncrement / 2 + Math.random() * (max - min + roundingIncrement * .99)) / roundingIncrement) * roundingIncrement * returnFunction) / returnFunction;\n });\n},\n pipe = function pipe() {\n for (var _len = arguments.length, functions = new Array(_len), _key = 0; _key < _len; _key++) {\n functions[_key] = arguments[_key];\n }\n\n return function (value) {\n return functions.reduce(function (v, f) {\n return f(v);\n }, value);\n };\n},\n unitize = function unitize(func, unit) {\n return function (value) {\n return func(parseFloat(value)) + (unit || getUnit(value));\n };\n},\n normalize = function normalize(min, max, value) {\n return mapRange(min, max, 0, 1, value);\n},\n _wrapArray = function _wrapArray(a, wrapper, value) {\n return _conditionalReturn(value, function (index) {\n return a[~~wrapper(index)];\n });\n},\n wrap = function wrap(min, max, value) {\n // NOTE: wrap() CANNOT be an arrow function! A very odd compiling bug causes problems (unrelated to GSAP).\n var range = max - min;\n return _isArray(min) ? _wrapArray(min, wrap(0, min.length), max) : _conditionalReturn(value, function (value) {\n return (range + (value - min) % range) % range + min;\n });\n},\n wrapYoyo = function wrapYoyo(min, max, value) {\n var range = max - min,\n total = range * 2;\n return _isArray(min) ? _wrapArray(min, wrapYoyo(0, min.length - 1), max) : _conditionalReturn(value, function (value) {\n value = (total + (value - min) % total) % total || 0;\n return min + (value > range ? total - value : value);\n });\n},\n _replaceRandom = function _replaceRandom(value) {\n //replaces all occurrences of random(...) in a string with the calculated random value. can be a range like random(-100, 100, 5) or an array like random([0, 100, 500])\n var prev = 0,\n s = \"\",\n i,\n nums,\n end,\n isArray;\n\n while (~(i = value.indexOf(\"random(\", prev))) {\n end = value.indexOf(\")\", i);\n isArray = value.charAt(i + 7) === \"[\";\n nums = value.substr(i + 7, end - i - 7).match(isArray ? _delimitedValueExp : _strictNumExp);\n s += value.substr(prev, i - prev) + random(isArray ? nums : +nums[0], isArray ? 0 : +nums[1], +nums[2] || 1e-5);\n prev = end + 1;\n }\n\n return s + value.substr(prev, value.length - prev);\n},\n mapRange = function mapRange(inMin, inMax, outMin, outMax, value) {\n var inRange = inMax - inMin,\n outRange = outMax - outMin;\n return _conditionalReturn(value, function (value) {\n return outMin + ((value - inMin) / inRange * outRange || 0);\n });\n},\n interpolate = function interpolate(start, end, progress, mutate) {\n var func = isNaN(start + end) ? 0 : function (p) {\n return (1 - p) * start + p * end;\n };\n\n if (!func) {\n var isString = _isString(start),\n master = {},\n p,\n i,\n interpolators,\n l,\n il;\n\n progress === true && (mutate = 1) && (progress = null);\n\n if (isString) {\n start = {\n p: start\n };\n end = {\n p: end\n };\n } else if (_isArray(start) && !_isArray(end)) {\n interpolators = [];\n l = start.length;\n il = l - 2;\n\n for (i = 1; i < l; i++) {\n interpolators.push(interpolate(start[i - 1], start[i])); //build the interpolators up front as a performance optimization so that when the function is called many times, it can just reuse them.\n }\n\n l--;\n\n func = function func(p) {\n p *= l;\n var i = Math.min(il, ~~p);\n return interpolators[i](p - i);\n };\n\n progress = end;\n } else if (!mutate) {\n start = _merge(_isArray(start) ? [] : {}, start);\n }\n\n if (!interpolators) {\n for (p in end) {\n _addPropTween.call(master, start, p, \"get\", end[p]);\n }\n\n func = function func(p) {\n return _renderPropTweens(p, master) || (isString ? start.p : start);\n };\n }\n }\n\n return _conditionalReturn(progress, func);\n},\n _getLabelInDirection = function _getLabelInDirection(timeline, fromTime, backward) {\n //used for nextLabel() and previousLabel()\n var labels = timeline.labels,\n min = _bigNum,\n p,\n distance,\n label;\n\n for (p in labels) {\n distance = labels[p] - fromTime;\n\n if (distance < 0 === !!backward && distance && min > (distance = Math.abs(distance))) {\n label = p;\n min = distance;\n }\n }\n\n return label;\n},\n _callback = function _callback(animation, type, executeLazyFirst) {\n var v = animation.vars,\n callback = v[type],\n prevContext = _context,\n context = animation._ctx,\n params,\n scope,\n result;\n\n if (!callback) {\n return;\n }\n\n params = v[type + \"Params\"];\n scope = v.callbackScope || animation;\n executeLazyFirst && _lazyTweens.length && _lazyRender(); //in case rendering caused any tweens to lazy-init, we should render them because typically when a timeline finishes, users expect things to have rendered fully. Imagine an onUpdate on a timeline that reports/checks tweened values.\n\n context && (_context = context);\n result = params ? callback.apply(scope, params) : callback.call(scope);\n _context = prevContext;\n return result;\n},\n _interrupt = function _interrupt(animation) {\n _removeFromParent(animation);\n\n animation.scrollTrigger && animation.scrollTrigger.kill(!!_reverting);\n animation.progress() < 1 && _callback(animation, \"onInterrupt\");\n return animation;\n},\n _quickTween,\n _registerPluginQueue = [],\n _createPlugin = function _createPlugin(config) {\n if (!config) return;\n config = !config.name && config[\"default\"] || config; // UMD packaging wraps things oddly, so for example MotionPathHelper becomes {MotionPathHelper:MotionPathHelper, default:MotionPathHelper}.\n\n if (_windowExists() || config.headless) {\n // edge case: some build tools may pass in a null/undefined value\n var name = config.name,\n isFunc = _isFunction(config),\n Plugin = name && !isFunc && config.init ? function () {\n this._props = [];\n } : config,\n //in case someone passes in an object that's not a plugin, like CustomEase\n instanceDefaults = {\n init: _emptyFunc,\n render: _renderPropTweens,\n add: _addPropTween,\n kill: _killPropTweensOf,\n modifier: _addPluginModifier,\n rawVars: 0\n },\n statics = {\n targetTest: 0,\n get: 0,\n getSetter: _getSetter,\n aliases: {},\n register: 0\n };\n\n _wake();\n\n if (config !== Plugin) {\n if (_plugins[name]) {\n return;\n }\n\n _setDefaults(Plugin, _setDefaults(_copyExcluding(config, instanceDefaults), statics)); //static methods\n\n\n _merge(Plugin.prototype, _merge(instanceDefaults, _copyExcluding(config, statics))); //instance methods\n\n\n _plugins[Plugin.prop = name] = Plugin;\n\n if (config.targetTest) {\n _harnessPlugins.push(Plugin);\n\n _reservedProps[name] = 1;\n }\n\n name = (name === \"css\" ? \"CSS\" : name.charAt(0).toUpperCase() + name.substr(1)) + \"Plugin\"; //for the global name. \"motionPath\" should become MotionPathPlugin\n }\n\n _addGlobal(name, Plugin);\n\n config.register && config.register(gsap, Plugin, PropTween);\n } else {\n _registerPluginQueue.push(config);\n }\n},\n\n/*\n * --------------------------------------------------------------------------------------\n * COLORS\n * --------------------------------------------------------------------------------------\n */\n_255 = 255,\n _colorLookup = {\n aqua: [0, _255, _255],\n lime: [0, _255, 0],\n silver: [192, 192, 192],\n black: [0, 0, 0],\n maroon: [128, 0, 0],\n teal: [0, 128, 128],\n blue: [0, 0, _255],\n navy: [0, 0, 128],\n white: [_255, _255, _255],\n olive: [128, 128, 0],\n yellow: [_255, _255, 0],\n orange: [_255, 165, 0],\n gray: [128, 128, 128],\n purple: [128, 0, 128],\n green: [0, 128, 0],\n red: [_255, 0, 0],\n pink: [_255, 192, 203],\n cyan: [0, _255, _255],\n transparent: [_255, _255, _255, 0]\n},\n // possible future idea to replace the hard-coded color name values - put this in the ticker.wake() where we set the _doc:\n// let ctx = _doc.createElement(\"canvas\").getContext(\"2d\");\n// _forEachName(\"aqua,lime,silver,black,maroon,teal,blue,navy,white,olive,yellow,orange,gray,purple,green,red,pink,cyan\", color => {ctx.fillStyle = color; _colorLookup[color] = splitColor(ctx.fillStyle)});\n_hue = function _hue(h, m1, m2) {\n h += h < 0 ? 1 : h > 1 ? -1 : 0;\n 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;\n},\n splitColor = function splitColor(v, toHSL, forceAlpha) {\n var a = !v ? _colorLookup.black : _isNumber(v) ? [v >> 16, v >> 8 & _255, v & _255] : 0,\n r,\n g,\n b,\n h,\n s,\n l,\n max,\n min,\n d,\n wasHSL;\n\n if (!a) {\n if (v.substr(-1) === \",\") {\n //sometimes a trailing comma is included and we should chop it off (typically from a comma-delimited list of values like a textShadow:\"2px 2px 2px blue, 5px 5px 5px rgb(255,0,0)\" - in this example \"blue,\" has a trailing comma. We could strip it out inside parseComplex() but we'd need to do it to the beginning and ending values plus it wouldn't provide protection from other potential scenarios like if the user passes in a similar value.\n v = v.substr(0, v.length - 1);\n }\n\n if (_colorLookup[v]) {\n a = _colorLookup[v];\n } else if (v.charAt(0) === \"#\") {\n if (v.length < 6) {\n //for shorthand like #9F0 or #9F0F (could have alpha)\n r = v.charAt(1);\n g = v.charAt(2);\n b = v.charAt(3);\n v = \"#\" + r + r + g + g + b + b + (v.length === 5 ? v.charAt(4) + v.charAt(4) : \"\");\n }\n\n if (v.length === 9) {\n // hex with alpha, like #fd5e53ff\n a = parseInt(v.substr(1, 6), 16);\n return [a >> 16, a >> 8 & _255, a & _255, parseInt(v.substr(7), 16) / 255];\n }\n\n v = parseInt(v.substr(1), 16);\n a = [v >> 16, v >> 8 & _255, v & _255];\n } else if (v.substr(0, 3) === \"hsl\") {\n a = wasHSL = v.match(_strictNumExp);\n\n if (!toHSL) {\n h = +a[0] % 360 / 360;\n s = +a[1] / 100;\n l = +a[2] / 100;\n g = l <= .5 ? l * (s + 1) : l + s - l * s;\n r = l * 2 - g;\n a.length > 3 && (a[3] *= 1); //cast as number\n\n a[0] = _hue(h + 1 / 3, r, g);\n a[1] = _hue(h, r, g);\n a[2] = _hue(h - 1 / 3, r, g);\n } else if (~v.indexOf(\"=\")) {\n //if relative values are found, just return the raw strings with the relative prefixes in place.\n a = v.match(_numExp);\n forceAlpha && a.length < 4 && (a[3] = 1);\n return a;\n }\n } else {\n a = v.match(_strictNumExp) || _colorLookup.transparent;\n }\n\n a = a.map(Number);\n }\n\n if (toHSL && !wasHSL) {\n r = a[0] / _255;\n g = a[1] / _255;\n b = a[2] / _255;\n max = Math.max(r, g, b);\n min = Math.min(r, g, b);\n l = (max + min) / 2;\n\n if (max === min) {\n h = s = 0;\n } else {\n d = max - min;\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n h = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4;\n h *= 60;\n }\n\n a[0] = ~~(h + .5);\n a[1] = ~~(s * 100 + .5);\n a[2] = ~~(l * 100 + .5);\n }\n\n forceAlpha && a.length < 4 && (a[3] = 1);\n return a;\n},\n _colorOrderData = function _colorOrderData(v) {\n // strips out the colors from the string, finds all the numeric slots (with units) and returns an array of those. The Array also has a \"c\" property which is an Array of the index values where the colors belong. This is to help work around issues where there's a mis-matched order of color/numeric data like drop-shadow(#f00 0px 1px 2px) and drop-shadow(0x 1px 2px #f00). This is basically a helper function used in _formatColors()\n var values = [],\n c = [],\n i = -1;\n v.split(_colorExp).forEach(function (v) {\n var a = v.match(_numWithUnitExp) || [];\n values.push.apply(values, a);\n c.push(i += a.length + 1);\n });\n values.c = c;\n return values;\n},\n _formatColors = function _formatColors(s, toHSL, orderMatchData) {\n var result = \"\",\n colors = (s + result).match(_colorExp),\n type = toHSL ? \"hsla(\" : \"rgba(\",\n i = 0,\n c,\n shell,\n d,\n l;\n\n if (!colors) {\n return s;\n }\n\n colors = colors.map(function (color) {\n return (color = splitColor(color, toHSL, 1)) && type + (toHSL ? color[0] + \",\" + color[1] + \"%,\" + color[2] + \"%,\" + color[3] : color.join(\",\")) + \")\";\n });\n\n if (orderMatchData) {\n d = _colorOrderData(s);\n c = orderMatchData.c;\n\n if (c.join(result) !== d.c.join(result)) {\n shell = s.replace(_colorExp, \"1\").split(_numWithUnitExp);\n l = shell.length - 1;\n\n for (; i < l; i++) {\n result += shell[i] + (~c.indexOf(i) ? colors.shift() || type + \"0,0,0,0)\" : (d.length ? d : colors.length ? colors : orderMatchData).shift());\n }\n }\n }\n\n if (!shell) {\n shell = s.split(_colorExp);\n l = shell.length - 1;\n\n for (; i < l; i++) {\n result += shell[i] + colors[i];\n }\n }\n\n return result + shell[l];\n},\n _colorExp = function () {\n var s = \"(?:\\\\b(?:(?:rgb|rgba|hsl|hsla)\\\\(.+?\\\\))|\\\\B#(?:[0-9a-f]{3,4}){1,2}\\\\b\",\n //we'll dynamically build this Regular Expression to conserve file size. After building it, it will be able to find rgb(), rgba(), # (hexadecimal), and named color values like red, blue, purple, etc.,\n p;\n\n for (p in _colorLookup) {\n s += \"|\" + p + \"\\\\b\";\n }\n\n return new RegExp(s + \")\", \"gi\");\n}(),\n _hslExp = /hsl[a]?\\(/,\n _colorStringFilter = function _colorStringFilter(a) {\n var combined = a.join(\" \"),\n toHSL;\n _colorExp.lastIndex = 0;\n\n if (_colorExp.test(combined)) {\n toHSL = _hslExp.test(combined);\n a[1] = _formatColors(a[1], toHSL);\n a[0] = _formatColors(a[0], toHSL, _colorOrderData(a[1])); // make sure the order of numbers/colors match with the END value.\n\n return true;\n }\n},\n\n/*\n * --------------------------------------------------------------------------------------\n * TICKER\n * --------------------------------------------------------------------------------------\n */\n_tickerActive,\n _ticker = function () {\n var _getTime = Date.now,\n _lagThreshold = 500,\n _adjustedLag = 33,\n _startTime = _getTime(),\n _lastUpdate = _startTime,\n _gap = 1000 / 240,\n _nextTime = _gap,\n _listeners = [],\n _id,\n _req,\n _raf,\n _self,\n _delta,\n _i,\n _tick = function _tick(v) {\n var elapsed = _getTime() - _lastUpdate,\n manual = v === true,\n overlap,\n dispatch,\n time,\n frame;\n\n (elapsed > _lagThreshold || elapsed < 0) && (_startTime += elapsed - _adjustedLag);\n _lastUpdate += elapsed;\n time = _lastUpdate - _startTime;\n overlap = time - _nextTime;\n\n if (overlap > 0 || manual) {\n frame = ++_self.frame;\n _delta = time - _self.time * 1000;\n _self.time = time = time / 1000;\n _nextTime += overlap + (overlap >= _gap ? 4 : _gap - overlap);\n dispatch = 1;\n }\n\n manual || (_id = _req(_tick)); //make sure the request is made before we dispatch the \"tick\" event so that timing is maintained. Otherwise, if processing the \"tick\" requires a bunch of time (like 15ms) and we're using a setTimeout() that's based on 16.7ms, it'd technically take 31.7ms between frames otherwise.\n\n if (dispatch) {\n for (_i = 0; _i < _listeners.length; _i++) {\n // use _i and check _listeners.length instead of a variable because a listener could get removed during the loop, and if that happens to an element less than the current index, it'd throw things off in the loop.\n _listeners[_i](time, _delta, frame, v);\n }\n }\n };\n\n _self = {\n time: 0,\n frame: 0,\n tick: function tick() {\n _tick(true);\n },\n deltaRatio: function deltaRatio(fps) {\n return _delta / (1000 / (fps || 60));\n },\n wake: function wake() {\n if (_coreReady) {\n if (!_coreInitted && _windowExists()) {\n _win = _coreInitted = window;\n _doc = _win.document || {};\n _globals.gsap = gsap;\n (_win.gsapVersions || (_win.gsapVersions = [])).push(gsap.version);\n\n _install(_installScope || _win.GreenSockGlobals || !_win.gsap && _win || {});\n\n _registerPluginQueue.forEach(_createPlugin);\n }\n\n _raf = typeof requestAnimationFrame !== \"undefined\" && requestAnimationFrame;\n _id && _self.sleep();\n\n _req = _raf || function (f) {\n return setTimeout(f, _nextTime - _self.time * 1000 + 1 | 0);\n };\n\n _tickerActive = 1;\n\n _tick(2);\n }\n },\n sleep: function sleep() {\n (_raf ? cancelAnimationFrame : clearTimeout)(_id);\n _tickerActive = 0;\n _req = _emptyFunc;\n },\n lagSmoothing: function lagSmoothing(threshold, adjustedLag) {\n _lagThreshold = threshold || Infinity; // zero should be interpreted as basically unlimited\n\n _adjustedLag = Math.min(adjustedLag || 33, _lagThreshold);\n },\n fps: function fps(_fps) {\n _gap = 1000 / (_fps || 240);\n _nextTime = _self.time * 1000 + _gap;\n },\n add: function add(callback, once, prioritize) {\n var func = once ? function (t, d, f, v) {\n callback(t, d, f, v);\n\n _self.remove(func);\n } : callback;\n\n _self.remove(callback);\n\n _listeners[prioritize ? \"unshift\" : \"push\"](func);\n\n _wake();\n\n return func;\n },\n remove: function remove(callback, i) {\n ~(i = _listeners.indexOf(callback)) && _listeners.splice(i, 1) && _i >= i && _i--;\n },\n _listeners: _listeners\n };\n return _self;\n}(),\n _wake = function _wake() {\n return !_tickerActive && _ticker.wake();\n},\n //also ensures the core classes are initialized.\n\n/*\n* -------------------------------------------------\n* EASING\n* -------------------------------------------------\n*/\n_easeMap = {},\n _customEaseExp = /^[\\d.\\-M][\\d.\\-,\\s]/,\n _quotesExp = /[\"']/g,\n _parseObjectInString = function _parseObjectInString(value) {\n //takes a string like \"{wiggles:10, type:anticipate})\" and turns it into a real object. Notice it ends in \")\" and includes the {} wrappers. This is because we only use this function for parsing ease configs and prioritized optimization rather than reusability.\n var obj = {},\n split = value.substr(1, value.length - 3).split(\":\"),\n key = split[0],\n i = 1,\n l = split.length,\n index,\n val,\n parsedVal;\n\n for (; i < l; i++) {\n val = split[i];\n index = i !== l - 1 ? val.lastIndexOf(\",\") : val.length;\n parsedVal = val.substr(0, index);\n obj[key] = isNaN(parsedVal) ? parsedVal.replace(_quotesExp, \"\").trim() : +parsedVal;\n key = val.substr(index + 1).trim();\n }\n\n return obj;\n},\n _valueInParentheses = function _valueInParentheses(value) {\n var open = value.indexOf(\"(\") + 1,\n close = value.indexOf(\")\"),\n nested = value.indexOf(\"(\", open);\n return value.substring(open, ~nested && nested < close ? value.indexOf(\")\", close + 1) : close);\n},\n _configEaseFromString = function _configEaseFromString(name) {\n //name can be a string like \"elastic.out(1,0.5)\", and pass in _easeMap as obj and it'll parse it out and call the actual function like _easeMap.Elastic.easeOut.config(1,0.5). It will also parse custom ease strings as long as CustomEase is loaded and registered (internally as _easeMap._CE).\n var split = (name + \"\").split(\"(\"),\n ease = _easeMap[split[0]];\n 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;\n},\n _invertEase = function _invertEase(ease) {\n return function (p) {\n return 1 - ease(1 - p);\n };\n},\n // allow yoyoEase to be set in children and have those affected when the parent/ancestor timeline yoyos.\n_propagateYoyoEase = function _propagateYoyoEase(timeline, isYoyo) {\n var child = timeline._first,\n ease;\n\n while (child) {\n if (child instanceof Timeline) {\n _propagateYoyoEase(child, isYoyo);\n } else if (child.vars.yoyoEase && (!child._yoyo || !child._repeat) && child._yoyo !== isYoyo) {\n if (child.timeline) {\n _propagateYoyoEase(child.timeline, isYoyo);\n } else {\n ease = child._ease;\n child._ease = child._yEase;\n child._yEase = ease;\n child._yoyo = isYoyo;\n }\n }\n\n child = child._next;\n }\n},\n _parseEase = function _parseEase(ease, defaultEase) {\n return !ease ? defaultEase : (_isFunction(ease) ? ease : _easeMap[ease] || _configEaseFromString(ease)) || defaultEase;\n},\n _insertEase = function _insertEase(names, easeIn, easeOut, easeInOut) {\n if (easeOut === void 0) {\n easeOut = function easeOut(p) {\n return 1 - easeIn(1 - p);\n };\n }\n\n if (easeInOut === void 0) {\n easeInOut = function easeInOut(p) {\n return p < .5 ? easeIn(p * 2) / 2 : 1 - easeIn((1 - p) * 2) / 2;\n };\n }\n\n var ease = {\n easeIn: easeIn,\n easeOut: easeOut,\n easeInOut: easeInOut\n },\n lowercaseName;\n\n _forEachName(names, function (name) {\n _easeMap[name] = _globals[name] = ease;\n _easeMap[lowercaseName = name.toLowerCase()] = easeOut;\n\n for (var p in ease) {\n _easeMap[lowercaseName + (p === \"easeIn\" ? \".in\" : p === \"easeOut\" ? \".out\" : \".inOut\")] = _easeMap[name + \".\" + p] = ease[p];\n }\n });\n\n return ease;\n},\n _easeInOutFromOut = function _easeInOutFromOut(easeOut) {\n return function (p) {\n return p < .5 ? (1 - easeOut(1 - p * 2)) / 2 : .5 + easeOut((p - .5) * 2) / 2;\n };\n},\n _configElastic = function _configElastic(type, amplitude, period) {\n var p1 = amplitude >= 1 ? amplitude : 1,\n //note: if amplitude is < 1, we simply adjust the period for a more natural feel. Otherwise the math doesn't work right and the curve starts at 1.\n p2 = (period || (type ? .3 : .45)) / (amplitude < 1 ? amplitude : 1),\n p3 = p2 / _2PI * (Math.asin(1 / p1) || 0),\n easeOut = function easeOut(p) {\n return p === 1 ? 1 : p1 * Math.pow(2, -10 * p) * _sin((p - p3) * p2) + 1;\n },\n ease = type === \"out\" ? easeOut : type === \"in\" ? function (p) {\n return 1 - easeOut(1 - p);\n } : _easeInOutFromOut(easeOut);\n\n p2 = _2PI / p2; //precalculate to optimize\n\n ease.config = function (amplitude, period) {\n return _configElastic(type, amplitude, period);\n };\n\n return ease;\n},\n _configBack = function _configBack(type, overshoot) {\n if (overshoot === void 0) {\n overshoot = 1.70158;\n }\n\n var easeOut = function easeOut(p) {\n return p ? --p * p * ((overshoot + 1) * p + overshoot) + 1 : 0;\n },\n ease = type === \"out\" ? easeOut : type === \"in\" ? function (p) {\n return 1 - easeOut(1 - p);\n } : _easeInOutFromOut(easeOut);\n\n ease.config = function (overshoot) {\n return _configBack(type, overshoot);\n };\n\n return ease;\n}; // a cheaper (kb and cpu) but more mild way to get a parameterized weighted ease by feeding in a value between -1 (easeIn) and 1 (easeOut) where 0 is linear.\n// _weightedEase = ratio => {\n// \tlet y = 0.5 + ratio / 2;\n// \treturn p => (2 * (1 - p) * p * y + p * p);\n// },\n// a stronger (but more expensive kb/cpu) parameterized weighted ease that lets you feed in a value between -1 (easeIn) and 1 (easeOut) where 0 is linear.\n// _weightedEaseStrong = ratio => {\n// \tratio = .5 + ratio / 2;\n// \tlet o = 1 / 3 * (ratio < .5 ? ratio : 1 - ratio),\n// \t\tb = ratio - o,\n// \t\tc = ratio + o;\n// \treturn p => p === 1 ? p : 3 * b * (1 - p) * (1 - p) * p + 3 * c * (1 - p) * p * p + p * p * p;\n// };\n\n\n_forEachName(\"Linear,Quad,Cubic,Quart,Quint,Strong\", function (name, i) {\n var power = i < 5 ? i + 1 : i;\n\n _insertEase(name + \",Power\" + (power - 1), i ? function (p) {\n return Math.pow(p, power);\n } : function (p) {\n return p;\n }, function (p) {\n return 1 - Math.pow(1 - p, power);\n }, function (p) {\n return p < .5 ? Math.pow(p * 2, power) / 2 : 1 - Math.pow((1 - p) * 2, power) / 2;\n });\n});\n\n_easeMap.Linear.easeNone = _easeMap.none = _easeMap.Linear.easeIn;\n\n_insertEase(\"Elastic\", _configElastic(\"in\"), _configElastic(\"out\"), _configElastic());\n\n(function (n, c) {\n var n1 = 1 / c,\n n2 = 2 * n1,\n n3 = 2.5 * n1,\n easeOut = function easeOut(p) {\n 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;\n };\n\n _insertEase(\"Bounce\", function (p) {\n return 1 - easeOut(1 - p);\n }, easeOut);\n})(7.5625, 2.75);\n\n_insertEase(\"Expo\", function (p) {\n return p ? Math.pow(2, 10 * (p - 1)) : 0;\n});\n\n_insertEase(\"Circ\", function (p) {\n return -(_sqrt(1 - p * p) - 1);\n});\n\n_insertEase(\"Sine\", function (p) {\n return p === 1 ? 1 : -_cos(p * _HALF_PI) + 1;\n});\n\n_insertEase(\"Back\", _configBack(\"in\"), _configBack(\"out\"), _configBack());\n\n_easeMap.SteppedEase = _easeMap.steps = _globals.SteppedEase = {\n config: function config(steps, immediateStart) {\n if (steps === void 0) {\n steps = 1;\n }\n\n var p1 = 1 / steps,\n p2 = steps + (immediateStart ? 0 : 1),\n p3 = immediateStart ? 1 : 0,\n max = 1 - _tinyNum;\n return function (p) {\n return ((p2 * _clamp(0, max, p) | 0) + p3) * p1;\n };\n }\n};\n_defaults.ease = _easeMap[\"quad.out\"];\n\n_forEachName(\"onComplete,onUpdate,onStart,onRepeat,onReverseComplete,onInterrupt\", function (name) {\n return _callbackNames += name + \",\" + name + \"Params,\";\n});\n/*\n * --------------------------------------------------------------------------------------\n * CACHE\n * --------------------------------------------------------------------------------------\n */\n\n\nvar GSCache = function GSCache(target, harness) {\n this.id = _gsID++;\n target._gsap = this;\n this.target = target;\n this.harness = harness;\n this.get = harness ? harness.get : _getProperty;\n this.set = harness ? harness.getSetter : _getSetter;\n};\n/*\n * --------------------------------------------------------------------------------------\n * ANIMATION\n * --------------------------------------------------------------------------------------\n */\n\nvar Animation = /*#__PURE__*/function () {\n function Animation(vars) {\n this.vars = vars;\n this._delay = +vars.delay || 0;\n\n if (this._repeat = vars.repeat === Infinity ? -2 : vars.repeat || 0) {\n // TODO: repeat: Infinity on a timeline's children must flag that timeline internally and affect its totalDuration, otherwise it'll stop in the negative direction when reaching the start.\n this._rDelay = vars.repeatDelay || 0;\n this._yoyo = !!vars.yoyo || !!vars.yoyoEase;\n }\n\n this._ts = 1;\n\n _setDuration(this, +vars.duration, 1, 1);\n\n this.data = vars.data;\n\n if (_context) {\n this._ctx = _context;\n\n _context.data.push(this);\n }\n\n _tickerActive || _ticker.wake();\n }\n\n var _proto = Animation.prototype;\n\n _proto.delay = function delay(value) {\n if (value || value === 0) {\n this.parent && this.parent.smoothChildTiming && this.startTime(this._start + value - this._delay);\n this._delay = value;\n return this;\n }\n\n return this._delay;\n };\n\n _proto.duration = function duration(value) {\n return arguments.length ? this.totalDuration(this._repeat > 0 ? value + (value + this._rDelay) * this._repeat : value) : this.totalDuration() && this._dur;\n };\n\n _proto.totalDuration = function totalDuration(value) {\n if (!arguments.length) {\n return this._tDur;\n }\n\n this._dirty = 0;\n return _setDuration(this, this._repeat < 0 ? value : (value - this._repeat * this._rDelay) / (this._repeat + 1));\n };\n\n _proto.totalTime = function totalTime(_totalTime, suppressEvents) {\n _wake();\n\n if (!arguments.length) {\n return this._tTime;\n }\n\n var parent = this._dp;\n\n if (parent && parent.smoothChildTiming && this._ts) {\n _alignPlayhead(this, _totalTime);\n\n !parent._dp || parent.parent || _postAddChecks(parent, this); // edge case: if this is a child of a timeline that already completed, for example, we must re-activate the parent.\n //in case any of the ancestor timelines had completed but should now be enabled, we should reset their totalTime() which will also ensure that they're lined up properly and enabled. Skip for animations that are on the root (wasteful). Example: a TimelineLite.exportRoot() is performed when there's a paused tween on the root, the export will not complete until that tween is unpaused, but imagine a child gets restarted later, after all [unpaused] tweens have completed. The start of that child would get pushed out, but one of the ancestors may have completed.\n\n while (parent && parent.parent) {\n if (parent.parent._time !== parent._start + (parent._ts >= 0 ? parent._tTime / parent._ts : (parent.totalDuration() - parent._tTime) / -parent._ts)) {\n parent.totalTime(parent._tTime, true);\n }\n\n parent = parent.parent;\n }\n\n if (!this.parent && this._dp.autoRemoveChildren && (this._ts > 0 && _totalTime < this._tDur || this._ts < 0 && _totalTime > 0 || !this._tDur && !_totalTime)) {\n //if the animation doesn't have a parent, put it back into its last parent (recorded as _dp for exactly cases like this). Limit to parents with autoRemoveChildren (like globalTimeline) so that if the user manually removes an animation from a timeline and then alters its playhead, it doesn't get added back in.\n _addToTimeline(this._dp, this, this._start - this._delay);\n }\n }\n\n if (this._tTime !== _totalTime || !this._dur && !suppressEvents || this._initted && Math.abs(this._zTime) === _tinyNum || !_totalTime && !this._initted && (this.add || this._ptLookup)) {\n // check for _ptLookup on a Tween instance to ensure it has actually finished being instantiated, otherwise if this.reverse() gets called in the Animation constructor, it could trigger a render() here even though the _targets weren't populated, thus when _init() is called there won't be any PropTweens (it'll act like the tween is non-functional)\n this._ts || (this._pTime = _totalTime); // otherwise, if an animation is paused, then the playhead is moved back to zero, then resumed, it'd revert back to the original time at the pause\n //if (!this._lock) { // avoid endless recursion (not sure we need this yet or if it's worth the performance hit)\n // this._lock = 1;\n\n _lazySafeRender(this, _totalTime, suppressEvents); // this._lock = 0;\n //}\n\n }\n\n return this;\n };\n\n _proto.time = function time(value, suppressEvents) {\n return arguments.length ? this.totalTime(Math.min(this.totalDuration(), value + _elapsedCycleDuration(this)) % (this._dur + this._rDelay) || (value ? this._dur : 0), suppressEvents) : this._time; // note: if the modulus results in 0, the playhead could be exactly at the end or the beginning, and we always defer to the END with a non-zero value, otherwise if you set the time() to the very end (duration()), it would render at the START!\n };\n\n _proto.totalProgress = function totalProgress(value, suppressEvents) {\n return arguments.length ? this.totalTime(this.totalDuration() * value, suppressEvents) : this.totalDuration() ? Math.min(1, this._tTime / this._tDur) : this.rawTime() > 0 ? 1 : 0;\n };\n\n _proto.progress = function progress(value, suppressEvents) {\n return arguments.length ? this.totalTime(this.duration() * (this._yoyo && !(this.iteration() & 1) ? 1 - value : value) + _elapsedCycleDuration(this), suppressEvents) : this.duration() ? Math.min(1, this._time / this._dur) : this.rawTime() > 0 ? 1 : 0;\n };\n\n _proto.iteration = function iteration(value, suppressEvents) {\n var cycleDuration = this.duration() + this._rDelay;\n\n return arguments.length ? this.totalTime(this._time + (value - 1) * cycleDuration, suppressEvents) : this._repeat ? _animationCycle(this._tTime, cycleDuration) + 1 : 1;\n } // potential future addition:\n // isPlayingBackwards() {\n // \tlet animation = this,\n // \t\torientation = 1; // 1 = forward, -1 = backward\n // \twhile (animation) {\n // \t\torientation *= animation.reversed() || (animation.repeat() && !(animation.iteration() & 1)) ? -1 : 1;\n // \t\tanimation = animation.parent;\n // \t}\n // \treturn orientation < 0;\n // }\n ;\n\n _proto.timeScale = function timeScale(value, suppressEvents) {\n if (!arguments.length) {\n return this._rts === -_tinyNum ? 0 : this._rts; // recorded timeScale. Special case: if someone calls reverse() on an animation with timeScale of 0, we assign it -_tinyNum to remember it's reversed.\n }\n\n if (this._rts === value) {\n return this;\n }\n\n var tTime = this.parent && this._ts ? _parentToChildTotalTime(this.parent._time, this) : this._tTime; // make sure to do the parentToChildTotalTime() BEFORE setting the new _ts because the old one must be used in that calculation.\n // future addition? Up side: fast and minimal file size. Down side: only works on this animation; if a timeline is reversed, for example, its childrens' onReverse wouldn't get called.\n //(+value < 0 && this._rts >= 0) && _callback(this, \"onReverse\", true);\n // prioritize rendering where the parent's playhead lines up instead of this._tTime because there could be a tween that's animating another tween's timeScale in the same rendering loop (same parent), thus if the timeScale tween renders first, it would alter _start BEFORE _tTime was set on that tick (in the rendering loop), effectively freezing it until the timeScale tween finishes.\n\n this._rts = +value || 0;\n this._ts = this._ps || value === -_tinyNum ? 0 : this._rts; // _ts is the functional timeScale which would be 0 if the animation is paused.\n\n this.totalTime(_clamp(-Math.abs(this._delay), this._tDur, tTime), suppressEvents !== false);\n\n _setEnd(this); // if parent.smoothChildTiming was false, the end time didn't get updated in the _alignPlayhead() method, so do it here.\n\n\n return _recacheAncestors(this);\n };\n\n _proto.paused = function paused(value) {\n if (!arguments.length) {\n return this._ps;\n }\n\n if (this._ps !== value) {\n this._ps = value;\n\n if (value) {\n this._pTime = this._tTime || Math.max(-this._delay, this.rawTime()); // if the pause occurs during the delay phase, make sure that's factored in when resuming.\n\n this._ts = this._act = 0; // _ts is the functional timeScale, so a paused tween would effectively have a timeScale of 0. We record the \"real\" timeScale as _rts (recorded time scale)\n } else {\n _wake();\n\n this._ts = this._rts; //only defer to _pTime (pauseTime) if tTime is zero. Remember, someone could pause() an animation, then scrub the playhead and resume(). If the parent doesn't have smoothChildTiming, we render at the rawTime() because the startTime won't get updated.\n\n this.totalTime(this.parent && !this.parent.smoothChildTiming ? this.rawTime() : this._tTime || this._pTime, this.progress() === 1 && Math.abs(this._zTime) !== _tinyNum && (this._tTime -= _tinyNum)); // edge case: animation.progress(1).pause().play() wouldn't render again because the playhead is already at the end, but the call to totalTime() below will add it back to its parent...and not remove it again (since removing only happens upon rendering at a new time). Offsetting the _tTime slightly is done simply to cause the final render in totalTime() that'll pop it off its timeline (if autoRemoveChildren is true, of course). Check to make sure _zTime isn't -_tinyNum to avoid an edge case where the playhead is pushed to the end but INSIDE a tween/callback, the timeline itself is paused thus halting rendering and leaving a few unrendered. When resuming, it wouldn't render those otherwise.\n }\n }\n\n return this;\n };\n\n _proto.startTime = function startTime(value) {\n if (arguments.length) {\n this._start = value;\n var parent = this.parent || this._dp;\n parent && (parent._sort || !this.parent) && _addToTimeline(parent, this, value - this._delay);\n return this;\n }\n\n return this._start;\n };\n\n _proto.endTime = function endTime(includeRepeats) {\n return this._start + (_isNotFalse(includeRepeats) ? this.totalDuration() : this.duration()) / Math.abs(this._ts || 1);\n };\n\n _proto.rawTime = function rawTime(wrapRepeats) {\n var parent = this.parent || this._dp; // _dp = detached parent\n\n 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);\n };\n\n _proto.revert = function revert(config) {\n if (config === void 0) {\n config = _revertConfig;\n }\n\n var prevIsReverting = _reverting;\n _reverting = config;\n\n if (this._initted || this._startAt) {\n this.timeline && this.timeline.revert(config);\n this.totalTime(-0.01, config.suppressEvents);\n }\n\n this.data !== \"nested\" && config.kill !== false && this.kill();\n _reverting = prevIsReverting;\n return this;\n };\n\n _proto.globalTime = function globalTime(rawTime) {\n var animation = this,\n time = arguments.length ? rawTime : animation.rawTime();\n\n while (animation) {\n time = animation._start + time / (Math.abs(animation._ts) || 1);\n animation = animation._dp;\n }\n\n return !this.parent && this._sat ? this._sat.globalTime(rawTime) : time; // the _startAt tweens for .fromTo() and .from() that have immediateRender should always be FIRST in the timeline (important for context.revert()). \"_sat\" stands for _startAtTween, referring to the parent tween that created the _startAt. We must discern if that tween had immediateRender so that we can know whether or not to prioritize it in revert().\n };\n\n _proto.repeat = function repeat(value) {\n if (arguments.length) {\n this._repeat = value === Infinity ? -2 : value;\n return _onUpdateTotalDuration(this);\n }\n\n return this._repeat === -2 ? Infinity : this._repeat;\n };\n\n _proto.repeatDelay = function repeatDelay(value) {\n if (arguments.length) {\n var time = this._time;\n this._rDelay = value;\n\n _onUpdateTotalDuration(this);\n\n return time ? this.time(time) : this;\n }\n\n return this._rDelay;\n };\n\n _proto.yoyo = function yoyo(value) {\n if (arguments.length) {\n this._yoyo = value;\n return this;\n }\n\n return this._yoyo;\n };\n\n _proto.seek = function seek(position, suppressEvents) {\n return this.totalTime(_parsePosition(this, position), _isNotFalse(suppressEvents));\n };\n\n _proto.restart = function restart(includeDelay, suppressEvents) {\n return this.play().totalTime(includeDelay ? -this._delay : 0, _isNotFalse(suppressEvents));\n };\n\n _proto.play = function play(from, suppressEvents) {\n from != null && this.seek(from, suppressEvents);\n return this.reversed(false).paused(false);\n };\n\n _proto.reverse = function reverse(from, suppressEvents) {\n from != null && this.seek(from || this.totalDuration(), suppressEvents);\n return this.reversed(true).paused(false);\n };\n\n _proto.pause = function pause(atTime, suppressEvents) {\n atTime != null && this.seek(atTime, suppressEvents);\n return this.paused(true);\n };\n\n _proto.resume = function resume() {\n return this.paused(false);\n };\n\n _proto.reversed = function reversed(value) {\n if (arguments.length) {\n !!value !== this.reversed() && this.timeScale(-this._rts || (value ? -_tinyNum : 0)); // in case timeScale is zero, reversing would have no effect so we use _tinyNum.\n\n return this;\n }\n\n return this._rts < 0;\n };\n\n _proto.invalidate = function invalidate() {\n this._initted = this._act = 0;\n this._zTime = -_tinyNum;\n return this;\n };\n\n _proto.isActive = function isActive() {\n var parent = this.parent || this._dp,\n start = this._start,\n rawTime;\n return !!(!parent || this._ts && this._initted && parent.isActive() && (rawTime = parent.rawTime(true)) >= start && rawTime < this.endTime(true) - _tinyNum);\n };\n\n _proto.eventCallback = function eventCallback(type, callback, params) {\n var vars = this.vars;\n\n if (arguments.length > 1) {\n if (!callback) {\n delete vars[type];\n } else {\n vars[type] = callback;\n params && (vars[type + \"Params\"] = params);\n type === \"onUpdate\" && (this._onUpdate = callback);\n }\n\n return this;\n }\n\n return vars[type];\n };\n\n _proto.then = function then(onFulfilled) {\n var self = this;\n return new Promise(function (resolve) {\n var f = _isFunction(onFulfilled) ? onFulfilled : _passThrough,\n _resolve = function _resolve() {\n var _then = self.then;\n self.then = null; // temporarily null the then() method to avoid an infinite loop (see https://github.com/greensock/GSAP/issues/322)\n\n _isFunction(f) && (f = f(self)) && (f.then || f === self) && (self.then = _then);\n resolve(f);\n self.then = _then;\n };\n\n if (self._initted && self.totalProgress() === 1 && self._ts >= 0 || !self._tTime && self._ts < 0) {\n _resolve();\n } else {\n self._prom = _resolve;\n }\n });\n };\n\n _proto.kill = function kill() {\n _interrupt(this);\n };\n\n return Animation;\n}();\n\n_setDefaults(Animation.prototype, {\n _time: 0,\n _start: 0,\n _end: 0,\n _tTime: 0,\n _tDur: 0,\n _dirty: 0,\n _repeat: 0,\n _yoyo: false,\n parent: null,\n _initted: false,\n _rDelay: 0,\n _ts: 1,\n _dp: 0,\n ratio: 0,\n _zTime: -_tinyNum,\n _prom: 0,\n _ps: false,\n _rts: 1\n});\n/*\n * -------------------------------------------------\n * TIMELINE\n * -------------------------------------------------\n */\n\n\nvar Timeline = /*#__PURE__*/function (_Animation) {\n _inheritsLoose(Timeline, _Animation);\n\n function Timeline(vars, position) {\n var _this;\n\n if (vars === void 0) {\n vars = {};\n }\n\n _this = _Animation.call(this, vars) || this;\n _this.labels = {};\n _this.smoothChildTiming = !!vars.smoothChildTiming;\n _this.autoRemoveChildren = !!vars.autoRemoveChildren;\n _this._sort = _isNotFalse(vars.sortChildren);\n _globalTimeline && _addToTimeline(vars.parent || _globalTimeline, _assertThisInitialized(_this), position);\n vars.reversed && _this.reverse();\n vars.paused && _this.paused(true);\n vars.scrollTrigger && _scrollTrigger(_assertThisInitialized(_this), vars.scrollTrigger);\n return _this;\n }\n\n var _proto2 = Timeline.prototype;\n\n _proto2.to = function to(targets, vars, position) {\n _createTweenType(0, arguments, this);\n\n return this;\n };\n\n _proto2.from = function from(targets, vars, position) {\n _createTweenType(1, arguments, this);\n\n return this;\n };\n\n _proto2.fromTo = function fromTo(targets, fromVars, toVars, position) {\n _createTweenType(2, arguments, this);\n\n return this;\n };\n\n _proto2.set = function set(targets, vars, position) {\n vars.duration = 0;\n vars.parent = this;\n _inheritDefaults(vars).repeatDelay || (vars.repeat = 0);\n vars.immediateRender = !!vars.immediateRender;\n new Tween(targets, vars, _parsePosition(this, position), 1);\n return this;\n };\n\n _proto2.call = function call(callback, params, position) {\n return _addToTimeline(this, Tween.delayedCall(0, callback, params), position);\n } //ONLY for backward compatibility! Maybe delete?\n ;\n\n _proto2.staggerTo = function staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams) {\n vars.duration = duration;\n vars.stagger = vars.stagger || stagger;\n vars.onComplete = onCompleteAll;\n vars.onCompleteParams = onCompleteAllParams;\n vars.parent = this;\n new Tween(targets, vars, _parsePosition(this, position));\n return this;\n };\n\n _proto2.staggerFrom = function staggerFrom(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams) {\n vars.runBackwards = 1;\n _inheritDefaults(vars).immediateRender = _isNotFalse(vars.immediateRender);\n return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams);\n };\n\n _proto2.staggerFromTo = function staggerFromTo(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams) {\n toVars.startAt = fromVars;\n _inheritDefaults(toVars).immediateRender = _isNotFalse(toVars.immediateRender);\n return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams);\n };\n\n _proto2.render = function render(totalTime, suppressEvents, force) {\n var prevTime = this._time,\n tDur = this._dirty ? this.totalDuration() : this._tDur,\n dur = this._dur,\n tTime = totalTime <= 0 ? 0 : _roundPrecise(totalTime),\n // if a paused timeline is resumed (or its _start is updated for another reason...which rounds it), that could result in the playhead shifting a **tiny** amount and a zero-duration child at that spot may get rendered at a different ratio, like its totalTime in render() may be 1e-17 instead of 0, for example.\n crossingStart = this._zTime < 0 !== totalTime < 0 && (this._initted || !dur),\n time,\n child,\n next,\n iteration,\n cycleDuration,\n prevPaused,\n pauseTween,\n timeScale,\n prevStart,\n prevIteration,\n yoyo,\n isYoyo;\n this !== _globalTimeline && tTime > tDur && totalTime >= 0 && (tTime = tDur);\n\n if (tTime !== this._tTime || force || crossingStart) {\n if (prevTime !== this._time && dur) {\n //if totalDuration() finds a child with a negative startTime and smoothChildTiming is true, things get shifted around internally so we need to adjust the time accordingly. For example, if a tween starts at -30 we must shift EVERYTHING forward 30 seconds and move this timeline's startTime backward by 30 seconds so that things align with the playhead (no jump).\n tTime += this._time - prevTime;\n totalTime += this._time - prevTime;\n }\n\n time = tTime;\n prevStart = this._start;\n timeScale = this._ts;\n prevPaused = !timeScale;\n\n if (crossingStart) {\n dur || (prevTime = this._zTime); //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect.\n\n (totalTime || !suppressEvents) && (this._zTime = totalTime);\n }\n\n if (this._repeat) {\n //adjust the time for repeats and yoyos\n yoyo = this._yoyo;\n cycleDuration = dur + this._rDelay;\n\n if (this._repeat < -1 && totalTime < 0) {\n return this.totalTime(cycleDuration * 100 + totalTime, suppressEvents, force);\n }\n\n time = _roundPrecise(tTime % cycleDuration); //round to avoid floating point errors. (4 % 0.8 should be 0 but some browsers report it as 0.79999999!)\n\n if (tTime === tDur) {\n // the tDur === tTime is for edge cases where there's a lengthy decimal on the duration and it may reach the very end but the time is rendered as not-quite-there (remember, tDur is rounded to 4 decimals whereas dur isn't)\n iteration = this._repeat;\n time = dur;\n } else {\n iteration = ~~(tTime / cycleDuration);\n\n if (iteration && iteration === tTime / cycleDuration) {\n time = dur;\n iteration--;\n }\n\n time > dur && (time = dur);\n }\n\n prevIteration = _animationCycle(this._tTime, cycleDuration);\n !prevTime && this._tTime && prevIteration !== iteration && this._tTime - prevIteration * cycleDuration - this._dur <= 0 && (prevIteration = iteration); // edge case - if someone does addPause() at the very beginning of a repeating timeline, that pause is technically at the same spot as the end which causes this._time to get set to 0 when the totalTime would normally place the playhead at the end. See https://gsap.com/forums/topic/23823-closing-nav-animation-not-working-on-ie-and-iphone-6-maybe-other-older-browser/?tab=comments#comment-113005 also, this._tTime - prevIteration * cycleDuration - this._dur <= 0 just checks to make sure it wasn't previously in the \"repeatDelay\" portion\n\n if (yoyo && iteration & 1) {\n time = dur - time;\n isYoyo = 1;\n }\n /*\n make sure children at the end/beginning of the timeline are rendered properly. If, for example,\n a 3-second long timeline rendered at 2.9 seconds previously, and now renders at 3.2 seconds (which\n would get translated to 2.8 seconds if the timeline yoyos or 0.2 seconds if it just repeats), there\n could be a callback or a short tween that's at 2.95 or 3 seconds in which wouldn't render. So\n we need to push the timeline to the end (and/or beginning depending on its yoyo value). Also we must\n ensure that zero-duration tweens at the very beginning or end of the Timeline work.\n */\n\n\n if (iteration !== prevIteration && !this._lock) {\n var rewinding = yoyo && prevIteration & 1,\n doesWrap = rewinding === (yoyo && iteration & 1);\n iteration < prevIteration && (rewinding = !rewinding);\n prevTime = rewinding ? 0 : tTime % dur ? dur : tTime; // if the playhead is landing exactly at the end of an iteration, use that totalTime rather than only the duration, otherwise it'll skip the 2nd render since it's effectively at the same time.\n\n this._lock = 1;\n this.render(prevTime || (isYoyo ? 0 : _roundPrecise(iteration * cycleDuration)), suppressEvents, !dur)._lock = 0;\n this._tTime = tTime; // if a user gets the iteration() inside the onRepeat, for example, it should be accurate.\n\n !suppressEvents && this.parent && _callback(this, \"onRepeat\");\n this.vars.repeatRefresh && !isYoyo && (this.invalidate()._lock = 1);\n\n if (prevTime && prevTime !== this._time || prevPaused !== !this._ts || this.vars.onRepeat && !this.parent && !this._act) {\n // if prevTime is 0 and we render at the very end, _time will be the end, thus won't match. So in this edge case, prevTime won't match _time but that's okay. If it gets killed in the onRepeat, eject as well.\n return this;\n }\n\n dur = this._dur; // in case the duration changed in the onRepeat\n\n tDur = this._tDur;\n\n if (doesWrap) {\n this._lock = 2;\n prevTime = rewinding ? dur : -0.0001;\n this.render(prevTime, true);\n this.vars.repeatRefresh && !isYoyo && this.invalidate();\n }\n\n this._lock = 0;\n\n if (!this._ts && !prevPaused) {\n return this;\n } //in order for yoyoEase to work properly when there's a stagger, we must swap out the ease in each sub-tween.\n\n\n _propagateYoyoEase(this, isYoyo);\n }\n }\n\n if (this._hasPause && !this._forcing && this._lock < 2) {\n pauseTween = _findNextPauseTween(this, _roundPrecise(prevTime), _roundPrecise(time));\n\n if (pauseTween) {\n tTime -= time - (time = pauseTween._start);\n }\n }\n\n this._tTime = tTime;\n this._time = time;\n this._act = !timeScale; //as long as it's not paused, force it to be active so that if the user renders independent of the parent timeline, it'll be forced to re-render on the next tick.\n\n if (!this._initted) {\n this._onUpdate = this.vars.onUpdate;\n this._initted = 1;\n this._zTime = totalTime;\n prevTime = 0; // upon init, the playhead should always go forward; someone could invalidate() a completed timeline and then if they restart(), that would make child tweens render in reverse order which could lock in the wrong starting values if they build on each other, like tl.to(obj, {x: 100}).to(obj, {x: 0}).\n }\n\n if (!prevTime && time && !suppressEvents && !iteration) {\n _callback(this, \"onStart\");\n\n if (this._tTime !== tTime) {\n // in case the onStart triggered a render at a different spot, eject. Like if someone did animation.pause(0.5) or something inside the onStart.\n return this;\n }\n }\n\n if (time >= prevTime && totalTime >= 0) {\n child = this._first;\n\n while (child) {\n next = child._next;\n\n if ((child._act || time >= child._start) && child._ts && pauseTween !== child) {\n if (child.parent !== this) {\n // an extreme edge case - the child's render could do something like kill() the \"next\" one in the linked list, or reparent it. In that case we must re-initiate the whole render to be safe.\n return this.render(totalTime, suppressEvents, force);\n }\n\n child.render(child._ts > 0 ? (time - child._start) * child._ts : (child._dirty ? child.totalDuration() : child._tDur) + (time - child._start) * child._ts, suppressEvents, force);\n\n if (time !== this._time || !this._ts && !prevPaused) {\n //in case a tween pauses or seeks the timeline when rendering, like inside of an onUpdate/onComplete\n pauseTween = 0;\n next && (tTime += this._zTime = -_tinyNum); // it didn't finish rendering, so flag zTime as negative so that so that the next time render() is called it'll be forced (to render any remaining children)\n\n break;\n }\n }\n\n child = next;\n }\n } else {\n child = this._last;\n var adjustedTime = totalTime < 0 ? totalTime : time; //when the playhead goes backward beyond the start of this timeline, we must pass that information down to the child animations so that zero-duration tweens know whether to render their starting or ending values.\n\n while (child) {\n next = child._prev;\n\n if ((child._act || adjustedTime <= child._end) && child._ts && pauseTween !== child) {\n if (child.parent !== this) {\n // an extreme edge case - the child's render could do something like kill() the \"next\" one in the linked list, or reparent it. In that case we must re-initiate the whole render to be safe.\n return this.render(totalTime, suppressEvents, force);\n }\n\n child.render(child._ts > 0 ? (adjustedTime - child._start) * child._ts : (child._dirty ? child.totalDuration() : child._tDur) + (adjustedTime - child._start) * child._ts, suppressEvents, force || _reverting && (child._initted || child._startAt)); // if reverting, we should always force renders of initted tweens (but remember that .fromTo() or .from() may have a _startAt but not _initted yet). If, for example, a .fromTo() tween with a stagger (which creates an internal timeline) gets reverted BEFORE some of its child tweens render for the first time, it may not properly trigger them to revert.\n\n if (time !== this._time || !this._ts && !prevPaused) {\n //in case a tween pauses or seeks the timeline when rendering, like inside of an onUpdate/onComplete\n pauseTween = 0;\n next && (tTime += this._zTime = adjustedTime ? -_tinyNum : _tinyNum); // it didn't finish rendering, so adjust zTime so that so that the next time render() is called it'll be forced (to render any remaining children)\n\n break;\n }\n }\n\n child = next;\n }\n }\n\n if (pauseTween && !suppressEvents) {\n this.pause();\n pauseTween.render(time >= prevTime ? 0 : -_tinyNum)._zTime = time >= prevTime ? 1 : -1;\n\n if (this._ts) {\n //the callback resumed playback! So since we may have held back the playhead due to where the pause is positioned, go ahead and jump to where it's SUPPOSED to be (if no pause happened).\n this._start = prevStart; //if the pause was at an earlier time and the user resumed in the callback, it could reposition the timeline (changing its startTime), throwing things off slightly, so we make sure the _start doesn't shift.\n\n _setEnd(this);\n\n return this.render(totalTime, suppressEvents, force);\n }\n }\n\n this._onUpdate && !suppressEvents && _callback(this, \"onUpdate\", true);\n if (tTime === tDur && this._tTime >= this.totalDuration() || !tTime && prevTime) if (prevStart === this._start || Math.abs(timeScale) !== Math.abs(this._ts)) if (!this._lock) {\n // remember, a child's callback may alter this timeline's playhead or timeScale which is why we need to add some of these checks.\n (totalTime || !dur) && (tTime === tDur && this._ts > 0 || !tTime && this._ts < 0) && _removeFromParent(this, 1); // don't remove if the timeline is reversed and the playhead isn't at 0, otherwise tl.progress(1).reverse() won't work. Only remove if the playhead is at the end and timeScale is positive, or if the playhead is at 0 and the timeScale is negative.\n\n if (!suppressEvents && !(totalTime < 0 && !prevTime) && (tTime || prevTime || !tDur)) {\n _callback(this, tTime === tDur && totalTime >= 0 ? \"onComplete\" : \"onReverseComplete\", true);\n\n this._prom && !(tTime < tDur && this.timeScale() > 0) && this._prom();\n }\n }\n }\n\n return this;\n };\n\n _proto2.add = function add(child, position) {\n var _this2 = this;\n\n _isNumber(position) || (position = _parsePosition(this, position, child));\n\n if (!(child instanceof Animation)) {\n if (_isArray(child)) {\n child.forEach(function (obj) {\n return _this2.add(obj, position);\n });\n return this;\n }\n\n if (_isString(child)) {\n return this.addLabel(child, position);\n }\n\n if (_isFunction(child)) {\n child = Tween.delayedCall(0, child);\n } else {\n return this;\n }\n }\n\n return this !== child ? _addToTimeline(this, child, position) : this; //don't allow a timeline to be added to itself as a child!\n };\n\n _proto2.getChildren = function getChildren(nested, tweens, timelines, ignoreBeforeTime) {\n if (nested === void 0) {\n nested = true;\n }\n\n if (tweens === void 0) {\n tweens = true;\n }\n\n if (timelines === void 0) {\n timelines = true;\n }\n\n if (ignoreBeforeTime === void 0) {\n ignoreBeforeTime = -_bigNum;\n }\n\n var a = [],\n child = this._first;\n\n while (child) {\n if (child._start >= ignoreBeforeTime) {\n if (child instanceof Tween) {\n tweens && a.push(child);\n } else {\n timelines && a.push(child);\n nested && a.push.apply(a, child.getChildren(true, tweens, timelines));\n }\n }\n\n child = child._next;\n }\n\n return a;\n };\n\n _proto2.getById = function getById(id) {\n var animations = this.getChildren(1, 1, 1),\n i = animations.length;\n\n while (i--) {\n if (animations[i].vars.id === id) {\n return animations[i];\n }\n }\n };\n\n _proto2.remove = function remove(child) {\n if (_isString(child)) {\n return this.removeLabel(child);\n }\n\n if (_isFunction(child)) {\n return this.killTweensOf(child);\n }\n\n _removeLinkedListItem(this, child);\n\n if (child === this._recent) {\n this._recent = this._last;\n }\n\n return _uncache(this);\n };\n\n _proto2.totalTime = function totalTime(_totalTime2, suppressEvents) {\n if (!arguments.length) {\n return this._tTime;\n }\n\n this._forcing = 1;\n\n if (!this._dp && this._ts) {\n //special case for the global timeline (or any other that has no parent or detached parent).\n this._start = _roundPrecise(_ticker.time - (this._ts > 0 ? _totalTime2 / this._ts : (this.totalDuration() - _totalTime2) / -this._ts));\n }\n\n _Animation.prototype.totalTime.call(this, _totalTime2, suppressEvents);\n\n this._forcing = 0;\n return this;\n };\n\n _proto2.addLabel = function addLabel(label, position) {\n this.labels[label] = _parsePosition(this, position);\n return this;\n };\n\n _proto2.removeLabel = function removeLabel(label) {\n delete this.labels[label];\n return this;\n };\n\n _proto2.addPause = function addPause(position, callback, params) {\n var t = Tween.delayedCall(0, callback || _emptyFunc, params);\n t.data = \"isPause\";\n this._hasPause = 1;\n return _addToTimeline(this, t, _parsePosition(this, position));\n };\n\n _proto2.removePause = function removePause(position) {\n var child = this._first;\n position = _parsePosition(this, position);\n\n while (child) {\n if (child._start === position && child.data === \"isPause\") {\n _removeFromParent(child);\n }\n\n child = child._next;\n }\n };\n\n _proto2.killTweensOf = function killTweensOf(targets, props, onlyActive) {\n var tweens = this.getTweensOf(targets, onlyActive),\n i = tweens.length;\n\n while (i--) {\n _overwritingTween !== tweens[i] && tweens[i].kill(targets, props);\n }\n\n return this;\n };\n\n _proto2.getTweensOf = function getTweensOf(targets, onlyActive) {\n var a = [],\n parsedTargets = toArray(targets),\n child = this._first,\n isGlobalTime = _isNumber(onlyActive),\n // a number is interpreted as a global time. If the animation spans\n children;\n\n while (child) {\n if (child instanceof Tween) {\n if (_arrayContainsAny(child._targets, parsedTargets) && (isGlobalTime ? (!_overwritingTween || child._initted && child._ts) && child.globalTime(0) <= onlyActive && child.globalTime(child.totalDuration()) > onlyActive : !onlyActive || child.isActive())) {\n // note: if this is for overwriting, it should only be for tweens that aren't paused and are initted.\n a.push(child);\n }\n } else if ((children = child.getTweensOf(parsedTargets, onlyActive)).length) {\n a.push.apply(a, children);\n }\n\n child = child._next;\n }\n\n return a;\n } // potential future feature - targets() on timelines\n // targets() {\n // \tlet result = [];\n // \tthis.getChildren(true, true, false).forEach(t => result.push(...t.targets()));\n // \treturn result.filter((v, i) => result.indexOf(v) === i);\n // }\n ;\n\n _proto2.tweenTo = function tweenTo(position, vars) {\n vars = vars || {};\n\n var tl = this,\n endTime = _parsePosition(tl, position),\n _vars = vars,\n startAt = _vars.startAt,\n _onStart = _vars.onStart,\n onStartParams = _vars.onStartParams,\n immediateRender = _vars.immediateRender,\n initted,\n tween = Tween.to(tl, _setDefaults({\n ease: vars.ease || \"none\",\n lazy: false,\n immediateRender: false,\n time: endTime,\n overwrite: \"auto\",\n duration: vars.duration || Math.abs((endTime - (startAt && \"time\" in startAt ? startAt.time : tl._time)) / tl.timeScale()) || _tinyNum,\n onStart: function onStart() {\n tl.pause();\n\n if (!initted) {\n var duration = vars.duration || Math.abs((endTime - (startAt && \"time\" in startAt ? startAt.time : tl._time)) / tl.timeScale());\n tween._dur !== duration && _setDuration(tween, duration, 0, 1).render(tween._time, true, true);\n initted = 1;\n }\n\n _onStart && _onStart.apply(tween, onStartParams || []); //in case the user had an onStart in the vars - we don't want to overwrite it.\n }\n }, vars));\n\n return immediateRender ? tween.render(0) : tween;\n };\n\n _proto2.tweenFromTo = function tweenFromTo(fromPosition, toPosition, vars) {\n return this.tweenTo(toPosition, _setDefaults({\n startAt: {\n time: _parsePosition(this, fromPosition)\n }\n }, vars));\n };\n\n _proto2.recent = function recent() {\n return this._recent;\n };\n\n _proto2.nextLabel = function nextLabel(afterTime) {\n if (afterTime === void 0) {\n afterTime = this._time;\n }\n\n return _getLabelInDirection(this, _parsePosition(this, afterTime));\n };\n\n _proto2.previousLabel = function previousLabel(beforeTime) {\n if (beforeTime === void 0) {\n beforeTime = this._time;\n }\n\n return _getLabelInDirection(this, _parsePosition(this, beforeTime), 1);\n };\n\n _proto2.currentLabel = function currentLabel(value) {\n return arguments.length ? this.seek(value, true) : this.previousLabel(this._time + _tinyNum);\n };\n\n _proto2.shiftChildren = function shiftChildren(amount, adjustLabels, ignoreBeforeTime) {\n if (ignoreBeforeTime === void 0) {\n ignoreBeforeTime = 0;\n }\n\n var child = this._first,\n labels = this.labels,\n p;\n\n while (child) {\n if (child._start >= ignoreBeforeTime) {\n child._start += amount;\n child._end += amount;\n }\n\n child = child._next;\n }\n\n if (adjustLabels) {\n for (p in labels) {\n if (labels[p] >= ignoreBeforeTime) {\n labels[p] += amount;\n }\n }\n }\n\n return _uncache(this);\n };\n\n _proto2.invalidate = function invalidate(soft) {\n var child = this._first;\n this._lock = 0;\n\n while (child) {\n child.invalidate(soft);\n child = child._next;\n }\n\n return _Animation.prototype.invalidate.call(this, soft);\n };\n\n _proto2.clear = function clear(includeLabels) {\n if (includeLabels === void 0) {\n includeLabels = true;\n }\n\n var child = this._first,\n next;\n\n while (child) {\n next = child._next;\n this.remove(child);\n child = next;\n }\n\n this._dp && (this._time = this._tTime = this._pTime = 0);\n includeLabels && (this.labels = {});\n return _uncache(this);\n };\n\n _proto2.totalDuration = function totalDuration(value) {\n var max = 0,\n self = this,\n child = self._last,\n prevStart = _bigNum,\n prev,\n start,\n parent;\n\n if (arguments.length) {\n return self.timeScale((self._repeat < 0 ? self.duration() : self.totalDuration()) / (self.reversed() ? -value : value));\n }\n\n if (self._dirty) {\n parent = self.parent;\n\n while (child) {\n prev = child._prev; //record it here in case the tween changes position in the sequence...\n\n child._dirty && child.totalDuration(); //could change the tween._startTime, so make sure the animation's cache is clean before analyzing it.\n\n start = child._start;\n\n if (start > prevStart && self._sort && child._ts && !self._lock) {\n //in case one of the tweens shifted out of order, it needs to be re-inserted into the correct position in the sequence\n self._lock = 1; //prevent endless recursive calls - there are methods that get triggered that check duration/totalDuration when we add().\n\n _addToTimeline(self, child, start - child._delay, 1)._lock = 0;\n } else {\n prevStart = start;\n }\n\n if (start < 0 && child._ts) {\n //children aren't allowed to have negative startTimes unless smoothChildTiming is true, so adjust here if one is found.\n max -= start;\n\n if (!parent && !self._dp || parent && parent.smoothChildTiming) {\n self._start += start / self._ts;\n self._time -= start;\n self._tTime -= start;\n }\n\n self.shiftChildren(-start, false, -1e999);\n prevStart = 0;\n }\n\n child._end > max && child._ts && (max = child._end);\n child = prev;\n }\n\n _setDuration(self, self === _globalTimeline && self._time > max ? self._time : max, 1, 1);\n\n self._dirty = 0;\n }\n\n return self._tDur;\n };\n\n Timeline.updateRoot = function updateRoot(time) {\n if (_globalTimeline._ts) {\n _lazySafeRender(_globalTimeline, _parentToChildTotalTime(time, _globalTimeline));\n\n _lastRenderedFrame = _ticker.frame;\n }\n\n if (_ticker.frame >= _nextGCFrame) {\n _nextGCFrame += _config.autoSleep || 120;\n var child = _globalTimeline._first;\n if (!child || !child._ts) if (_config.autoSleep && _ticker._listeners.length < 2) {\n while (child && !child._ts) {\n child = child._next;\n }\n\n child || _ticker.sleep();\n }\n }\n };\n\n return Timeline;\n}(Animation);\n\n_setDefaults(Timeline.prototype, {\n _lock: 0,\n _hasPause: 0,\n _forcing: 0\n});\n\nvar _addComplexStringPropTween = function _addComplexStringPropTween(target, prop, start, end, setter, stringFilter, funcParam) {\n //note: we call _addComplexStringPropTween.call(tweenInstance...) to ensure that it's scoped properly. We may call it from within a plugin too, thus \"this\" would refer to the plugin.\n var pt = new PropTween(this._pt, target, prop, 0, 1, _renderComplexString, null, setter),\n index = 0,\n matchIndex = 0,\n result,\n startNums,\n color,\n endNum,\n chunk,\n startNum,\n hasRandom,\n a;\n pt.b = start;\n pt.e = end;\n start += \"\"; //ensure values are strings\n\n end += \"\";\n\n if (hasRandom = ~end.indexOf(\"random(\")) {\n end = _replaceRandom(end);\n }\n\n if (stringFilter) {\n a = [start, end];\n stringFilter(a, target, prop); //pass an array with the starting and ending values and let the filter do whatever it needs to the values.\n\n start = a[0];\n end = a[1];\n }\n\n startNums = start.match(_complexStringNumExp) || [];\n\n while (result = _complexStringNumExp.exec(end)) {\n endNum = result[0];\n chunk = end.substring(index, result.index);\n\n if (color) {\n color = (color + 1) % 5;\n } else if (chunk.substr(-5) === \"rgba(\") {\n color = 1;\n }\n\n if (endNum !== startNums[matchIndex++]) {\n startNum = parseFloat(startNums[matchIndex - 1]) || 0; //these nested PropTweens are handled in a special way - we'll never actually call a render or setter method on them. We'll just loop through them in the parent complex string PropTween's render method.\n\n pt._pt = {\n _next: pt._pt,\n p: chunk || matchIndex === 1 ? chunk : \",\",\n //note: SVG spec allows omission of comma/space when a negative sign is wedged between two numbers, like 2.5-5.3 instead of 2.5,-5.3 but when tweening, the negative value may switch to positive, so we insert the comma just in case.\n s: startNum,\n c: endNum.charAt(1) === \"=\" ? _parseRelative(startNum, endNum) - startNum : parseFloat(endNum) - startNum,\n m: color && color < 4 ? Math.round : 0\n };\n index = _complexStringNumExp.lastIndex;\n }\n }\n\n pt.c = index < end.length ? end.substring(index, end.length) : \"\"; //we use the \"c\" of the PropTween to store the final part of the string (after the last number)\n\n pt.fp = funcParam;\n\n if (_relExp.test(end) || hasRandom) {\n pt.e = 0; //if the end string contains relative values or dynamic random(...) values, delete the end it so that on the final render we don't actually set it to the string with += or -= characters (forces it to use the calculated value).\n }\n\n this._pt = pt; //start the linked list with this new PropTween. Remember, we call _addComplexStringPropTween.call(tweenInstance...) to ensure that it's scoped properly. We may call it from within a plugin too, thus \"this\" would refer to the plugin.\n\n return pt;\n},\n _addPropTween = function _addPropTween(target, prop, start, end, index, targets, modifier, stringFilter, funcParam, optional) {\n _isFunction(end) && (end = end(index || 0, target, targets));\n var currentValue = target[prop],\n 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](),\n setter = !_isFunction(currentValue) ? _setterPlain : funcParam ? _setterFuncWithParam : _setterFunc,\n pt;\n\n if (_isString(end)) {\n if (~end.indexOf(\"random(\")) {\n end = _replaceRandom(end);\n }\n\n if (end.charAt(1) === \"=\") {\n pt = _parseRelative(parsedStart, end) + (getUnit(parsedStart) || 0);\n\n if (pt || pt === 0) {\n // to avoid isNaN, like if someone passes in a value like \"!= whatever\"\n end = pt;\n }\n }\n }\n\n if (!optional || parsedStart !== end || _forceAllPropTweens) {\n if (!isNaN(parsedStart * end) && end !== \"\") {\n // fun fact: any number multiplied by \"\" is evaluated as the number 0!\n pt = new PropTween(this._pt, target, prop, +parsedStart || 0, end - (parsedStart || 0), typeof currentValue === \"boolean\" ? _renderBoolean : _renderPlain, 0, setter);\n funcParam && (pt.fp = funcParam);\n modifier && pt.modifier(modifier, this, target);\n return this._pt = pt;\n }\n\n !currentValue && !(prop in target) && _missingPlugin(prop, end);\n return _addComplexStringPropTween.call(this, target, prop, parsedStart, end, setter, stringFilter || _config.stringFilter, funcParam);\n }\n},\n //creates a copy of the vars object and processes any function-based values (putting the resulting values directly into the copy) as well as strings with \"random()\" in them. It does NOT process relative values.\n_processVars = function _processVars(vars, index, target, targets, tween) {\n _isFunction(vars) && (vars = _parseFuncOrString(vars, tween, index, target, targets));\n\n if (!_isObject(vars) || vars.style && vars.nodeType || _isArray(vars) || _isTypedArray(vars)) {\n return _isString(vars) ? _parseFuncOrString(vars, tween, index, target, targets) : vars;\n }\n\n var copy = {},\n p;\n\n for (p in vars) {\n copy[p] = _parseFuncOrString(vars[p], tween, index, target, targets);\n }\n\n return copy;\n},\n _checkPlugin = function _checkPlugin(property, vars, tween, index, target, targets) {\n var plugin, pt, ptLookup, i;\n\n if (_plugins[property] && (plugin = new _plugins[property]()).init(target, plugin.rawVars ? vars[property] : _processVars(vars[property], index, target, targets, tween), tween, index, targets) !== false) {\n tween._pt = pt = new PropTween(tween._pt, target, property, 0, 1, plugin.render, plugin, 0, plugin.priority);\n\n if (tween !== _quickTween) {\n ptLookup = tween._ptLookup[tween._targets.indexOf(target)]; //note: we can't use tween._ptLookup[index] because for staggered tweens, the index from the fullTargets array won't match what it is in each individual tween that spawns from the stagger.\n\n i = plugin._props.length;\n\n while (i--) {\n ptLookup[plugin._props[i]] = pt;\n }\n }\n }\n\n return plugin;\n},\n _overwritingTween,\n //store a reference temporarily so we can avoid overwriting itself.\n_forceAllPropTweens,\n _initTween = function _initTween(tween, time, tTime) {\n var vars = tween.vars,\n ease = vars.ease,\n startAt = vars.startAt,\n immediateRender = vars.immediateRender,\n lazy = vars.lazy,\n onUpdate = vars.onUpdate,\n runBackwards = vars.runBackwards,\n yoyoEase = vars.yoyoEase,\n keyframes = vars.keyframes,\n autoRevert = vars.autoRevert,\n dur = tween._dur,\n prevStartAt = tween._startAt,\n targets = tween._targets,\n parent = tween.parent,\n fullTargets = parent && parent.data === \"nested\" ? parent.vars.targets : targets,\n autoOverwrite = tween._overwrite === \"auto\" && !_suppressOverwrites,\n tl = tween.timeline,\n cleanVars,\n i,\n p,\n pt,\n target,\n hasPriority,\n gsData,\n harness,\n plugin,\n ptLookup,\n index,\n harnessVars,\n overwritten;\n tl && (!keyframes || !ease) && (ease = \"none\");\n tween._ease = _parseEase(ease, _defaults.ease);\n tween._yEase = yoyoEase ? _invertEase(_parseEase(yoyoEase === true ? ease : yoyoEase, _defaults.ease)) : 0;\n\n if (yoyoEase && tween._yoyo && !tween._repeat) {\n //there must have been a parent timeline with yoyo:true that is currently in its yoyo phase, so flip the eases.\n yoyoEase = tween._yEase;\n tween._yEase = tween._ease;\n tween._ease = yoyoEase;\n }\n\n tween._from = !tl && !!vars.runBackwards; //nested timelines should never run backwards - the backwards-ness is in the child tweens.\n\n if (!tl || keyframes && !vars.stagger) {\n //if there's an internal timeline, skip all the parsing because we passed that task down the chain.\n harness = targets[0] ? _getCache(targets[0]).harness : 0;\n harnessVars = harness && vars[harness.prop]; //someone may need to specify CSS-specific values AND non-CSS values, like if the element has an \"x\" property plus it's a standard DOM element. We allow people to distinguish by wrapping plugin-specific stuff in a css:{} object for example.\n\n cleanVars = _copyExcluding(vars, _reservedProps);\n\n if (prevStartAt) {\n prevStartAt._zTime < 0 && prevStartAt.progress(1); // in case it's a lazy startAt that hasn't rendered yet.\n\n time < 0 && runBackwards && immediateRender && !autoRevert ? prevStartAt.render(-1, true) : prevStartAt.revert(runBackwards && dur ? _revertConfigNoKill : _startAtRevertConfig); // if it's a \"startAt\" (not \"from()\" or runBackwards: true), we only need to do a shallow revert (keep transforms cached in CSSPlugin)\n // don't just _removeFromParent(prevStartAt.render(-1, true)) because that'll leave inline styles. We're creating a new _startAt for \"startAt\" tweens that re-capture things to ensure that if the pre-tween values changed since the tween was created, they're recorded.\n\n prevStartAt._lazy = 0;\n }\n\n if (startAt) {\n _removeFromParent(tween._startAt = Tween.set(targets, _setDefaults({\n data: \"isStart\",\n overwrite: false,\n parent: parent,\n immediateRender: true,\n lazy: !prevStartAt && _isNotFalse(lazy),\n startAt: null,\n delay: 0,\n onUpdate: onUpdate && function () {\n return _callback(tween, \"onUpdate\");\n },\n stagger: 0\n }, startAt))); //copy the properties/values into a new object to avoid collisions, like var to = {x:0}, from = {x:500}; timeline.fromTo(e, from, to).fromTo(e, to, from);\n\n\n tween._startAt._dp = 0; // don't allow it to get put back into root timeline! Like when revert() is called and totalTime() gets set.\n\n tween._startAt._sat = tween; // used in globalTime(). _sat stands for _startAtTween\n\n time < 0 && (_reverting || !immediateRender && !autoRevert) && tween._startAt.revert(_revertConfigNoKill); // rare edge case, like if a render is forced in the negative direction of a non-initted tween.\n\n if (immediateRender) {\n if (dur && time <= 0 && tTime <= 0) {\n // check tTime here because in the case of a yoyo tween whose playhead gets pushed to the end like tween.progress(1), we should allow it through so that the onComplete gets fired properly.\n time && (tween._zTime = time);\n return; //we skip initialization here so that overwriting doesn't occur until the tween actually begins. Otherwise, if you create several immediateRender:true tweens of the same target/properties to drop into a Timeline, the last one created would overwrite the first ones because they didn't get placed into the timeline yet before the first render occurs and kicks in overwriting.\n }\n }\n } else if (runBackwards && dur) {\n //from() tweens must be handled uniquely: their beginning values must be rendered but we don't want overwriting to occur yet (when time is still 0). Wait until the tween actually begins before doing all the routines like overwriting. At that time, we should render at the END of the tween to ensure that things initialize correctly (remember, from() tweens go backwards)\n if (!prevStartAt) {\n time && (immediateRender = false); //in rare cases (like if a from() tween runs and then is invalidate()-ed), immediateRender could be true but the initial forced-render gets skipped, so there's no need to force the render in this context when the _time is greater than 0\n\n p = _setDefaults({\n overwrite: false,\n data: \"isFromStart\",\n //we tag the tween with as \"isFromStart\" so that if [inside a plugin] we need to only do something at the very END of a tween, we have a way of identifying this tween as merely the one that's setting the beginning values for a \"from()\" tween. For example, clearProps in CSSPlugin should only get applied at the very END of a tween and without this tag, from(...{height:100, clearProps:\"height\", delay:1}) would wipe the height at the beginning of the tween and after 1 second, it'd kick back in.\n lazy: immediateRender && !prevStartAt && _isNotFalse(lazy),\n immediateRender: immediateRender,\n //zero-duration tweens render immediately by default, but if we're not specifically instructed to render this tween immediately, we should skip this and merely _init() to record the starting values (rendering them immediately would push them to completion which is wasteful in that case - we'd have to render(-1) immediately after)\n stagger: 0,\n parent: parent //ensures that nested tweens that had a stagger are handled properly, like gsap.from(\".class\", {y: gsap.utils.wrap([-100,100]), stagger: 0.5})\n\n }, cleanVars);\n harnessVars && (p[harness.prop] = harnessVars); // in case someone does something like .from(..., {css:{}})\n\n _removeFromParent(tween._startAt = Tween.set(targets, p));\n\n tween._startAt._dp = 0; // don't allow it to get put back into root timeline!\n\n tween._startAt._sat = tween; // used in globalTime()\n\n time < 0 && (_reverting ? tween._startAt.revert(_revertConfigNoKill) : tween._startAt.render(-1, true));\n tween._zTime = time;\n\n if (!immediateRender) {\n _initTween(tween._startAt, _tinyNum, _tinyNum); //ensures that the initial values are recorded\n\n } else if (!time) {\n return;\n }\n }\n }\n\n tween._pt = tween._ptCache = 0;\n lazy = dur && _isNotFalse(lazy) || lazy && !dur;\n\n for (i = 0; i < targets.length; i++) {\n target = targets[i];\n gsData = target._gsap || _harness(targets)[i]._gsap;\n tween._ptLookup[i] = ptLookup = {};\n _lazyLookup[gsData.id] && _lazyTweens.length && _lazyRender(); //if other tweens of the same target have recently initted but haven't rendered yet, we've got to force the render so that the starting values are correct (imagine populating a timeline with a bunch of sequential tweens and then jumping to the end)\n\n index = fullTargets === targets ? i : fullTargets.indexOf(target);\n\n if (harness && (plugin = new harness()).init(target, harnessVars || cleanVars, tween, index, fullTargets) !== false) {\n tween._pt = pt = new PropTween(tween._pt, target, plugin.name, 0, 1, plugin.render, plugin, 0, plugin.priority);\n\n plugin._props.forEach(function (name) {\n ptLookup[name] = pt;\n });\n\n plugin.priority && (hasPriority = 1);\n }\n\n if (!harness || harnessVars) {\n for (p in cleanVars) {\n if (_plugins[p] && (plugin = _checkPlugin(p, cleanVars, tween, index, target, fullTargets))) {\n plugin.priority && (hasPriority = 1);\n } else {\n ptLookup[p] = pt = _addPropTween.call(tween, target, p, \"get\", cleanVars[p], index, fullTargets, 0, vars.stringFilter);\n }\n }\n }\n\n tween._op && tween._op[i] && tween.kill(target, tween._op[i]);\n\n if (autoOverwrite && tween._pt) {\n _overwritingTween = tween;\n\n _globalTimeline.killTweensOf(target, ptLookup, tween.globalTime(time)); // make sure the overwriting doesn't overwrite THIS tween!!!\n\n\n overwritten = !tween.parent;\n _overwritingTween = 0;\n }\n\n tween._pt && lazy && (_lazyLookup[gsData.id] = 1);\n }\n\n hasPriority && _sortPropTweensByPriority(tween);\n tween._onInit && tween._onInit(tween); //plugins like RoundProps must wait until ALL of the PropTweens are instantiated. In the plugin's init() function, it sets the _onInit on the tween instance. May not be pretty/intuitive, but it's fast and keeps file size down.\n }\n\n tween._onUpdate = onUpdate;\n tween._initted = (!tween._op || tween._pt) && !overwritten; // if overwrittenProps resulted in the entire tween being killed, do NOT flag it as initted or else it may render for one tick.\n\n keyframes && time <= 0 && tl.render(_bigNum, true, true); // if there's a 0% keyframe, it'll render in the \"before\" state for any staggered/delayed animations thus when the following tween initializes, it'll use the \"before\" state instead of the \"after\" state as the initial values.\n},\n _updatePropTweens = function _updatePropTweens(tween, property, value, start, startIsRelative, ratio, time, skipRecursion) {\n var ptCache = (tween._pt && tween._ptCache || (tween._ptCache = {}))[property],\n pt,\n rootPT,\n lookup,\n i;\n\n if (!ptCache) {\n ptCache = tween._ptCache[property] = [];\n lookup = tween._ptLookup;\n i = tween._targets.length;\n\n while (i--) {\n pt = lookup[i][property];\n\n if (pt && pt.d && pt.d._pt) {\n // it's a plugin, so find the nested PropTween\n pt = pt.d._pt;\n\n while (pt && pt.p !== property && pt.fp !== property) {\n // \"fp\" is functionParam for things like setting CSS variables which require .setProperty(\"--var-name\", value)\n pt = pt._next;\n }\n }\n\n if (!pt) {\n // there is no PropTween associated with that property, so we must FORCE one to be created and ditch out of this\n // if the tween has other properties that already rendered at new positions, we'd normally have to rewind to put them back like tween.render(0, true) before forcing an _initTween(), but that can create another edge case like tweening a timeline's progress would trigger onUpdates to fire which could move other things around. It's better to just inform users that .resetTo() should ONLY be used for tweens that already have that property. For example, you can't gsap.to(...{ y: 0 }) and then tween.restTo(\"x\", 200) for example.\n _forceAllPropTweens = 1; // otherwise, when we _addPropTween() and it finds no change between the start and end values, it skips creating a PropTween (for efficiency...why tween when there's no difference?) but in this case we NEED that PropTween created so we can edit it.\n\n tween.vars[property] = \"+=0\";\n\n _initTween(tween, time);\n\n _forceAllPropTweens = 0;\n return skipRecursion ? _warn(property + \" not eligible for reset\") : 1; // if someone tries to do a quickTo() on a special property like borderRadius which must get split into 4 different properties, that's not eligible for .resetTo().\n }\n\n ptCache.push(pt);\n }\n }\n\n i = ptCache.length;\n\n while (i--) {\n rootPT = ptCache[i];\n pt = rootPT._pt || rootPT; // complex values may have nested PropTweens. We only accommodate the FIRST value.\n\n pt.s = (start || start === 0) && !startIsRelative ? start : pt.s + (start || 0) + ratio * pt.c;\n pt.c = value - pt.s;\n rootPT.e && (rootPT.e = _round(value) + getUnit(rootPT.e)); // mainly for CSSPlugin (end value)\n\n rootPT.b && (rootPT.b = pt.s + getUnit(rootPT.b)); // (beginning value)\n }\n},\n _addAliasesToVars = function _addAliasesToVars(targets, vars) {\n var harness = targets[0] ? _getCache(targets[0]).harness : 0,\n propertyAliases = harness && harness.aliases,\n copy,\n p,\n i,\n aliases;\n\n if (!propertyAliases) {\n return vars;\n }\n\n copy = _merge({}, vars);\n\n for (p in propertyAliases) {\n if (p in copy) {\n aliases = propertyAliases[p].split(\",\");\n i = aliases.length;\n\n while (i--) {\n copy[aliases[i]] = copy[p];\n }\n }\n }\n\n return copy;\n},\n // parses multiple formats, like {\"0%\": {x: 100}, {\"50%\": {x: -20}} and { x: {\"0%\": 100, \"50%\": -20} }, and an \"ease\" can be set on any object. We populate an \"allProps\" object with an Array for each property, like {x: [{}, {}], y:[{}, {}]} with data for each property tween. The objects have a \"t\" (time), \"v\", (value), and \"e\" (ease) property. This allows us to piece together a timeline later.\n_parseKeyframe = function _parseKeyframe(prop, obj, allProps, easeEach) {\n var ease = obj.ease || easeEach || \"power1.inOut\",\n p,\n a;\n\n if (_isArray(obj)) {\n a = allProps[prop] || (allProps[prop] = []); // t = time (out of 100), v = value, e = ease\n\n obj.forEach(function (value, i) {\n return a.push({\n t: i / (obj.length - 1) * 100,\n v: value,\n e: ease\n });\n });\n } else {\n for (p in obj) {\n a = allProps[p] || (allProps[p] = []);\n p === \"ease\" || a.push({\n t: parseFloat(prop),\n v: obj[p],\n e: ease\n });\n }\n }\n},\n _parseFuncOrString = function _parseFuncOrString(value, tween, i, target, targets) {\n return _isFunction(value) ? value.call(tween, i, target, targets) : _isString(value) && ~value.indexOf(\"random(\") ? _replaceRandom(value) : value;\n},\n _staggerTweenProps = _callbackNames + \"repeat,repeatDelay,yoyo,repeatRefresh,yoyoEase,autoRevert\",\n _staggerPropsToSkip = {};\n\n_forEachName(_staggerTweenProps + \",id,stagger,delay,duration,paused,scrollTrigger\", function (name) {\n return _staggerPropsToSkip[name] = 1;\n});\n/*\n * --------------------------------------------------------------------------------------\n * TWEEN\n * --------------------------------------------------------------------------------------\n */\n\n\nvar Tween = /*#__PURE__*/function (_Animation2) {\n _inheritsLoose(Tween, _Animation2);\n\n function Tween(targets, vars, position, skipInherit) {\n var _this3;\n\n if (typeof vars === \"number\") {\n position.duration = vars;\n vars = position;\n position = null;\n }\n\n _this3 = _Animation2.call(this, skipInherit ? vars : _inheritDefaults(vars)) || this;\n var _this3$vars = _this3.vars,\n duration = _this3$vars.duration,\n delay = _this3$vars.delay,\n immediateRender = _this3$vars.immediateRender,\n stagger = _this3$vars.stagger,\n overwrite = _this3$vars.overwrite,\n keyframes = _this3$vars.keyframes,\n defaults = _this3$vars.defaults,\n scrollTrigger = _this3$vars.scrollTrigger,\n yoyoEase = _this3$vars.yoyoEase,\n parent = vars.parent || _globalTimeline,\n parsedTargets = (_isArray(targets) || _isTypedArray(targets) ? _isNumber(targets[0]) : \"length\" in vars) ? [targets] : toArray(targets),\n tl,\n i,\n copy,\n l,\n p,\n curTarget,\n staggerFunc,\n staggerVarsToMerge;\n _this3._targets = parsedTargets.length ? _harness(parsedTargets) : _warn(\"GSAP target \" + targets + \" not found. https://gsap.com\", !_config.nullTargetWarn) || [];\n _this3._ptLookup = []; //PropTween lookup. An array containing an object for each target, having keys for each tweening property\n\n _this3._overwrite = overwrite;\n\n if (keyframes || stagger || _isFuncOrString(duration) || _isFuncOrString(delay)) {\n vars = _this3.vars;\n tl = _this3.timeline = new Timeline({\n data: \"nested\",\n defaults: defaults || {},\n targets: parent && parent.data === \"nested\" ? parent.vars.targets : parsedTargets\n }); // we need to store the targets because for staggers and keyframes, we end up creating an individual tween for each but function-based values need to know the index and the whole Array of targets.\n\n tl.kill();\n tl.parent = tl._dp = _assertThisInitialized(_this3);\n tl._start = 0;\n\n if (stagger || _isFuncOrString(duration) || _isFuncOrString(delay)) {\n l = parsedTargets.length;\n staggerFunc = stagger && distribute(stagger);\n\n if (_isObject(stagger)) {\n //users can pass in callbacks like onStart/onComplete in the stagger object. These should fire with each individual tween.\n for (p in stagger) {\n if (~_staggerTweenProps.indexOf(p)) {\n staggerVarsToMerge || (staggerVarsToMerge = {});\n staggerVarsToMerge[p] = stagger[p];\n }\n }\n }\n\n for (i = 0; i < l; i++) {\n copy = _copyExcluding(vars, _staggerPropsToSkip);\n copy.stagger = 0;\n yoyoEase && (copy.yoyoEase = yoyoEase);\n staggerVarsToMerge && _merge(copy, staggerVarsToMerge);\n curTarget = parsedTargets[i]; //don't just copy duration or delay because if they're a string or function, we'd end up in an infinite loop because _isFuncOrString() would evaluate as true in the child tweens, entering this loop, etc. So we parse the value straight from vars and default to 0.\n\n copy.duration = +_parseFuncOrString(duration, _assertThisInitialized(_this3), i, curTarget, parsedTargets);\n copy.delay = (+_parseFuncOrString(delay, _assertThisInitialized(_this3), i, curTarget, parsedTargets) || 0) - _this3._delay;\n\n if (!stagger && l === 1 && copy.delay) {\n // if someone does delay:\"random(1, 5)\", repeat:-1, for example, the delay shouldn't be inside the repeat.\n _this3._delay = delay = copy.delay;\n _this3._start += delay;\n copy.delay = 0;\n }\n\n tl.to(curTarget, copy, staggerFunc ? staggerFunc(i, curTarget, parsedTargets) : 0);\n tl._ease = _easeMap.none;\n }\n\n tl.duration() ? duration = delay = 0 : _this3.timeline = 0; // if the timeline's duration is 0, we don't need a timeline internally!\n } else if (keyframes) {\n _inheritDefaults(_setDefaults(tl.vars.defaults, {\n ease: \"none\"\n }));\n\n tl._ease = _parseEase(keyframes.ease || vars.ease || \"none\");\n var time = 0,\n a,\n kf,\n v;\n\n if (_isArray(keyframes)) {\n keyframes.forEach(function (frame) {\n return tl.to(parsedTargets, frame, \">\");\n });\n tl.duration(); // to ensure tl._dur is cached because we tap into it for performance purposes in the render() method.\n } else {\n copy = {};\n\n for (p in keyframes) {\n p === \"ease\" || p === \"easeEach\" || _parseKeyframe(p, keyframes[p], copy, keyframes.easeEach);\n }\n\n for (p in copy) {\n a = copy[p].sort(function (a, b) {\n return a.t - b.t;\n });\n time = 0;\n\n for (i = 0; i < a.length; i++) {\n kf = a[i];\n v = {\n ease: kf.e,\n duration: (kf.t - (i ? a[i - 1].t : 0)) / 100 * duration\n };\n v[p] = kf.v;\n tl.to(parsedTargets, v, time);\n time += v.duration;\n }\n }\n\n tl.duration() < duration && tl.to({}, {\n duration: duration - tl.duration()\n }); // in case keyframes didn't go to 100%\n }\n }\n\n duration || _this3.duration(duration = tl.duration());\n } else {\n _this3.timeline = 0; //speed optimization, faster lookups (no going up the prototype chain)\n }\n\n if (overwrite === true && !_suppressOverwrites) {\n _overwritingTween = _assertThisInitialized(_this3);\n\n _globalTimeline.killTweensOf(parsedTargets);\n\n _overwritingTween = 0;\n }\n\n _addToTimeline(parent, _assertThisInitialized(_this3), position);\n\n vars.reversed && _this3.reverse();\n vars.paused && _this3.paused(true);\n\n if (immediateRender || !duration && !keyframes && _this3._start === _roundPrecise(parent._time) && _isNotFalse(immediateRender) && _hasNoPausedAncestors(_assertThisInitialized(_this3)) && parent.data !== \"nested\") {\n _this3._tTime = -_tinyNum; //forces a render without having to set the render() \"force\" parameter to true because we want to allow lazying by default (using the \"force\" parameter always forces an immediate full render)\n\n _this3.render(Math.max(0, -delay) || 0); //in case delay is negative\n\n }\n\n scrollTrigger && _scrollTrigger(_assertThisInitialized(_this3), scrollTrigger);\n return _this3;\n }\n\n var _proto3 = Tween.prototype;\n\n _proto3.render = function render(totalTime, suppressEvents, force) {\n var prevTime = this._time,\n tDur = this._tDur,\n dur = this._dur,\n isNegative = totalTime < 0,\n tTime = totalTime > tDur - _tinyNum && !isNegative ? tDur : totalTime < _tinyNum ? 0 : totalTime,\n time,\n pt,\n iteration,\n cycleDuration,\n prevIteration,\n isYoyo,\n ratio,\n timeline,\n yoyoEase;\n\n if (!dur) {\n _renderZeroDurationTween(this, totalTime, suppressEvents, force);\n } else if (tTime !== this._tTime || !totalTime || force || !this._initted && this._tTime || this._startAt && this._zTime < 0 !== isNegative) {\n //this senses if we're crossing over the start time, in which case we must record _zTime and force the render, but we do it in this lengthy conditional way for performance reasons (usually we can skip the calculations): this._initted && (this._zTime < 0) !== (totalTime < 0)\n time = tTime;\n timeline = this.timeline;\n\n if (this._repeat) {\n //adjust the time for repeats and yoyos\n cycleDuration = dur + this._rDelay;\n\n if (this._repeat < -1 && isNegative) {\n return this.totalTime(cycleDuration * 100 + totalTime, suppressEvents, force);\n }\n\n time = _roundPrecise(tTime % cycleDuration); //round to avoid floating point errors. (4 % 0.8 should be 0 but some browsers report it as 0.79999999!)\n\n if (tTime === tDur) {\n // the tDur === tTime is for edge cases where there's a lengthy decimal on the duration and it may reach the very end but the time is rendered as not-quite-there (remember, tDur is rounded to 4 decimals whereas dur isn't)\n iteration = this._repeat;\n time = dur;\n } else {\n iteration = ~~(tTime / cycleDuration);\n\n if (iteration && iteration === _roundPrecise(tTime / cycleDuration)) {\n time = dur;\n iteration--;\n }\n\n time > dur && (time = dur);\n }\n\n isYoyo = this._yoyo && iteration & 1;\n\n if (isYoyo) {\n yoyoEase = this._yEase;\n time = dur - time;\n }\n\n prevIteration = _animationCycle(this._tTime, cycleDuration);\n\n if (time === prevTime && !force && this._initted && iteration === prevIteration) {\n //could be during the repeatDelay part. No need to render and fire callbacks.\n this._tTime = tTime;\n return this;\n }\n\n if (iteration !== prevIteration) {\n timeline && this._yEase && _propagateYoyoEase(timeline, isYoyo); //repeatRefresh functionality\n\n if (this.vars.repeatRefresh && !isYoyo && !this._lock && this._time !== cycleDuration && this._initted) {\n // this._time will === cycleDuration when we render at EXACTLY the end of an iteration. Without this condition, it'd often do the repeatRefresh render TWICE (again on the very next tick).\n this._lock = force = 1; //force, otherwise if lazy is true, the _attemptInitTween() will return and we'll jump out and get caught bouncing on each tick.\n\n this.render(_roundPrecise(cycleDuration * iteration), true).invalidate()._lock = 0;\n }\n }\n }\n\n if (!this._initted) {\n if (_attemptInitTween(this, isNegative ? totalTime : time, force, suppressEvents, tTime)) {\n this._tTime = 0; // in constructor if immediateRender is true, we set _tTime to -_tinyNum to have the playhead cross the starting point but we can't leave _tTime as a negative number.\n\n return this;\n }\n\n if (prevTime !== this._time && !(force && this.vars.repeatRefresh && iteration !== prevIteration)) {\n // rare edge case - during initialization, an onUpdate in the _startAt (.fromTo()) might force this tween to render at a different spot in which case we should ditch this render() call so that it doesn't revert the values. But we also don't want to dump if we're doing a repeatRefresh render!\n return this;\n }\n\n if (dur !== this._dur) {\n // while initting, a plugin like InertiaPlugin might alter the duration, so rerun from the start to ensure everything renders as it should.\n return this.render(totalTime, suppressEvents, force);\n }\n }\n\n this._tTime = tTime;\n this._time = time;\n\n if (!this._act && this._ts) {\n this._act = 1; //as long as it's not paused, force it to be active so that if the user renders independent of the parent timeline, it'll be forced to re-render on the next tick.\n\n this._lazy = 0;\n }\n\n this.ratio = ratio = (yoyoEase || this._ease)(time / dur);\n\n if (this._from) {\n this.ratio = ratio = 1 - ratio;\n }\n\n if (time && !prevTime && !suppressEvents && !iteration) {\n _callback(this, \"onStart\");\n\n if (this._tTime !== tTime) {\n // in case the onStart triggered a render at a different spot, eject. Like if someone did animation.pause(0.5) or something inside the onStart.\n return this;\n }\n }\n\n pt = this._pt;\n\n while (pt) {\n pt.r(ratio, pt.d);\n pt = pt._next;\n }\n\n timeline && timeline.render(totalTime < 0 ? totalTime : timeline._dur * timeline._ease(time / this._dur), suppressEvents, force) || this._startAt && (this._zTime = totalTime);\n\n if (this._onUpdate && !suppressEvents) {\n isNegative && _rewindStartAt(this, totalTime, suppressEvents, force); //note: for performance reasons, we tuck this conditional logic inside less traveled areas (most tweens don't have an onUpdate). We'd just have it at the end before the onComplete, but the values should be updated before any onUpdate is called, so we ALSO put it here and then if it's not called, we do so later near the onComplete.\n\n _callback(this, \"onUpdate\");\n }\n\n this._repeat && iteration !== prevIteration && this.vars.onRepeat && !suppressEvents && this.parent && _callback(this, \"onRepeat\");\n\n if ((tTime === this._tDur || !tTime) && this._tTime === tTime) {\n isNegative && !this._onUpdate && _rewindStartAt(this, totalTime, true, true);\n (totalTime || !dur) && (tTime === this._tDur && this._ts > 0 || !tTime && this._ts < 0) && _removeFromParent(this, 1); // don't remove if we're rendering at exactly a time of 0, as there could be autoRevert values that should get set on the next tick (if the playhead goes backward beyond the startTime, negative totalTime). Don't remove if the timeline is reversed and the playhead isn't at 0, otherwise tl.progress(1).reverse() won't work. Only remove if the playhead is at the end and timeScale is positive, or if the playhead is at 0 and the timeScale is negative.\n\n if (!suppressEvents && !(isNegative && !prevTime) && (tTime || prevTime || isYoyo)) {\n // if prevTime and tTime are zero, we shouldn't fire the onReverseComplete. This could happen if you gsap.to(... {paused:true}).play();\n _callback(this, tTime === tDur ? \"onComplete\" : \"onReverseComplete\", true);\n\n this._prom && !(tTime < tDur && this.timeScale() > 0) && this._prom();\n }\n }\n }\n\n return this;\n };\n\n _proto3.targets = function targets() {\n return this._targets;\n };\n\n _proto3.invalidate = function invalidate(soft) {\n // \"soft\" gives us a way to clear out everything EXCEPT the recorded pre-\"from\" portion of from() tweens. Otherwise, for example, if you tween.progress(1).render(0, true true).invalidate(), the \"from\" values would persist and then on the next render, the from() tweens would initialize and the current value would match the \"from\" values, thus animate from the same value to the same value (no animation). We tap into this in ScrollTrigger's refresh() where we must push a tween to completion and then back again but honor its init state in case the tween is dependent on another tween further up on the page.\n (!soft || !this.vars.runBackwards) && (this._startAt = 0);\n this._pt = this._op = this._onUpdate = this._lazy = this.ratio = 0;\n this._ptLookup = [];\n this.timeline && this.timeline.invalidate(soft);\n return _Animation2.prototype.invalidate.call(this, soft);\n };\n\n _proto3.resetTo = function resetTo(property, value, start, startIsRelative, skipRecursion) {\n _tickerActive || _ticker.wake();\n this._ts || this.play();\n var time = Math.min(this._dur, (this._dp._time - this._start) * this._ts),\n ratio;\n this._initted || _initTween(this, time);\n ratio = this._ease(time / this._dur); // don't just get tween.ratio because it may not have rendered yet.\n // possible future addition to allow an object with multiple values to update, like tween.resetTo({x: 100, y: 200}); At this point, it doesn't seem worth the added kb given the fact that most users will likely opt for the convenient gsap.quickTo() way of interacting with this method.\n // if (_isObject(property)) { // performance optimization\n // \tfor (p in property) {\n // \t\tif (_updatePropTweens(this, p, property[p], value ? value[p] : null, start, ratio, time)) {\n // \t\t\treturn this.resetTo(property, value, start, startIsRelative); // if a PropTween wasn't found for the property, it'll get forced with a re-initialization so we need to jump out and start over again.\n // \t\t}\n // \t}\n // } else {\n\n if (_updatePropTweens(this, property, value, start, startIsRelative, ratio, time, skipRecursion)) {\n return this.resetTo(property, value, start, startIsRelative, 1); // if a PropTween wasn't found for the property, it'll get forced with a re-initialization so we need to jump out and start over again.\n } //}\n\n\n _alignPlayhead(this, 0);\n\n this.parent || _addLinkedListItem(this._dp, this, \"_first\", \"_last\", this._dp._sort ? \"_start\" : 0);\n return this.render(0);\n };\n\n _proto3.kill = function kill(targets, vars) {\n if (vars === void 0) {\n vars = \"all\";\n }\n\n if (!targets && (!vars || vars === \"all\")) {\n this._lazy = this._pt = 0;\n return this.parent ? _interrupt(this) : this;\n }\n\n if (this.timeline) {\n var tDur = this.timeline.totalDuration();\n this.timeline.killTweensOf(targets, vars, _overwritingTween && _overwritingTween.vars.overwrite !== true)._first || _interrupt(this); // if nothing is left tweening, interrupt.\n\n this.parent && tDur !== this.timeline.totalDuration() && _setDuration(this, this._dur * this.timeline._tDur / tDur, 0, 1); // if a nested tween is killed that changes the duration, it should affect this tween's duration. We must use the ratio, though, because sometimes the internal timeline is stretched like for keyframes where they don't all add up to whatever the parent tween's duration was set to.\n\n return this;\n }\n\n var parsedTargets = this._targets,\n killingTargets = targets ? toArray(targets) : parsedTargets,\n propTweenLookup = this._ptLookup,\n firstPT = this._pt,\n overwrittenProps,\n curLookup,\n curOverwriteProps,\n props,\n p,\n pt,\n i;\n\n if ((!vars || vars === \"all\") && _arraysMatch(parsedTargets, killingTargets)) {\n vars === \"all\" && (this._pt = 0);\n return _interrupt(this);\n }\n\n overwrittenProps = this._op = this._op || [];\n\n if (vars !== \"all\") {\n //so people can pass in a comma-delimited list of property names\n if (_isString(vars)) {\n p = {};\n\n _forEachName(vars, function (name) {\n return p[name] = 1;\n });\n\n vars = p;\n }\n\n vars = _addAliasesToVars(parsedTargets, vars);\n }\n\n i = parsedTargets.length;\n\n while (i--) {\n if (~killingTargets.indexOf(parsedTargets[i])) {\n curLookup = propTweenLookup[i];\n\n if (vars === \"all\") {\n overwrittenProps[i] = vars;\n props = curLookup;\n curOverwriteProps = {};\n } else {\n curOverwriteProps = overwrittenProps[i] = overwrittenProps[i] || {};\n props = vars;\n }\n\n for (p in props) {\n pt = curLookup && curLookup[p];\n\n if (pt) {\n if (!(\"kill\" in pt.d) || pt.d.kill(p) === true) {\n _removeLinkedListItem(this, pt, \"_pt\");\n }\n\n delete curLookup[p];\n }\n\n if (curOverwriteProps !== \"all\") {\n curOverwriteProps[p] = 1;\n }\n }\n }\n }\n\n this._initted && !this._pt && firstPT && _interrupt(this); //if all tweening properties are killed, kill the tween. Without this line, if there's a tween with multiple targets and then you killTweensOf() each target individually, the tween would technically still remain active and fire its onComplete even though there aren't any more properties tweening.\n\n return this;\n };\n\n Tween.to = function to(targets, vars) {\n return new Tween(targets, vars, arguments[2]);\n };\n\n Tween.from = function from(targets, vars) {\n return _createTweenType(1, arguments);\n };\n\n Tween.delayedCall = function delayedCall(delay, callback, params, scope) {\n return new Tween(callback, 0, {\n immediateRender: false,\n lazy: false,\n overwrite: false,\n delay: delay,\n onComplete: callback,\n onReverseComplete: callback,\n onCompleteParams: params,\n onReverseCompleteParams: params,\n callbackScope: scope\n }); // we must use onReverseComplete too for things like timeline.add(() => {...}) which should be triggered in BOTH directions (forward and reverse)\n };\n\n Tween.fromTo = function fromTo(targets, fromVars, toVars) {\n return _createTweenType(2, arguments);\n };\n\n Tween.set = function set(targets, vars) {\n vars.duration = 0;\n vars.repeatDelay || (vars.repeat = 0);\n return new Tween(targets, vars);\n };\n\n Tween.killTweensOf = function killTweensOf(targets, props, onlyActive) {\n return _globalTimeline.killTweensOf(targets, props, onlyActive);\n };\n\n return Tween;\n}(Animation);\n\n_setDefaults(Tween.prototype, {\n _targets: [],\n _lazy: 0,\n _startAt: 0,\n _op: 0,\n _onInit: 0\n}); //add the pertinent timeline methods to Tween instances so that users can chain conveniently and create a timeline automatically. (removed due to concerns that it'd ultimately add to more confusion especially for beginners)\n// _forEachName(\"to,from,fromTo,set,call,add,addLabel,addPause\", name => {\n// \tTween.prototype[name] = function() {\n// \t\tlet tl = new Timeline();\n// \t\treturn _addToTimeline(tl, this)[name].apply(tl, toArray(arguments));\n// \t}\n// });\n//for backward compatibility. Leverage the timeline calls.\n\n\n_forEachName(\"staggerTo,staggerFrom,staggerFromTo\", function (name) {\n Tween[name] = function () {\n var tl = new Timeline(),\n params = _slice.call(arguments, 0);\n\n params.splice(name === \"staggerFromTo\" ? 5 : 4, 0, 0);\n return tl[name].apply(tl, params);\n };\n});\n/*\n * --------------------------------------------------------------------------------------\n * PROPTWEEN\n * --------------------------------------------------------------------------------------\n */\n\n\nvar _setterPlain = function _setterPlain(target, property, value) {\n return target[property] = value;\n},\n _setterFunc = function _setterFunc(target, property, value) {\n return target[property](value);\n},\n _setterFuncWithParam = function _setterFuncWithParam(target, property, value, data) {\n return target[property](data.fp, value);\n},\n _setterAttribute = function _setterAttribute(target, property, value) {\n return target.setAttribute(property, value);\n},\n _getSetter = function _getSetter(target, property) {\n return _isFunction(target[property]) ? _setterFunc : _isUndefined(target[property]) && target.setAttribute ? _setterAttribute : _setterPlain;\n},\n _renderPlain = function _renderPlain(ratio, data) {\n return data.set(data.t, data.p, Math.round((data.s + data.c * ratio) * 1000000) / 1000000, data);\n},\n _renderBoolean = function _renderBoolean(ratio, data) {\n return data.set(data.t, data.p, !!(data.s + data.c * ratio), data);\n},\n _renderComplexString = function _renderComplexString(ratio, data) {\n var pt = data._pt,\n s = \"\";\n\n if (!ratio && data.b) {\n //b = beginning string\n s = data.b;\n } else if (ratio === 1 && data.e) {\n //e = ending string\n s = data.e;\n } else {\n while (pt) {\n s = pt.p + (pt.m ? pt.m(pt.s + pt.c * ratio) : Math.round((pt.s + pt.c * ratio) * 10000) / 10000) + s; //we use the \"p\" property for the text inbetween (like a suffix). And in the context of a complex string, the modifier (m) is typically just Math.round(), like for RGB colors.\n\n pt = pt._next;\n }\n\n s += data.c; //we use the \"c\" of the PropTween to store the final chunk of non-numeric text.\n }\n\n data.set(data.t, data.p, s, data);\n},\n _renderPropTweens = function _renderPropTweens(ratio, data) {\n var pt = data._pt;\n\n while (pt) {\n pt.r(ratio, pt.d);\n pt = pt._next;\n }\n},\n _addPluginModifier = function _addPluginModifier(modifier, tween, target, property) {\n var pt = this._pt,\n next;\n\n while (pt) {\n next = pt._next;\n pt.p === property && pt.modifier(modifier, tween, target);\n pt = next;\n }\n},\n _killPropTweensOf = function _killPropTweensOf(property) {\n var pt = this._pt,\n hasNonDependentRemaining,\n next;\n\n while (pt) {\n next = pt._next;\n\n if (pt.p === property && !pt.op || pt.op === property) {\n _removeLinkedListItem(this, pt, \"_pt\");\n } else if (!pt.dep) {\n hasNonDependentRemaining = 1;\n }\n\n pt = next;\n }\n\n return !hasNonDependentRemaining;\n},\n _setterWithModifier = function _setterWithModifier(target, property, value, data) {\n data.mSet(target, property, data.m.call(data.tween, value, data.mt), data);\n},\n _sortPropTweensByPriority = function _sortPropTweensByPriority(parent) {\n var pt = parent._pt,\n next,\n pt2,\n first,\n last; //sorts the PropTween linked list in order of priority because some plugins need to do their work after ALL of the PropTweens were created (like RoundPropsPlugin and ModifiersPlugin)\n\n while (pt) {\n next = pt._next;\n pt2 = first;\n\n while (pt2 && pt2.pr > pt.pr) {\n pt2 = pt2._next;\n }\n\n if (pt._prev = pt2 ? pt2._prev : last) {\n pt._prev._next = pt;\n } else {\n first = pt;\n }\n\n if (pt._next = pt2) {\n pt2._prev = pt;\n } else {\n last = pt;\n }\n\n pt = next;\n }\n\n parent._pt = first;\n}; //PropTween key: t = target, p = prop, r = renderer, d = data, s = start, c = change, op = overwriteProperty (ONLY populated when it's different than p), pr = priority, _next/_prev for the linked list siblings, set = setter, m = modifier, mSet = modifierSetter (the original setter, before a modifier was added)\n\n\nvar PropTween = /*#__PURE__*/function () {\n function PropTween(next, target, prop, start, change, renderer, data, setter, priority) {\n this.t = target;\n this.s = start;\n this.c = change;\n this.p = prop;\n this.r = renderer || _renderPlain;\n this.d = data || this;\n this.set = setter || _setterPlain;\n this.pr = priority || 0;\n this._next = next;\n\n if (next) {\n next._prev = this;\n }\n }\n\n var _proto4 = PropTween.prototype;\n\n _proto4.modifier = function modifier(func, tween, target) {\n this.mSet = this.mSet || this.set; //in case it was already set (a PropTween can only have one modifier)\n\n this.set = _setterWithModifier;\n this.m = func;\n this.mt = target; //modifier target\n\n this.tween = tween;\n };\n\n return PropTween;\n}(); //Initialization tasks\n\n_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) {\n return _reservedProps[name] = 1;\n});\n\n_globals.TweenMax = _globals.TweenLite = Tween;\n_globals.TimelineLite = _globals.TimelineMax = Timeline;\n_globalTimeline = new Timeline({\n sortChildren: false,\n defaults: _defaults,\n autoRemoveChildren: true,\n id: \"root\",\n smoothChildTiming: true\n});\n_config.stringFilter = _colorStringFilter;\n\nvar _media = [],\n _listeners = {},\n _emptyArray = [],\n _lastMediaTime = 0,\n _contextID = 0,\n _dispatch = function _dispatch(type) {\n return (_listeners[type] || _emptyArray).map(function (f) {\n return f();\n });\n},\n _onMediaChange = function _onMediaChange() {\n var time = Date.now(),\n matches = [];\n\n if (time - _lastMediaTime > 2) {\n _dispatch(\"matchMediaInit\");\n\n _media.forEach(function (c) {\n var queries = c.queries,\n conditions = c.conditions,\n match,\n p,\n anyMatch,\n toggled;\n\n for (p in queries) {\n match = _win.matchMedia(queries[p]).matches; // Firefox doesn't update the \"matches\" property of the MediaQueryList object correctly - it only does so as it calls its change handler - so we must re-create a media query here to ensure it's accurate.\n\n match && (anyMatch = 1);\n\n if (match !== conditions[p]) {\n conditions[p] = match;\n toggled = 1;\n }\n }\n\n if (toggled) {\n c.revert();\n anyMatch && matches.push(c);\n }\n });\n\n _dispatch(\"matchMediaRevert\");\n\n matches.forEach(function (c) {\n return c.onMatch(c, function (func) {\n return c.add(null, func);\n });\n });\n _lastMediaTime = time;\n\n _dispatch(\"matchMedia\");\n }\n};\n\nvar Context = /*#__PURE__*/function () {\n function Context(func, scope) {\n this.selector = scope && selector(scope);\n this.data = [];\n this._r = []; // returned/cleanup functions\n\n this.isReverted = false;\n this.id = _contextID++; // to work around issues that frameworks like Vue cause by making things into Proxies which make it impossible to do something like _media.indexOf(this) because \"this\" would no longer refer to the Context instance itself - it'd refer to a Proxy! We needed a way to identify the context uniquely\n\n func && this.add(func);\n }\n\n var _proto5 = Context.prototype;\n\n _proto5.add = function add(name, func, scope) {\n // possible future addition if we need the ability to add() an animation to a context and for whatever reason cannot create that animation inside of a context.add(() => {...}) function.\n // if (name && _isFunction(name.revert)) {\n // \tthis.data.push(name);\n // \treturn (name._ctx = this);\n // }\n if (_isFunction(name)) {\n scope = func;\n func = name;\n name = _isFunction;\n }\n\n var self = this,\n f = function f() {\n var prev = _context,\n prevSelector = self.selector,\n result;\n prev && prev !== self && prev.data.push(self);\n scope && (self.selector = selector(scope));\n _context = self;\n result = func.apply(self, arguments);\n _isFunction(result) && self._r.push(result);\n _context = prev;\n self.selector = prevSelector;\n self.isReverted = false;\n return result;\n };\n\n self.last = f;\n return name === _isFunction ? f(self, function (func) {\n return self.add(null, func);\n }) : name ? self[name] = f : f;\n };\n\n _proto5.ignore = function ignore(func) {\n var prev = _context;\n _context = null;\n func(this);\n _context = prev;\n };\n\n _proto5.getTweens = function getTweens() {\n var a = [];\n this.data.forEach(function (e) {\n return e instanceof Context ? a.push.apply(a, e.getTweens()) : e instanceof Tween && !(e.parent && e.parent.data === \"nested\") && a.push(e);\n });\n return a;\n };\n\n _proto5.clear = function clear() {\n this._r.length = this.data.length = 0;\n };\n\n _proto5.kill = function kill(revert, matchMedia) {\n var _this4 = this;\n\n if (revert) {\n (function () {\n var tweens = _this4.getTweens(),\n i = _this4.data.length,\n t;\n\n while (i--) {\n // Flip plugin tweens are very different in that they should actually be pushed to their end. The plugin replaces the timeline's .revert() method to do exactly that. But we also need to remove any of those nested tweens inside the flip timeline so that they don't get individually reverted.\n t = _this4.data[i];\n\n if (t.data === \"isFlip\") {\n t.revert();\n t.getChildren(true, true, false).forEach(function (tween) {\n return tweens.splice(tweens.indexOf(tween), 1);\n });\n }\n } // save as an object so that we can cache the globalTime for each tween to optimize performance during the sort\n\n\n tweens.map(function (t) {\n return {\n g: t._dur || t._delay || t._sat && !t._sat.vars.immediateRender ? t.globalTime(0) : -Infinity,\n t: t\n };\n }).sort(function (a, b) {\n return b.g - a.g || -Infinity;\n }).forEach(function (o) {\n return o.t.revert(revert);\n }); // note: all of the _startAt tweens should be reverted in reverse order that they were created, and they'll all have the same globalTime (-1) so the \" || -1\" in the sort keeps the order properly.\n\n i = _this4.data.length;\n\n while (i--) {\n // make sure we loop backwards so that, for example, SplitTexts that were created later on the same element get reverted first\n t = _this4.data[i];\n\n if (t instanceof Timeline) {\n if (t.data !== \"nested\") {\n t.scrollTrigger && t.scrollTrigger.revert();\n t.kill(); // don't revert() the timeline because that's duplicating efforts since we already reverted all the tweens\n }\n } else {\n !(t instanceof Tween) && t.revert && t.revert(revert);\n }\n }\n\n _this4._r.forEach(function (f) {\n return f(revert, _this4);\n });\n\n _this4.isReverted = true;\n })();\n } else {\n this.data.forEach(function (e) {\n return e.kill && e.kill();\n });\n }\n\n this.clear();\n\n if (matchMedia) {\n var i = _media.length;\n\n while (i--) {\n // previously, we checked _media.indexOf(this), but some frameworks like Vue enforce Proxy objects that make it impossible to get the proper result that way, so we must use a unique ID number instead.\n _media[i].id === this.id && _media.splice(i, 1);\n }\n }\n };\n\n _proto5.revert = function revert(config) {\n this.kill(config || {});\n };\n\n return Context;\n}();\n\nvar MatchMedia = /*#__PURE__*/function () {\n function MatchMedia(scope) {\n this.contexts = [];\n this.scope = scope;\n _context && _context.data.push(this);\n }\n\n var _proto6 = MatchMedia.prototype;\n\n _proto6.add = function add(conditions, func, scope) {\n _isObject(conditions) || (conditions = {\n matches: conditions\n });\n var context = new Context(0, scope || this.scope),\n cond = context.conditions = {},\n mq,\n p,\n active;\n _context && !context.selector && (context.selector = _context.selector); // in case a context is created inside a context. Like a gsap.matchMedia() that's inside a scoped gsap.context()\n\n this.contexts.push(context);\n func = context.add(\"onMatch\", func);\n context.queries = conditions;\n\n for (p in conditions) {\n if (p === \"all\") {\n active = 1;\n } else {\n mq = _win.matchMedia(conditions[p]);\n\n if (mq) {\n _media.indexOf(context) < 0 && _media.push(context);\n (cond[p] = mq.matches) && (active = 1);\n mq.addListener ? mq.addListener(_onMediaChange) : mq.addEventListener(\"change\", _onMediaChange);\n }\n }\n }\n\n active && func(context, function (f) {\n return context.add(null, f);\n });\n return this;\n } // refresh() {\n // \tlet time = _lastMediaTime,\n // \t\tmedia = _media;\n // \t_lastMediaTime = -1;\n // \t_media = this.contexts;\n // \t_onMediaChange();\n // \t_lastMediaTime = time;\n // \t_media = media;\n // }\n ;\n\n _proto6.revert = function revert(config) {\n this.kill(config || {});\n };\n\n _proto6.kill = function kill(revert) {\n this.contexts.forEach(function (c) {\n return c.kill(revert, true);\n });\n };\n\n return MatchMedia;\n}();\n/*\n * --------------------------------------------------------------------------------------\n * GSAP\n * --------------------------------------------------------------------------------------\n */\n\n\nvar _gsap = {\n registerPlugin: function registerPlugin() {\n for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n args[_key2] = arguments[_key2];\n }\n\n args.forEach(function (config) {\n return _createPlugin(config);\n });\n },\n timeline: function timeline(vars) {\n return new Timeline(vars);\n },\n getTweensOf: function getTweensOf(targets, onlyActive) {\n return _globalTimeline.getTweensOf(targets, onlyActive);\n },\n getProperty: function getProperty(target, property, unit, uncache) {\n _isString(target) && (target = toArray(target)[0]); //in case selector text or an array is passed in\n\n var getter = _getCache(target || {}).get,\n format = unit ? _passThrough : _numericIfPossible;\n\n unit === \"native\" && (unit = \"\");\n return !target ? target : !property ? function (property, unit, uncache) {\n return format((_plugins[property] && _plugins[property].get || getter)(target, property, unit, uncache));\n } : format((_plugins[property] && _plugins[property].get || getter)(target, property, unit, uncache));\n },\n quickSetter: function quickSetter(target, property, unit) {\n target = toArray(target);\n\n if (target.length > 1) {\n var setters = target.map(function (t) {\n return gsap.quickSetter(t, property, unit);\n }),\n l = setters.length;\n return function (value) {\n var i = l;\n\n while (i--) {\n setters[i](value);\n }\n };\n }\n\n target = target[0] || {};\n\n var Plugin = _plugins[property],\n cache = _getCache(target),\n p = cache.harness && (cache.harness.aliases || {})[property] || property,\n // in case it's an alias, like \"rotate\" for \"rotation\".\n setter = Plugin ? function (value) {\n var p = new Plugin();\n _quickTween._pt = 0;\n p.init(target, unit ? value + unit : value, _quickTween, 0, [target]);\n p.render(1, p);\n _quickTween._pt && _renderPropTweens(1, _quickTween);\n } : cache.set(target, p);\n\n return Plugin ? setter : function (value) {\n return setter(target, p, unit ? value + unit : value, cache, 1);\n };\n },\n quickTo: function quickTo(target, property, vars) {\n var _merge2;\n\n var tween = gsap.to(target, _merge((_merge2 = {}, _merge2[property] = \"+=0.1\", _merge2.paused = true, _merge2), vars || {})),\n func = function func(value, start, startIsRelative) {\n return tween.resetTo(property, value, start, startIsRelative);\n };\n\n func.tween = tween;\n return func;\n },\n isTweening: function isTweening(targets) {\n return _globalTimeline.getTweensOf(targets, true).length > 0;\n },\n defaults: function defaults(value) {\n value && value.ease && (value.ease = _parseEase(value.ease, _defaults.ease));\n return _mergeDeep(_defaults, value || {});\n },\n config: function config(value) {\n return _mergeDeep(_config, value || {});\n },\n registerEffect: function registerEffect(_ref3) {\n var name = _ref3.name,\n effect = _ref3.effect,\n plugins = _ref3.plugins,\n defaults = _ref3.defaults,\n extendTimeline = _ref3.extendTimeline;\n (plugins || \"\").split(\",\").forEach(function (pluginName) {\n return pluginName && !_plugins[pluginName] && !_globals[pluginName] && _warn(name + \" effect requires \" + pluginName + \" plugin.\");\n });\n\n _effects[name] = function (targets, vars, tl) {\n return effect(toArray(targets), _setDefaults(vars || {}, defaults), tl);\n };\n\n if (extendTimeline) {\n Timeline.prototype[name] = function (targets, vars, position) {\n return this.add(_effects[name](targets, _isObject(vars) ? vars : (position = vars) && {}, this), position);\n };\n }\n },\n registerEase: function registerEase(name, ease) {\n _easeMap[name] = _parseEase(ease);\n },\n parseEase: function parseEase(ease, defaultEase) {\n return arguments.length ? _parseEase(ease, defaultEase) : _easeMap;\n },\n getById: function getById(id) {\n return _globalTimeline.getById(id);\n },\n exportRoot: function exportRoot(vars, includeDelayedCalls) {\n if (vars === void 0) {\n vars = {};\n }\n\n var tl = new Timeline(vars),\n child,\n next;\n tl.smoothChildTiming = _isNotFalse(vars.smoothChildTiming);\n\n _globalTimeline.remove(tl);\n\n tl._dp = 0; //otherwise it'll get re-activated when adding children and be re-introduced into _globalTimeline's linked list (then added to itself).\n\n tl._time = tl._tTime = _globalTimeline._time;\n child = _globalTimeline._first;\n\n while (child) {\n next = child._next;\n\n if (includeDelayedCalls || !(!child._dur && child instanceof Tween && child.vars.onComplete === child._targets[0])) {\n _addToTimeline(tl, child, child._start - child._delay);\n }\n\n child = next;\n }\n\n _addToTimeline(_globalTimeline, tl, 0);\n\n return tl;\n },\n context: function context(func, scope) {\n return func ? new Context(func, scope) : _context;\n },\n matchMedia: function matchMedia(scope) {\n return new MatchMedia(scope);\n },\n matchMediaRefresh: function matchMediaRefresh() {\n return _media.forEach(function (c) {\n var cond = c.conditions,\n found,\n p;\n\n for (p in cond) {\n if (cond[p]) {\n cond[p] = false;\n found = 1;\n }\n }\n\n found && c.revert();\n }) || _onMediaChange();\n },\n addEventListener: function addEventListener(type, callback) {\n var a = _listeners[type] || (_listeners[type] = []);\n ~a.indexOf(callback) || a.push(callback);\n },\n removeEventListener: function removeEventListener(type, callback) {\n var a = _listeners[type],\n i = a && a.indexOf(callback);\n i >= 0 && a.splice(i, 1);\n },\n utils: {\n wrap: wrap,\n wrapYoyo: wrapYoyo,\n distribute: distribute,\n random: random,\n snap: snap,\n normalize: normalize,\n getUnit: getUnit,\n clamp: clamp,\n splitColor: splitColor,\n toArray: toArray,\n selector: selector,\n mapRange: mapRange,\n pipe: pipe,\n unitize: unitize,\n interpolate: interpolate,\n shuffle: shuffle\n },\n install: _install,\n effects: _effects,\n ticker: _ticker,\n updateRoot: Timeline.updateRoot,\n plugins: _plugins,\n globalTimeline: _globalTimeline,\n core: {\n PropTween: PropTween,\n globals: _addGlobal,\n Tween: Tween,\n Timeline: Timeline,\n Animation: Animation,\n getCache: _getCache,\n _removeLinkedListItem: _removeLinkedListItem,\n reverting: function reverting() {\n return _reverting;\n },\n context: function context(toAdd) {\n if (toAdd && _context) {\n _context.data.push(toAdd);\n\n toAdd._ctx = _context;\n }\n\n return _context;\n },\n suppressOverwrites: function suppressOverwrites(value) {\n return _suppressOverwrites = value;\n }\n }\n};\n\n_forEachName(\"to,from,fromTo,delayedCall,set,killTweensOf\", function (name) {\n return _gsap[name] = Tween[name];\n});\n\n_ticker.add(Timeline.updateRoot);\n\n_quickTween = _gsap.to({}, {\n duration: 0\n}); // ---- EXTRA PLUGINS --------------------------------------------------------\n\nvar _getPluginPropTween = function _getPluginPropTween(plugin, prop) {\n var pt = plugin._pt;\n\n while (pt && pt.p !== prop && pt.op !== prop && pt.fp !== prop) {\n pt = pt._next;\n }\n\n return pt;\n},\n _addModifiers = function _addModifiers(tween, modifiers) {\n var targets = tween._targets,\n p,\n i,\n pt;\n\n for (p in modifiers) {\n i = targets.length;\n\n while (i--) {\n pt = tween._ptLookup[i][p];\n\n if (pt && (pt = pt.d)) {\n if (pt._pt) {\n // is a plugin\n pt = _getPluginPropTween(pt, p);\n }\n\n pt && pt.modifier && pt.modifier(modifiers[p], tween, targets[i], p);\n }\n }\n }\n},\n _buildModifierPlugin = function _buildModifierPlugin(name, modifier) {\n return {\n name: name,\n rawVars: 1,\n //don't pre-process function-based values or \"random()\" strings.\n init: function init(target, vars, tween) {\n tween._onInit = function (tween) {\n var temp, p;\n\n if (_isString(vars)) {\n temp = {};\n\n _forEachName(vars, function (name) {\n return temp[name] = 1;\n }); //if the user passes in a comma-delimited list of property names to roundProps, like \"x,y\", we round to whole numbers.\n\n\n vars = temp;\n }\n\n if (modifier) {\n temp = {};\n\n for (p in vars) {\n temp[p] = modifier(vars[p]);\n }\n\n vars = temp;\n }\n\n _addModifiers(tween, vars);\n };\n }\n };\n}; //register core plugins\n\n\nvar gsap = _gsap.registerPlugin({\n name: \"attr\",\n init: function init(target, vars, tween, index, targets) {\n var p, pt, v;\n this.tween = tween;\n\n for (p in vars) {\n v = target.getAttribute(p) || \"\";\n pt = this.add(target, \"setAttribute\", (v || 0) + \"\", vars[p], index, targets, 0, 0, p);\n pt.op = p;\n pt.b = v; // record the beginning value so we can revert()\n\n this._props.push(p);\n }\n },\n render: function render(ratio, data) {\n var pt = data._pt;\n\n while (pt) {\n _reverting ? pt.set(pt.t, pt.p, pt.b, pt) : pt.r(ratio, pt.d); // if reverting, go back to the original (pt.b)\n\n pt = pt._next;\n }\n }\n}, {\n name: \"endArray\",\n init: function init(target, value) {\n var i = value.length;\n\n while (i--) {\n this.add(target, i, target[i] || 0, value[i], 0, 0, 0, 0, 0, 1);\n }\n }\n}, _buildModifierPlugin(\"roundProps\", _roundModifier), _buildModifierPlugin(\"modifiers\"), _buildModifierPlugin(\"snap\", snap)) || _gsap; //to prevent the core plugins from being dropped via aggressive tree shaking, we must include them in the variable declaration in this way.\n\nTween.version = Timeline.version = gsap.version = \"3.12.5\";\n_coreReady = 1;\n_windowExists() && _wake();\nvar Power0 = _easeMap.Power0,\n Power1 = _easeMap.Power1,\n Power2 = _easeMap.Power2,\n Power3 = _easeMap.Power3,\n Power4 = _easeMap.Power4,\n Linear = _easeMap.Linear,\n Quad = _easeMap.Quad,\n Cubic = _easeMap.Cubic,\n Quart = _easeMap.Quart,\n Quint = _easeMap.Quint,\n Strong = _easeMap.Strong,\n Elastic = _easeMap.Elastic,\n Back = _easeMap.Back,\n SteppedEase = _easeMap.SteppedEase,\n Bounce = _easeMap.Bounce,\n Sine = _easeMap.Sine,\n Expo = _easeMap.Expo,\n Circ = _easeMap.Circ;\n\n //export some internal methods/orojects for use in CSSPlugin so that we can externalize that file and allow custom builds that exclude it.\n\n\n;// CONCATENATED MODULE: ./node_modules/gsap/CSSPlugin.js\n/*!\n * CSSPlugin 3.12.5\n * https://gsap.com\n *\n * Copyright 2008-2024, GreenSock. All rights reserved.\n * Subject to the terms at https://gsap.com/standard-license or for\n * Club GSAP members, the agreement issued with that membership.\n * @author: Jack Doyle, jack@greensock.com\n*/\n\n/* eslint-disable */\n\n\nvar CSSPlugin_win,\n CSSPlugin_doc,\n _docElement,\n _pluginInitted,\n _tempDiv,\n _tempDivStyler,\n _recentSetterPlugin,\n CSSPlugin_reverting,\n CSSPlugin_windowExists = function _windowExists() {\n return typeof window !== \"undefined\";\n},\n _transformProps = {},\n _RAD2DEG = 180 / Math.PI,\n _DEG2RAD = Math.PI / 180,\n _atan2 = Math.atan2,\n CSSPlugin_bigNum = 1e8,\n _capsExp = /([A-Z])/g,\n _horizontalExp = /(left|right|width|margin|padding|x)/i,\n _complexExp = /[\\s,\\(]\\S/,\n _propertyAliases = {\n autoAlpha: \"opacity,visibility\",\n scale: \"scaleX,scaleY\",\n alpha: \"opacity\"\n},\n _renderCSSProp = function _renderCSSProp(ratio, data) {\n return data.set(data.t, data.p, Math.round((data.s + data.c * ratio) * 10000) / 10000 + data.u, data);\n},\n _renderPropWithEnd = function _renderPropWithEnd(ratio, data) {\n return data.set(data.t, data.p, ratio === 1 ? data.e : Math.round((data.s + data.c * ratio) * 10000) / 10000 + data.u, data);\n},\n _renderCSSPropWithBeginning = function _renderCSSPropWithBeginning(ratio, data) {\n return data.set(data.t, data.p, ratio ? Math.round((data.s + data.c * ratio) * 10000) / 10000 + data.u : data.b, data);\n},\n //if units change, we need a way to render the original unit/value when the tween goes all the way back to the beginning (ratio:0)\n_renderRoundedCSSProp = function _renderRoundedCSSProp(ratio, data) {\n var value = data.s + data.c * ratio;\n data.set(data.t, data.p, ~~(value + (value < 0 ? -.5 : .5)) + data.u, data);\n},\n _renderNonTweeningValue = function _renderNonTweeningValue(ratio, data) {\n return data.set(data.t, data.p, ratio ? data.e : data.b, data);\n},\n _renderNonTweeningValueOnlyAtEnd = function _renderNonTweeningValueOnlyAtEnd(ratio, data) {\n return data.set(data.t, data.p, ratio !== 1 ? data.b : data.e, data);\n},\n _setterCSSStyle = function _setterCSSStyle(target, property, value) {\n return target.style[property] = value;\n},\n _setterCSSProp = function _setterCSSProp(target, property, value) {\n return target.style.setProperty(property, value);\n},\n _setterTransform = function _setterTransform(target, property, value) {\n return target._gsap[property] = value;\n},\n _setterScale = function _setterScale(target, property, value) {\n return target._gsap.scaleX = target._gsap.scaleY = value;\n},\n _setterScaleWithRender = function _setterScaleWithRender(target, property, value, data, ratio) {\n var cache = target._gsap;\n cache.scaleX = cache.scaleY = value;\n cache.renderTransform(ratio, cache);\n},\n _setterTransformWithRender = function _setterTransformWithRender(target, property, value, data, ratio) {\n var cache = target._gsap;\n cache[property] = value;\n cache.renderTransform(ratio, cache);\n},\n _transformProp = \"transform\",\n _transformOriginProp = _transformProp + \"Origin\",\n _saveStyle = function _saveStyle(property, isNotCSS) {\n var _this = this;\n\n var target = this.target,\n style = target.style,\n cache = target._gsap;\n\n if (property in _transformProps && style) {\n this.tfm = this.tfm || {};\n\n if (property !== \"transform\") {\n property = _propertyAliases[property] || property;\n ~property.indexOf(\",\") ? property.split(\",\").forEach(function (a) {\n return _this.tfm[a] = _get(target, a);\n }) : this.tfm[property] = cache.x ? cache[property] : _get(target, property); // note: scale would map to \"scaleX,scaleY\", thus we loop and apply them both.\n\n property === _transformOriginProp && (this.tfm.zOrigin = cache.zOrigin);\n } else {\n return _propertyAliases.transform.split(\",\").forEach(function (p) {\n return _saveStyle.call(_this, p, isNotCSS);\n });\n }\n\n if (this.props.indexOf(_transformProp) >= 0) {\n return;\n }\n\n if (cache.svg) {\n this.svgo = target.getAttribute(\"data-svg-origin\");\n this.props.push(_transformOriginProp, isNotCSS, \"\");\n }\n\n property = _transformProp;\n }\n\n (style || isNotCSS) && this.props.push(property, isNotCSS, style[property]);\n},\n _removeIndependentTransforms = function _removeIndependentTransforms(style) {\n if (style.translate) {\n style.removeProperty(\"translate\");\n style.removeProperty(\"scale\");\n style.removeProperty(\"rotate\");\n }\n},\n _revertStyle = function _revertStyle() {\n var props = this.props,\n target = this.target,\n style = target.style,\n cache = target._gsap,\n i,\n p;\n\n for (i = 0; i < props.length; i += 3) {\n // stored like this: property, isNotCSS, value\n props[i + 1] ? target[props[i]] = props[i + 2] : props[i + 2] ? style[props[i]] = props[i + 2] : style.removeProperty(props[i].substr(0, 2) === \"--\" ? props[i] : props[i].replace(_capsExp, \"-$1\").toLowerCase());\n }\n\n if (this.tfm) {\n for (p in this.tfm) {\n cache[p] = this.tfm[p];\n }\n\n if (cache.svg) {\n cache.renderTransform();\n target.setAttribute(\"data-svg-origin\", this.svgo || \"\");\n }\n\n i = CSSPlugin_reverting();\n\n if ((!i || !i.isStart) && !style[_transformProp]) {\n _removeIndependentTransforms(style);\n\n if (cache.zOrigin && style[_transformOriginProp]) {\n style[_transformOriginProp] += \" \" + cache.zOrigin + \"px\"; // since we're uncaching, we must put the zOrigin back into the transformOrigin so that we can pull it out accurately when we parse again. Otherwise, we'd lose the z portion of the origin since we extract it to protect from Safari bugs.\n\n cache.zOrigin = 0;\n cache.renderTransform();\n }\n\n cache.uncache = 1; // if it's a startAt that's being reverted in the _initTween() of the core, we don't need to uncache transforms. This is purely a performance optimization.\n }\n }\n},\n _getStyleSaver = function _getStyleSaver(target, properties) {\n var saver = {\n target: target,\n props: [],\n revert: _revertStyle,\n save: _saveStyle\n };\n target._gsap || gsap.core.getCache(target); // just make sure there's a _gsap cache defined because we read from it in _saveStyle() and it's more efficient to just check it here once.\n\n properties && properties.split(\",\").forEach(function (p) {\n return saver.save(p);\n });\n return saver;\n},\n _supports3D,\n _createElement = function _createElement(type, ns) {\n var e = CSSPlugin_doc.createElementNS ? CSSPlugin_doc.createElementNS((ns || \"http://www.w3.org/1999/xhtml\").replace(/^https/, \"http\"), type) : CSSPlugin_doc.createElement(type); //some servers swap in https for http in the namespace which can break things, making \"style\" inaccessible.\n\n return e && e.style ? e : CSSPlugin_doc.createElement(type); //some environments won't allow access to the element's style when created with a namespace in which case we default to the standard createElement() to work around the issue. Also note that when GSAP is embedded directly inside an SVG file, createElement() won't allow access to the style object in Firefox (see https://gsap.com/forums/topic/20215-problem-using-tweenmax-in-standalone-self-containing-svg-file-err-cannot-set-property-csstext-of-undefined/).\n},\n _getComputedProperty = function _getComputedProperty(target, property, skipPrefixFallback) {\n var cs = getComputedStyle(target);\n return cs[property] || cs.getPropertyValue(property.replace(_capsExp, \"-$1\").toLowerCase()) || cs.getPropertyValue(property) || !skipPrefixFallback && _getComputedProperty(target, _checkPropPrefix(property) || property, 1) || \"\"; //css variables may not need caps swapped out for dashes and lowercase.\n},\n _prefixes = \"O,Moz,ms,Ms,Webkit\".split(\",\"),\n _checkPropPrefix = function _checkPropPrefix(property, element, preferPrefix) {\n var e = element || _tempDiv,\n s = e.style,\n i = 5;\n\n if (property in s && !preferPrefix) {\n return property;\n }\n\n property = property.charAt(0).toUpperCase() + property.substr(1);\n\n while (i-- && !(_prefixes[i] + property in s)) {}\n\n return i < 0 ? null : (i === 3 ? \"ms\" : i >= 0 ? _prefixes[i] : \"\") + property;\n},\n _initCore = function _initCore() {\n if (CSSPlugin_windowExists() && window.document) {\n CSSPlugin_win = window;\n CSSPlugin_doc = CSSPlugin_win.document;\n _docElement = CSSPlugin_doc.documentElement;\n _tempDiv = _createElement(\"div\") || {\n style: {}\n };\n _tempDivStyler = _createElement(\"div\");\n _transformProp = _checkPropPrefix(_transformProp);\n _transformOriginProp = _transformProp + \"Origin\";\n _tempDiv.style.cssText = \"border-width:0;line-height:0;position:absolute;padding:0\"; //make sure to override certain properties that may contaminate measurements, in case the user has overreaching style sheets.\n\n _supports3D = !!_checkPropPrefix(\"perspective\");\n CSSPlugin_reverting = gsap.core.reverting;\n _pluginInitted = 1;\n }\n},\n _getBBoxHack = function _getBBoxHack(swapIfPossible) {\n //works around issues in some browsers (like Firefox) that don't correctly report getBBox() on SVG elements inside a element and/or . We try creating an SVG, adding it to the documentElement and toss the element in there so that it's definitely part of the rendering tree, then grab the bbox and if it works, we actually swap out the original getBBox() method for our own that does these extra steps whenever getBBox is needed. This helps ensure that performance is optimal (only do all these extra steps when absolutely necessary...most elements don't need it).\n var svg = _createElement(\"svg\", this.ownerSVGElement && this.ownerSVGElement.getAttribute(\"xmlns\") || \"http://www.w3.org/2000/svg\"),\n oldParent = this.parentNode,\n oldSibling = this.nextSibling,\n oldCSS = this.style.cssText,\n bbox;\n\n _docElement.appendChild(svg);\n\n svg.appendChild(this);\n this.style.display = \"block\";\n\n if (swapIfPossible) {\n try {\n bbox = this.getBBox();\n this._gsapBBox = this.getBBox; //store the original\n\n this.getBBox = _getBBoxHack;\n } catch (e) {}\n } else if (this._gsapBBox) {\n bbox = this._gsapBBox();\n }\n\n if (oldParent) {\n if (oldSibling) {\n oldParent.insertBefore(this, oldSibling);\n } else {\n oldParent.appendChild(this);\n }\n }\n\n _docElement.removeChild(svg);\n\n this.style.cssText = oldCSS;\n return bbox;\n},\n _getAttributeFallbacks = function _getAttributeFallbacks(target, attributesArray) {\n var i = attributesArray.length;\n\n while (i--) {\n if (target.hasAttribute(attributesArray[i])) {\n return target.getAttribute(attributesArray[i]);\n }\n }\n},\n _getBBox = function _getBBox(target) {\n var bounds;\n\n try {\n bounds = target.getBBox(); //Firefox throws errors if you try calling getBBox() on an SVG element that's not rendered (like in a or ). https://bugzilla.mozilla.org/show_bug.cgi?id=612118\n } catch (error) {\n bounds = _getBBoxHack.call(target, true);\n }\n\n bounds && (bounds.width || bounds.height) || target.getBBox === _getBBoxHack || (bounds = _getBBoxHack.call(target, true)); //some browsers (like Firefox) misreport the bounds if the element has zero width and height (it just assumes it's at x:0, y:0), thus we need to manually grab the position in that case.\n\n return bounds && !bounds.width && !bounds.x && !bounds.y ? {\n x: +_getAttributeFallbacks(target, [\"x\", \"cx\", \"x1\"]) || 0,\n y: +_getAttributeFallbacks(target, [\"y\", \"cy\", \"y1\"]) || 0,\n width: 0,\n height: 0\n } : bounds;\n},\n _isSVG = function _isSVG(e) {\n return !!(e.getCTM && (!e.parentNode || e.ownerSVGElement) && _getBBox(e));\n},\n //reports if the element is an SVG on which getBBox() actually works\n_removeProperty = function _removeProperty(target, property) {\n if (property) {\n var style = target.style,\n first2Chars;\n\n if (property in _transformProps && property !== _transformOriginProp) {\n property = _transformProp;\n }\n\n if (style.removeProperty) {\n first2Chars = property.substr(0, 2);\n\n if (first2Chars === \"ms\" || property.substr(0, 6) === \"webkit\") {\n //Microsoft and some Webkit browsers don't conform to the standard of capitalizing the first prefix character, so we adjust so that when we prefix the caps with a dash, it's correct (otherwise it'd be \"ms-transform\" instead of \"-ms-transform\" for IE9, for example)\n property = \"-\" + property;\n }\n\n style.removeProperty(first2Chars === \"--\" ? property : property.replace(_capsExp, \"-$1\").toLowerCase());\n } else {\n //note: old versions of IE use \"removeAttribute()\" instead of \"removeProperty()\"\n style.removeAttribute(property);\n }\n }\n},\n _addNonTweeningPT = function _addNonTweeningPT(plugin, target, property, beginning, end, onlySetAtEnd) {\n var pt = new PropTween(plugin._pt, target, property, 0, 1, onlySetAtEnd ? _renderNonTweeningValueOnlyAtEnd : _renderNonTweeningValue);\n plugin._pt = pt;\n pt.b = beginning;\n pt.e = end;\n\n plugin._props.push(property);\n\n return pt;\n},\n _nonConvertibleUnits = {\n deg: 1,\n rad: 1,\n turn: 1\n},\n _nonStandardLayouts = {\n grid: 1,\n flex: 1\n},\n //takes a single value like 20px and converts it to the unit specified, like \"%\", returning only the numeric amount.\n_convertToUnit = function _convertToUnit(target, property, value, unit) {\n var curValue = parseFloat(value) || 0,\n curUnit = (value + \"\").trim().substr((curValue + \"\").length) || \"px\",\n // some browsers leave extra whitespace at the beginning of CSS variables, hence the need to trim()\n style = _tempDiv.style,\n horizontal = _horizontalExp.test(property),\n isRootSVG = target.tagName.toLowerCase() === \"svg\",\n measureProperty = (isRootSVG ? \"client\" : \"offset\") + (horizontal ? \"Width\" : \"Height\"),\n amount = 100,\n toPixels = unit === \"px\",\n toPercent = unit === \"%\",\n px,\n parent,\n cache,\n isSVG;\n\n if (unit === curUnit || !curValue || _nonConvertibleUnits[unit] || _nonConvertibleUnits[curUnit]) {\n return curValue;\n }\n\n curUnit !== \"px\" && !toPixels && (curValue = _convertToUnit(target, property, value, \"px\"));\n isSVG = target.getCTM && _isSVG(target);\n\n if ((toPercent || curUnit === \"%\") && (_transformProps[property] || ~property.indexOf(\"adius\"))) {\n px = isSVG ? target.getBBox()[horizontal ? \"width\" : \"height\"] : target[measureProperty];\n return _round(toPercent ? curValue / px * amount : curValue / 100 * px);\n }\n\n style[horizontal ? \"width\" : \"height\"] = amount + (toPixels ? curUnit : unit);\n parent = ~property.indexOf(\"adius\") || unit === \"em\" && target.appendChild && !isRootSVG ? target : target.parentNode;\n\n if (isSVG) {\n parent = (target.ownerSVGElement || {}).parentNode;\n }\n\n if (!parent || parent === CSSPlugin_doc || !parent.appendChild) {\n parent = CSSPlugin_doc.body;\n }\n\n cache = parent._gsap;\n\n if (cache && toPercent && cache.width && horizontal && cache.time === _ticker.time && !cache.uncache) {\n return _round(curValue / cache.width * amount);\n } else {\n if (toPercent && (property === \"height\" || property === \"width\")) {\n // if we're dealing with width/height that's inside a container with padding and/or it's a flexbox/grid container, we must apply it to the target itself rather than the _tempDiv in order to ensure complete accuracy, factoring in the parent's padding.\n var v = target.style[property];\n target.style[property] = amount + unit;\n px = target[measureProperty];\n v ? target.style[property] = v : _removeProperty(target, property);\n } else {\n (toPercent || curUnit === \"%\") && !_nonStandardLayouts[_getComputedProperty(parent, \"display\")] && (style.position = _getComputedProperty(target, \"position\"));\n parent === target && (style.position = \"static\"); // like for borderRadius, if it's a % we must have it relative to the target itself but that may not have position: relative or position: absolute in which case it'd go up the chain until it finds its offsetParent (bad). position: static protects against that.\n\n parent.appendChild(_tempDiv);\n px = _tempDiv[measureProperty];\n parent.removeChild(_tempDiv);\n style.position = \"absolute\";\n }\n\n if (horizontal && toPercent) {\n cache = _getCache(parent);\n cache.time = _ticker.time;\n cache.width = parent[measureProperty];\n }\n }\n\n return _round(toPixels ? px * curValue / amount : px && curValue ? amount / px * curValue : 0);\n},\n _get = function _get(target, property, unit, uncache) {\n var value;\n _pluginInitted || _initCore();\n\n if (property in _propertyAliases && property !== \"transform\") {\n property = _propertyAliases[property];\n\n if (~property.indexOf(\",\")) {\n property = property.split(\",\")[0];\n }\n }\n\n if (_transformProps[property] && property !== \"transform\") {\n value = _parseTransform(target, uncache);\n value = property !== \"transformOrigin\" ? value[property] : value.svg ? value.origin : _firstTwoOnly(_getComputedProperty(target, _transformOriginProp)) + \" \" + value.zOrigin + \"px\";\n } else {\n value = target.style[property];\n\n if (!value || value === \"auto\" || uncache || ~(value + \"\").indexOf(\"calc(\")) {\n value = _specialProps[property] && _specialProps[property](target, property, unit) || _getComputedProperty(target, property) || _getProperty(target, property) || (property === \"opacity\" ? 1 : 0); // note: some browsers, like Firefox, don't report borderRadius correctly! Instead, it only reports every corner like borderTopLeftRadius\n }\n }\n\n return unit && !~(value + \"\").trim().indexOf(\" \") ? _convertToUnit(target, property, value, unit) + unit : value;\n},\n _tweenComplexCSSString = function _tweenComplexCSSString(target, prop, start, end) {\n // note: we call _tweenComplexCSSString.call(pluginInstance...) to ensure that it's scoped properly. We may call it from within a plugin too, thus \"this\" would refer to the plugin.\n if (!start || start === \"none\") {\n // some browsers like Safari actually PREFER the prefixed property and mis-report the unprefixed value like clipPath (BUG). In other words, even though clipPath exists in the style (\"clipPath\" in target.style) and it's set in the CSS properly (along with -webkit-clip-path), Safari reports clipPath as \"none\" whereas WebkitClipPath reports accurately like \"ellipse(100% 0% at 50% 0%)\", so in this case we must SWITCH to using the prefixed property instead. See https://gsap.com/forums/topic/18310-clippath-doesnt-work-on-ios/\n var p = _checkPropPrefix(prop, target, 1),\n s = p && _getComputedProperty(target, p, 1);\n\n if (s && s !== start) {\n prop = p;\n start = s;\n } else if (prop === \"borderColor\") {\n start = _getComputedProperty(target, \"borderTopColor\"); // Firefox bug: always reports \"borderColor\" as \"\", so we must fall back to borderTopColor. See https://gsap.com/forums/topic/24583-how-to-return-colors-that-i-had-after-reverse/\n }\n }\n\n var pt = new PropTween(this._pt, target.style, prop, 0, 1, _renderComplexString),\n index = 0,\n matchIndex = 0,\n a,\n result,\n startValues,\n startNum,\n color,\n startValue,\n endValue,\n endNum,\n chunk,\n endUnit,\n startUnit,\n endValues;\n pt.b = start;\n pt.e = end;\n start += \"\"; // ensure values are strings\n\n end += \"\";\n\n if (end === \"auto\") {\n startValue = target.style[prop];\n target.style[prop] = end;\n end = _getComputedProperty(target, prop) || end;\n startValue ? target.style[prop] = startValue : _removeProperty(target, prop);\n }\n\n a = [start, end];\n\n _colorStringFilter(a); // pass an array with the starting and ending values and let the filter do whatever it needs to the values. If colors are found, it returns true and then we must match where the color shows up order-wise because for things like boxShadow, sometimes the browser provides the computed values with the color FIRST, but the user provides it with the color LAST, so flip them if necessary. Same for drop-shadow().\n\n\n start = a[0];\n end = a[1];\n startValues = start.match(_numWithUnitExp) || [];\n endValues = end.match(_numWithUnitExp) || [];\n\n if (endValues.length) {\n while (result = _numWithUnitExp.exec(end)) {\n endValue = result[0];\n chunk = end.substring(index, result.index);\n\n if (color) {\n color = (color + 1) % 5;\n } else if (chunk.substr(-5) === \"rgba(\" || chunk.substr(-5) === \"hsla(\") {\n color = 1;\n }\n\n if (endValue !== (startValue = startValues[matchIndex++] || \"\")) {\n startNum = parseFloat(startValue) || 0;\n startUnit = startValue.substr((startNum + \"\").length);\n endValue.charAt(1) === \"=\" && (endValue = _parseRelative(startNum, endValue) + startUnit);\n endNum = parseFloat(endValue);\n endUnit = endValue.substr((endNum + \"\").length);\n index = _numWithUnitExp.lastIndex - endUnit.length;\n\n if (!endUnit) {\n //if something like \"perspective:300\" is passed in and we must add a unit to the end\n endUnit = endUnit || _config.units[prop] || startUnit;\n\n if (index === end.length) {\n end += endUnit;\n pt.e += endUnit;\n }\n }\n\n if (startUnit !== endUnit) {\n startNum = _convertToUnit(target, prop, startValue, endUnit) || 0;\n } // these nested PropTweens are handled in a special way - we'll never actually call a render or setter method on them. We'll just loop through them in the parent complex string PropTween's render method.\n\n\n pt._pt = {\n _next: pt._pt,\n p: chunk || matchIndex === 1 ? chunk : \",\",\n //note: SVG spec allows omission of comma/space when a negative sign is wedged between two numbers, like 2.5-5.3 instead of 2.5,-5.3 but when tweening, the negative value may switch to positive, so we insert the comma just in case.\n s: startNum,\n c: endNum - startNum,\n m: color && color < 4 || prop === \"zIndex\" ? Math.round : 0\n };\n }\n }\n\n pt.c = index < end.length ? end.substring(index, end.length) : \"\"; //we use the \"c\" of the PropTween to store the final part of the string (after the last number)\n } else {\n pt.r = prop === \"display\" && end === \"none\" ? _renderNonTweeningValueOnlyAtEnd : _renderNonTweeningValue;\n }\n\n _relExp.test(end) && (pt.e = 0); //if the end string contains relative values or dynamic random(...) values, delete the end it so that on the final render we don't actually set it to the string with += or -= characters (forces it to use the calculated value).\n\n this._pt = pt; //start the linked list with this new PropTween. Remember, we call _tweenComplexCSSString.call(pluginInstance...) to ensure that it's scoped properly. We may call it from within another plugin too, thus \"this\" would refer to the plugin.\n\n return pt;\n},\n _keywordToPercent = {\n top: \"0%\",\n bottom: \"100%\",\n left: \"0%\",\n right: \"100%\",\n center: \"50%\"\n},\n _convertKeywordsToPercentages = function _convertKeywordsToPercentages(value) {\n var split = value.split(\" \"),\n x = split[0],\n y = split[1] || \"50%\";\n\n if (x === \"top\" || x === \"bottom\" || y === \"left\" || y === \"right\") {\n //the user provided them in the wrong order, so flip them\n value = x;\n x = y;\n y = value;\n }\n\n split[0] = _keywordToPercent[x] || x;\n split[1] = _keywordToPercent[y] || y;\n return split.join(\" \");\n},\n _renderClearProps = function _renderClearProps(ratio, data) {\n if (data.tween && data.tween._time === data.tween._dur) {\n var target = data.t,\n style = target.style,\n props = data.u,\n cache = target._gsap,\n prop,\n clearTransforms,\n i;\n\n if (props === \"all\" || props === true) {\n style.cssText = \"\";\n clearTransforms = 1;\n } else {\n props = props.split(\",\");\n i = props.length;\n\n while (--i > -1) {\n prop = props[i];\n\n if (_transformProps[prop]) {\n clearTransforms = 1;\n prop = prop === \"transformOrigin\" ? _transformOriginProp : _transformProp;\n }\n\n _removeProperty(target, prop);\n }\n }\n\n if (clearTransforms) {\n _removeProperty(target, _transformProp);\n\n if (cache) {\n cache.svg && target.removeAttribute(\"transform\");\n\n _parseTransform(target, 1); // force all the cached values back to \"normal\"/identity, otherwise if there's another tween that's already set to render transforms on this element, it could display the wrong values.\n\n\n cache.uncache = 1;\n\n _removeIndependentTransforms(style);\n }\n }\n }\n},\n // note: specialProps should return 1 if (and only if) they have a non-zero priority. It indicates we need to sort the linked list.\n_specialProps = {\n clearProps: function clearProps(plugin, target, property, endValue, tween) {\n if (tween.data !== \"isFromStart\") {\n var pt = plugin._pt = new PropTween(plugin._pt, target, property, 0, 0, _renderClearProps);\n pt.u = endValue;\n pt.pr = -10;\n pt.tween = tween;\n\n plugin._props.push(property);\n\n return 1;\n }\n }\n /* className feature (about 0.4kb gzipped).\n , className(plugin, target, property, endValue, tween) {\n \tlet _renderClassName = (ratio, data) => {\n \t\t\tdata.css.render(ratio, data.css);\n \t\t\tif (!ratio || ratio === 1) {\n \t\t\t\tlet inline = data.rmv,\n \t\t\t\t\ttarget = data.t,\n \t\t\t\t\tp;\n \t\t\t\ttarget.setAttribute(\"class\", ratio ? data.e : data.b);\n \t\t\t\tfor (p in inline) {\n \t\t\t\t\t_removeProperty(target, p);\n \t\t\t\t}\n \t\t\t}\n \t\t},\n \t\t_getAllStyles = (target) => {\n \t\t\tlet styles = {},\n \t\t\t\tcomputed = getComputedStyle(target),\n \t\t\t\tp;\n \t\t\tfor (p in computed) {\n \t\t\t\tif (isNaN(p) && p !== \"cssText\" && p !== \"length\") {\n \t\t\t\t\tstyles[p] = computed[p];\n \t\t\t\t}\n \t\t\t}\n \t\t\t_setDefaults(styles, _parseTransform(target, 1));\n \t\t\treturn styles;\n \t\t},\n \t\tstartClassList = target.getAttribute(\"class\"),\n \t\tstyle = target.style,\n \t\tcssText = style.cssText,\n \t\tcache = target._gsap,\n \t\tclassPT = cache.classPT,\n \t\tinlineToRemoveAtEnd = {},\n \t\tdata = {t:target, plugin:plugin, rmv:inlineToRemoveAtEnd, b:startClassList, e:(endValue.charAt(1) !== \"=\") ? endValue : startClassList.replace(new RegExp(\"(?:\\\\s|^)\" + endValue.substr(2) + \"(?![\\\\w-])\"), \"\") + ((endValue.charAt(0) === \"+\") ? \" \" + endValue.substr(2) : \"\")},\n \t\tchangingVars = {},\n \t\tstartVars = _getAllStyles(target),\n \t\ttransformRelated = /(transform|perspective)/i,\n \t\tendVars, p;\n \tif (classPT) {\n \t\tclassPT.r(1, classPT.d);\n \t\t_removeLinkedListItem(classPT.d.plugin, classPT, \"_pt\");\n \t}\n \ttarget.setAttribute(\"class\", data.e);\n \tendVars = _getAllStyles(target, true);\n \ttarget.setAttribute(\"class\", startClassList);\n \tfor (p in endVars) {\n \t\tif (endVars[p] !== startVars[p] && !transformRelated.test(p)) {\n \t\t\tchangingVars[p] = endVars[p];\n \t\t\tif (!style[p] && style[p] !== \"0\") {\n \t\t\t\tinlineToRemoveAtEnd[p] = 1;\n \t\t\t}\n \t\t}\n \t}\n \tcache.classPT = plugin._pt = new PropTween(plugin._pt, target, \"className\", 0, 0, _renderClassName, data, 0, -11);\n \tif (style.cssText !== cssText) { //only apply if things change. Otherwise, in cases like a background-image that's pulled dynamically, it could cause a refresh. See https://gsap.com/forums/topic/20368-possible-gsap-bug-switching-classnames-in-chrome/.\n \t\tstyle.cssText = cssText; //we recorded cssText before we swapped classes and ran _getAllStyles() because in cases when a className tween is overwritten, we remove all the related tweening properties from that class change (otherwise class-specific stuff can't override properties we've directly set on the target's style object due to specificity).\n \t}\n \t_parseTransform(target, true); //to clear the caching of transforms\n \tdata.css = new gsap.plugins.css();\n \tdata.css.init(target, changingVars, tween);\n \tplugin._props.push(...data.css._props);\n \treturn 1;\n }\n */\n\n},\n\n/*\n * --------------------------------------------------------------------------------------\n * TRANSFORMS\n * --------------------------------------------------------------------------------------\n */\n_identity2DMatrix = [1, 0, 0, 1, 0, 0],\n _rotationalProperties = {},\n _isNullTransform = function _isNullTransform(value) {\n return value === \"matrix(1, 0, 0, 1, 0, 0)\" || value === \"none\" || !value;\n},\n _getComputedTransformMatrixAsArray = function _getComputedTransformMatrixAsArray(target) {\n var matrixString = _getComputedProperty(target, _transformProp);\n\n return _isNullTransform(matrixString) ? _identity2DMatrix : matrixString.substr(7).match(_numExp).map(_round);\n},\n _getMatrix = function _getMatrix(target, force2D) {\n var cache = target._gsap || _getCache(target),\n style = target.style,\n matrix = _getComputedTransformMatrixAsArray(target),\n parent,\n nextSibling,\n temp,\n addedToDOM;\n\n if (cache.svg && target.getAttribute(\"transform\")) {\n temp = target.transform.baseVal.consolidate().matrix; //ensures that even complex values like \"translate(50,60) rotate(135,0,0)\" are parsed because it mashes it into a matrix.\n\n matrix = [temp.a, temp.b, temp.c, temp.d, temp.e, temp.f];\n return matrix.join(\",\") === \"1,0,0,1,0,0\" ? _identity2DMatrix : matrix;\n } else if (matrix === _identity2DMatrix && !target.offsetParent && target !== _docElement && !cache.svg) {\n //note: if offsetParent is null, that means the element isn't in the normal document flow, like if it has display:none or one of its ancestors has display:none). Firefox returns null for getComputedStyle() if the element is in an iframe that has display:none. https://bugzilla.mozilla.org/show_bug.cgi?id=548397\n //browsers don't report transforms accurately unless the element is in the DOM and has a display value that's not \"none\". Firefox and Microsoft browsers have a partial bug where they'll report transforms even if display:none BUT not any percentage-based values like translate(-50%, 8px) will be reported as if it's translate(0, 8px).\n temp = style.display;\n style.display = \"block\";\n parent = target.parentNode;\n\n if (!parent || !target.offsetParent) {\n // note: in 3.3.0 we switched target.offsetParent to _doc.body.contains(target) to avoid [sometimes unnecessary] MutationObserver calls but that wasn't adequate because there are edge cases where nested position: fixed elements need to get reparented to accurately sense transforms. See https://github.com/greensock/GSAP/issues/388 and https://github.com/greensock/GSAP/issues/375\n addedToDOM = 1; //flag\n\n nextSibling = target.nextElementSibling;\n\n _docElement.appendChild(target); //we must add it to the DOM in order to get values properly\n\n }\n\n matrix = _getComputedTransformMatrixAsArray(target);\n temp ? style.display = temp : _removeProperty(target, \"display\");\n\n if (addedToDOM) {\n nextSibling ? parent.insertBefore(target, nextSibling) : parent ? parent.appendChild(target) : _docElement.removeChild(target);\n }\n }\n\n return force2D && matrix.length > 6 ? [matrix[0], matrix[1], matrix[4], matrix[5], matrix[12], matrix[13]] : matrix;\n},\n _applySVGOrigin = function _applySVGOrigin(target, origin, originIsAbsolute, smooth, matrixArray, pluginToAddPropTweensTo) {\n var cache = target._gsap,\n matrix = matrixArray || _getMatrix(target, true),\n xOriginOld = cache.xOrigin || 0,\n yOriginOld = cache.yOrigin || 0,\n xOffsetOld = cache.xOffset || 0,\n yOffsetOld = cache.yOffset || 0,\n a = matrix[0],\n b = matrix[1],\n c = matrix[2],\n d = matrix[3],\n tx = matrix[4],\n ty = matrix[5],\n originSplit = origin.split(\" \"),\n xOrigin = parseFloat(originSplit[0]) || 0,\n yOrigin = parseFloat(originSplit[1]) || 0,\n bounds,\n determinant,\n x,\n y;\n\n if (!originIsAbsolute) {\n bounds = _getBBox(target);\n xOrigin = bounds.x + (~originSplit[0].indexOf(\"%\") ? xOrigin / 100 * bounds.width : xOrigin);\n yOrigin = bounds.y + (~(originSplit[1] || originSplit[0]).indexOf(\"%\") ? yOrigin / 100 * bounds.height : yOrigin); // if (!(\"xOrigin\" in cache) && (xOrigin || yOrigin)) { // added in 3.12.3, reverted in 3.12.4; requires more exploration\n // \txOrigin -= bounds.x;\n // \tyOrigin -= bounds.y;\n // }\n } else if (matrix !== _identity2DMatrix && (determinant = a * d - b * c)) {\n //if it's zero (like if scaleX and scaleY are zero), skip it to avoid errors with dividing by zero.\n x = xOrigin * (d / determinant) + yOrigin * (-c / determinant) + (c * ty - d * tx) / determinant;\n y = xOrigin * (-b / determinant) + yOrigin * (a / determinant) - (a * ty - b * tx) / determinant;\n xOrigin = x;\n yOrigin = y; // theory: we only had to do this for smoothing and it assumes that the previous one was not originIsAbsolute.\n }\n\n if (smooth || smooth !== false && cache.smooth) {\n tx = xOrigin - xOriginOld;\n ty = yOrigin - yOriginOld;\n cache.xOffset = xOffsetOld + (tx * a + ty * c) - tx;\n cache.yOffset = yOffsetOld + (tx * b + ty * d) - ty;\n } else {\n cache.xOffset = cache.yOffset = 0;\n }\n\n cache.xOrigin = xOrigin;\n cache.yOrigin = yOrigin;\n cache.smooth = !!smooth;\n cache.origin = origin;\n cache.originIsAbsolute = !!originIsAbsolute;\n target.style[_transformOriginProp] = \"0px 0px\"; //otherwise, if someone sets an origin via CSS, it will likely interfere with the SVG transform attribute ones (because remember, we're baking the origin into the matrix() value).\n\n if (pluginToAddPropTweensTo) {\n _addNonTweeningPT(pluginToAddPropTweensTo, cache, \"xOrigin\", xOriginOld, xOrigin);\n\n _addNonTweeningPT(pluginToAddPropTweensTo, cache, \"yOrigin\", yOriginOld, yOrigin);\n\n _addNonTweeningPT(pluginToAddPropTweensTo, cache, \"xOffset\", xOffsetOld, cache.xOffset);\n\n _addNonTweeningPT(pluginToAddPropTweensTo, cache, \"yOffset\", yOffsetOld, cache.yOffset);\n }\n\n target.setAttribute(\"data-svg-origin\", xOrigin + \" \" + yOrigin);\n},\n _parseTransform = function _parseTransform(target, uncache) {\n var cache = target._gsap || new GSCache(target);\n\n if (\"x\" in cache && !uncache && !cache.uncache) {\n return cache;\n }\n\n var style = target.style,\n invertedScaleX = cache.scaleX < 0,\n px = \"px\",\n deg = \"deg\",\n cs = getComputedStyle(target),\n origin = _getComputedProperty(target, _transformOriginProp) || \"0\",\n x,\n y,\n z,\n scaleX,\n scaleY,\n rotation,\n rotationX,\n rotationY,\n skewX,\n skewY,\n perspective,\n xOrigin,\n yOrigin,\n matrix,\n angle,\n cos,\n sin,\n a,\n b,\n c,\n d,\n a12,\n a22,\n t1,\n t2,\n t3,\n a13,\n a23,\n a33,\n a42,\n a43,\n a32;\n x = y = z = rotation = rotationX = rotationY = skewX = skewY = perspective = 0;\n scaleX = scaleY = 1;\n cache.svg = !!(target.getCTM && _isSVG(target));\n\n if (cs.translate) {\n // accommodate independent transforms by combining them into normal ones.\n if (cs.translate !== \"none\" || cs.scale !== \"none\" || cs.rotate !== \"none\") {\n style[_transformProp] = (cs.translate !== \"none\" ? \"translate3d(\" + (cs.translate + \" 0 0\").split(\" \").slice(0, 3).join(\", \") + \") \" : \"\") + (cs.rotate !== \"none\" ? \"rotate(\" + cs.rotate + \") \" : \"\") + (cs.scale !== \"none\" ? \"scale(\" + cs.scale.split(\" \").join(\",\") + \") \" : \"\") + (cs[_transformProp] !== \"none\" ? cs[_transformProp] : \"\");\n }\n\n style.scale = style.rotate = style.translate = \"none\";\n }\n\n matrix = _getMatrix(target, cache.svg);\n\n if (cache.svg) {\n if (cache.uncache) {\n // if cache.uncache is true (and maybe if origin is 0,0), we need to set element.style.transformOrigin = (cache.xOrigin - bbox.x) + \"px \" + (cache.yOrigin - bbox.y) + \"px\". Previously we let the data-svg-origin stay instead, but when introducing revert(), it complicated things.\n t2 = target.getBBox();\n origin = cache.xOrigin - t2.x + \"px \" + (cache.yOrigin - t2.y) + \"px\";\n t1 = \"\";\n } else {\n t1 = !uncache && target.getAttribute(\"data-svg-origin\"); // Remember, to work around browser inconsistencies we always force SVG elements' transformOrigin to 0,0 and offset the translation accordingly.\n }\n\n _applySVGOrigin(target, t1 || origin, !!t1 || cache.originIsAbsolute, cache.smooth !== false, matrix);\n }\n\n xOrigin = cache.xOrigin || 0;\n yOrigin = cache.yOrigin || 0;\n\n if (matrix !== _identity2DMatrix) {\n a = matrix[0]; //a11\n\n b = matrix[1]; //a21\n\n c = matrix[2]; //a31\n\n d = matrix[3]; //a41\n\n x = a12 = matrix[4];\n y = a22 = matrix[5]; //2D matrix\n\n if (matrix.length === 6) {\n scaleX = Math.sqrt(a * a + b * b);\n scaleY = Math.sqrt(d * d + c * c);\n rotation = a || b ? _atan2(b, a) * _RAD2DEG : 0; //note: if scaleX is 0, we cannot accurately measure rotation. Same for skewX with a scaleY of 0. Therefore, we default to the previously recorded value (or zero if that doesn't exist).\n\n skewX = c || d ? _atan2(c, d) * _RAD2DEG + rotation : 0;\n skewX && (scaleY *= Math.abs(Math.cos(skewX * _DEG2RAD)));\n\n if (cache.svg) {\n x -= xOrigin - (xOrigin * a + yOrigin * c);\n y -= yOrigin - (xOrigin * b + yOrigin * d);\n } //3D matrix\n\n } else {\n a32 = matrix[6];\n a42 = matrix[7];\n a13 = matrix[8];\n a23 = matrix[9];\n a33 = matrix[10];\n a43 = matrix[11];\n x = matrix[12];\n y = matrix[13];\n z = matrix[14];\n angle = _atan2(a32, a33);\n rotationX = angle * _RAD2DEG; //rotationX\n\n if (angle) {\n cos = Math.cos(-angle);\n sin = Math.sin(-angle);\n t1 = a12 * cos + a13 * sin;\n t2 = a22 * cos + a23 * sin;\n t3 = a32 * cos + a33 * sin;\n a13 = a12 * -sin + a13 * cos;\n a23 = a22 * -sin + a23 * cos;\n a33 = a32 * -sin + a33 * cos;\n a43 = a42 * -sin + a43 * cos;\n a12 = t1;\n a22 = t2;\n a32 = t3;\n } //rotationY\n\n\n angle = _atan2(-c, a33);\n rotationY = angle * _RAD2DEG;\n\n if (angle) {\n cos = Math.cos(-angle);\n sin = Math.sin(-angle);\n t1 = a * cos - a13 * sin;\n t2 = b * cos - a23 * sin;\n t3 = c * cos - a33 * sin;\n a43 = d * sin + a43 * cos;\n a = t1;\n b = t2;\n c = t3;\n } //rotationZ\n\n\n angle = _atan2(b, a);\n rotation = angle * _RAD2DEG;\n\n if (angle) {\n cos = Math.cos(angle);\n sin = Math.sin(angle);\n t1 = a * cos + b * sin;\n t2 = a12 * cos + a22 * sin;\n b = b * cos - a * sin;\n a22 = a22 * cos - a12 * sin;\n a = t1;\n a12 = t2;\n }\n\n if (rotationX && Math.abs(rotationX) + Math.abs(rotation) > 359.9) {\n //when rotationY is set, it will often be parsed as 180 degrees different than it should be, and rotationX and rotation both being 180 (it looks the same), so we adjust for that here.\n rotationX = rotation = 0;\n rotationY = 180 - rotationY;\n }\n\n scaleX = _round(Math.sqrt(a * a + b * b + c * c));\n scaleY = _round(Math.sqrt(a22 * a22 + a32 * a32));\n angle = _atan2(a12, a22);\n skewX = Math.abs(angle) > 0.0002 ? angle * _RAD2DEG : 0;\n perspective = a43 ? 1 / (a43 < 0 ? -a43 : a43) : 0;\n }\n\n if (cache.svg) {\n //sense if there are CSS transforms applied on an SVG element in which case we must overwrite them when rendering. The transform attribute is more reliable cross-browser, but we can't just remove the CSS ones because they may be applied in a CSS rule somewhere (not just inline).\n t1 = target.getAttribute(\"transform\");\n cache.forceCSS = target.setAttribute(\"transform\", \"\") || !_isNullTransform(_getComputedProperty(target, _transformProp));\n t1 && target.setAttribute(\"transform\", t1);\n }\n }\n\n if (Math.abs(skewX) > 90 && Math.abs(skewX) < 270) {\n if (invertedScaleX) {\n scaleX *= -1;\n skewX += rotation <= 0 ? 180 : -180;\n rotation += rotation <= 0 ? 180 : -180;\n } else {\n scaleY *= -1;\n skewX += skewX <= 0 ? 180 : -180;\n }\n }\n\n uncache = uncache || cache.uncache;\n cache.x = x - ((cache.xPercent = x && (!uncache && cache.xPercent || (Math.round(target.offsetWidth / 2) === Math.round(-x) ? -50 : 0))) ? target.offsetWidth * cache.xPercent / 100 : 0) + px;\n cache.y = y - ((cache.yPercent = y && (!uncache && cache.yPercent || (Math.round(target.offsetHeight / 2) === Math.round(-y) ? -50 : 0))) ? target.offsetHeight * cache.yPercent / 100 : 0) + px;\n cache.z = z + px;\n cache.scaleX = _round(scaleX);\n cache.scaleY = _round(scaleY);\n cache.rotation = _round(rotation) + deg;\n cache.rotationX = _round(rotationX) + deg;\n cache.rotationY = _round(rotationY) + deg;\n cache.skewX = skewX + deg;\n cache.skewY = skewY + deg;\n cache.transformPerspective = perspective + px;\n\n if (cache.zOrigin = parseFloat(origin.split(\" \")[2]) || !uncache && cache.zOrigin || 0) {\n style[_transformOriginProp] = _firstTwoOnly(origin);\n }\n\n cache.xOffset = cache.yOffset = 0;\n cache.force3D = _config.force3D;\n cache.renderTransform = cache.svg ? _renderSVGTransforms : _supports3D ? _renderCSSTransforms : _renderNon3DTransforms;\n cache.uncache = 0;\n return cache;\n},\n _firstTwoOnly = function _firstTwoOnly(value) {\n return (value = value.split(\" \"))[0] + \" \" + value[1];\n},\n //for handling transformOrigin values, stripping out the 3rd dimension\n_addPxTranslate = function _addPxTranslate(target, start, value) {\n var unit = getUnit(start);\n return _round(parseFloat(start) + parseFloat(_convertToUnit(target, \"x\", value + \"px\", unit))) + unit;\n},\n _renderNon3DTransforms = function _renderNon3DTransforms(ratio, cache) {\n cache.z = \"0px\";\n cache.rotationY = cache.rotationX = \"0deg\";\n cache.force3D = 0;\n\n _renderCSSTransforms(ratio, cache);\n},\n _zeroDeg = \"0deg\",\n _zeroPx = \"0px\",\n _endParenthesis = \") \",\n _renderCSSTransforms = function _renderCSSTransforms(ratio, cache) {\n var _ref = cache || this,\n xPercent = _ref.xPercent,\n yPercent = _ref.yPercent,\n x = _ref.x,\n y = _ref.y,\n z = _ref.z,\n rotation = _ref.rotation,\n rotationY = _ref.rotationY,\n rotationX = _ref.rotationX,\n skewX = _ref.skewX,\n skewY = _ref.skewY,\n scaleX = _ref.scaleX,\n scaleY = _ref.scaleY,\n transformPerspective = _ref.transformPerspective,\n force3D = _ref.force3D,\n target = _ref.target,\n zOrigin = _ref.zOrigin,\n transforms = \"\",\n use3D = force3D === \"auto\" && ratio && ratio !== 1 || force3D === true; // Safari has a bug that causes it not to render 3D transform-origin values properly, so we force the z origin to 0, record it in the cache, and then do the math here to offset the translate values accordingly (basically do the 3D transform-origin part manually)\n\n\n if (zOrigin && (rotationX !== _zeroDeg || rotationY !== _zeroDeg)) {\n var angle = parseFloat(rotationY) * _DEG2RAD,\n a13 = Math.sin(angle),\n a33 = Math.cos(angle),\n cos;\n\n angle = parseFloat(rotationX) * _DEG2RAD;\n cos = Math.cos(angle);\n x = _addPxTranslate(target, x, a13 * cos * -zOrigin);\n y = _addPxTranslate(target, y, -Math.sin(angle) * -zOrigin);\n z = _addPxTranslate(target, z, a33 * cos * -zOrigin + zOrigin);\n }\n\n if (transformPerspective !== _zeroPx) {\n transforms += \"perspective(\" + transformPerspective + _endParenthesis;\n }\n\n if (xPercent || yPercent) {\n transforms += \"translate(\" + xPercent + \"%, \" + yPercent + \"%) \";\n }\n\n if (use3D || x !== _zeroPx || y !== _zeroPx || z !== _zeroPx) {\n transforms += z !== _zeroPx || use3D ? \"translate3d(\" + x + \", \" + y + \", \" + z + \") \" : \"translate(\" + x + \", \" + y + _endParenthesis;\n }\n\n if (rotation !== _zeroDeg) {\n transforms += \"rotate(\" + rotation + _endParenthesis;\n }\n\n if (rotationY !== _zeroDeg) {\n transforms += \"rotateY(\" + rotationY + _endParenthesis;\n }\n\n if (rotationX !== _zeroDeg) {\n transforms += \"rotateX(\" + rotationX + _endParenthesis;\n }\n\n if (skewX !== _zeroDeg || skewY !== _zeroDeg) {\n transforms += \"skew(\" + skewX + \", \" + skewY + _endParenthesis;\n }\n\n if (scaleX !== 1 || scaleY !== 1) {\n transforms += \"scale(\" + scaleX + \", \" + scaleY + _endParenthesis;\n }\n\n target.style[_transformProp] = transforms || \"translate(0, 0)\";\n},\n _renderSVGTransforms = function _renderSVGTransforms(ratio, cache) {\n var _ref2 = cache || this,\n xPercent = _ref2.xPercent,\n yPercent = _ref2.yPercent,\n x = _ref2.x,\n y = _ref2.y,\n rotation = _ref2.rotation,\n skewX = _ref2.skewX,\n skewY = _ref2.skewY,\n scaleX = _ref2.scaleX,\n scaleY = _ref2.scaleY,\n target = _ref2.target,\n xOrigin = _ref2.xOrigin,\n yOrigin = _ref2.yOrigin,\n xOffset = _ref2.xOffset,\n yOffset = _ref2.yOffset,\n forceCSS = _ref2.forceCSS,\n tx = parseFloat(x),\n ty = parseFloat(y),\n a11,\n a21,\n a12,\n a22,\n temp;\n\n rotation = parseFloat(rotation);\n skewX = parseFloat(skewX);\n skewY = parseFloat(skewY);\n\n if (skewY) {\n //for performance reasons, we combine all skewing into the skewX and rotation values. Remember, a skewY of 10 degrees looks the same as a rotation of 10 degrees plus a skewX of 10 degrees.\n skewY = parseFloat(skewY);\n skewX += skewY;\n rotation += skewY;\n }\n\n if (rotation || skewX) {\n rotation *= _DEG2RAD;\n skewX *= _DEG2RAD;\n a11 = Math.cos(rotation) * scaleX;\n a21 = Math.sin(rotation) * scaleX;\n a12 = Math.sin(rotation - skewX) * -scaleY;\n a22 = Math.cos(rotation - skewX) * scaleY;\n\n if (skewX) {\n skewY *= _DEG2RAD;\n temp = Math.tan(skewX - skewY);\n temp = Math.sqrt(1 + temp * temp);\n a12 *= temp;\n a22 *= temp;\n\n if (skewY) {\n temp = Math.tan(skewY);\n temp = Math.sqrt(1 + temp * temp);\n a11 *= temp;\n a21 *= temp;\n }\n }\n\n a11 = _round(a11);\n a21 = _round(a21);\n a12 = _round(a12);\n a22 = _round(a22);\n } else {\n a11 = scaleX;\n a22 = scaleY;\n a21 = a12 = 0;\n }\n\n if (tx && !~(x + \"\").indexOf(\"px\") || ty && !~(y + \"\").indexOf(\"px\")) {\n tx = _convertToUnit(target, \"x\", x, \"px\");\n ty = _convertToUnit(target, \"y\", y, \"px\");\n }\n\n if (xOrigin || yOrigin || xOffset || yOffset) {\n tx = _round(tx + xOrigin - (xOrigin * a11 + yOrigin * a12) + xOffset);\n ty = _round(ty + yOrigin - (xOrigin * a21 + yOrigin * a22) + yOffset);\n }\n\n if (xPercent || yPercent) {\n //The SVG spec doesn't support percentage-based translation in the \"transform\" attribute, so we merge it into the translation to simulate it.\n temp = target.getBBox();\n tx = _round(tx + xPercent / 100 * temp.width);\n ty = _round(ty + yPercent / 100 * temp.height);\n }\n\n temp = \"matrix(\" + a11 + \",\" + a21 + \",\" + a12 + \",\" + a22 + \",\" + tx + \",\" + ty + \")\";\n target.setAttribute(\"transform\", temp);\n forceCSS && (target.style[_transformProp] = temp); //some browsers prioritize CSS transforms over the transform attribute. When we sense that the user has CSS transforms applied, we must overwrite them this way (otherwise some browser simply won't render the transform attribute changes!)\n},\n _addRotationalPropTween = function _addRotationalPropTween(plugin, target, property, startNum, endValue) {\n var cap = 360,\n isString = _isString(endValue),\n endNum = parseFloat(endValue) * (isString && ~endValue.indexOf(\"rad\") ? _RAD2DEG : 1),\n change = endNum - startNum,\n finalValue = startNum + change + \"deg\",\n direction,\n pt;\n\n if (isString) {\n direction = endValue.split(\"_\")[1];\n\n if (direction === \"short\") {\n change %= cap;\n\n if (change !== change % (cap / 2)) {\n change += change < 0 ? cap : -cap;\n }\n }\n\n if (direction === \"cw\" && change < 0) {\n change = (change + cap * CSSPlugin_bigNum) % cap - ~~(change / cap) * cap;\n } else if (direction === \"ccw\" && change > 0) {\n change = (change - cap * CSSPlugin_bigNum) % cap - ~~(change / cap) * cap;\n }\n }\n\n plugin._pt = pt = new PropTween(plugin._pt, target, property, startNum, change, _renderPropWithEnd);\n pt.e = finalValue;\n pt.u = \"deg\";\n\n plugin._props.push(property);\n\n return pt;\n},\n _assign = function _assign(target, source) {\n // Internet Explorer doesn't have Object.assign(), so we recreate it here.\n for (var p in source) {\n target[p] = source[p];\n }\n\n return target;\n},\n _addRawTransformPTs = function _addRawTransformPTs(plugin, transforms, target) {\n //for handling cases where someone passes in a whole transform string, like transform: \"scale(2, 3) rotate(20deg) translateY(30em)\"\n var startCache = _assign({}, target._gsap),\n exclude = \"perspective,force3D,transformOrigin,svgOrigin\",\n style = target.style,\n endCache,\n p,\n startValue,\n endValue,\n startNum,\n endNum,\n startUnit,\n endUnit;\n\n if (startCache.svg) {\n startValue = target.getAttribute(\"transform\");\n target.setAttribute(\"transform\", \"\");\n style[_transformProp] = transforms;\n endCache = _parseTransform(target, 1);\n\n _removeProperty(target, _transformProp);\n\n target.setAttribute(\"transform\", startValue);\n } else {\n startValue = getComputedStyle(target)[_transformProp];\n style[_transformProp] = transforms;\n endCache = _parseTransform(target, 1);\n style[_transformProp] = startValue;\n }\n\n for (p in _transformProps) {\n startValue = startCache[p];\n endValue = endCache[p];\n\n if (startValue !== endValue && exclude.indexOf(p) < 0) {\n //tweening to no perspective gives very unintuitive results - just keep the same perspective in that case.\n startUnit = getUnit(startValue);\n endUnit = getUnit(endValue);\n startNum = startUnit !== endUnit ? _convertToUnit(target, p, startValue, endUnit) : parseFloat(startValue);\n endNum = parseFloat(endValue);\n plugin._pt = new PropTween(plugin._pt, endCache, p, startNum, endNum - startNum, _renderCSSProp);\n plugin._pt.u = endUnit || 0;\n\n plugin._props.push(p);\n }\n }\n\n _assign(endCache, startCache);\n}; // handle splitting apart padding, margin, borderWidth, and borderRadius into their 4 components. Firefox, for example, won't report borderRadius correctly - it will only do borderTopLeftRadius and the other corners. We also want to handle paddingTop, marginLeft, borderRightWidth, etc.\n\n\n_forEachName(\"padding,margin,Width,Radius\", function (name, index) {\n var t = \"Top\",\n r = \"Right\",\n b = \"Bottom\",\n l = \"Left\",\n props = (index < 3 ? [t, r, b, l] : [t + l, t + r, b + r, b + l]).map(function (side) {\n return index < 2 ? name + side : \"border\" + side + name;\n });\n\n _specialProps[index > 1 ? \"border\" + name : name] = function (plugin, target, property, endValue, tween) {\n var a, vars;\n\n if (arguments.length < 4) {\n // getter, passed target, property, and unit (from _get())\n a = props.map(function (prop) {\n return _get(plugin, prop, property);\n });\n vars = a.join(\" \");\n return vars.split(a[0]).length === 5 ? a[0] : vars;\n }\n\n a = (endValue + \"\").split(\" \");\n vars = {};\n props.forEach(function (prop, i) {\n return vars[prop] = a[i] = a[i] || a[(i - 1) / 2 | 0];\n });\n plugin.init(target, vars, tween);\n };\n});\n\nvar CSSPlugin = {\n name: \"css\",\n register: _initCore,\n targetTest: function targetTest(target) {\n return target.style && target.nodeType;\n },\n init: function init(target, vars, tween, index, targets) {\n var props = this._props,\n style = target.style,\n startAt = tween.vars.startAt,\n startValue,\n endValue,\n endNum,\n startNum,\n type,\n specialProp,\n p,\n startUnit,\n endUnit,\n relative,\n isTransformRelated,\n transformPropTween,\n cache,\n smooth,\n hasPriority,\n inlineProps;\n _pluginInitted || _initCore(); // we may call init() multiple times on the same plugin instance, like when adding special properties, so make sure we don't overwrite the revert data or inlineProps\n\n this.styles = this.styles || _getStyleSaver(target);\n inlineProps = this.styles.props;\n this.tween = tween;\n\n for (p in vars) {\n if (p === \"autoRound\") {\n continue;\n }\n\n endValue = vars[p];\n\n if (_plugins[p] && _checkPlugin(p, vars, tween, index, target, targets)) {\n // plugins\n continue;\n }\n\n type = typeof endValue;\n specialProp = _specialProps[p];\n\n if (type === \"function\") {\n endValue = endValue.call(tween, index, target, targets);\n type = typeof endValue;\n }\n\n if (type === \"string\" && ~endValue.indexOf(\"random(\")) {\n endValue = _replaceRandom(endValue);\n }\n\n if (specialProp) {\n specialProp(this, target, p, endValue, tween) && (hasPriority = 1);\n } else if (p.substr(0, 2) === \"--\") {\n //CSS variable\n startValue = (getComputedStyle(target).getPropertyValue(p) + \"\").trim();\n endValue += \"\";\n _colorExp.lastIndex = 0;\n\n if (!_colorExp.test(startValue)) {\n // colors don't have units\n startUnit = getUnit(startValue);\n endUnit = getUnit(endValue);\n }\n\n endUnit ? startUnit !== endUnit && (startValue = _convertToUnit(target, p, startValue, endUnit) + endUnit) : startUnit && (endValue += startUnit);\n this.add(style, \"setProperty\", startValue, endValue, index, targets, 0, 0, p);\n props.push(p);\n inlineProps.push(p, 0, style[p]);\n } else if (type !== \"undefined\") {\n if (startAt && p in startAt) {\n // in case someone hard-codes a complex value as the start, like top: \"calc(2vh / 2)\". Without this, it'd use the computed value (always in px)\n startValue = typeof startAt[p] === \"function\" ? startAt[p].call(tween, index, target, targets) : startAt[p];\n _isString(startValue) && ~startValue.indexOf(\"random(\") && (startValue = _replaceRandom(startValue));\n getUnit(startValue + \"\") || startValue === \"auto\" || (startValue += _config.units[p] || getUnit(_get(target, p)) || \"\"); // for cases when someone passes in a unitless value like {x: 100}; if we try setting translate(100, 0px) it won't work.\n\n (startValue + \"\").charAt(1) === \"=\" && (startValue = _get(target, p)); // can't work with relative values\n } else {\n startValue = _get(target, p);\n }\n\n startNum = parseFloat(startValue);\n relative = type === \"string\" && endValue.charAt(1) === \"=\" && endValue.substr(0, 2);\n relative && (endValue = endValue.substr(2));\n endNum = parseFloat(endValue);\n\n if (p in _propertyAliases) {\n if (p === \"autoAlpha\") {\n //special case where we control the visibility along with opacity. We still allow the opacity value to pass through and get tweened.\n if (startNum === 1 && _get(target, \"visibility\") === \"hidden\" && endNum) {\n //if visibility is initially set to \"hidden\", we should interpret that as intent to make opacity 0 (a convenience)\n startNum = 0;\n }\n\n inlineProps.push(\"visibility\", 0, style.visibility);\n\n _addNonTweeningPT(this, style, \"visibility\", startNum ? \"inherit\" : \"hidden\", endNum ? \"inherit\" : \"hidden\", !endNum);\n }\n\n if (p !== \"scale\" && p !== \"transform\") {\n p = _propertyAliases[p];\n ~p.indexOf(\",\") && (p = p.split(\",\")[0]);\n }\n }\n\n isTransformRelated = p in _transformProps; //--- TRANSFORM-RELATED ---\n\n if (isTransformRelated) {\n this.styles.save(p);\n\n if (!transformPropTween) {\n cache = target._gsap;\n cache.renderTransform && !vars.parseTransform || _parseTransform(target, vars.parseTransform); // if, for example, gsap.set(... {transform:\"translateX(50vw)\"}), the _get() call doesn't parse the transform, thus cache.renderTransform won't be set yet so force the parsing of the transform here.\n\n smooth = vars.smoothOrigin !== false && cache.smooth;\n transformPropTween = this._pt = new PropTween(this._pt, style, _transformProp, 0, 1, cache.renderTransform, cache, 0, -1); //the first time through, create the rendering PropTween so that it runs LAST (in the linked list, we keep adding to the beginning)\n\n transformPropTween.dep = 1; //flag it as dependent so that if things get killed/overwritten and this is the only PropTween left, we can safely kill the whole tween.\n }\n\n if (p === \"scale\") {\n this._pt = new PropTween(this._pt, cache, \"scaleY\", cache.scaleY, (relative ? _parseRelative(cache.scaleY, relative + endNum) : endNum) - cache.scaleY || 0, _renderCSSProp);\n this._pt.u = 0;\n props.push(\"scaleY\", p);\n p += \"X\";\n } else if (p === \"transformOrigin\") {\n inlineProps.push(_transformOriginProp, 0, style[_transformOriginProp]);\n endValue = _convertKeywordsToPercentages(endValue); //in case something like \"left top\" or \"bottom right\" is passed in. Convert to percentages.\n\n if (cache.svg) {\n _applySVGOrigin(target, endValue, 0, smooth, 0, this);\n } else {\n endUnit = parseFloat(endValue.split(\" \")[2]) || 0; //handle the zOrigin separately!\n\n endUnit !== cache.zOrigin && _addNonTweeningPT(this, cache, \"zOrigin\", cache.zOrigin, endUnit);\n\n _addNonTweeningPT(this, style, p, _firstTwoOnly(startValue), _firstTwoOnly(endValue));\n }\n\n continue;\n } else if (p === \"svgOrigin\") {\n _applySVGOrigin(target, endValue, 1, smooth, 0, this);\n\n continue;\n } else if (p in _rotationalProperties) {\n _addRotationalPropTween(this, cache, p, startNum, relative ? _parseRelative(startNum, relative + endValue) : endValue);\n\n continue;\n } else if (p === \"smoothOrigin\") {\n _addNonTweeningPT(this, cache, \"smooth\", cache.smooth, endValue);\n\n continue;\n } else if (p === \"force3D\") {\n cache[p] = endValue;\n continue;\n } else if (p === \"transform\") {\n _addRawTransformPTs(this, endValue, target);\n\n continue;\n }\n } else if (!(p in style)) {\n p = _checkPropPrefix(p) || p;\n }\n\n if (isTransformRelated || (endNum || endNum === 0) && (startNum || startNum === 0) && !_complexExp.test(endValue) && p in style) {\n startUnit = (startValue + \"\").substr((startNum + \"\").length);\n endNum || (endNum = 0); // protect against NaN\n\n endUnit = getUnit(endValue) || (p in _config.units ? _config.units[p] : startUnit);\n startUnit !== endUnit && (startNum = _convertToUnit(target, p, startValue, endUnit));\n this._pt = new PropTween(this._pt, isTransformRelated ? cache : style, p, startNum, (relative ? _parseRelative(startNum, relative + endNum) : endNum) - startNum, !isTransformRelated && (endUnit === \"px\" || p === \"zIndex\") && vars.autoRound !== false ? _renderRoundedCSSProp : _renderCSSProp);\n this._pt.u = endUnit || 0;\n\n if (startUnit !== endUnit && endUnit !== \"%\") {\n //when the tween goes all the way back to the beginning, we need to revert it to the OLD/ORIGINAL value (with those units). We record that as a \"b\" (beginning) property and point to a render method that handles that. (performance optimization)\n this._pt.b = startValue;\n this._pt.r = _renderCSSPropWithBeginning;\n }\n } else if (!(p in style)) {\n if (p in target) {\n //maybe it's not a style - it could be a property added directly to an element in which case we'll try to animate that.\n this.add(target, p, startValue || target[p], relative ? relative + endValue : endValue, index, targets);\n } else if (p !== \"parseTransform\") {\n _missingPlugin(p, endValue);\n\n continue;\n }\n } else {\n _tweenComplexCSSString.call(this, target, p, startValue, relative ? relative + endValue : endValue);\n }\n\n isTransformRelated || (p in style ? inlineProps.push(p, 0, style[p]) : inlineProps.push(p, 1, startValue || target[p]));\n props.push(p);\n }\n }\n\n hasPriority && _sortPropTweensByPriority(this);\n },\n render: function render(ratio, data) {\n if (data.tween._time || !CSSPlugin_reverting()) {\n var pt = data._pt;\n\n while (pt) {\n pt.r(ratio, pt.d);\n pt = pt._next;\n }\n } else {\n data.styles.revert();\n }\n },\n get: _get,\n aliases: _propertyAliases,\n getSetter: function getSetter(target, property, plugin) {\n //returns a setter function that accepts target, property, value and applies it accordingly. Remember, properties like \"x\" aren't as simple as target.style.property = value because they've got to be applied to a proxy object and then merged into a transform string in a renderer.\n var p = _propertyAliases[property];\n p && p.indexOf(\",\") < 0 && (property = p);\n 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);\n },\n core: {\n _removeProperty: _removeProperty,\n _getMatrix: _getMatrix\n }\n};\ngsap.utils.checkPrefix = _checkPropPrefix;\ngsap.core.getStyleSaver = _getStyleSaver;\n\n(function (positionAndScale, rotation, others, aliases) {\n var all = _forEachName(positionAndScale + \",\" + rotation + \",\" + others, function (name) {\n _transformProps[name] = 1;\n });\n\n _forEachName(rotation, function (name) {\n _config.units[name] = \"deg\";\n _rotationalProperties[name] = 1;\n });\n\n _propertyAliases[all[13]] = positionAndScale + \",\" + rotation;\n\n _forEachName(aliases, function (name) {\n var split = name.split(\":\");\n _propertyAliases[split[1]] = all[split[0]];\n });\n})(\"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\");\n\n_forEachName(\"x,y,z,top,right,bottom,left,width,height,fontSize,padding,margin,perspective\", function (name) {\n _config.units[name] = \"px\";\n});\n\ngsap.registerPlugin(CSSPlugin);\n\n;// CONCATENATED MODULE: ./node_modules/gsap/index.js\n\n\nvar gsapWithCSS = gsap.registerPlugin(CSSPlugin) || gsap,\n // to protect from tree shaking\nTweenMaxWithCSS = gsapWithCSS.core.Tween;\n\n;// CONCATENATED MODULE: ./node_modules/gsap/Observer.js\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n/*!\n * Observer 3.12.5\n * https://gsap.com\n *\n * @license Copyright 2008-2024, GreenSock. All rights reserved.\n * Subject to the terms at https://gsap.com/standard-license or for\n * Club GSAP members, the agreement issued with that membership.\n * @author: Jack Doyle, jack@greensock.com\n*/\n\n/* eslint-disable */\nvar Observer_gsap,\n Observer_coreInitted,\n Observer_clamp,\n Observer_win,\n Observer_doc,\n _docEl,\n _body,\n _isTouch,\n _pointerType,\n ScrollTrigger,\n _root,\n _normalizer,\n _eventTypes,\n Observer_context,\n _getGSAP = function _getGSAP() {\n return Observer_gsap || typeof window !== \"undefined\" && (Observer_gsap = window.gsap) && Observer_gsap.registerPlugin && Observer_gsap;\n},\n _startup = 1,\n _observers = [],\n _scrollers = [],\n _proxies = [],\n _getTime = Date.now,\n _bridge = function _bridge(name, value) {\n return value;\n},\n _integrate = function _integrate() {\n var core = ScrollTrigger.core,\n data = core.bridge || {},\n scrollers = core._scrollers,\n proxies = core._proxies;\n scrollers.push.apply(scrollers, _scrollers);\n proxies.push.apply(proxies, _proxies);\n _scrollers = scrollers;\n _proxies = proxies;\n\n _bridge = function _bridge(name, value) {\n return data[name](value);\n };\n},\n _getProxyProp = function _getProxyProp(element, property) {\n return ~_proxies.indexOf(element) && _proxies[_proxies.indexOf(element) + 1][property];\n},\n _isViewport = function _isViewport(el) {\n return !!~_root.indexOf(el);\n},\n _addListener = function _addListener(element, type, func, passive, capture) {\n return element.addEventListener(type, func, {\n passive: passive !== false,\n capture: !!capture\n });\n},\n _removeListener = function _removeListener(element, type, func, capture) {\n return element.removeEventListener(type, func, !!capture);\n},\n _scrollLeft = \"scrollLeft\",\n _scrollTop = \"scrollTop\",\n _onScroll = function _onScroll() {\n return _normalizer && _normalizer.isPressed || _scrollers.cache++;\n},\n _scrollCacheFunc = function _scrollCacheFunc(f, doNotCache) {\n var cachingFunc = function cachingFunc(value) {\n // since reading the scrollTop/scrollLeft/pageOffsetY/pageOffsetX can trigger a layout, this function allows us to cache the value so it only gets read fresh after a \"scroll\" event fires (or while we're refreshing because that can lengthen the page and alter the scroll position). when \"soft\" is true, that means don't actually set the scroll, but cache the new value instead (useful in ScrollSmoother)\n if (value || value === 0) {\n _startup && (Observer_win.history.scrollRestoration = \"manual\"); // otherwise the new position will get overwritten by the browser onload.\n\n var isNormalizing = _normalizer && _normalizer.isPressed;\n value = cachingFunc.v = Math.round(value) || (_normalizer && _normalizer.iOS ? 1 : 0); //TODO: iOS Bug: if you allow it to go to 0, Safari can start to report super strange (wildly inaccurate) touch positions!\n\n f(value);\n cachingFunc.cacheID = _scrollers.cache;\n isNormalizing && _bridge(\"ss\", value); // set scroll (notify ScrollTrigger so it can dispatch a \"scrollStart\" event if necessary\n } else if (doNotCache || _scrollers.cache !== cachingFunc.cacheID || _bridge(\"ref\")) {\n cachingFunc.cacheID = _scrollers.cache;\n cachingFunc.v = f();\n }\n\n return cachingFunc.v + cachingFunc.offset;\n };\n\n cachingFunc.offset = 0;\n return f && cachingFunc;\n},\n _horizontal = {\n s: _scrollLeft,\n p: \"left\",\n p2: \"Left\",\n os: \"right\",\n os2: \"Right\",\n d: \"width\",\n d2: \"Width\",\n a: \"x\",\n sc: _scrollCacheFunc(function (value) {\n return arguments.length ? Observer_win.scrollTo(value, _vertical.sc()) : Observer_win.pageXOffset || Observer_doc[_scrollLeft] || _docEl[_scrollLeft] || _body[_scrollLeft] || 0;\n })\n},\n _vertical = {\n s: _scrollTop,\n p: \"top\",\n p2: \"Top\",\n os: \"bottom\",\n os2: \"Bottom\",\n d: \"height\",\n d2: \"Height\",\n a: \"y\",\n op: _horizontal,\n sc: _scrollCacheFunc(function (value) {\n return arguments.length ? Observer_win.scrollTo(_horizontal.sc(), value) : Observer_win.pageYOffset || Observer_doc[_scrollTop] || _docEl[_scrollTop] || _body[_scrollTop] || 0;\n })\n},\n _getTarget = function _getTarget(t, self) {\n return (self && self._ctx && self._ctx.selector || Observer_gsap.utils.toArray)(t)[0] || (typeof t === \"string\" && Observer_gsap.config().nullTargetWarn !== false ? console.warn(\"Element not found:\", t) : null);\n},\n _getScrollFunc = function _getScrollFunc(element, _ref) {\n var s = _ref.s,\n sc = _ref.sc;\n // we store the scroller functions in an alternating sequenced Array like [element, verticalScrollFunc, horizontalScrollFunc, ...] so that we can minimize memory, maximize performance, and we also record the last position as a \".rec\" property in order to revert to that after refreshing to ensure things don't shift around.\n _isViewport(element) && (element = Observer_doc.scrollingElement || _docEl);\n\n var i = _scrollers.indexOf(element),\n offset = sc === _vertical.sc ? 1 : 2;\n\n !~i && (i = _scrollers.push(element) - 1);\n _scrollers[i + offset] || _addListener(element, \"scroll\", _onScroll); // clear the cache when a scroll occurs\n\n var prev = _scrollers[i + offset],\n func = prev || (_scrollers[i + offset] = _scrollCacheFunc(_getProxyProp(element, s), true) || (_isViewport(element) ? sc : _scrollCacheFunc(function (value) {\n return arguments.length ? element[s] = value : element[s];\n })));\n func.target = element;\n prev || (func.smooth = Observer_gsap.getProperty(element, \"scrollBehavior\") === \"smooth\"); // only set it the first time (don't reset every time a scrollFunc is requested because perhaps it happens during a refresh() when it's disabled in ScrollTrigger.\n\n return func;\n},\n _getVelocityProp = function _getVelocityProp(value, minTimeRefresh, useDelta) {\n var v1 = value,\n v2 = value,\n t1 = _getTime(),\n t2 = t1,\n min = minTimeRefresh || 50,\n dropToZeroTime = Math.max(500, min * 3),\n update = function update(value, force) {\n var t = _getTime();\n\n if (force || t - t1 > min) {\n v2 = v1;\n v1 = value;\n t2 = t1;\n t1 = t;\n } else if (useDelta) {\n v1 += value;\n } else {\n // not totally necessary, but makes it a bit more accurate by adjusting the v1 value according to the new slope. This way we're not just ignoring the incoming data. Removing for now because it doesn't seem to make much practical difference and it's probably not worth the kb.\n v1 = v2 + (value - v2) / (t - t2) * (t1 - t2);\n }\n },\n reset = function reset() {\n v2 = v1 = useDelta ? 0 : v1;\n t2 = t1 = 0;\n },\n getVelocity = function getVelocity(latestValue) {\n var tOld = t2,\n vOld = v2,\n t = _getTime();\n\n (latestValue || latestValue === 0) && latestValue !== v1 && update(latestValue);\n return t1 === t2 || t - t2 > dropToZeroTime ? 0 : (v1 + (useDelta ? vOld : -vOld)) / ((useDelta ? t : t1) - tOld) * 1000;\n };\n\n return {\n update: update,\n reset: reset,\n getVelocity: getVelocity\n };\n},\n _getEvent = function _getEvent(e, preventDefault) {\n preventDefault && !e._gsapAllow && e.preventDefault();\n return e.changedTouches ? e.changedTouches[0] : e;\n},\n _getAbsoluteMax = function _getAbsoluteMax(a) {\n var max = Math.max.apply(Math, a),\n min = Math.min.apply(Math, a);\n return Math.abs(max) >= Math.abs(min) ? max : min;\n},\n _setScrollTrigger = function _setScrollTrigger() {\n ScrollTrigger = Observer_gsap.core.globals().ScrollTrigger;\n ScrollTrigger && ScrollTrigger.core && _integrate();\n},\n Observer_initCore = function _initCore(core) {\n Observer_gsap = core || _getGSAP();\n\n if (!Observer_coreInitted && Observer_gsap && typeof document !== \"undefined\" && document.body) {\n Observer_win = window;\n Observer_doc = document;\n _docEl = Observer_doc.documentElement;\n _body = Observer_doc.body;\n _root = [Observer_win, Observer_doc, _docEl, _body];\n Observer_clamp = Observer_gsap.utils.clamp;\n\n Observer_context = Observer_gsap.core.context || function () {};\n\n _pointerType = \"onpointerenter\" in _body ? \"pointer\" : \"mouse\"; // isTouch is 0 if no touch, 1 if ONLY touch, and 2 if it can accommodate touch but also other types like mouse/pointer.\n\n _isTouch = Observer.isTouch = Observer_win.matchMedia && Observer_win.matchMedia(\"(hover: none), (pointer: coarse)\").matches ? 1 : \"ontouchstart\" in Observer_win || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0 ? 2 : 0;\n _eventTypes = Observer.eventTypes = (\"ontouchstart\" in _docEl ? \"touchstart,touchmove,touchcancel,touchend\" : !(\"onpointerdown\" in _docEl) ? \"mousedown,mousemove,mouseup,mouseup\" : \"pointerdown,pointermove,pointercancel,pointerup\").split(\",\");\n setTimeout(function () {\n return _startup = 0;\n }, 500);\n\n _setScrollTrigger();\n\n Observer_coreInitted = 1;\n }\n\n return Observer_coreInitted;\n};\n\n_horizontal.op = _vertical;\n_scrollers.cache = 0;\nvar Observer = /*#__PURE__*/function () {\n function Observer(vars) {\n this.init(vars);\n }\n\n var _proto = Observer.prototype;\n\n _proto.init = function init(vars) {\n Observer_coreInitted || Observer_initCore(Observer_gsap) || console.warn(\"Please gsap.registerPlugin(Observer)\");\n ScrollTrigger || _setScrollTrigger();\n var tolerance = vars.tolerance,\n dragMinimum = vars.dragMinimum,\n type = vars.type,\n target = vars.target,\n lineHeight = vars.lineHeight,\n debounce = vars.debounce,\n preventDefault = vars.preventDefault,\n onStop = vars.onStop,\n onStopDelay = vars.onStopDelay,\n ignore = vars.ignore,\n wheelSpeed = vars.wheelSpeed,\n event = vars.event,\n onDragStart = vars.onDragStart,\n onDragEnd = vars.onDragEnd,\n onDrag = vars.onDrag,\n onPress = vars.onPress,\n onRelease = vars.onRelease,\n onRight = vars.onRight,\n onLeft = vars.onLeft,\n onUp = vars.onUp,\n onDown = vars.onDown,\n onChangeX = vars.onChangeX,\n onChangeY = vars.onChangeY,\n onChange = vars.onChange,\n onToggleX = vars.onToggleX,\n onToggleY = vars.onToggleY,\n onHover = vars.onHover,\n onHoverEnd = vars.onHoverEnd,\n onMove = vars.onMove,\n ignoreCheck = vars.ignoreCheck,\n isNormalizer = vars.isNormalizer,\n onGestureStart = vars.onGestureStart,\n onGestureEnd = vars.onGestureEnd,\n onWheel = vars.onWheel,\n onEnable = vars.onEnable,\n onDisable = vars.onDisable,\n onClick = vars.onClick,\n scrollSpeed = vars.scrollSpeed,\n capture = vars.capture,\n allowClicks = vars.allowClicks,\n lockAxis = vars.lockAxis,\n onLockAxis = vars.onLockAxis;\n this.target = target = _getTarget(target) || _docEl;\n this.vars = vars;\n ignore && (ignore = Observer_gsap.utils.toArray(ignore));\n tolerance = tolerance || 1e-9;\n dragMinimum = dragMinimum || 0;\n wheelSpeed = wheelSpeed || 1;\n scrollSpeed = scrollSpeed || 1;\n type = type || \"wheel,touch,pointer\";\n debounce = debounce !== false;\n lineHeight || (lineHeight = parseFloat(Observer_win.getComputedStyle(_body).lineHeight) || 22); // note: browser may report \"normal\", so default to 22.\n\n var id,\n onStopDelayedCall,\n dragged,\n moved,\n wheeled,\n locked,\n axis,\n self = this,\n prevDeltaX = 0,\n prevDeltaY = 0,\n passive = vars.passive || !preventDefault,\n scrollFuncX = _getScrollFunc(target, _horizontal),\n scrollFuncY = _getScrollFunc(target, _vertical),\n scrollX = scrollFuncX(),\n scrollY = scrollFuncY(),\n limitToTouch = ~type.indexOf(\"touch\") && !~type.indexOf(\"pointer\") && _eventTypes[0] === \"pointerdown\",\n // for devices that accommodate mouse events and touch events, we need to distinguish.\n isViewport = _isViewport(target),\n ownerDoc = target.ownerDocument || Observer_doc,\n deltaX = [0, 0, 0],\n // wheel, scroll, pointer/touch\n deltaY = [0, 0, 0],\n onClickTime = 0,\n clickCapture = function clickCapture() {\n return onClickTime = _getTime();\n },\n _ignoreCheck = function _ignoreCheck(e, isPointerOrTouch) {\n return (self.event = e) && ignore && ~ignore.indexOf(e.target) || isPointerOrTouch && limitToTouch && e.pointerType !== \"touch\" || ignoreCheck && ignoreCheck(e, isPointerOrTouch);\n },\n onStopFunc = function onStopFunc() {\n self._vx.reset();\n\n self._vy.reset();\n\n onStopDelayedCall.pause();\n onStop && onStop(self);\n },\n update = function update() {\n var dx = self.deltaX = _getAbsoluteMax(deltaX),\n dy = self.deltaY = _getAbsoluteMax(deltaY),\n changedX = Math.abs(dx) >= tolerance,\n changedY = Math.abs(dy) >= tolerance;\n\n onChange && (changedX || changedY) && onChange(self, dx, dy, deltaX, deltaY); // in ScrollTrigger.normalizeScroll(), we need to know if it was touch/pointer so we need access to the deltaX/deltaY Arrays before we clear them out.\n\n if (changedX) {\n onRight && self.deltaX > 0 && onRight(self);\n onLeft && self.deltaX < 0 && onLeft(self);\n onChangeX && onChangeX(self);\n onToggleX && self.deltaX < 0 !== prevDeltaX < 0 && onToggleX(self);\n prevDeltaX = self.deltaX;\n deltaX[0] = deltaX[1] = deltaX[2] = 0;\n }\n\n if (changedY) {\n onDown && self.deltaY > 0 && onDown(self);\n onUp && self.deltaY < 0 && onUp(self);\n onChangeY && onChangeY(self);\n onToggleY && self.deltaY < 0 !== prevDeltaY < 0 && onToggleY(self);\n prevDeltaY = self.deltaY;\n deltaY[0] = deltaY[1] = deltaY[2] = 0;\n }\n\n if (moved || dragged) {\n onMove && onMove(self);\n\n if (dragged) {\n onDrag(self);\n dragged = false;\n }\n\n moved = false;\n }\n\n locked && !(locked = false) && onLockAxis && onLockAxis(self);\n\n if (wheeled) {\n onWheel(self);\n wheeled = false;\n }\n\n id = 0;\n },\n onDelta = function onDelta(x, y, index) {\n deltaX[index] += x;\n deltaY[index] += y;\n\n self._vx.update(x);\n\n self._vy.update(y);\n\n debounce ? id || (id = requestAnimationFrame(update)) : update();\n },\n onTouchOrPointerDelta = function onTouchOrPointerDelta(x, y) {\n if (lockAxis && !axis) {\n self.axis = axis = Math.abs(x) > Math.abs(y) ? \"x\" : \"y\";\n locked = true;\n }\n\n if (axis !== \"y\") {\n deltaX[2] += x;\n\n self._vx.update(x, true); // update the velocity as frequently as possible instead of in the debounced function so that very quick touch-scrolls (flicks) feel natural. If it's the mouse/touch/pointer, force it so that we get snappy/accurate momentum scroll.\n\n }\n\n if (axis !== \"x\") {\n deltaY[2] += y;\n\n self._vy.update(y, true);\n }\n\n debounce ? id || (id = requestAnimationFrame(update)) : update();\n },\n _onDrag = function _onDrag(e) {\n if (_ignoreCheck(e, 1)) {\n return;\n }\n\n e = _getEvent(e, preventDefault);\n var x = e.clientX,\n y = e.clientY,\n dx = x - self.x,\n dy = y - self.y,\n isDragging = self.isDragging;\n self.x = x;\n self.y = y;\n\n if (isDragging || Math.abs(self.startX - x) >= dragMinimum || Math.abs(self.startY - y) >= dragMinimum) {\n onDrag && (dragged = true);\n isDragging || (self.isDragging = true);\n onTouchOrPointerDelta(dx, dy);\n isDragging || onDragStart && onDragStart(self);\n }\n },\n _onPress = self.onPress = function (e) {\n if (_ignoreCheck(e, 1) || e && e.button) {\n return;\n }\n\n self.axis = axis = null;\n onStopDelayedCall.pause();\n self.isPressed = true;\n e = _getEvent(e); // note: may need to preventDefault(?) Won't side-scroll on iOS Safari if we do, though.\n\n prevDeltaX = prevDeltaY = 0;\n self.startX = self.x = e.clientX;\n self.startY = self.y = e.clientY;\n\n self._vx.reset(); // otherwise the t2 may be stale if the user touches and flicks super fast and releases in less than 2 requestAnimationFrame ticks, causing velocity to be 0.\n\n\n self._vy.reset();\n\n _addListener(isNormalizer ? target : ownerDoc, _eventTypes[1], _onDrag, passive, true);\n\n self.deltaX = self.deltaY = 0;\n onPress && onPress(self);\n },\n _onRelease = self.onRelease = function (e) {\n if (_ignoreCheck(e, 1)) {\n return;\n }\n\n _removeListener(isNormalizer ? target : ownerDoc, _eventTypes[1], _onDrag, true);\n\n var isTrackingDrag = !isNaN(self.y - self.startY),\n wasDragging = self.isDragging,\n isDragNotClick = wasDragging && (Math.abs(self.x - self.startX) > 3 || Math.abs(self.y - self.startY) > 3),\n // some touch devices need some wiggle room in terms of sensing clicks - the finger may move a few pixels.\n eventData = _getEvent(e);\n\n if (!isDragNotClick && isTrackingDrag) {\n self._vx.reset();\n\n self._vy.reset(); //if (preventDefault && allowClicks && self.isPressed) { // check isPressed because in a rare edge case, the inputObserver in ScrollTrigger may stopPropagation() on the press/drag, so the onRelease may get fired without the onPress/onDrag ever getting called, thus it could trigger a click to occur on a link after scroll-dragging it.\n\n\n if (preventDefault && allowClicks) {\n Observer_gsap.delayedCall(0.08, function () {\n // some browsers (like Firefox) won't trust script-generated clicks, so if the user tries to click on a video to play it, for example, it simply won't work. Since a regular \"click\" event will most likely be generated anyway (one that has its isTrusted flag set to true), we must slightly delay our script-generated click so that the \"real\"/trusted one is prioritized. Remember, when there are duplicate events in quick succession, we suppress all but the first one. Some browsers don't even trigger the \"real\" one at all, so our synthetic one is a safety valve that ensures that no matter what, a click event does get dispatched.\n if (_getTime() - onClickTime > 300 && !e.defaultPrevented) {\n if (e.target.click) {\n //some browsers (like mobile Safari) don't properly trigger the click event\n e.target.click();\n } else if (ownerDoc.createEvent) {\n var syntheticEvent = ownerDoc.createEvent(\"MouseEvents\");\n syntheticEvent.initMouseEvent(\"click\", true, true, Observer_win, 1, eventData.screenX, eventData.screenY, eventData.clientX, eventData.clientY, false, false, false, false, 0, null);\n e.target.dispatchEvent(syntheticEvent);\n }\n }\n });\n }\n }\n\n self.isDragging = self.isGesturing = self.isPressed = false;\n onStop && wasDragging && !isNormalizer && onStopDelayedCall.restart(true);\n onDragEnd && wasDragging && onDragEnd(self);\n onRelease && onRelease(self, isDragNotClick);\n },\n _onGestureStart = function _onGestureStart(e) {\n return e.touches && e.touches.length > 1 && (self.isGesturing = true) && onGestureStart(e, self.isDragging);\n },\n _onGestureEnd = function _onGestureEnd() {\n return (self.isGesturing = false) || onGestureEnd(self);\n },\n onScroll = function onScroll(e) {\n if (_ignoreCheck(e)) {\n return;\n }\n\n var x = scrollFuncX(),\n y = scrollFuncY();\n onDelta((x - scrollX) * scrollSpeed, (y - scrollY) * scrollSpeed, 1);\n scrollX = x;\n scrollY = y;\n onStop && onStopDelayedCall.restart(true);\n },\n _onWheel = function _onWheel(e) {\n if (_ignoreCheck(e)) {\n return;\n }\n\n e = _getEvent(e, preventDefault);\n onWheel && (wheeled = true);\n var multiplier = (e.deltaMode === 1 ? lineHeight : e.deltaMode === 2 ? Observer_win.innerHeight : 1) * wheelSpeed;\n onDelta(e.deltaX * multiplier, e.deltaY * multiplier, 0);\n onStop && !isNormalizer && onStopDelayedCall.restart(true);\n },\n _onMove = function _onMove(e) {\n if (_ignoreCheck(e)) {\n return;\n }\n\n var x = e.clientX,\n y = e.clientY,\n dx = x - self.x,\n dy = y - self.y;\n self.x = x;\n self.y = y;\n moved = true;\n onStop && onStopDelayedCall.restart(true);\n (dx || dy) && onTouchOrPointerDelta(dx, dy);\n },\n _onHover = function _onHover(e) {\n self.event = e;\n onHover(self);\n },\n _onHoverEnd = function _onHoverEnd(e) {\n self.event = e;\n onHoverEnd(self);\n },\n _onClick = function _onClick(e) {\n return _ignoreCheck(e) || _getEvent(e, preventDefault) && onClick(self);\n };\n\n onStopDelayedCall = self._dc = Observer_gsap.delayedCall(onStopDelay || 0.25, onStopFunc).pause();\n self.deltaX = self.deltaY = 0;\n self._vx = _getVelocityProp(0, 50, true);\n self._vy = _getVelocityProp(0, 50, true);\n self.scrollX = scrollFuncX;\n self.scrollY = scrollFuncY;\n self.isDragging = self.isGesturing = self.isPressed = false;\n\n Observer_context(this);\n\n self.enable = function (e) {\n if (!self.isEnabled) {\n _addListener(isViewport ? ownerDoc : target, \"scroll\", _onScroll);\n\n type.indexOf(\"scroll\") >= 0 && _addListener(isViewport ? ownerDoc : target, \"scroll\", onScroll, passive, capture);\n type.indexOf(\"wheel\") >= 0 && _addListener(target, \"wheel\", _onWheel, passive, capture);\n\n if (type.indexOf(\"touch\") >= 0 && _isTouch || type.indexOf(\"pointer\") >= 0) {\n _addListener(target, _eventTypes[0], _onPress, passive, capture);\n\n _addListener(ownerDoc, _eventTypes[2], _onRelease);\n\n _addListener(ownerDoc, _eventTypes[3], _onRelease);\n\n allowClicks && _addListener(target, \"click\", clickCapture, true, true);\n onClick && _addListener(target, \"click\", _onClick);\n onGestureStart && _addListener(ownerDoc, \"gesturestart\", _onGestureStart);\n onGestureEnd && _addListener(ownerDoc, \"gestureend\", _onGestureEnd);\n onHover && _addListener(target, _pointerType + \"enter\", _onHover);\n onHoverEnd && _addListener(target, _pointerType + \"leave\", _onHoverEnd);\n onMove && _addListener(target, _pointerType + \"move\", _onMove);\n }\n\n self.isEnabled = true;\n e && e.type && _onPress(e);\n onEnable && onEnable(self);\n }\n\n return self;\n };\n\n self.disable = function () {\n if (self.isEnabled) {\n // only remove the _onScroll listener if there aren't any others that rely on the functionality.\n _observers.filter(function (o) {\n return o !== self && _isViewport(o.target);\n }).length || _removeListener(isViewport ? ownerDoc : target, \"scroll\", _onScroll);\n\n if (self.isPressed) {\n self._vx.reset();\n\n self._vy.reset();\n\n _removeListener(isNormalizer ? target : ownerDoc, _eventTypes[1], _onDrag, true);\n }\n\n _removeListener(isViewport ? ownerDoc : target, \"scroll\", onScroll, capture);\n\n _removeListener(target, \"wheel\", _onWheel, capture);\n\n _removeListener(target, _eventTypes[0], _onPress, capture);\n\n _removeListener(ownerDoc, _eventTypes[2], _onRelease);\n\n _removeListener(ownerDoc, _eventTypes[3], _onRelease);\n\n _removeListener(target, \"click\", clickCapture, true);\n\n _removeListener(target, \"click\", _onClick);\n\n _removeListener(ownerDoc, \"gesturestart\", _onGestureStart);\n\n _removeListener(ownerDoc, \"gestureend\", _onGestureEnd);\n\n _removeListener(target, _pointerType + \"enter\", _onHover);\n\n _removeListener(target, _pointerType + \"leave\", _onHoverEnd);\n\n _removeListener(target, _pointerType + \"move\", _onMove);\n\n self.isEnabled = self.isPressed = self.isDragging = false;\n onDisable && onDisable(self);\n }\n };\n\n self.kill = self.revert = function () {\n self.disable();\n\n var i = _observers.indexOf(self);\n\n i >= 0 && _observers.splice(i, 1);\n _normalizer === self && (_normalizer = 0);\n };\n\n _observers.push(self);\n\n isNormalizer && _isViewport(target) && (_normalizer = self);\n self.enable(event);\n };\n\n _createClass(Observer, [{\n key: \"velocityX\",\n get: function get() {\n return this._vx.getVelocity();\n }\n }, {\n key: \"velocityY\",\n get: function get() {\n return this._vy.getVelocity();\n }\n }]);\n\n return Observer;\n}();\nObserver.version = \"3.12.5\";\n\nObserver.create = function (vars) {\n return new Observer(vars);\n};\n\nObserver.register = Observer_initCore;\n\nObserver.getAll = function () {\n return _observers.slice();\n};\n\nObserver.getById = function (id) {\n return _observers.filter(function (o) {\n return o.vars.id === id;\n })[0];\n};\n\n_getGSAP() && Observer_gsap.registerPlugin(Observer);\n\n;// CONCATENATED MODULE: ./node_modules/gsap/ScrollTrigger.js\n/*!\n * ScrollTrigger 3.12.5\n * https://gsap.com\n *\n * @license Copyright 2008-2024, GreenSock. All rights reserved.\n * Subject to the terms at https://gsap.com/standard-license or for\n * Club GSAP members, the agreement issued with that membership.\n * @author: Jack Doyle, jack@greensock.com\n*/\n\n/* eslint-disable */\n\n\nvar ScrollTrigger_gsap,\n ScrollTrigger_coreInitted,\n ScrollTrigger_win,\n ScrollTrigger_doc,\n ScrollTrigger_docEl,\n ScrollTrigger_body,\n ScrollTrigger_root,\n _resizeDelay,\n _toArray,\n ScrollTrigger_clamp,\n _time2,\n _syncInterval,\n _refreshing,\n _pointerIsDown,\n ScrollTrigger_transformProp,\n _i,\n _prevWidth,\n _prevHeight,\n _autoRefresh,\n _sort,\n ScrollTrigger_suppressOverwrites,\n _ignoreResize,\n ScrollTrigger_normalizer,\n _ignoreMobileResize,\n _baseScreenHeight,\n _baseScreenWidth,\n _fixIOSBug,\n ScrollTrigger_context,\n _scrollRestoration,\n _div100vh,\n _100vh,\n _isReverted,\n _clampingMax,\n _limitCallbacks,\n // if true, we'll only trigger callbacks if the active state toggles, so if you scroll immediately past both the start and end positions of a ScrollTrigger (thus inactive to inactive), neither its onEnter nor onLeave will be called. This is useful during startup.\nScrollTrigger_startup = 1,\n ScrollTrigger_getTime = Date.now,\n _time1 = ScrollTrigger_getTime(),\n _lastScrollTime = 0,\n _enabled = 0,\n _parseClamp = function _parseClamp(value, type, self) {\n var clamp = ScrollTrigger_isString(value) && (value.substr(0, 6) === \"clamp(\" || value.indexOf(\"max\") > -1);\n self[\"_\" + type + \"Clamp\"] = clamp;\n return clamp ? value.substr(6, value.length - 7) : value;\n},\n _keepClamp = function _keepClamp(value, clamp) {\n return clamp && (!ScrollTrigger_isString(value) || value.substr(0, 6) !== \"clamp(\") ? \"clamp(\" + value + \")\" : value;\n},\n _rafBugFix = function _rafBugFix() {\n return _enabled && requestAnimationFrame(_rafBugFix);\n},\n // in some browsers (like Firefox), screen repaints weren't consistent unless we had SOMETHING queued up in requestAnimationFrame()! So this just creates a super simple loop to keep it alive and smooth out repaints.\n_pointerDownHandler = function _pointerDownHandler() {\n return _pointerIsDown = 1;\n},\n _pointerUpHandler = function _pointerUpHandler() {\n return _pointerIsDown = 0;\n},\n ScrollTrigger_passThrough = function _passThrough(v) {\n return v;\n},\n ScrollTrigger_round = function _round(value) {\n return Math.round(value * 100000) / 100000 || 0;\n},\n ScrollTrigger_windowExists = function _windowExists() {\n return typeof window !== \"undefined\";\n},\n ScrollTrigger_getGSAP = function _getGSAP() {\n return ScrollTrigger_gsap || ScrollTrigger_windowExists() && (ScrollTrigger_gsap = window.gsap) && ScrollTrigger_gsap.registerPlugin && ScrollTrigger_gsap;\n},\n ScrollTrigger_isViewport = function _isViewport(e) {\n return !!~ScrollTrigger_root.indexOf(e);\n},\n _getViewportDimension = function _getViewportDimension(dimensionProperty) {\n return (dimensionProperty === \"Height\" ? _100vh : ScrollTrigger_win[\"inner\" + dimensionProperty]) || ScrollTrigger_docEl[\"client\" + dimensionProperty] || ScrollTrigger_body[\"client\" + dimensionProperty];\n},\n _getBoundsFunc = function _getBoundsFunc(element) {\n return _getProxyProp(element, \"getBoundingClientRect\") || (ScrollTrigger_isViewport(element) ? function () {\n _winOffsets.width = ScrollTrigger_win.innerWidth;\n _winOffsets.height = _100vh;\n return _winOffsets;\n } : function () {\n return _getBounds(element);\n });\n},\n _getSizeFunc = function _getSizeFunc(scroller, isViewport, _ref) {\n var d = _ref.d,\n d2 = _ref.d2,\n a = _ref.a;\n return (a = _getProxyProp(scroller, \"getBoundingClientRect\")) ? function () {\n return a()[d];\n } : function () {\n return (isViewport ? _getViewportDimension(d2) : scroller[\"client\" + d2]) || 0;\n };\n},\n _getOffsetsFunc = function _getOffsetsFunc(element, isViewport) {\n return !isViewport || ~_proxies.indexOf(element) ? _getBoundsFunc(element) : function () {\n return _winOffsets;\n };\n},\n _maxScroll = function _maxScroll(element, _ref2) {\n var s = _ref2.s,\n d2 = _ref2.d2,\n d = _ref2.d,\n a = _ref2.a;\n return Math.max(0, (s = \"scroll\" + d2) && (a = _getProxyProp(element, s)) ? a() - _getBoundsFunc(element)()[d] : ScrollTrigger_isViewport(element) ? (ScrollTrigger_docEl[s] || ScrollTrigger_body[s]) - _getViewportDimension(d2) : element[s] - element[\"offset\" + d2]);\n},\n _iterateAutoRefresh = function _iterateAutoRefresh(func, events) {\n for (var i = 0; i < _autoRefresh.length; i += 3) {\n (!events || ~events.indexOf(_autoRefresh[i + 1])) && func(_autoRefresh[i], _autoRefresh[i + 1], _autoRefresh[i + 2]);\n }\n},\n ScrollTrigger_isString = function _isString(value) {\n return typeof value === \"string\";\n},\n ScrollTrigger_isFunction = function _isFunction(value) {\n return typeof value === \"function\";\n},\n ScrollTrigger_isNumber = function _isNumber(value) {\n return typeof value === \"number\";\n},\n ScrollTrigger_isObject = function _isObject(value) {\n return typeof value === \"object\";\n},\n _endAnimation = function _endAnimation(animation, reversed, pause) {\n return animation && animation.progress(reversed ? 0 : 1) && pause && animation.pause();\n},\n ScrollTrigger_callback = function _callback(self, func) {\n if (self.enabled) {\n var result = self._ctx ? self._ctx.add(function () {\n return func(self);\n }) : func(self);\n result && result.totalTime && (self.callbackAnimation = result);\n }\n},\n _abs = Math.abs,\n _left = \"left\",\n _top = \"top\",\n _right = \"right\",\n _bottom = \"bottom\",\n _width = \"width\",\n _height = \"height\",\n _Right = \"Right\",\n _Left = \"Left\",\n _Top = \"Top\",\n _Bottom = \"Bottom\",\n _padding = \"padding\",\n _margin = \"margin\",\n _Width = \"Width\",\n _Height = \"Height\",\n _px = \"px\",\n _getComputedStyle = function _getComputedStyle(element) {\n return ScrollTrigger_win.getComputedStyle(element);\n},\n _makePositionable = function _makePositionable(element) {\n // if the element already has position: absolute or fixed, leave that, otherwise make it position: relative\n var position = _getComputedStyle(element).position;\n\n element.style.position = position === \"absolute\" || position === \"fixed\" ? position : \"relative\";\n},\n ScrollTrigger_setDefaults = function _setDefaults(obj, defaults) {\n for (var p in defaults) {\n p in obj || (obj[p] = defaults[p]);\n }\n\n return obj;\n},\n _getBounds = function _getBounds(element, withoutTransforms) {\n var tween = withoutTransforms && _getComputedStyle(element)[ScrollTrigger_transformProp] !== \"matrix(1, 0, 0, 1, 0, 0)\" && ScrollTrigger_gsap.to(element, {\n x: 0,\n y: 0,\n xPercent: 0,\n yPercent: 0,\n rotation: 0,\n rotationX: 0,\n rotationY: 0,\n scale: 1,\n skewX: 0,\n skewY: 0\n }).progress(1),\n bounds = element.getBoundingClientRect();\n tween && tween.progress(0).kill();\n return bounds;\n},\n _getSize = function _getSize(element, _ref3) {\n var d2 = _ref3.d2;\n return element[\"offset\" + d2] || element[\"client\" + d2] || 0;\n},\n _getLabelRatioArray = function _getLabelRatioArray(timeline) {\n var a = [],\n labels = timeline.labels,\n duration = timeline.duration(),\n p;\n\n for (p in labels) {\n a.push(labels[p] / duration);\n }\n\n return a;\n},\n _getClosestLabel = function _getClosestLabel(animation) {\n return function (value) {\n return ScrollTrigger_gsap.utils.snap(_getLabelRatioArray(animation), value);\n };\n},\n _snapDirectional = function _snapDirectional(snapIncrementOrArray) {\n var snap = ScrollTrigger_gsap.utils.snap(snapIncrementOrArray),\n a = Array.isArray(snapIncrementOrArray) && snapIncrementOrArray.slice(0).sort(function (a, b) {\n return a - b;\n });\n return a ? function (value, direction, threshold) {\n if (threshold === void 0) {\n threshold = 1e-3;\n }\n\n var i;\n\n if (!direction) {\n return snap(value);\n }\n\n if (direction > 0) {\n value -= threshold; // to avoid rounding errors. If we're too strict, it might snap forward, then immediately again, and again.\n\n for (i = 0; i < a.length; i++) {\n if (a[i] >= value) {\n return a[i];\n }\n }\n\n return a[i - 1];\n } else {\n i = a.length;\n value += threshold;\n\n while (i--) {\n if (a[i] <= value) {\n return a[i];\n }\n }\n }\n\n return a[0];\n } : function (value, direction, threshold) {\n if (threshold === void 0) {\n threshold = 1e-3;\n }\n\n var snapped = snap(value);\n return !direction || Math.abs(snapped - value) < threshold || snapped - value < 0 === direction < 0 ? snapped : snap(direction < 0 ? value - snapIncrementOrArray : value + snapIncrementOrArray);\n };\n},\n _getLabelAtDirection = function _getLabelAtDirection(timeline) {\n return function (value, st) {\n return _snapDirectional(_getLabelRatioArray(timeline))(value, st.direction);\n };\n},\n _multiListener = function _multiListener(func, element, types, callback) {\n return types.split(\",\").forEach(function (type) {\n return func(element, type, callback);\n });\n},\n ScrollTrigger_addListener = function _addListener(element, type, func, nonPassive, capture) {\n return element.addEventListener(type, func, {\n passive: !nonPassive,\n capture: !!capture\n });\n},\n ScrollTrigger_removeListener = function _removeListener(element, type, func, capture) {\n return element.removeEventListener(type, func, !!capture);\n},\n _wheelListener = function _wheelListener(func, el, scrollFunc) {\n scrollFunc = scrollFunc && scrollFunc.wheelHandler;\n\n if (scrollFunc) {\n func(el, \"wheel\", scrollFunc);\n func(el, \"touchmove\", scrollFunc);\n }\n},\n _markerDefaults = {\n startColor: \"green\",\n endColor: \"red\",\n indent: 0,\n fontSize: \"16px\",\n fontWeight: \"normal\"\n},\n ScrollTrigger_defaults = {\n toggleActions: \"play\",\n anticipatePin: 0\n},\n _keywords = {\n top: 0,\n left: 0,\n center: 0.5,\n bottom: 1,\n right: 1\n},\n _offsetToPx = function _offsetToPx(value, size) {\n if (ScrollTrigger_isString(value)) {\n var eqIndex = value.indexOf(\"=\"),\n relative = ~eqIndex ? +(value.charAt(eqIndex - 1) + 1) * parseFloat(value.substr(eqIndex + 1)) : 0;\n\n if (~eqIndex) {\n value.indexOf(\"%\") > eqIndex && (relative *= size / 100);\n value = value.substr(0, eqIndex - 1);\n }\n\n value = relative + (value in _keywords ? _keywords[value] * size : ~value.indexOf(\"%\") ? parseFloat(value) * size / 100 : parseFloat(value) || 0);\n }\n\n return value;\n},\n _createMarker = function _createMarker(type, name, container, direction, _ref4, offset, matchWidthEl, containerAnimation) {\n var startColor = _ref4.startColor,\n endColor = _ref4.endColor,\n fontSize = _ref4.fontSize,\n indent = _ref4.indent,\n fontWeight = _ref4.fontWeight;\n\n var e = ScrollTrigger_doc.createElement(\"div\"),\n useFixedPosition = ScrollTrigger_isViewport(container) || _getProxyProp(container, \"pinType\") === \"fixed\",\n isScroller = type.indexOf(\"scroller\") !== -1,\n parent = useFixedPosition ? ScrollTrigger_body : container,\n isStart = type.indexOf(\"start\") !== -1,\n color = isStart ? startColor : endColor,\n css = \"border-color:\" + color + \";font-size:\" + fontSize + \";color:\" + color + \";font-weight:\" + fontWeight + \";pointer-events:none;white-space:nowrap;font-family:sans-serif,Arial;z-index:1000;padding:4px 8px;border-width:0;border-style:solid;\";\n\n css += \"position:\" + ((isScroller || containerAnimation) && useFixedPosition ? \"fixed;\" : \"absolute;\");\n (isScroller || containerAnimation || !useFixedPosition) && (css += (direction === _vertical ? _right : _bottom) + \":\" + (offset + parseFloat(indent)) + \"px;\");\n matchWidthEl && (css += \"box-sizing:border-box;text-align:left;width:\" + matchWidthEl.offsetWidth + \"px;\");\n e._isStart = isStart;\n e.setAttribute(\"class\", \"gsap-marker-\" + type + (name ? \" marker-\" + name : \"\"));\n e.style.cssText = css;\n e.innerText = name || name === 0 ? type + \"-\" + name : type;\n parent.children[0] ? parent.insertBefore(e, parent.children[0]) : parent.appendChild(e);\n e._offset = e[\"offset\" + direction.op.d2];\n\n _positionMarker(e, 0, direction, isStart);\n\n return e;\n},\n _positionMarker = function _positionMarker(marker, start, direction, flipped) {\n var vars = {\n display: \"block\"\n },\n side = direction[flipped ? \"os2\" : \"p2\"],\n oppositeSide = direction[flipped ? \"p2\" : \"os2\"];\n marker._isFlipped = flipped;\n vars[direction.a + \"Percent\"] = flipped ? -100 : 0;\n vars[direction.a] = flipped ? \"1px\" : 0;\n vars[\"border\" + side + _Width] = 1;\n vars[\"border\" + oppositeSide + _Width] = 0;\n vars[direction.p] = start + \"px\";\n ScrollTrigger_gsap.set(marker, vars);\n},\n _triggers = [],\n _ids = {},\n _rafID,\n _sync = function _sync() {\n return ScrollTrigger_getTime() - _lastScrollTime > 34 && (_rafID || (_rafID = requestAnimationFrame(_updateAll)));\n},\n ScrollTrigger_onScroll = function _onScroll() {\n // previously, we tried to optimize performance by batching/deferring to the next requestAnimationFrame(), but discovered that Safari has a few bugs that make this unworkable (especially on iOS). See https://codepen.io/GreenSock/pen/16c435b12ef09c38125204818e7b45fc?editors=0010 and https://codepen.io/GreenSock/pen/JjOxYpQ/3dd65ccec5a60f1d862c355d84d14562?editors=0010 and https://codepen.io/GreenSock/pen/ExbrPNa/087cef197dc35445a0951e8935c41503?editors=0010\n if (!ScrollTrigger_normalizer || !ScrollTrigger_normalizer.isPressed || ScrollTrigger_normalizer.startX > ScrollTrigger_body.clientWidth) {\n // if the user is dragging the scrollbar, allow it.\n _scrollers.cache++;\n\n if (ScrollTrigger_normalizer) {\n _rafID || (_rafID = requestAnimationFrame(_updateAll));\n } else {\n _updateAll(); // Safari in particular (on desktop) NEEDS the immediate update rather than waiting for a requestAnimationFrame() whereas iOS seems to benefit from waiting for the requestAnimationFrame() tick, at least when normalizing. See https://codepen.io/GreenSock/pen/qBYozqO?editors=0110\n\n }\n\n _lastScrollTime || ScrollTrigger_dispatch(\"scrollStart\");\n _lastScrollTime = ScrollTrigger_getTime();\n }\n},\n _setBaseDimensions = function _setBaseDimensions() {\n _baseScreenWidth = ScrollTrigger_win.innerWidth;\n _baseScreenHeight = ScrollTrigger_win.innerHeight;\n},\n _onResize = function _onResize() {\n _scrollers.cache++;\n !_refreshing && !_ignoreResize && !ScrollTrigger_doc.fullscreenElement && !ScrollTrigger_doc.webkitFullscreenElement && (!_ignoreMobileResize || _baseScreenWidth !== ScrollTrigger_win.innerWidth || Math.abs(ScrollTrigger_win.innerHeight - _baseScreenHeight) > ScrollTrigger_win.innerHeight * 0.25) && _resizeDelay.restart(true);\n},\n // ignore resizes triggered by refresh()\nScrollTrigger_listeners = {},\n ScrollTrigger_emptyArray = [],\n _softRefresh = function _softRefresh() {\n return ScrollTrigger_removeListener(ScrollTrigger_ScrollTrigger, \"scrollEnd\", _softRefresh) || _refreshAll(true);\n},\n ScrollTrigger_dispatch = function _dispatch(type) {\n return ScrollTrigger_listeners[type] && ScrollTrigger_listeners[type].map(function (f) {\n return f();\n }) || ScrollTrigger_emptyArray;\n},\n _savedStyles = [],\n // when ScrollTrigger.saveStyles() is called, the inline styles are recorded in this Array in a sequential format like [element, cssText, gsCache, media]. This keeps it very memory-efficient and fast to iterate through.\n_revertRecorded = function _revertRecorded(media) {\n for (var i = 0; i < _savedStyles.length; i += 5) {\n if (!media || _savedStyles[i + 4] && _savedStyles[i + 4].query === media) {\n _savedStyles[i].style.cssText = _savedStyles[i + 1];\n _savedStyles[i].getBBox && _savedStyles[i].setAttribute(\"transform\", _savedStyles[i + 2] || \"\");\n _savedStyles[i + 3].uncache = 1;\n }\n }\n},\n _revertAll = function _revertAll(kill, media) {\n var trigger;\n\n for (_i = 0; _i < _triggers.length; _i++) {\n trigger = _triggers[_i];\n\n if (trigger && (!media || trigger._ctx === media)) {\n if (kill) {\n trigger.kill(1);\n } else {\n trigger.revert(true, true);\n }\n }\n }\n\n _isReverted = true;\n media && _revertRecorded(media);\n media || ScrollTrigger_dispatch(\"revert\");\n},\n _clearScrollMemory = function _clearScrollMemory(scrollRestoration, force) {\n // zero-out all the recorded scroll positions. Don't use _triggers because if, for example, .matchMedia() is used to create some ScrollTriggers and then the user resizes and it removes ALL ScrollTriggers, and then go back to a size where there are ScrollTriggers, it would have kept the position(s) saved from the initial state.\n _scrollers.cache++;\n (force || !_refreshingAll) && _scrollers.forEach(function (obj) {\n return ScrollTrigger_isFunction(obj) && obj.cacheID++ && (obj.rec = 0);\n });\n ScrollTrigger_isString(scrollRestoration) && (ScrollTrigger_win.history.scrollRestoration = _scrollRestoration = scrollRestoration);\n},\n _refreshingAll,\n _refreshID = 0,\n _queueRefreshID,\n _queueRefreshAll = function _queueRefreshAll() {\n // we don't want to call _refreshAll() every time we create a new ScrollTrigger (for performance reasons) - it's better to batch them. Some frameworks dynamically load content and we can't rely on the window's \"load\" or \"DOMContentLoaded\" events to trigger it.\n if (_queueRefreshID !== _refreshID) {\n var id = _queueRefreshID = _refreshID;\n requestAnimationFrame(function () {\n return id === _refreshID && _refreshAll(true);\n });\n }\n},\n _refresh100vh = function _refresh100vh() {\n ScrollTrigger_body.appendChild(_div100vh);\n\n _100vh = !ScrollTrigger_normalizer && _div100vh.offsetHeight || ScrollTrigger_win.innerHeight;\n\n ScrollTrigger_body.removeChild(_div100vh);\n},\n _hideAllMarkers = function _hideAllMarkers(hide) {\n return _toArray(\".gsap-marker-start, .gsap-marker-end, .gsap-marker-scroller-start, .gsap-marker-scroller-end\").forEach(function (el) {\n return el.style.display = hide ? \"none\" : \"block\";\n });\n},\n _refreshAll = function _refreshAll(force, skipRevert) {\n if (_lastScrollTime && !force && !_isReverted) {\n ScrollTrigger_addListener(ScrollTrigger_ScrollTrigger, \"scrollEnd\", _softRefresh);\n\n return;\n }\n\n _refresh100vh();\n\n _refreshingAll = ScrollTrigger_ScrollTrigger.isRefreshing = true;\n\n _scrollers.forEach(function (obj) {\n return ScrollTrigger_isFunction(obj) && ++obj.cacheID && (obj.rec = obj());\n }); // force the clearing of the cache because some browsers take a little while to dispatch the \"scroll\" event and the user may have changed the scroll position and then called ScrollTrigger.refresh() right away\n\n\n var refreshInits = ScrollTrigger_dispatch(\"refreshInit\");\n\n _sort && ScrollTrigger_ScrollTrigger.sort();\n skipRevert || _revertAll();\n\n _scrollers.forEach(function (obj) {\n if (ScrollTrigger_isFunction(obj)) {\n obj.smooth && (obj.target.style.scrollBehavior = \"auto\"); // smooth scrolling interferes\n\n obj(0);\n }\n });\n\n _triggers.slice(0).forEach(function (t) {\n return t.refresh();\n }); // don't loop with _i because during a refresh() someone could call ScrollTrigger.update() which would iterate through _i resulting in a skip.\n\n\n _isReverted = false;\n\n _triggers.forEach(function (t) {\n // nested pins (pinnedContainer) with pinSpacing may expand the container, so we must accommodate that here.\n if (t._subPinOffset && t.pin) {\n var prop = t.vars.horizontal ? \"offsetWidth\" : \"offsetHeight\",\n original = t.pin[prop];\n t.revert(true, 1);\n t.adjustPinSpacing(t.pin[prop] - original);\n t.refresh();\n }\n });\n\n _clampingMax = 1; // pinSpacing might be propping a page open, thus when we .setPositions() to clamp a ScrollTrigger's end we should leave the pinSpacing alone. That's what this flag is for.\n\n _hideAllMarkers(true);\n\n _triggers.forEach(function (t) {\n // the scroller's max scroll position may change after all the ScrollTriggers refreshed (like pinning could push it down), so we need to loop back and correct any with end: \"max\". Same for anything with a clamped end\n var max = _maxScroll(t.scroller, t._dir),\n endClamp = t.vars.end === \"max\" || t._endClamp && t.end > max,\n startClamp = t._startClamp && t.start >= max;\n\n (endClamp || startClamp) && t.setPositions(startClamp ? max - 1 : t.start, endClamp ? Math.max(startClamp ? max : t.start + 1, max) : t.end, true);\n });\n\n _hideAllMarkers(false);\n\n _clampingMax = 0;\n refreshInits.forEach(function (result) {\n return result && result.render && result.render(-1);\n }); // if the onRefreshInit() returns an animation (typically a gsap.set()), revert it. This makes it easy to put things in a certain spot before refreshing for measurement purposes, and then put things back.\n\n _scrollers.forEach(function (obj) {\n if (ScrollTrigger_isFunction(obj)) {\n obj.smooth && requestAnimationFrame(function () {\n return obj.target.style.scrollBehavior = \"smooth\";\n });\n obj.rec && obj(obj.rec);\n }\n });\n\n _clearScrollMemory(_scrollRestoration, 1);\n\n _resizeDelay.pause();\n\n _refreshID++;\n _refreshingAll = 2;\n\n _updateAll(2);\n\n _triggers.forEach(function (t) {\n return ScrollTrigger_isFunction(t.vars.onRefresh) && t.vars.onRefresh(t);\n });\n\n _refreshingAll = ScrollTrigger_ScrollTrigger.isRefreshing = false;\n\n ScrollTrigger_dispatch(\"refresh\");\n},\n _lastScroll = 0,\n _direction = 1,\n _primary,\n _updateAll = function _updateAll(force) {\n if (force === 2 || !_refreshingAll && !_isReverted) {\n // _isReverted could be true if, for example, a matchMedia() is in the process of executing. We don't want to update during the time everything is reverted.\n ScrollTrigger_ScrollTrigger.isUpdating = true;\n _primary && _primary.update(0); // ScrollSmoother uses refreshPriority -9999 to become the primary that gets updated before all others because it affects the scroll position.\n\n var l = _triggers.length,\n time = ScrollTrigger_getTime(),\n recordVelocity = time - _time1 >= 50,\n scroll = l && _triggers[0].scroll();\n\n _direction = _lastScroll > scroll ? -1 : 1;\n _refreshingAll || (_lastScroll = scroll);\n\n if (recordVelocity) {\n if (_lastScrollTime && !_pointerIsDown && time - _lastScrollTime > 200) {\n _lastScrollTime = 0;\n\n ScrollTrigger_dispatch(\"scrollEnd\");\n }\n\n _time2 = _time1;\n _time1 = time;\n }\n\n if (_direction < 0) {\n _i = l;\n\n while (_i-- > 0) {\n _triggers[_i] && _triggers[_i].update(0, recordVelocity);\n }\n\n _direction = 1;\n } else {\n for (_i = 0; _i < l; _i++) {\n _triggers[_i] && _triggers[_i].update(0, recordVelocity);\n }\n }\n\n ScrollTrigger_ScrollTrigger.isUpdating = false;\n }\n\n _rafID = 0;\n},\n _propNamesToCopy = [_left, _top, _bottom, _right, _margin + _Bottom, _margin + _Right, _margin + _Top, _margin + _Left, \"display\", \"flexShrink\", \"float\", \"zIndex\", \"gridColumnStart\", \"gridColumnEnd\", \"gridRowStart\", \"gridRowEnd\", \"gridArea\", \"justifySelf\", \"alignSelf\", \"placeSelf\", \"order\"],\n _stateProps = _propNamesToCopy.concat([_width, _height, \"boxSizing\", \"max\" + _Width, \"max\" + _Height, \"position\", _margin, _padding, _padding + _Top, _padding + _Right, _padding + _Bottom, _padding + _Left]),\n _swapPinOut = function _swapPinOut(pin, spacer, state) {\n _setState(state);\n\n var cache = pin._gsap;\n\n if (cache.spacerIsNative) {\n _setState(cache.spacerState);\n } else if (pin._gsap.swappedIn) {\n var parent = spacer.parentNode;\n\n if (parent) {\n parent.insertBefore(pin, spacer);\n parent.removeChild(spacer);\n }\n }\n\n pin._gsap.swappedIn = false;\n},\n _swapPinIn = function _swapPinIn(pin, spacer, cs, spacerState) {\n if (!pin._gsap.swappedIn) {\n var i = _propNamesToCopy.length,\n spacerStyle = spacer.style,\n pinStyle = pin.style,\n p;\n\n while (i--) {\n p = _propNamesToCopy[i];\n spacerStyle[p] = cs[p];\n }\n\n spacerStyle.position = cs.position === \"absolute\" ? \"absolute\" : \"relative\";\n cs.display === \"inline\" && (spacerStyle.display = \"inline-block\");\n pinStyle[_bottom] = pinStyle[_right] = \"auto\";\n spacerStyle.flexBasis = cs.flexBasis || \"auto\";\n spacerStyle.overflow = \"visible\";\n spacerStyle.boxSizing = \"border-box\";\n spacerStyle[_width] = _getSize(pin, _horizontal) + _px;\n spacerStyle[_height] = _getSize(pin, _vertical) + _px;\n spacerStyle[_padding] = pinStyle[_margin] = pinStyle[_top] = pinStyle[_left] = \"0\";\n\n _setState(spacerState);\n\n pinStyle[_width] = pinStyle[\"max\" + _Width] = cs[_width];\n pinStyle[_height] = pinStyle[\"max\" + _Height] = cs[_height];\n pinStyle[_padding] = cs[_padding];\n\n if (pin.parentNode !== spacer) {\n pin.parentNode.insertBefore(spacer, pin);\n spacer.appendChild(pin);\n }\n\n pin._gsap.swappedIn = true;\n }\n},\n ScrollTrigger_capsExp = /([A-Z])/g,\n _setState = function _setState(state) {\n if (state) {\n var style = state.t.style,\n l = state.length,\n i = 0,\n p,\n value;\n (state.t._gsap || ScrollTrigger_gsap.core.getCache(state.t)).uncache = 1; // otherwise transforms may be off\n\n for (; i < l; i += 2) {\n value = state[i + 1];\n p = state[i];\n\n if (value) {\n style[p] = value;\n } else if (style[p]) {\n style.removeProperty(p.replace(ScrollTrigger_capsExp, \"-$1\").toLowerCase());\n }\n }\n }\n},\n _getState = function _getState(element) {\n // returns an Array with alternating values like [property, value, property, value] and a \"t\" property pointing to the target (element). Makes it fast and cheap.\n var l = _stateProps.length,\n style = element.style,\n state = [],\n i = 0;\n\n for (; i < l; i++) {\n state.push(_stateProps[i], style[_stateProps[i]]);\n }\n\n state.t = element;\n return state;\n},\n _copyState = function _copyState(state, override, omitOffsets) {\n var result = [],\n l = state.length,\n i = omitOffsets ? 8 : 0,\n // skip top, left, right, bottom if omitOffsets is true\n p;\n\n for (; i < l; i += 2) {\n p = state[i];\n result.push(p, p in override ? override[p] : state[i + 1]);\n }\n\n result.t = state.t;\n return result;\n},\n _winOffsets = {\n left: 0,\n top: 0\n},\n // // potential future feature (?) Allow users to calculate where a trigger hits (scroll position) like getScrollPosition(\"#id\", \"top bottom\")\n// _getScrollPosition = (trigger, position, {scroller, containerAnimation, horizontal}) => {\n// \tscroller = _getTarget(scroller || _win);\n// \tlet direction = horizontal ? _horizontal : _vertical,\n// \t\tisViewport = _isViewport(scroller);\n// \t_getSizeFunc(scroller, isViewport, direction);\n// \treturn _parsePosition(position, _getTarget(trigger), _getSizeFunc(scroller, isViewport, direction)(), direction, _getScrollFunc(scroller, direction)(), 0, 0, 0, _getOffsetsFunc(scroller, isViewport)(), isViewport ? 0 : parseFloat(_getComputedStyle(scroller)[\"border\" + direction.p2 + _Width]) || 0, 0, containerAnimation ? containerAnimation.duration() : _maxScroll(scroller), containerAnimation);\n// },\nScrollTrigger_parsePosition = function _parsePosition(value, trigger, scrollerSize, direction, scroll, marker, markerScroller, self, scrollerBounds, borderWidth, useFixedPosition, scrollerMax, containerAnimation, clampZeroProp) {\n ScrollTrigger_isFunction(value) && (value = value(self));\n\n if (ScrollTrigger_isString(value) && value.substr(0, 3) === \"max\") {\n value = scrollerMax + (value.charAt(4) === \"=\" ? _offsetToPx(\"0\" + value.substr(3), scrollerSize) : 0);\n }\n\n var time = containerAnimation ? containerAnimation.time() : 0,\n p1,\n p2,\n element;\n containerAnimation && containerAnimation.seek(0);\n isNaN(value) || (value = +value); // convert a string number like \"45\" to an actual number\n\n if (!ScrollTrigger_isNumber(value)) {\n ScrollTrigger_isFunction(trigger) && (trigger = trigger(self));\n var offsets = (value || \"0\").split(\" \"),\n bounds,\n localOffset,\n globalOffset,\n display;\n element = _getTarget(trigger, self) || ScrollTrigger_body;\n bounds = _getBounds(element) || {};\n\n if ((!bounds || !bounds.left && !bounds.top) && _getComputedStyle(element).display === \"none\") {\n // if display is \"none\", it won't report getBoundingClientRect() properly\n display = element.style.display;\n element.style.display = \"block\";\n bounds = _getBounds(element);\n display ? element.style.display = display : element.style.removeProperty(\"display\");\n }\n\n localOffset = _offsetToPx(offsets[0], bounds[direction.d]);\n globalOffset = _offsetToPx(offsets[1] || \"0\", scrollerSize);\n value = bounds[direction.p] - scrollerBounds[direction.p] - borderWidth + localOffset + scroll - globalOffset;\n markerScroller && _positionMarker(markerScroller, globalOffset, direction, scrollerSize - globalOffset < 20 || markerScroller._isStart && globalOffset > 20);\n scrollerSize -= scrollerSize - globalOffset; // adjust for the marker\n } else {\n containerAnimation && (value = ScrollTrigger_gsap.utils.mapRange(containerAnimation.scrollTrigger.start, containerAnimation.scrollTrigger.end, 0, scrollerMax, value));\n markerScroller && _positionMarker(markerScroller, scrollerSize, direction, true);\n }\n\n if (clampZeroProp) {\n self[clampZeroProp] = value || -0.001;\n value < 0 && (value = 0);\n }\n\n if (marker) {\n var position = value + scrollerSize,\n isStart = marker._isStart;\n p1 = \"scroll\" + direction.d2;\n\n _positionMarker(marker, position, direction, isStart && position > 20 || !isStart && (useFixedPosition ? Math.max(ScrollTrigger_body[p1], ScrollTrigger_docEl[p1]) : marker.parentNode[p1]) <= position + 1);\n\n if (useFixedPosition) {\n scrollerBounds = _getBounds(markerScroller);\n useFixedPosition && (marker.style[direction.op.p] = scrollerBounds[direction.op.p] - direction.op.m - marker._offset + _px);\n }\n }\n\n if (containerAnimation && element) {\n p1 = _getBounds(element);\n containerAnimation.seek(scrollerMax);\n p2 = _getBounds(element);\n containerAnimation._caScrollDist = p1[direction.p] - p2[direction.p];\n value = value / containerAnimation._caScrollDist * scrollerMax;\n }\n\n containerAnimation && containerAnimation.seek(time);\n return containerAnimation ? value : Math.round(value);\n},\n _prefixExp = /(webkit|moz|length|cssText|inset)/i,\n _reparent = function _reparent(element, parent, top, left) {\n if (element.parentNode !== parent) {\n var style = element.style,\n p,\n cs;\n\n if (parent === ScrollTrigger_body) {\n element._stOrig = style.cssText; // record original inline styles so we can revert them later\n\n cs = _getComputedStyle(element);\n\n for (p in cs) {\n // must copy all relevant styles to ensure that nothing changes visually when we reparent to the . Skip the vendor prefixed ones.\n if (!+p && !_prefixExp.test(p) && cs[p] && typeof style[p] === \"string\" && p !== \"0\") {\n style[p] = cs[p];\n }\n }\n\n style.top = top;\n style.left = left;\n } else {\n style.cssText = element._stOrig;\n }\n\n ScrollTrigger_gsap.core.getCache(element).uncache = 1;\n parent.appendChild(element);\n }\n},\n _interruptionTracker = function _interruptionTracker(getValueFunc, initialValue, onInterrupt) {\n var last1 = initialValue,\n last2 = last1;\n return function (value) {\n var current = Math.round(getValueFunc()); // round because in some [very uncommon] Windows environments, scroll can get reported with decimals even though it was set without.\n\n if (current !== last1 && current !== last2 && Math.abs(current - last1) > 3 && Math.abs(current - last2) > 3) {\n // if the user scrolls, kill the tween. iOS Safari intermittently misreports the scroll position, it may be the most recently-set one or the one before that! When Safari is zoomed (CMD-+), it often misreports as 1 pixel off too! So if we set the scroll position to 125, for example, it'll actually report it as 124.\n value = current;\n onInterrupt && onInterrupt();\n }\n\n last2 = last1;\n last1 = value;\n return value;\n };\n},\n _shiftMarker = function _shiftMarker(marker, direction, value) {\n var vars = {};\n vars[direction.p] = \"+=\" + value;\n ScrollTrigger_gsap.set(marker, vars);\n},\n // _mergeAnimations = animations => {\n// \tlet tl = gsap.timeline({smoothChildTiming: true}).startTime(Math.min(...animations.map(a => a.globalTime(0))));\n// \tanimations.forEach(a => {let time = a.totalTime(); tl.add(a); a.totalTime(time); });\n// \ttl.smoothChildTiming = false;\n// \treturn tl;\n// },\n// returns a function that can be used to tween the scroll position in the direction provided, and when doing so it'll add a .tween property to the FUNCTION itself, and remove it when the tween completes or gets killed. This gives us a way to have multiple ScrollTriggers use a central function for any given scroller and see if there's a scroll tween running (which would affect if/how things get updated)\n_getTweenCreator = function _getTweenCreator(scroller, direction) {\n var getScroll = _getScrollFunc(scroller, direction),\n prop = \"_scroll\" + direction.p2,\n // add a tweenable property to the scroller that's a getter/setter function, like _scrollTop or _scrollLeft. This way, if someone does gsap.killTweensOf(scroller) it'll kill the scroll tween.\n getTween = function getTween(scrollTo, vars, initialValue, change1, change2) {\n var tween = getTween.tween,\n onComplete = vars.onComplete,\n modifiers = {};\n initialValue = initialValue || getScroll();\n\n var checkForInterruption = _interruptionTracker(getScroll, initialValue, function () {\n tween.kill();\n getTween.tween = 0;\n });\n\n change2 = change1 && change2 || 0; // if change1 is 0, we set that to the difference and ignore change2. Otherwise, there would be a compound effect.\n\n change1 = change1 || scrollTo - initialValue;\n tween && tween.kill();\n vars[prop] = scrollTo;\n vars.inherit = false;\n vars.modifiers = modifiers;\n\n modifiers[prop] = function () {\n return checkForInterruption(initialValue + change1 * tween.ratio + change2 * tween.ratio * tween.ratio);\n };\n\n vars.onUpdate = function () {\n _scrollers.cache++;\n getTween.tween && _updateAll(); // if it was interrupted/killed, like in a context.revert(), don't force an updateAll()\n };\n\n vars.onComplete = function () {\n getTween.tween = 0;\n onComplete && onComplete.call(tween);\n };\n\n tween = getTween.tween = ScrollTrigger_gsap.to(scroller, vars);\n return tween;\n };\n\n scroller[prop] = getScroll;\n\n getScroll.wheelHandler = function () {\n return getTween.tween && getTween.tween.kill() && (getTween.tween = 0);\n };\n\n ScrollTrigger_addListener(scroller, \"wheel\", getScroll.wheelHandler); // Windows machines handle mousewheel scrolling in chunks (like \"3 lines per scroll\") meaning the typical strategy for cancelling the scroll isn't as sensitive. It's much more likely to match one of the previous 2 scroll event positions. So we kill any snapping as soon as there's a wheel event.\n\n\n ScrollTrigger_ScrollTrigger.isTouch && ScrollTrigger_addListener(scroller, \"touchmove\", getScroll.wheelHandler);\n return getTween;\n};\n\nvar ScrollTrigger_ScrollTrigger = /*#__PURE__*/function () {\n function ScrollTrigger(vars, animation) {\n ScrollTrigger_coreInitted || ScrollTrigger.register(ScrollTrigger_gsap) || console.warn(\"Please gsap.registerPlugin(ScrollTrigger)\");\n\n ScrollTrigger_context(this);\n\n this.init(vars, animation);\n }\n\n var _proto = ScrollTrigger.prototype;\n\n _proto.init = function init(vars, animation) {\n this.progress = this.start = 0;\n this.vars && this.kill(true, true); // in case it's being initted again\n\n if (!_enabled) {\n this.update = this.refresh = this.kill = ScrollTrigger_passThrough;\n return;\n }\n\n vars = ScrollTrigger_setDefaults(ScrollTrigger_isString(vars) || ScrollTrigger_isNumber(vars) || vars.nodeType ? {\n trigger: vars\n } : vars, ScrollTrigger_defaults);\n\n var _vars = vars,\n onUpdate = _vars.onUpdate,\n toggleClass = _vars.toggleClass,\n id = _vars.id,\n onToggle = _vars.onToggle,\n onRefresh = _vars.onRefresh,\n scrub = _vars.scrub,\n trigger = _vars.trigger,\n pin = _vars.pin,\n pinSpacing = _vars.pinSpacing,\n invalidateOnRefresh = _vars.invalidateOnRefresh,\n anticipatePin = _vars.anticipatePin,\n onScrubComplete = _vars.onScrubComplete,\n onSnapComplete = _vars.onSnapComplete,\n once = _vars.once,\n snap = _vars.snap,\n pinReparent = _vars.pinReparent,\n pinSpacer = _vars.pinSpacer,\n containerAnimation = _vars.containerAnimation,\n fastScrollEnd = _vars.fastScrollEnd,\n preventOverlaps = _vars.preventOverlaps,\n direction = vars.horizontal || vars.containerAnimation && vars.horizontal !== false ? _horizontal : _vertical,\n isToggle = !scrub && scrub !== 0,\n scroller = _getTarget(vars.scroller || ScrollTrigger_win),\n scrollerCache = ScrollTrigger_gsap.core.getCache(scroller),\n isViewport = ScrollTrigger_isViewport(scroller),\n useFixedPosition = (\"pinType\" in vars ? vars.pinType : _getProxyProp(scroller, \"pinType\") || isViewport && \"fixed\") === \"fixed\",\n callbacks = [vars.onEnter, vars.onLeave, vars.onEnterBack, vars.onLeaveBack],\n toggleActions = isToggle && vars.toggleActions.split(\" \"),\n markers = \"markers\" in vars ? vars.markers : ScrollTrigger_defaults.markers,\n borderWidth = isViewport ? 0 : parseFloat(_getComputedStyle(scroller)[\"border\" + direction.p2 + _Width]) || 0,\n self = this,\n onRefreshInit = vars.onRefreshInit && function () {\n return vars.onRefreshInit(self);\n },\n getScrollerSize = _getSizeFunc(scroller, isViewport, direction),\n getScrollerOffsets = _getOffsetsFunc(scroller, isViewport),\n lastSnap = 0,\n lastRefresh = 0,\n prevProgress = 0,\n scrollFunc = _getScrollFunc(scroller, direction),\n tweenTo,\n pinCache,\n snapFunc,\n scroll1,\n scroll2,\n start,\n end,\n markerStart,\n markerEnd,\n markerStartTrigger,\n markerEndTrigger,\n markerVars,\n executingOnRefresh,\n change,\n pinOriginalState,\n pinActiveState,\n pinState,\n spacer,\n offset,\n pinGetter,\n pinSetter,\n pinStart,\n pinChange,\n spacingStart,\n spacerState,\n markerStartSetter,\n pinMoves,\n markerEndSetter,\n cs,\n snap1,\n snap2,\n scrubTween,\n scrubSmooth,\n snapDurClamp,\n snapDelayedCall,\n prevScroll,\n prevAnimProgress,\n caMarkerSetter,\n customRevertReturn; // for the sake of efficiency, _startClamp/_endClamp serve like a truthy value indicating that clamping was enabled on the start/end, and ALSO store the actual pre-clamped numeric value. We tap into that in ScrollSmoother for speed effects. So for example, if start=\"clamp(top bottom)\" results in a start of -100 naturally, it would get clamped to 0 but -100 would be stored in _startClamp.\n\n\n self._startClamp = self._endClamp = false;\n self._dir = direction;\n anticipatePin *= 45;\n self.scroller = scroller;\n self.scroll = containerAnimation ? containerAnimation.time.bind(containerAnimation) : scrollFunc;\n scroll1 = scrollFunc();\n self.vars = vars;\n animation = animation || vars.animation;\n\n if (\"refreshPriority\" in vars) {\n _sort = 1;\n vars.refreshPriority === -9999 && (_primary = self); // used by ScrollSmoother\n }\n\n scrollerCache.tweenScroll = scrollerCache.tweenScroll || {\n top: _getTweenCreator(scroller, _vertical),\n left: _getTweenCreator(scroller, _horizontal)\n };\n self.tweenTo = tweenTo = scrollerCache.tweenScroll[direction.p];\n\n self.scrubDuration = function (value) {\n scrubSmooth = ScrollTrigger_isNumber(value) && value;\n\n if (!scrubSmooth) {\n scrubTween && scrubTween.progress(1).kill();\n scrubTween = 0;\n } else {\n scrubTween ? scrubTween.duration(value) : scrubTween = ScrollTrigger_gsap.to(animation, {\n ease: \"expo\",\n totalProgress: \"+=0\",\n inherit: false,\n duration: scrubSmooth,\n paused: true,\n onComplete: function onComplete() {\n return onScrubComplete && onScrubComplete(self);\n }\n });\n }\n };\n\n if (animation) {\n animation.vars.lazy = false;\n animation._initted && !self.isReverted || animation.vars.immediateRender !== false && vars.immediateRender !== false && animation.duration() && animation.render(0, true, true); // special case: if this ScrollTrigger gets re-initted, a from() tween with a stagger could get initted initially and then reverted on the re-init which means it'll need to get rendered again here to properly display things. Otherwise, See https://gsap.com/forums/topic/36777-scrollsmoother-splittext-nextjs/ and https://codepen.io/GreenSock/pen/eYPyPpd?editors=0010\n\n self.animation = animation.pause();\n animation.scrollTrigger = self;\n self.scrubDuration(scrub);\n snap1 = 0;\n id || (id = animation.vars.id);\n }\n\n if (snap) {\n // TODO: potential idea: use legitimate CSS scroll snapping by pushing invisible elements into the DOM that serve as snap positions, and toggle the document.scrollingElement.style.scrollSnapType onToggle. See https://codepen.io/GreenSock/pen/JjLrgWM for a quick proof of concept.\n if (!ScrollTrigger_isObject(snap) || snap.push) {\n snap = {\n snapTo: snap\n };\n }\n\n \"scrollBehavior\" in ScrollTrigger_body.style && ScrollTrigger_gsap.set(isViewport ? [ScrollTrigger_body, ScrollTrigger_docEl] : scroller, {\n scrollBehavior: \"auto\"\n }); // smooth scrolling doesn't work with snap.\n\n _scrollers.forEach(function (o) {\n return ScrollTrigger_isFunction(o) && o.target === (isViewport ? ScrollTrigger_doc.scrollingElement || ScrollTrigger_docEl : scroller) && (o.smooth = false);\n }); // note: set smooth to false on both the vertical and horizontal scroll getters/setters\n\n\n snapFunc = ScrollTrigger_isFunction(snap.snapTo) ? snap.snapTo : snap.snapTo === \"labels\" ? _getClosestLabel(animation) : snap.snapTo === \"labelsDirectional\" ? _getLabelAtDirection(animation) : snap.directional !== false ? function (value, st) {\n return _snapDirectional(snap.snapTo)(value, ScrollTrigger_getTime() - lastRefresh < 500 ? 0 : st.direction);\n } : ScrollTrigger_gsap.utils.snap(snap.snapTo);\n snapDurClamp = snap.duration || {\n min: 0.1,\n max: 2\n };\n snapDurClamp = ScrollTrigger_isObject(snapDurClamp) ? ScrollTrigger_clamp(snapDurClamp.min, snapDurClamp.max) : ScrollTrigger_clamp(snapDurClamp, snapDurClamp);\n snapDelayedCall = ScrollTrigger_gsap.delayedCall(snap.delay || scrubSmooth / 2 || 0.1, function () {\n var scroll = scrollFunc(),\n refreshedRecently = ScrollTrigger_getTime() - lastRefresh < 500,\n tween = tweenTo.tween;\n\n if ((refreshedRecently || Math.abs(self.getVelocity()) < 10) && !tween && !_pointerIsDown && lastSnap !== scroll) {\n var progress = (scroll - start) / change,\n totalProgress = animation && !isToggle ? animation.totalProgress() : progress,\n velocity = refreshedRecently ? 0 : (totalProgress - snap2) / (ScrollTrigger_getTime() - _time2) * 1000 || 0,\n change1 = ScrollTrigger_gsap.utils.clamp(-progress, 1 - progress, _abs(velocity / 2) * velocity / 0.185),\n naturalEnd = progress + (snap.inertia === false ? 0 : change1),\n endValue,\n endScroll,\n _snap = snap,\n onStart = _snap.onStart,\n _onInterrupt = _snap.onInterrupt,\n _onComplete = _snap.onComplete;\n endValue = snapFunc(naturalEnd, self);\n ScrollTrigger_isNumber(endValue) || (endValue = naturalEnd); // in case the function didn't return a number, fall back to using the naturalEnd\n\n endScroll = Math.round(start + endValue * change);\n\n if (scroll <= end && scroll >= start && endScroll !== scroll) {\n if (tween && !tween._initted && tween.data <= _abs(endScroll - scroll)) {\n // there's an overlapping snap! So we must figure out which one is closer and let that tween live.\n return;\n }\n\n if (snap.inertia === false) {\n change1 = endValue - progress;\n }\n\n tweenTo(endScroll, {\n duration: snapDurClamp(_abs(Math.max(_abs(naturalEnd - totalProgress), _abs(endValue - totalProgress)) * 0.185 / velocity / 0.05 || 0)),\n ease: snap.ease || \"power3\",\n data: _abs(endScroll - scroll),\n // record the distance so that if another snap tween occurs (conflict) we can prioritize the closest snap.\n onInterrupt: function onInterrupt() {\n return snapDelayedCall.restart(true) && _onInterrupt && _onInterrupt(self);\n },\n onComplete: function onComplete() {\n self.update();\n lastSnap = scrollFunc();\n\n if (animation) {\n // the resolution of the scrollbar is limited, so we should correct the scrubbed animation's playhead at the end to match EXACTLY where it was supposed to snap\n scrubTween ? scrubTween.resetTo(\"totalProgress\", endValue, animation._tTime / animation._tDur) : animation.progress(endValue);\n }\n\n snap1 = snap2 = animation && !isToggle ? animation.totalProgress() : self.progress;\n onSnapComplete && onSnapComplete(self);\n _onComplete && _onComplete(self);\n }\n }, scroll, change1 * change, endScroll - scroll - change1 * change);\n onStart && onStart(self, tweenTo.tween);\n }\n } else if (self.isActive && lastSnap !== scroll) {\n snapDelayedCall.restart(true);\n }\n }).pause();\n }\n\n id && (_ids[id] = self);\n trigger = self.trigger = _getTarget(trigger || pin !== true && pin); // if a trigger has some kind of scroll-related effect applied that could contaminate the \"y\" or \"x\" position (like a ScrollSmoother effect), we needed a way to temporarily revert it, so we use the stRevert property of the gsCache. It can return another function that we'll call at the end so it can return to its normal state.\n\n customRevertReturn = trigger && trigger._gsap && trigger._gsap.stRevert;\n customRevertReturn && (customRevertReturn = customRevertReturn(self));\n pin = pin === true ? trigger : _getTarget(pin);\n ScrollTrigger_isString(toggleClass) && (toggleClass = {\n targets: trigger,\n className: toggleClass\n });\n\n if (pin) {\n pinSpacing === false || pinSpacing === _margin || (pinSpacing = !pinSpacing && pin.parentNode && pin.parentNode.style && _getComputedStyle(pin.parentNode).display === \"flex\" ? false : _padding); // if the parent is display: flex, don't apply pinSpacing by default. We should check that pin.parentNode is an element (not shadow dom window)\n\n self.pin = pin;\n pinCache = ScrollTrigger_gsap.core.getCache(pin);\n\n if (!pinCache.spacer) {\n // record the spacer and pinOriginalState on the cache in case someone tries pinning the same element with MULTIPLE ScrollTriggers - we don't want to have multiple spacers or record the \"original\" pin state after it has already been affected by another ScrollTrigger.\n if (pinSpacer) {\n pinSpacer = _getTarget(pinSpacer);\n pinSpacer && !pinSpacer.nodeType && (pinSpacer = pinSpacer.current || pinSpacer.nativeElement); // for React & Angular\n\n pinCache.spacerIsNative = !!pinSpacer;\n pinSpacer && (pinCache.spacerState = _getState(pinSpacer));\n }\n\n pinCache.spacer = spacer = pinSpacer || ScrollTrigger_doc.createElement(\"div\");\n spacer.classList.add(\"pin-spacer\");\n id && spacer.classList.add(\"pin-spacer-\" + id);\n pinCache.pinState = pinOriginalState = _getState(pin);\n } else {\n pinOriginalState = pinCache.pinState;\n }\n\n vars.force3D !== false && ScrollTrigger_gsap.set(pin, {\n force3D: true\n });\n self.spacer = spacer = pinCache.spacer;\n cs = _getComputedStyle(pin);\n spacingStart = cs[pinSpacing + direction.os2];\n pinGetter = ScrollTrigger_gsap.getProperty(pin);\n pinSetter = ScrollTrigger_gsap.quickSetter(pin, direction.a, _px); // pin.firstChild && !_maxScroll(pin, direction) && (pin.style.overflow = \"hidden\"); // protects from collapsing margins, but can have unintended consequences as demonstrated here: https://codepen.io/GreenSock/pen/1e42c7a73bfa409d2cf1e184e7a4248d so it was removed in favor of just telling people to set up their CSS to avoid the collapsing margins (overflow: hidden | auto is just one option. Another is border-top: 1px solid transparent).\n\n _swapPinIn(pin, spacer, cs);\n\n pinState = _getState(pin);\n }\n\n if (markers) {\n markerVars = ScrollTrigger_isObject(markers) ? ScrollTrigger_setDefaults(markers, _markerDefaults) : _markerDefaults;\n markerStartTrigger = _createMarker(\"scroller-start\", id, scroller, direction, markerVars, 0);\n markerEndTrigger = _createMarker(\"scroller-end\", id, scroller, direction, markerVars, 0, markerStartTrigger);\n offset = markerStartTrigger[\"offset\" + direction.op.d2];\n\n var content = _getTarget(_getProxyProp(scroller, \"content\") || scroller);\n\n markerStart = this.markerStart = _createMarker(\"start\", id, content, direction, markerVars, offset, 0, containerAnimation);\n markerEnd = this.markerEnd = _createMarker(\"end\", id, content, direction, markerVars, offset, 0, containerAnimation);\n containerAnimation && (caMarkerSetter = ScrollTrigger_gsap.quickSetter([markerStart, markerEnd], direction.a, _px));\n\n if (!useFixedPosition && !(_proxies.length && _getProxyProp(scroller, \"fixedMarkers\") === true)) {\n _makePositionable(isViewport ? ScrollTrigger_body : scroller);\n\n ScrollTrigger_gsap.set([markerStartTrigger, markerEndTrigger], {\n force3D: true\n });\n markerStartSetter = ScrollTrigger_gsap.quickSetter(markerStartTrigger, direction.a, _px);\n markerEndSetter = ScrollTrigger_gsap.quickSetter(markerEndTrigger, direction.a, _px);\n }\n }\n\n if (containerAnimation) {\n var oldOnUpdate = containerAnimation.vars.onUpdate,\n oldParams = containerAnimation.vars.onUpdateParams;\n containerAnimation.eventCallback(\"onUpdate\", function () {\n self.update(0, 0, 1);\n oldOnUpdate && oldOnUpdate.apply(containerAnimation, oldParams || []);\n });\n }\n\n self.previous = function () {\n return _triggers[_triggers.indexOf(self) - 1];\n };\n\n self.next = function () {\n return _triggers[_triggers.indexOf(self) + 1];\n };\n\n self.revert = function (revert, temp) {\n if (!temp) {\n return self.kill(true);\n } // for compatibility with gsap.context() and gsap.matchMedia() which call revert()\n\n\n var r = revert !== false || !self.enabled,\n prevRefreshing = _refreshing;\n\n if (r !== self.isReverted) {\n if (r) {\n prevScroll = Math.max(scrollFunc(), self.scroll.rec || 0); // record the scroll so we can revert later (repositioning/pinning things can affect scroll position). In the static refresh() method, we first record all the scroll positions as a reference.\n\n prevProgress = self.progress;\n prevAnimProgress = animation && animation.progress();\n }\n\n markerStart && [markerStart, markerEnd, markerStartTrigger, markerEndTrigger].forEach(function (m) {\n return m.style.display = r ? \"none\" : \"block\";\n });\n\n if (r) {\n _refreshing = self;\n self.update(r); // make sure the pin is back in its original position so that all the measurements are correct. do this BEFORE swapping the pin out\n }\n\n if (pin && (!pinReparent || !self.isActive)) {\n if (r) {\n _swapPinOut(pin, spacer, pinOriginalState);\n } else {\n _swapPinIn(pin, spacer, _getComputedStyle(pin), spacerState);\n }\n }\n\n r || self.update(r); // when we're restoring, the update should run AFTER swapping the pin into its pin-spacer.\n\n _refreshing = prevRefreshing; // restore. We set it to true during the update() so that things fire properly in there.\n\n self.isReverted = r;\n }\n };\n\n self.refresh = function (soft, force, position, pinOffset) {\n // position is typically only defined if it's coming from setPositions() - it's a way to skip the normal parsing. pinOffset is also only from setPositions() and is mostly related to fancy stuff we need to do in ScrollSmoother with effects\n if ((_refreshing || !self.enabled) && !force) {\n return;\n }\n\n if (pin && soft && _lastScrollTime) {\n ScrollTrigger_addListener(ScrollTrigger, \"scrollEnd\", _softRefresh);\n\n return;\n }\n\n !_refreshingAll && onRefreshInit && onRefreshInit(self);\n _refreshing = self;\n\n if (tweenTo.tween && !position) {\n // we skip this if a position is passed in because typically that's from .setPositions() and it's best to allow in-progress snapping to continue.\n tweenTo.tween.kill();\n tweenTo.tween = 0;\n }\n\n scrubTween && scrubTween.pause();\n invalidateOnRefresh && animation && animation.revert({\n kill: false\n }).invalidate();\n self.isReverted || self.revert(true, true);\n self._subPinOffset = false; // we'll set this to true in the sub-pins if we find any\n\n var size = getScrollerSize(),\n scrollerBounds = getScrollerOffsets(),\n max = containerAnimation ? containerAnimation.duration() : _maxScroll(scroller, direction),\n isFirstRefresh = change <= 0.01,\n offset = 0,\n otherPinOffset = pinOffset || 0,\n parsedEnd = ScrollTrigger_isObject(position) ? position.end : vars.end,\n parsedEndTrigger = vars.endTrigger || trigger,\n parsedStart = ScrollTrigger_isObject(position) ? position.start : vars.start || (vars.start === 0 || !trigger ? 0 : pin ? \"0 0\" : \"0 100%\"),\n pinnedContainer = self.pinnedContainer = vars.pinnedContainer && _getTarget(vars.pinnedContainer, self),\n triggerIndex = trigger && Math.max(0, _triggers.indexOf(self)) || 0,\n i = triggerIndex,\n cs,\n bounds,\n scroll,\n isVertical,\n override,\n curTrigger,\n curPin,\n oppositeScroll,\n initted,\n revertedPins,\n forcedOverflow,\n markerStartOffset,\n markerEndOffset;\n\n if (markers && ScrollTrigger_isObject(position)) {\n // if we alter the start/end positions with .setPositions(), it generally feeds in absolute NUMBERS which don't convey information about where to line up the markers, so to keep it intuitive, we record how far the trigger positions shift after applying the new numbers and then offset by that much in the opposite direction. We do the same to the associated trigger markers too of course.\n markerStartOffset = ScrollTrigger_gsap.getProperty(markerStartTrigger, direction.p);\n markerEndOffset = ScrollTrigger_gsap.getProperty(markerEndTrigger, direction.p);\n }\n\n while (i--) {\n // user might try to pin the same element more than once, so we must find any prior triggers with the same pin, revert them, and determine how long they're pinning so that we can offset things appropriately. Make sure we revert from last to first so that things \"rewind\" properly.\n curTrigger = _triggers[i];\n curTrigger.end || curTrigger.refresh(0, 1) || (_refreshing = self); // if it's a timeline-based trigger that hasn't been fully initialized yet because it's waiting for 1 tick, just force the refresh() here, otherwise if it contains a pin that's supposed to affect other ScrollTriggers further down the page, they won't be adjusted properly.\n\n curPin = curTrigger.pin;\n\n if (curPin && (curPin === trigger || curPin === pin || curPin === pinnedContainer) && !curTrigger.isReverted) {\n revertedPins || (revertedPins = []);\n revertedPins.unshift(curTrigger); // we'll revert from first to last to make sure things reach their end state properly\n\n curTrigger.revert(true, true);\n }\n\n if (curTrigger !== _triggers[i]) {\n // in case it got removed.\n triggerIndex--;\n i--;\n }\n }\n\n ScrollTrigger_isFunction(parsedStart) && (parsedStart = parsedStart(self));\n parsedStart = _parseClamp(parsedStart, \"start\", self);\n start = ScrollTrigger_parsePosition(parsedStart, trigger, size, direction, scrollFunc(), markerStart, markerStartTrigger, self, scrollerBounds, borderWidth, useFixedPosition, max, containerAnimation, self._startClamp && \"_startClamp\") || (pin ? -0.001 : 0);\n ScrollTrigger_isFunction(parsedEnd) && (parsedEnd = parsedEnd(self));\n\n if (ScrollTrigger_isString(parsedEnd) && !parsedEnd.indexOf(\"+=\")) {\n if (~parsedEnd.indexOf(\" \")) {\n parsedEnd = (ScrollTrigger_isString(parsedStart) ? parsedStart.split(\" \")[0] : \"\") + parsedEnd;\n } else {\n offset = _offsetToPx(parsedEnd.substr(2), size);\n parsedEnd = ScrollTrigger_isString(parsedStart) ? parsedStart : (containerAnimation ? ScrollTrigger_gsap.utils.mapRange(0, containerAnimation.duration(), containerAnimation.scrollTrigger.start, containerAnimation.scrollTrigger.end, start) : start) + offset; // _parsePosition won't factor in the offset if the start is a number, so do it here.\n\n parsedEndTrigger = trigger;\n }\n }\n\n parsedEnd = _parseClamp(parsedEnd, \"end\", self);\n end = Math.max(start, ScrollTrigger_parsePosition(parsedEnd || (parsedEndTrigger ? \"100% 0\" : max), parsedEndTrigger, size, direction, scrollFunc() + offset, markerEnd, markerEndTrigger, self, scrollerBounds, borderWidth, useFixedPosition, max, containerAnimation, self._endClamp && \"_endClamp\")) || -0.001;\n offset = 0;\n i = triggerIndex;\n\n while (i--) {\n curTrigger = _triggers[i];\n curPin = curTrigger.pin;\n\n if (curPin && curTrigger.start - curTrigger._pinPush <= start && !containerAnimation && curTrigger.end > 0) {\n cs = curTrigger.end - (self._startClamp ? Math.max(0, curTrigger.start) : curTrigger.start);\n\n if ((curPin === trigger && curTrigger.start - curTrigger._pinPush < start || curPin === pinnedContainer) && isNaN(parsedStart)) {\n // numeric start values shouldn't be offset at all - treat them as absolute\n offset += cs * (1 - curTrigger.progress);\n }\n\n curPin === pin && (otherPinOffset += cs);\n }\n }\n\n start += offset;\n end += offset;\n self._startClamp && (self._startClamp += offset);\n\n if (self._endClamp && !_refreshingAll) {\n self._endClamp = end || -0.001;\n end = Math.min(end, _maxScroll(scroller, direction));\n }\n\n change = end - start || (start -= 0.01) && 0.001;\n\n if (isFirstRefresh) {\n // on the very first refresh(), the prevProgress couldn't have been accurate yet because the start/end were never calculated, so we set it here. Before 3.11.5, it could lead to an inaccurate scroll position restoration with snapping.\n prevProgress = ScrollTrigger_gsap.utils.clamp(0, 1, ScrollTrigger_gsap.utils.normalize(start, end, prevScroll));\n }\n\n self._pinPush = otherPinOffset;\n\n if (markerStart && offset) {\n // offset the markers if necessary\n cs = {};\n cs[direction.a] = \"+=\" + offset;\n pinnedContainer && (cs[direction.p] = \"-=\" + scrollFunc());\n ScrollTrigger_gsap.set([markerStart, markerEnd], cs);\n }\n\n if (pin && !(_clampingMax && self.end >= _maxScroll(scroller, direction))) {\n cs = _getComputedStyle(pin);\n isVertical = direction === _vertical;\n scroll = scrollFunc(); // recalculate because the triggers can affect the scroll\n\n pinStart = parseFloat(pinGetter(direction.a)) + otherPinOffset;\n\n if (!max && end > 1) {\n // makes sure the scroller has a scrollbar, otherwise if something has width: 100%, for example, it would be too big (exclude the scrollbar). See https://gsap.com/forums/topic/25182-scrolltrigger-width-of-page-increase-where-markers-are-set-to-false/\n forcedOverflow = (isViewport ? ScrollTrigger_doc.scrollingElement || ScrollTrigger_docEl : scroller).style;\n forcedOverflow = {\n style: forcedOverflow,\n value: forcedOverflow[\"overflow\" + direction.a.toUpperCase()]\n };\n\n if (isViewport && _getComputedStyle(ScrollTrigger_body)[\"overflow\" + direction.a.toUpperCase()] !== \"scroll\") {\n // avoid an extra scrollbar if BOTH and have overflow set to \"scroll\"\n forcedOverflow.style[\"overflow\" + direction.a.toUpperCase()] = \"scroll\";\n }\n }\n\n _swapPinIn(pin, spacer, cs);\n\n pinState = _getState(pin); // transforms will interfere with the top/left/right/bottom placement, so remove them temporarily. getBoundingClientRect() factors in transforms.\n\n bounds = _getBounds(pin, true);\n oppositeScroll = useFixedPosition && _getScrollFunc(scroller, isVertical ? _horizontal : _vertical)();\n\n if (pinSpacing) {\n spacerState = [pinSpacing + direction.os2, change + otherPinOffset + _px];\n spacerState.t = spacer;\n i = pinSpacing === _padding ? _getSize(pin, direction) + change + otherPinOffset : 0;\n\n if (i) {\n spacerState.push(direction.d, i + _px); // for box-sizing: border-box (must include padding).\n\n spacer.style.flexBasis !== \"auto\" && (spacer.style.flexBasis = i + _px);\n }\n\n _setState(spacerState);\n\n if (pinnedContainer) {\n // in ScrollTrigger.refresh(), we need to re-evaluate the pinContainer's size because this pinSpacing may stretch it out, but we can't just add the exact distance because depending on layout, it may not push things down or it may only do so partially.\n _triggers.forEach(function (t) {\n if (t.pin === pinnedContainer && t.vars.pinSpacing !== false) {\n t._subPinOffset = true;\n }\n });\n }\n\n useFixedPosition && scrollFunc(prevScroll);\n } else {\n i = _getSize(pin, direction);\n i && spacer.style.flexBasis !== \"auto\" && (spacer.style.flexBasis = i + _px);\n }\n\n if (useFixedPosition) {\n override = {\n top: bounds.top + (isVertical ? scroll - start : oppositeScroll) + _px,\n left: bounds.left + (isVertical ? oppositeScroll : scroll - start) + _px,\n boxSizing: \"border-box\",\n position: \"fixed\"\n };\n override[_width] = override[\"max\" + _Width] = Math.ceil(bounds.width) + _px;\n override[_height] = override[\"max\" + _Height] = Math.ceil(bounds.height) + _px;\n override[_margin] = override[_margin + _Top] = override[_margin + _Right] = override[_margin + _Bottom] = override[_margin + _Left] = \"0\";\n override[_padding] = cs[_padding];\n override[_padding + _Top] = cs[_padding + _Top];\n override[_padding + _Right] = cs[_padding + _Right];\n override[_padding + _Bottom] = cs[_padding + _Bottom];\n override[_padding + _Left] = cs[_padding + _Left];\n pinActiveState = _copyState(pinOriginalState, override, pinReparent);\n _refreshingAll && scrollFunc(0);\n }\n\n if (animation) {\n // the animation might be affecting the transform, so we must jump to the end, check the value, and compensate accordingly. Otherwise, when it becomes unpinned, the pinSetter() will get set to a value that doesn't include whatever the animation did.\n initted = animation._initted; // if not, we must invalidate() after this step, otherwise it could lock in starting values prematurely.\n\n ScrollTrigger_suppressOverwrites(1);\n\n animation.render(animation.duration(), true, true);\n pinChange = pinGetter(direction.a) - pinStart + change + otherPinOffset;\n pinMoves = Math.abs(change - pinChange) > 1;\n useFixedPosition && pinMoves && pinActiveState.splice(pinActiveState.length - 2, 2); // transform is the last property/value set in the state Array. Since the animation is controlling that, we should omit it.\n\n animation.render(0, true, true);\n initted || animation.invalidate(true);\n animation.parent || animation.totalTime(animation.totalTime()); // if, for example, a toggleAction called play() and then refresh() happens and when we render(1) above, it would cause the animation to complete and get removed from its parent, so this makes sure it gets put back in.\n\n ScrollTrigger_suppressOverwrites(0);\n } else {\n pinChange = change;\n }\n\n forcedOverflow && (forcedOverflow.value ? forcedOverflow.style[\"overflow\" + direction.a.toUpperCase()] = forcedOverflow.value : forcedOverflow.style.removeProperty(\"overflow-\" + direction.a));\n } else if (trigger && scrollFunc() && !containerAnimation) {\n // it may be INSIDE a pinned element, so walk up the tree and look for any elements with _pinOffset to compensate because anything with pinSpacing that's already scrolled would throw off the measurements in getBoundingClientRect()\n bounds = trigger.parentNode;\n\n while (bounds && bounds !== ScrollTrigger_body) {\n if (bounds._pinOffset) {\n start -= bounds._pinOffset;\n end -= bounds._pinOffset;\n }\n\n bounds = bounds.parentNode;\n }\n }\n\n revertedPins && revertedPins.forEach(function (t) {\n return t.revert(false, true);\n });\n self.start = start;\n self.end = end;\n scroll1 = scroll2 = _refreshingAll ? prevScroll : scrollFunc(); // reset velocity\n\n if (!containerAnimation && !_refreshingAll) {\n scroll1 < prevScroll && scrollFunc(prevScroll);\n self.scroll.rec = 0;\n }\n\n self.revert(false, true);\n lastRefresh = ScrollTrigger_getTime();\n\n if (snapDelayedCall) {\n lastSnap = -1; // just so snapping gets re-enabled, clear out any recorded last value\n // self.isActive && scrollFunc(start + change * prevProgress); // previously this line was here to ensure that when snapping kicks in, it's from the previous progress but in some cases that's not desirable, like an all-page ScrollTrigger when new content gets added to the page, that'd totally change the progress.\n\n snapDelayedCall.restart(true);\n }\n\n _refreshing = 0;\n animation && isToggle && (animation._initted || prevAnimProgress) && animation.progress() !== prevAnimProgress && animation.progress(prevAnimProgress || 0, true).render(animation.time(), true, true); // must force a re-render because if saveStyles() was used on the target(s), the styles could have been wiped out during the refresh().\n\n if (isFirstRefresh || prevProgress !== self.progress || containerAnimation || invalidateOnRefresh) {\n // ensures that the direction is set properly (when refreshing, progress is set back to 0 initially, then back again to wherever it needs to be) and that callbacks are triggered.\n animation && !isToggle && animation.totalProgress(containerAnimation && start < -0.001 && !prevProgress ? ScrollTrigger_gsap.utils.normalize(start, end, 0) : prevProgress, true); // to avoid issues where animation callbacks like onStart aren't triggered.\n\n self.progress = isFirstRefresh || (scroll1 - start) / change === prevProgress ? 0 : prevProgress;\n }\n\n pin && pinSpacing && (spacer._pinOffset = Math.round(self.progress * pinChange));\n scrubTween && scrubTween.invalidate();\n\n if (!isNaN(markerStartOffset)) {\n // numbers were passed in for the position which are absolute, so instead of just putting the markers at the very bottom of the viewport, we figure out how far they shifted down (it's safe to assume they were originally positioned in closer relation to the trigger element with values like \"top\", \"center\", a percentage or whatever, so we offset that much in the opposite direction to basically revert them to the relative position thy were at previously.\n markerStartOffset -= ScrollTrigger_gsap.getProperty(markerStartTrigger, direction.p);\n markerEndOffset -= ScrollTrigger_gsap.getProperty(markerEndTrigger, direction.p);\n\n _shiftMarker(markerStartTrigger, direction, markerStartOffset);\n\n _shiftMarker(markerStart, direction, markerStartOffset - (pinOffset || 0));\n\n _shiftMarker(markerEndTrigger, direction, markerEndOffset);\n\n _shiftMarker(markerEnd, direction, markerEndOffset - (pinOffset || 0));\n }\n\n isFirstRefresh && !_refreshingAll && self.update(); // edge case - when you reload a page when it's already scrolled down, some browsers fire a \"scroll\" event before DOMContentLoaded, triggering an updateAll(). If we don't update the self.progress as part of refresh(), then when it happens next, it may record prevProgress as 0 when it really shouldn't, potentially causing a callback in an animation to fire again.\n\n if (onRefresh && !_refreshingAll && !executingOnRefresh) {\n // when refreshing all, we do extra work to correct pinnedContainer sizes and ensure things don't exceed the maxScroll, so we should do all the refreshes at the end after all that work so that the start/end values are corrected.\n executingOnRefresh = true;\n onRefresh(self);\n executingOnRefresh = false;\n }\n };\n\n self.getVelocity = function () {\n return (scrollFunc() - scroll2) / (ScrollTrigger_getTime() - _time2) * 1000 || 0;\n };\n\n self.endAnimation = function () {\n _endAnimation(self.callbackAnimation);\n\n if (animation) {\n scrubTween ? scrubTween.progress(1) : !animation.paused() ? _endAnimation(animation, animation.reversed()) : isToggle || _endAnimation(animation, self.direction < 0, 1);\n }\n };\n\n self.labelToScroll = function (label) {\n return animation && animation.labels && (start || self.refresh() || start) + animation.labels[label] / animation.duration() * change || 0;\n };\n\n self.getTrailing = function (name) {\n var i = _triggers.indexOf(self),\n a = self.direction > 0 ? _triggers.slice(0, i).reverse() : _triggers.slice(i + 1);\n\n return (ScrollTrigger_isString(name) ? a.filter(function (t) {\n return t.vars.preventOverlaps === name;\n }) : a).filter(function (t) {\n return self.direction > 0 ? t.end <= start : t.start >= end;\n });\n };\n\n self.update = function (reset, recordVelocity, forceFake) {\n if (containerAnimation && !forceFake && !reset) {\n return;\n }\n\n var scroll = _refreshingAll === true ? prevScroll : self.scroll(),\n p = reset ? 0 : (scroll - start) / change,\n clipped = p < 0 ? 0 : p > 1 ? 1 : p || 0,\n prevProgress = self.progress,\n isActive,\n wasActive,\n toggleState,\n action,\n stateChanged,\n toggled,\n isAtMax,\n isTakingAction;\n\n if (recordVelocity) {\n scroll2 = scroll1;\n scroll1 = containerAnimation ? scrollFunc() : scroll;\n\n if (snap) {\n snap2 = snap1;\n snap1 = animation && !isToggle ? animation.totalProgress() : clipped;\n }\n } // anticipate the pinning a few ticks ahead of time based on velocity to avoid a visual glitch due to the fact that most browsers do scrolling on a separate thread (not synced with requestAnimationFrame).\n\n\n if (anticipatePin && pin && !_refreshing && !ScrollTrigger_startup && _lastScrollTime) {\n if (!clipped && start < scroll + (scroll - scroll2) / (ScrollTrigger_getTime() - _time2) * anticipatePin) {\n clipped = 0.0001;\n } else if (clipped === 1 && end > scroll + (scroll - scroll2) / (ScrollTrigger_getTime() - _time2) * anticipatePin) {\n clipped = 0.9999;\n }\n }\n\n if (clipped !== prevProgress && self.enabled) {\n isActive = self.isActive = !!clipped && clipped < 1;\n wasActive = !!prevProgress && prevProgress < 1;\n toggled = isActive !== wasActive;\n stateChanged = toggled || !!clipped !== !!prevProgress; // could go from start all the way to end, thus it didn't toggle but it did change state in a sense (may need to fire a callback)\n\n self.direction = clipped > prevProgress ? 1 : -1;\n self.progress = clipped;\n\n if (stateChanged && !_refreshing) {\n toggleState = clipped && !prevProgress ? 0 : clipped === 1 ? 1 : prevProgress === 1 ? 2 : 3; // 0 = enter, 1 = leave, 2 = enterBack, 3 = leaveBack (we prioritize the FIRST encounter, thus if you scroll really fast past the onEnter and onLeave in one tick, it'd prioritize onEnter.\n\n if (isToggle) {\n action = !toggled && toggleActions[toggleState + 1] !== \"none\" && toggleActions[toggleState + 1] || toggleActions[toggleState]; // if it didn't toggle, that means it shot right past and since we prioritize the \"enter\" action, we should switch to the \"leave\" in this case (but only if one is defined)\n\n isTakingAction = animation && (action === \"complete\" || action === \"reset\" || action in animation);\n }\n }\n\n preventOverlaps && (toggled || isTakingAction) && (isTakingAction || scrub || !animation) && (ScrollTrigger_isFunction(preventOverlaps) ? preventOverlaps(self) : self.getTrailing(preventOverlaps).forEach(function (t) {\n return t.endAnimation();\n }));\n\n if (!isToggle) {\n if (scrubTween && !_refreshing && !ScrollTrigger_startup) {\n scrubTween._dp._time - scrubTween._start !== scrubTween._time && scrubTween.render(scrubTween._dp._time - scrubTween._start); // if there's a scrub on both the container animation and this one (or a ScrollSmoother), the update order would cause this one not to have rendered yet, so it wouldn't make any progress before we .restart() it heading toward the new progress so it'd appear stuck thus we force a render here.\n\n if (scrubTween.resetTo) {\n scrubTween.resetTo(\"totalProgress\", clipped, animation._tTime / animation._tDur);\n } else {\n // legacy support (courtesy), before 3.10.0\n scrubTween.vars.totalProgress = clipped;\n scrubTween.invalidate().restart();\n }\n } else if (animation) {\n animation.totalProgress(clipped, !!(_refreshing && (lastRefresh || reset)));\n }\n }\n\n if (pin) {\n reset && pinSpacing && (spacer.style[pinSpacing + direction.os2] = spacingStart);\n\n if (!useFixedPosition) {\n pinSetter(ScrollTrigger_round(pinStart + pinChange * clipped));\n } else if (stateChanged) {\n isAtMax = !reset && clipped > prevProgress && end + 1 > scroll && scroll + 1 >= _maxScroll(scroller, direction); // if it's at the VERY end of the page, don't switch away from position: fixed because it's pointless and it could cause a brief flash when the user scrolls back up (when it gets pinned again)\n\n if (pinReparent) {\n if (!reset && (isActive || isAtMax)) {\n var bounds = _getBounds(pin, true),\n _offset = scroll - start;\n\n _reparent(pin, ScrollTrigger_body, bounds.top + (direction === _vertical ? _offset : 0) + _px, bounds.left + (direction === _vertical ? 0 : _offset) + _px);\n } else {\n _reparent(pin, spacer);\n }\n }\n\n _setState(isActive || isAtMax ? pinActiveState : pinState);\n\n pinMoves && clipped < 1 && isActive || pinSetter(pinStart + (clipped === 1 && !isAtMax ? pinChange : 0));\n }\n }\n\n snap && !tweenTo.tween && !_refreshing && !ScrollTrigger_startup && snapDelayedCall.restart(true);\n toggleClass && (toggled || once && clipped && (clipped < 1 || !_limitCallbacks)) && _toArray(toggleClass.targets).forEach(function (el) {\n return el.classList[isActive || once ? \"add\" : \"remove\"](toggleClass.className);\n }); // classes could affect positioning, so do it even if reset or refreshing is true.\n\n onUpdate && !isToggle && !reset && onUpdate(self);\n\n if (stateChanged && !_refreshing) {\n if (isToggle) {\n if (isTakingAction) {\n if (action === \"complete\") {\n animation.pause().totalProgress(1);\n } else if (action === \"reset\") {\n animation.restart(true).pause();\n } else if (action === \"restart\") {\n animation.restart(true);\n } else {\n animation[action]();\n }\n }\n\n onUpdate && onUpdate(self);\n }\n\n if (toggled || !_limitCallbacks) {\n // on startup, the page could be scrolled and we don't want to fire callbacks that didn't toggle. For example onEnter shouldn't fire if the ScrollTrigger isn't actually entered.\n onToggle && toggled && ScrollTrigger_callback(self, onToggle);\n callbacks[toggleState] && ScrollTrigger_callback(self, callbacks[toggleState]);\n once && (clipped === 1 ? self.kill(false, 1) : callbacks[toggleState] = 0); // a callback shouldn't be called again if once is true.\n\n if (!toggled) {\n // it's possible to go completely past, like from before the start to after the end (or vice-versa) in which case BOTH callbacks should be fired in that order\n toggleState = clipped === 1 ? 1 : 3;\n callbacks[toggleState] && ScrollTrigger_callback(self, callbacks[toggleState]);\n }\n }\n\n if (fastScrollEnd && !isActive && Math.abs(self.getVelocity()) > (ScrollTrigger_isNumber(fastScrollEnd) ? fastScrollEnd : 2500)) {\n _endAnimation(self.callbackAnimation);\n\n scrubTween ? scrubTween.progress(1) : _endAnimation(animation, action === \"reverse\" ? 1 : !clipped, 1);\n }\n } else if (isToggle && onUpdate && !_refreshing) {\n onUpdate(self);\n }\n } // update absolutely-positioned markers (only if the scroller isn't the viewport)\n\n\n if (markerEndSetter) {\n var n = containerAnimation ? scroll / containerAnimation.duration() * (containerAnimation._caScrollDist || 0) : scroll;\n markerStartSetter(n + (markerStartTrigger._isFlipped ? 1 : 0));\n markerEndSetter(n);\n }\n\n caMarkerSetter && caMarkerSetter(-scroll / containerAnimation.duration() * (containerAnimation._caScrollDist || 0));\n };\n\n self.enable = function (reset, refresh) {\n if (!self.enabled) {\n self.enabled = true;\n\n ScrollTrigger_addListener(scroller, \"resize\", _onResize);\n\n isViewport || ScrollTrigger_addListener(scroller, \"scroll\", ScrollTrigger_onScroll);\n onRefreshInit && ScrollTrigger_addListener(ScrollTrigger, \"refreshInit\", onRefreshInit);\n\n if (reset !== false) {\n self.progress = prevProgress = 0;\n scroll1 = scroll2 = lastSnap = scrollFunc();\n }\n\n refresh !== false && self.refresh();\n }\n };\n\n self.getTween = function (snap) {\n return snap && tweenTo ? tweenTo.tween : scrubTween;\n };\n\n self.setPositions = function (newStart, newEnd, keepClamp, pinOffset) {\n // doesn't persist after refresh()! Intended to be a way to override values that were set during refresh(), like you could set it in onRefresh()\n if (containerAnimation) {\n // convert ratios into scroll positions. Remember, start/end values on ScrollTriggers that have a containerAnimation refer to the time (in seconds), NOT scroll positions.\n var st = containerAnimation.scrollTrigger,\n duration = containerAnimation.duration(),\n _change = st.end - st.start;\n\n newStart = st.start + _change * newStart / duration;\n newEnd = st.start + _change * newEnd / duration;\n }\n\n self.refresh(false, false, {\n start: _keepClamp(newStart, keepClamp && !!self._startClamp),\n end: _keepClamp(newEnd, keepClamp && !!self._endClamp)\n }, pinOffset);\n self.update();\n };\n\n self.adjustPinSpacing = function (amount) {\n if (spacerState && amount) {\n var i = spacerState.indexOf(direction.d) + 1;\n spacerState[i] = parseFloat(spacerState[i]) + amount + _px;\n spacerState[1] = parseFloat(spacerState[1]) + amount + _px;\n\n _setState(spacerState);\n }\n };\n\n self.disable = function (reset, allowAnimation) {\n if (self.enabled) {\n reset !== false && self.revert(true, true);\n self.enabled = self.isActive = false;\n allowAnimation || scrubTween && scrubTween.pause();\n prevScroll = 0;\n pinCache && (pinCache.uncache = 1);\n onRefreshInit && ScrollTrigger_removeListener(ScrollTrigger, \"refreshInit\", onRefreshInit);\n\n if (snapDelayedCall) {\n snapDelayedCall.pause();\n tweenTo.tween && tweenTo.tween.kill() && (tweenTo.tween = 0);\n }\n\n if (!isViewport) {\n var i = _triggers.length;\n\n while (i--) {\n if (_triggers[i].scroller === scroller && _triggers[i] !== self) {\n return; //don't remove the listeners if there are still other triggers referencing it.\n }\n }\n\n ScrollTrigger_removeListener(scroller, \"resize\", _onResize);\n\n isViewport || ScrollTrigger_removeListener(scroller, \"scroll\", ScrollTrigger_onScroll);\n }\n }\n };\n\n self.kill = function (revert, allowAnimation) {\n self.disable(revert, allowAnimation);\n scrubTween && !allowAnimation && scrubTween.kill();\n id && delete _ids[id];\n\n var i = _triggers.indexOf(self);\n\n i >= 0 && _triggers.splice(i, 1);\n i === _i && _direction > 0 && _i--; // if we're in the middle of a refresh() or update(), splicing would cause skips in the index, so adjust...\n // if no other ScrollTrigger instances of the same scroller are found, wipe out any recorded scroll position. Otherwise, in a single page application, for example, it could maintain scroll position when it really shouldn't.\n\n i = 0;\n\n _triggers.forEach(function (t) {\n return t.scroller === self.scroller && (i = 1);\n });\n\n i || _refreshingAll || (self.scroll.rec = 0);\n\n if (animation) {\n animation.scrollTrigger = null;\n revert && animation.revert({\n kill: false\n });\n allowAnimation || animation.kill();\n }\n\n markerStart && [markerStart, markerEnd, markerStartTrigger, markerEndTrigger].forEach(function (m) {\n return m.parentNode && m.parentNode.removeChild(m);\n });\n _primary === self && (_primary = 0);\n\n if (pin) {\n pinCache && (pinCache.uncache = 1);\n i = 0;\n\n _triggers.forEach(function (t) {\n return t.pin === pin && i++;\n });\n\n i || (pinCache.spacer = 0); // if there aren't any more ScrollTriggers with the same pin, remove the spacer, otherwise it could be contaminated with old/stale values if the user re-creates a ScrollTrigger for the same element.\n }\n\n vars.onKill && vars.onKill(self);\n };\n\n _triggers.push(self);\n\n self.enable(false, false);\n customRevertReturn && customRevertReturn(self);\n\n if (animation && animation.add && !change) {\n // if the animation is a timeline, it may not have been populated yet, so it wouldn't render at the proper place on the first refresh(), thus we should schedule one for the next tick. If \"change\" is defined, we know it must be re-enabling, thus we can refresh() right away.\n var updateFunc = self.update; // some browsers may fire a scroll event BEFORE a tick elapses and/or the DOMContentLoaded fires. So there's a chance update() will be called BEFORE a refresh() has happened on a Timeline-attached ScrollTrigger which means the start/end won't be calculated yet. We don't want to add conditional logic inside the update() method (like check to see if end is defined and if not, force a refresh()) because that's a function that gets hit a LOT (performance). So we swap out the real update() method for this one that'll re-attach it the first time it gets called and of course forces a refresh().\n\n self.update = function () {\n self.update = updateFunc;\n start || end || self.refresh();\n };\n\n ScrollTrigger_gsap.delayedCall(0.01, self.update);\n change = 0.01;\n start = end = 0;\n } else {\n self.refresh();\n }\n\n pin && _queueRefreshAll(); // pinning could affect the positions of other things, so make sure we queue a full refresh()\n };\n\n ScrollTrigger.register = function register(core) {\n if (!ScrollTrigger_coreInitted) {\n ScrollTrigger_gsap = core || ScrollTrigger_getGSAP();\n ScrollTrigger_windowExists() && window.document && ScrollTrigger.enable();\n ScrollTrigger_coreInitted = _enabled;\n }\n\n return ScrollTrigger_coreInitted;\n };\n\n ScrollTrigger.defaults = function defaults(config) {\n if (config) {\n for (var p in config) {\n ScrollTrigger_defaults[p] = config[p];\n }\n }\n\n return ScrollTrigger_defaults;\n };\n\n ScrollTrigger.disable = function disable(reset, kill) {\n _enabled = 0;\n\n _triggers.forEach(function (trigger) {\n return trigger[kill ? \"kill\" : \"disable\"](reset);\n });\n\n ScrollTrigger_removeListener(ScrollTrigger_win, \"wheel\", ScrollTrigger_onScroll);\n\n ScrollTrigger_removeListener(ScrollTrigger_doc, \"scroll\", ScrollTrigger_onScroll);\n\n clearInterval(_syncInterval);\n\n ScrollTrigger_removeListener(ScrollTrigger_doc, \"touchcancel\", ScrollTrigger_passThrough);\n\n ScrollTrigger_removeListener(ScrollTrigger_body, \"touchstart\", ScrollTrigger_passThrough);\n\n _multiListener(ScrollTrigger_removeListener, ScrollTrigger_doc, \"pointerdown,touchstart,mousedown\", _pointerDownHandler);\n\n _multiListener(ScrollTrigger_removeListener, ScrollTrigger_doc, \"pointerup,touchend,mouseup\", _pointerUpHandler);\n\n _resizeDelay.kill();\n\n _iterateAutoRefresh(ScrollTrigger_removeListener);\n\n for (var i = 0; i < _scrollers.length; i += 3) {\n _wheelListener(ScrollTrigger_removeListener, _scrollers[i], _scrollers[i + 1]);\n\n _wheelListener(ScrollTrigger_removeListener, _scrollers[i], _scrollers[i + 2]);\n }\n };\n\n ScrollTrigger.enable = function enable() {\n ScrollTrigger_win = window;\n ScrollTrigger_doc = document;\n ScrollTrigger_docEl = ScrollTrigger_doc.documentElement;\n ScrollTrigger_body = ScrollTrigger_doc.body;\n\n if (ScrollTrigger_gsap) {\n _toArray = ScrollTrigger_gsap.utils.toArray;\n ScrollTrigger_clamp = ScrollTrigger_gsap.utils.clamp;\n ScrollTrigger_context = ScrollTrigger_gsap.core.context || ScrollTrigger_passThrough;\n ScrollTrigger_suppressOverwrites = ScrollTrigger_gsap.core.suppressOverwrites || ScrollTrigger_passThrough;\n _scrollRestoration = ScrollTrigger_win.history.scrollRestoration || \"auto\";\n _lastScroll = ScrollTrigger_win.pageYOffset;\n ScrollTrigger_gsap.core.globals(\"ScrollTrigger\", ScrollTrigger); // must register the global manually because in Internet Explorer, functions (classes) don't have a \"name\" property.\n\n if (ScrollTrigger_body) {\n _enabled = 1;\n _div100vh = document.createElement(\"div\"); // to solve mobile browser address bar show/hide resizing, we shouldn't rely on window.innerHeight. Instead, use a
with its height set to 100vh and measure that since that's what the scrolling is based on anyway and it's not affected by address bar showing/hiding.\n\n _div100vh.style.height = \"100vh\";\n _div100vh.style.position = \"absolute\";\n\n _refresh100vh();\n\n _rafBugFix();\n\n Observer.register(ScrollTrigger_gsap); // isTouch is 0 if no touch, 1 if ONLY touch, and 2 if it can accommodate touch but also other types like mouse/pointer.\n\n ScrollTrigger.isTouch = Observer.isTouch;\n _fixIOSBug = Observer.isTouch && /(iPad|iPhone|iPod|Mac)/g.test(navigator.userAgent); // since 2017, iOS has had a bug that causes event.clientX/Y to be inaccurate when a scroll occurs, thus we must alternate ignoring every other touchmove event to work around it. See https://bugs.webkit.org/show_bug.cgi?id=181954 and https://codepen.io/GreenSock/pen/ExbrPNa/087cef197dc35445a0951e8935c41503\n\n _ignoreMobileResize = Observer.isTouch === 1;\n\n ScrollTrigger_addListener(ScrollTrigger_win, \"wheel\", ScrollTrigger_onScroll); // mostly for 3rd party smooth scrolling libraries.\n\n\n ScrollTrigger_root = [ScrollTrigger_win, ScrollTrigger_doc, ScrollTrigger_docEl, ScrollTrigger_body];\n\n if (ScrollTrigger_gsap.matchMedia) {\n ScrollTrigger.matchMedia = function (vars) {\n var mm = ScrollTrigger_gsap.matchMedia(),\n p;\n\n for (p in vars) {\n mm.add(p, vars[p]);\n }\n\n return mm;\n };\n\n ScrollTrigger_gsap.addEventListener(\"matchMediaInit\", function () {\n return _revertAll();\n });\n ScrollTrigger_gsap.addEventListener(\"matchMediaRevert\", function () {\n return _revertRecorded();\n });\n ScrollTrigger_gsap.addEventListener(\"matchMedia\", function () {\n _refreshAll(0, 1);\n\n ScrollTrigger_dispatch(\"matchMedia\");\n });\n ScrollTrigger_gsap.matchMedia(\"(orientation: portrait)\", function () {\n // when orientation changes, we should take new base measurements for the ignoreMobileResize feature.\n _setBaseDimensions();\n\n return _setBaseDimensions;\n });\n } else {\n console.warn(\"Requires GSAP 3.11.0 or later\");\n }\n\n _setBaseDimensions();\n\n ScrollTrigger_addListener(ScrollTrigger_doc, \"scroll\", ScrollTrigger_onScroll); // some browsers (like Chrome), the window stops dispatching scroll events on the window if you scroll really fast, but it's consistent on the document!\n\n\n var bodyStyle = ScrollTrigger_body.style,\n border = bodyStyle.borderTopStyle,\n AnimationProto = ScrollTrigger_gsap.core.Animation.prototype,\n bounds,\n i;\n AnimationProto.revert || Object.defineProperty(AnimationProto, \"revert\", {\n value: function value() {\n return this.time(-0.01, true);\n }\n }); // only for backwards compatibility (Animation.revert() was added after 3.10.4)\n\n bodyStyle.borderTopStyle = \"solid\"; // works around an issue where a margin of a child element could throw off the bounds of the _body, making it seem like there's a margin when there actually isn't. The border ensures that the bounds are accurate.\n\n bounds = _getBounds(ScrollTrigger_body);\n _vertical.m = Math.round(bounds.top + _vertical.sc()) || 0; // accommodate the offset of the caused by margins and/or padding\n\n _horizontal.m = Math.round(bounds.left + _horizontal.sc()) || 0;\n border ? bodyStyle.borderTopStyle = border : bodyStyle.removeProperty(\"border-top-style\"); // TODO: (?) maybe move to leveraging the velocity mechanism in Observer and skip intervals.\n\n _syncInterval = setInterval(_sync, 250);\n ScrollTrigger_gsap.delayedCall(0.5, function () {\n return ScrollTrigger_startup = 0;\n });\n\n ScrollTrigger_addListener(ScrollTrigger_doc, \"touchcancel\", ScrollTrigger_passThrough); // some older Android devices intermittently stop dispatching \"touchmove\" events if we don't listen for \"touchcancel\" on the document.\n\n\n ScrollTrigger_addListener(ScrollTrigger_body, \"touchstart\", ScrollTrigger_passThrough); //works around Safari bug: https://gsap.com/forums/topic/21450-draggable-in-iframe-on-mobile-is-buggy/\n\n\n _multiListener(ScrollTrigger_addListener, ScrollTrigger_doc, \"pointerdown,touchstart,mousedown\", _pointerDownHandler);\n\n _multiListener(ScrollTrigger_addListener, ScrollTrigger_doc, \"pointerup,touchend,mouseup\", _pointerUpHandler);\n\n ScrollTrigger_transformProp = ScrollTrigger_gsap.utils.checkPrefix(\"transform\");\n\n _stateProps.push(ScrollTrigger_transformProp);\n\n ScrollTrigger_coreInitted = ScrollTrigger_getTime();\n _resizeDelay = ScrollTrigger_gsap.delayedCall(0.2, _refreshAll).pause();\n _autoRefresh = [ScrollTrigger_doc, \"visibilitychange\", function () {\n var w = ScrollTrigger_win.innerWidth,\n h = ScrollTrigger_win.innerHeight;\n\n if (ScrollTrigger_doc.hidden) {\n _prevWidth = w;\n _prevHeight = h;\n } else if (_prevWidth !== w || _prevHeight !== h) {\n _onResize();\n }\n }, ScrollTrigger_doc, \"DOMContentLoaded\", _refreshAll, ScrollTrigger_win, \"load\", _refreshAll, ScrollTrigger_win, \"resize\", _onResize];\n\n _iterateAutoRefresh(ScrollTrigger_addListener);\n\n _triggers.forEach(function (trigger) {\n return trigger.enable(0, 1);\n });\n\n for (i = 0; i < _scrollers.length; i += 3) {\n _wheelListener(ScrollTrigger_removeListener, _scrollers[i], _scrollers[i + 1]);\n\n _wheelListener(ScrollTrigger_removeListener, _scrollers[i], _scrollers[i + 2]);\n }\n }\n }\n };\n\n ScrollTrigger.config = function config(vars) {\n \"limitCallbacks\" in vars && (_limitCallbacks = !!vars.limitCallbacks);\n var ms = vars.syncInterval;\n ms && clearInterval(_syncInterval) || (_syncInterval = ms) && setInterval(_sync, ms);\n \"ignoreMobileResize\" in vars && (_ignoreMobileResize = ScrollTrigger.isTouch === 1 && vars.ignoreMobileResize);\n\n if (\"autoRefreshEvents\" in vars) {\n _iterateAutoRefresh(ScrollTrigger_removeListener) || _iterateAutoRefresh(ScrollTrigger_addListener, vars.autoRefreshEvents || \"none\");\n _ignoreResize = (vars.autoRefreshEvents + \"\").indexOf(\"resize\") === -1;\n }\n };\n\n ScrollTrigger.scrollerProxy = function scrollerProxy(target, vars) {\n var t = _getTarget(target),\n i = _scrollers.indexOf(t),\n isViewport = ScrollTrigger_isViewport(t);\n\n if (~i) {\n _scrollers.splice(i, isViewport ? 6 : 2);\n }\n\n if (vars) {\n isViewport ? _proxies.unshift(ScrollTrigger_win, vars, ScrollTrigger_body, vars, ScrollTrigger_docEl, vars) : _proxies.unshift(t, vars);\n }\n };\n\n ScrollTrigger.clearMatchMedia = function clearMatchMedia(query) {\n _triggers.forEach(function (t) {\n return t._ctx && t._ctx.query === query && t._ctx.kill(true, true);\n });\n };\n\n ScrollTrigger.isInViewport = function isInViewport(element, ratio, horizontal) {\n var bounds = (ScrollTrigger_isString(element) ? _getTarget(element) : element).getBoundingClientRect(),\n offset = bounds[horizontal ? _width : _height] * ratio || 0;\n return horizontal ? bounds.right - offset > 0 && bounds.left + offset < ScrollTrigger_win.innerWidth : bounds.bottom - offset > 0 && bounds.top + offset < ScrollTrigger_win.innerHeight;\n };\n\n ScrollTrigger.positionInViewport = function positionInViewport(element, referencePoint, horizontal) {\n ScrollTrigger_isString(element) && (element = _getTarget(element));\n var bounds = element.getBoundingClientRect(),\n size = bounds[horizontal ? _width : _height],\n offset = referencePoint == null ? size / 2 : referencePoint in _keywords ? _keywords[referencePoint] * size : ~referencePoint.indexOf(\"%\") ? parseFloat(referencePoint) * size / 100 : parseFloat(referencePoint) || 0;\n return horizontal ? (bounds.left + offset) / ScrollTrigger_win.innerWidth : (bounds.top + offset) / ScrollTrigger_win.innerHeight;\n };\n\n ScrollTrigger.killAll = function killAll(allowListeners) {\n _triggers.slice(0).forEach(function (t) {\n return t.vars.id !== \"ScrollSmoother\" && t.kill();\n });\n\n if (allowListeners !== true) {\n var listeners = ScrollTrigger_listeners.killAll || [];\n ScrollTrigger_listeners = {};\n listeners.forEach(function (f) {\n return f();\n });\n }\n };\n\n return ScrollTrigger;\n}();\nScrollTrigger_ScrollTrigger.version = \"3.12.5\";\n\nScrollTrigger_ScrollTrigger.saveStyles = function (targets) {\n return targets ? _toArray(targets).forEach(function (target) {\n // saved styles are recorded in a consecutive alternating Array, like [element, cssText, transform attribute, cache, matchMedia, ...]\n if (target && target.style) {\n var i = _savedStyles.indexOf(target);\n\n i >= 0 && _savedStyles.splice(i, 5);\n\n _savedStyles.push(target, target.style.cssText, target.getBBox && target.getAttribute(\"transform\"), ScrollTrigger_gsap.core.getCache(target), ScrollTrigger_context());\n }\n }) : _savedStyles;\n};\n\nScrollTrigger_ScrollTrigger.revert = function (soft, media) {\n return _revertAll(!soft, media);\n};\n\nScrollTrigger_ScrollTrigger.create = function (vars, animation) {\n return new ScrollTrigger_ScrollTrigger(vars, animation);\n};\n\nScrollTrigger_ScrollTrigger.refresh = function (safe) {\n return safe ? _onResize() : (ScrollTrigger_coreInitted || ScrollTrigger_ScrollTrigger.register()) && _refreshAll(true);\n};\n\nScrollTrigger_ScrollTrigger.update = function (force) {\n return ++_scrollers.cache && _updateAll(force === true ? 2 : 0);\n};\n\nScrollTrigger_ScrollTrigger.clearScrollMemory = _clearScrollMemory;\n\nScrollTrigger_ScrollTrigger.maxScroll = function (element, horizontal) {\n return _maxScroll(element, horizontal ? _horizontal : _vertical);\n};\n\nScrollTrigger_ScrollTrigger.getScrollFunc = function (element, horizontal) {\n return _getScrollFunc(_getTarget(element), horizontal ? _horizontal : _vertical);\n};\n\nScrollTrigger_ScrollTrigger.getById = function (id) {\n return _ids[id];\n};\n\nScrollTrigger_ScrollTrigger.getAll = function () {\n return _triggers.filter(function (t) {\n return t.vars.id !== \"ScrollSmoother\";\n });\n}; // it's common for people to ScrollTrigger.getAll(t => t.kill()) on page routes, for example, and we don't want it to ruin smooth scrolling by killing the main ScrollSmoother one.\n\n\nScrollTrigger_ScrollTrigger.isScrolling = function () {\n return !!_lastScrollTime;\n};\n\nScrollTrigger_ScrollTrigger.snapDirectional = _snapDirectional;\n\nScrollTrigger_ScrollTrigger.addEventListener = function (type, callback) {\n var a = ScrollTrigger_listeners[type] || (ScrollTrigger_listeners[type] = []);\n ~a.indexOf(callback) || a.push(callback);\n};\n\nScrollTrigger_ScrollTrigger.removeEventListener = function (type, callback) {\n var a = ScrollTrigger_listeners[type],\n i = a && a.indexOf(callback);\n i >= 0 && a.splice(i, 1);\n};\n\nScrollTrigger_ScrollTrigger.batch = function (targets, vars) {\n var result = [],\n varsCopy = {},\n interval = vars.interval || 0.016,\n batchMax = vars.batchMax || 1e9,\n proxyCallback = function proxyCallback(type, callback) {\n var elements = [],\n triggers = [],\n delay = ScrollTrigger_gsap.delayedCall(interval, function () {\n callback(elements, triggers);\n elements = [];\n triggers = [];\n }).pause();\n return function (self) {\n elements.length || delay.restart(true);\n elements.push(self.trigger);\n triggers.push(self);\n batchMax <= elements.length && delay.progress(1);\n };\n },\n p;\n\n for (p in vars) {\n varsCopy[p] = p.substr(0, 2) === \"on\" && ScrollTrigger_isFunction(vars[p]) && p !== \"onRefreshInit\" ? proxyCallback(p, vars[p]) : vars[p];\n }\n\n if (ScrollTrigger_isFunction(batchMax)) {\n batchMax = batchMax();\n\n ScrollTrigger_addListener(ScrollTrigger_ScrollTrigger, \"refresh\", function () {\n return batchMax = vars.batchMax();\n });\n }\n\n _toArray(targets).forEach(function (target) {\n var config = {};\n\n for (p in varsCopy) {\n config[p] = varsCopy[p];\n }\n\n config.trigger = target;\n result.push(ScrollTrigger_ScrollTrigger.create(config));\n });\n\n return result;\n}; // to reduce file size. clamps the scroll and also returns a duration multiplier so that if the scroll gets chopped shorter, the duration gets curtailed as well (otherwise if you're very close to the top of the page, for example, and swipe up really fast, it'll suddenly slow down and take a long time to reach the top).\n\n\nvar _clampScrollAndGetDurationMultiplier = function _clampScrollAndGetDurationMultiplier(scrollFunc, current, end, max) {\n current > max ? scrollFunc(max) : current < 0 && scrollFunc(0);\n return end > max ? (max - current) / (end - current) : end < 0 ? current / (current - end) : 1;\n},\n _allowNativePanning = function _allowNativePanning(target, direction) {\n if (direction === true) {\n target.style.removeProperty(\"touch-action\");\n } else {\n target.style.touchAction = direction === true ? \"auto\" : direction ? \"pan-\" + direction + (Observer.isTouch ? \" pinch-zoom\" : \"\") : \"none\"; // note: Firefox doesn't support it pinch-zoom properly, at least in addition to a pan-x or pan-y.\n }\n\n target === ScrollTrigger_docEl && _allowNativePanning(ScrollTrigger_body, direction);\n},\n _overflow = {\n auto: 1,\n scroll: 1\n},\n _nestedScroll = function _nestedScroll(_ref5) {\n var event = _ref5.event,\n target = _ref5.target,\n axis = _ref5.axis;\n\n var node = (event.changedTouches ? event.changedTouches[0] : event).target,\n cache = node._gsap || ScrollTrigger_gsap.core.getCache(node),\n time = ScrollTrigger_getTime(),\n cs;\n\n if (!cache._isScrollT || time - cache._isScrollT > 2000) {\n // cache for 2 seconds to improve performance.\n while (node && node !== ScrollTrigger_body && (node.scrollHeight <= node.clientHeight && node.scrollWidth <= node.clientWidth || !(_overflow[(cs = _getComputedStyle(node)).overflowY] || _overflow[cs.overflowX]))) {\n node = node.parentNode;\n }\n\n cache._isScroll = node && node !== target && !ScrollTrigger_isViewport(node) && (_overflow[(cs = _getComputedStyle(node)).overflowY] || _overflow[cs.overflowX]);\n cache._isScrollT = time;\n }\n\n if (cache._isScroll || axis === \"x\") {\n event.stopPropagation();\n event._gsapAllow = true;\n }\n},\n // capture events on scrollable elements INSIDE the and allow those by calling stopPropagation() when we find a scrollable ancestor\n_inputObserver = function _inputObserver(target, type, inputs, nested) {\n return Observer.create({\n target: target,\n capture: true,\n debounce: false,\n lockAxis: true,\n type: type,\n onWheel: nested = nested && _nestedScroll,\n onPress: nested,\n onDrag: nested,\n onScroll: nested,\n onEnable: function onEnable() {\n return inputs && ScrollTrigger_addListener(ScrollTrigger_doc, Observer.eventTypes[0], _captureInputs, false, true);\n },\n onDisable: function onDisable() {\n return ScrollTrigger_removeListener(ScrollTrigger_doc, Observer.eventTypes[0], _captureInputs, true);\n }\n });\n},\n _inputExp = /(input|label|select|textarea)/i,\n _inputIsFocused,\n _captureInputs = function _captureInputs(e) {\n var isInput = _inputExp.test(e.target.tagName);\n\n if (isInput || _inputIsFocused) {\n e._gsapAllow = true;\n _inputIsFocused = isInput;\n }\n},\n _getScrollNormalizer = function _getScrollNormalizer(vars) {\n ScrollTrigger_isObject(vars) || (vars = {});\n vars.preventDefault = vars.isNormalizer = vars.allowClicks = true;\n vars.type || (vars.type = \"wheel,touch\");\n vars.debounce = !!vars.debounce;\n vars.id = vars.id || \"normalizer\";\n\n var _vars2 = vars,\n normalizeScrollX = _vars2.normalizeScrollX,\n momentum = _vars2.momentum,\n allowNestedScroll = _vars2.allowNestedScroll,\n onRelease = _vars2.onRelease,\n self,\n maxY,\n target = _getTarget(vars.target) || ScrollTrigger_docEl,\n smoother = ScrollTrigger_gsap.core.globals().ScrollSmoother,\n smootherInstance = smoother && smoother.get(),\n content = _fixIOSBug && (vars.content && _getTarget(vars.content) || smootherInstance && vars.content !== false && !smootherInstance.smooth() && smootherInstance.content()),\n scrollFuncY = _getScrollFunc(target, _vertical),\n scrollFuncX = _getScrollFunc(target, _horizontal),\n scale = 1,\n initialScale = (Observer.isTouch && ScrollTrigger_win.visualViewport ? ScrollTrigger_win.visualViewport.scale * ScrollTrigger_win.visualViewport.width : ScrollTrigger_win.outerWidth) / ScrollTrigger_win.innerWidth,\n wheelRefresh = 0,\n resolveMomentumDuration = ScrollTrigger_isFunction(momentum) ? function () {\n return momentum(self);\n } : function () {\n return momentum || 2.8;\n },\n lastRefreshID,\n skipTouchMove,\n inputObserver = _inputObserver(target, vars.type, true, allowNestedScroll),\n resumeTouchMove = function resumeTouchMove() {\n return skipTouchMove = false;\n },\n scrollClampX = ScrollTrigger_passThrough,\n scrollClampY = ScrollTrigger_passThrough,\n updateClamps = function updateClamps() {\n maxY = _maxScroll(target, _vertical);\n scrollClampY = ScrollTrigger_clamp(_fixIOSBug ? 1 : 0, maxY);\n normalizeScrollX && (scrollClampX = ScrollTrigger_clamp(0, _maxScroll(target, _horizontal)));\n lastRefreshID = _refreshID;\n },\n removeContentOffset = function removeContentOffset() {\n content._gsap.y = ScrollTrigger_round(parseFloat(content._gsap.y) + scrollFuncY.offset) + \"px\";\n content.style.transform = \"matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, \" + parseFloat(content._gsap.y) + \", 0, 1)\";\n scrollFuncY.offset = scrollFuncY.cacheID = 0;\n },\n ignoreDrag = function ignoreDrag() {\n if (skipTouchMove) {\n requestAnimationFrame(resumeTouchMove);\n\n var offset = ScrollTrigger_round(self.deltaY / 2),\n scroll = scrollClampY(scrollFuncY.v - offset);\n\n if (content && scroll !== scrollFuncY.v + scrollFuncY.offset) {\n scrollFuncY.offset = scroll - scrollFuncY.v;\n\n var y = ScrollTrigger_round((parseFloat(content && content._gsap.y) || 0) - scrollFuncY.offset);\n\n content.style.transform = \"matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, \" + y + \", 0, 1)\";\n content._gsap.y = y + \"px\";\n scrollFuncY.cacheID = _scrollers.cache;\n\n _updateAll();\n }\n\n return true;\n }\n\n scrollFuncY.offset && removeContentOffset();\n skipTouchMove = true;\n },\n tween,\n startScrollX,\n startScrollY,\n onStopDelayedCall,\n onResize = function onResize() {\n // if the window resizes, like on an iPhone which Apple FORCES the address bar to show/hide even if we event.preventDefault(), it may be scrolling too far now that the address bar is showing, so we must dynamically adjust the momentum tween.\n updateClamps();\n\n if (tween.isActive() && tween.vars.scrollY > maxY) {\n scrollFuncY() > maxY ? tween.progress(1) && scrollFuncY(maxY) : tween.resetTo(\"scrollY\", maxY);\n }\n };\n\n content && ScrollTrigger_gsap.set(content, {\n y: \"+=0\"\n }); // to ensure there's a cache (element._gsap)\n\n vars.ignoreCheck = function (e) {\n return _fixIOSBug && e.type === \"touchmove\" && ignoreDrag(e) || scale > 1.05 && e.type !== \"touchstart\" || self.isGesturing || e.touches && e.touches.length > 1;\n };\n\n vars.onPress = function () {\n skipTouchMove = false;\n var prevScale = scale;\n scale = ScrollTrigger_round((ScrollTrigger_win.visualViewport && ScrollTrigger_win.visualViewport.scale || 1) / initialScale);\n tween.pause();\n prevScale !== scale && _allowNativePanning(target, scale > 1.01 ? true : normalizeScrollX ? false : \"x\");\n startScrollX = scrollFuncX();\n startScrollY = scrollFuncY();\n updateClamps();\n lastRefreshID = _refreshID;\n };\n\n vars.onRelease = vars.onGestureStart = function (self, wasDragging) {\n scrollFuncY.offset && removeContentOffset();\n\n if (!wasDragging) {\n onStopDelayedCall.restart(true);\n } else {\n _scrollers.cache++; // make sure we're pulling the non-cached value\n // alternate algorithm: durX = Math.min(6, Math.abs(self.velocityX / 800)),\tdur = Math.max(durX, Math.min(6, Math.abs(self.velocityY / 800))); dur = dur * (0.4 + (1 - _power4In(dur / 6)) * 0.6)) * (momentumSpeed || 1)\n\n var dur = resolveMomentumDuration(),\n currentScroll,\n endScroll;\n\n if (normalizeScrollX) {\n currentScroll = scrollFuncX();\n endScroll = currentScroll + dur * 0.05 * -self.velocityX / 0.227; // the constant .227 is from power4(0.05). velocity is inverted because scrolling goes in the opposite direction.\n\n dur *= _clampScrollAndGetDurationMultiplier(scrollFuncX, currentScroll, endScroll, _maxScroll(target, _horizontal));\n tween.vars.scrollX = scrollClampX(endScroll);\n }\n\n currentScroll = scrollFuncY();\n endScroll = currentScroll + dur * 0.05 * -self.velocityY / 0.227; // the constant .227 is from power4(0.05)\n\n dur *= _clampScrollAndGetDurationMultiplier(scrollFuncY, currentScroll, endScroll, _maxScroll(target, _vertical));\n tween.vars.scrollY = scrollClampY(endScroll);\n tween.invalidate().duration(dur).play(0.01);\n\n if (_fixIOSBug && tween.vars.scrollY >= maxY || currentScroll >= maxY - 1) {\n // iOS bug: it'll show the address bar but NOT fire the window \"resize\" event until the animation is done but we must protect against overshoot so we leverage an onUpdate to do so.\n ScrollTrigger_gsap.to({}, {\n onUpdate: onResize,\n duration: dur\n });\n }\n }\n\n onRelease && onRelease(self);\n };\n\n vars.onWheel = function () {\n tween._ts && tween.pause();\n\n if (ScrollTrigger_getTime() - wheelRefresh > 1000) {\n // after 1 second, refresh the clamps otherwise that'll only happen when ScrollTrigger.refresh() is called or for touch-scrolling.\n lastRefreshID = 0;\n wheelRefresh = ScrollTrigger_getTime();\n }\n };\n\n vars.onChange = function (self, dx, dy, xArray, yArray) {\n _refreshID !== lastRefreshID && updateClamps();\n dx && normalizeScrollX && scrollFuncX(scrollClampX(xArray[2] === dx ? startScrollX + (self.startX - self.x) : scrollFuncX() + dx - xArray[1])); // for more precision, we track pointer/touch movement from the start, otherwise it'll drift.\n\n if (dy) {\n scrollFuncY.offset && removeContentOffset();\n var isTouch = yArray[2] === dy,\n y = isTouch ? startScrollY + self.startY - self.y : scrollFuncY() + dy - yArray[1],\n yClamped = scrollClampY(y);\n isTouch && y !== yClamped && (startScrollY += yClamped - y);\n scrollFuncY(yClamped);\n }\n\n (dy || dx) && _updateAll();\n };\n\n vars.onEnable = function () {\n _allowNativePanning(target, normalizeScrollX ? false : \"x\");\n\n ScrollTrigger_ScrollTrigger.addEventListener(\"refresh\", onResize);\n\n ScrollTrigger_addListener(ScrollTrigger_win, \"resize\", onResize);\n\n if (scrollFuncY.smooth) {\n scrollFuncY.target.style.scrollBehavior = \"auto\";\n scrollFuncY.smooth = scrollFuncX.smooth = false;\n }\n\n inputObserver.enable();\n };\n\n vars.onDisable = function () {\n _allowNativePanning(target, true);\n\n ScrollTrigger_removeListener(ScrollTrigger_win, \"resize\", onResize);\n\n ScrollTrigger_ScrollTrigger.removeEventListener(\"refresh\", onResize);\n inputObserver.kill();\n };\n\n vars.lockAxis = vars.lockAxis !== false;\n self = new Observer(vars);\n self.iOS = _fixIOSBug; // used in the Observer getCachedScroll() function to work around an iOS bug that wreaks havoc with TouchEvent.clientY if we allow scroll to go all the way back to 0.\n\n _fixIOSBug && !scrollFuncY() && scrollFuncY(1); // iOS bug causes event.clientY values to freak out (wildly inaccurate) if the scroll position is exactly 0.\n\n _fixIOSBug && ScrollTrigger_gsap.ticker.add(ScrollTrigger_passThrough); // prevent the ticker from sleeping\n\n onStopDelayedCall = self._dc;\n tween = ScrollTrigger_gsap.to(self, {\n ease: \"power4\",\n paused: true,\n inherit: false,\n scrollX: normalizeScrollX ? \"+=0.1\" : \"+=0\",\n scrollY: \"+=0.1\",\n modifiers: {\n scrollY: _interruptionTracker(scrollFuncY, scrollFuncY(), function () {\n return tween.pause();\n })\n },\n onUpdate: _updateAll,\n onComplete: onStopDelayedCall.vars.onComplete\n }); // we need the modifier to sense if the scroll position is altered outside of the momentum tween (like with a scrollTo tween) so we can pause() it to prevent conflicts.\n\n return self;\n};\n\nScrollTrigger_ScrollTrigger.sort = function (func) {\n return _triggers.sort(func || function (a, b) {\n return (a.vars.refreshPriority || 0) * -1e6 + a.start - (b.start + (b.vars.refreshPriority || 0) * -1e6);\n });\n};\n\nScrollTrigger_ScrollTrigger.observe = function (vars) {\n return new Observer(vars);\n};\n\nScrollTrigger_ScrollTrigger.normalizeScroll = function (vars) {\n if (typeof vars === \"undefined\") {\n return ScrollTrigger_normalizer;\n }\n\n if (vars === true && ScrollTrigger_normalizer) {\n return ScrollTrigger_normalizer.enable();\n }\n\n if (vars === false) {\n ScrollTrigger_normalizer && ScrollTrigger_normalizer.kill();\n ScrollTrigger_normalizer = vars;\n return;\n }\n\n var normalizer = vars instanceof Observer ? vars : _getScrollNormalizer(vars);\n ScrollTrigger_normalizer && ScrollTrigger_normalizer.target === normalizer.target && ScrollTrigger_normalizer.kill();\n ScrollTrigger_isViewport(normalizer.target) && (ScrollTrigger_normalizer = normalizer);\n return normalizer;\n};\n\nScrollTrigger_ScrollTrigger.core = {\n // smaller file size way to leverage in ScrollSmoother and Observer\n _getVelocityProp: _getVelocityProp,\n _inputObserver: _inputObserver,\n _scrollers: _scrollers,\n _proxies: _proxies,\n bridge: {\n // when normalizeScroll sets the scroll position (ss = setScroll)\n ss: function ss() {\n _lastScrollTime || ScrollTrigger_dispatch(\"scrollStart\");\n _lastScrollTime = ScrollTrigger_getTime();\n },\n // a way to get the _refreshing value in Observer\n ref: function ref() {\n return _refreshing;\n }\n }\n};\nScrollTrigger_getGSAP() && ScrollTrigger_gsap.registerPlugin(ScrollTrigger_ScrollTrigger);\n\n;// CONCATENATED MODULE: ./node_modules/gsap/ScrollToPlugin.js\n/*!\n * ScrollToPlugin 3.12.5\n * https://gsap.com\n *\n * @license Copyright 2008-2024, GreenSock. All rights reserved.\n * Subject to the terms at https://gsap.com/standard-license or for\n * Club GSAP members, the agreement issued with that membership.\n * @author: Jack Doyle, jack@greensock.com\n*/\n\n/* eslint-disable */\nvar ScrollToPlugin_gsap,\n ScrollToPlugin_coreInitted,\n _window,\n ScrollToPlugin_docEl,\n ScrollToPlugin_body,\n ScrollToPlugin_toArray,\n ScrollToPlugin_config,\n ScrollToPlugin_ScrollTrigger,\n ScrollToPlugin_windowExists = function _windowExists() {\n return typeof window !== \"undefined\";\n},\n ScrollToPlugin_getGSAP = function _getGSAP() {\n return ScrollToPlugin_gsap || ScrollToPlugin_windowExists() && (ScrollToPlugin_gsap = window.gsap) && ScrollToPlugin_gsap.registerPlugin && ScrollToPlugin_gsap;\n},\n ScrollToPlugin_isString = function _isString(value) {\n return typeof value === \"string\";\n},\n ScrollToPlugin_isFunction = function _isFunction(value) {\n return typeof value === \"function\";\n},\n _max = function _max(element, axis) {\n var dim = axis === \"x\" ? \"Width\" : \"Height\",\n scroll = \"scroll\" + dim,\n client = \"client\" + dim;\n return element === _window || element === ScrollToPlugin_docEl || element === ScrollToPlugin_body ? Math.max(ScrollToPlugin_docEl[scroll], ScrollToPlugin_body[scroll]) - (_window[\"inner\" + dim] || ScrollToPlugin_docEl[client] || ScrollToPlugin_body[client]) : element[scroll] - element[\"offset\" + dim];\n},\n _buildGetter = function _buildGetter(e, axis) {\n //pass in an element and an axis (\"x\" or \"y\") and it'll return a getter function for the scroll position of that element (like scrollTop or scrollLeft, although if the element is the window, it'll use the pageXOffset/pageYOffset or the documentElement's scrollTop/scrollLeft or document.body's. Basically this streamlines things and makes a very fast getter across browsers.\n var p = \"scroll\" + (axis === \"x\" ? \"Left\" : \"Top\");\n\n if (e === _window) {\n if (e.pageXOffset != null) {\n p = \"page\" + axis.toUpperCase() + \"Offset\";\n } else {\n e = ScrollToPlugin_docEl[p] != null ? ScrollToPlugin_docEl : ScrollToPlugin_body;\n }\n }\n\n return function () {\n return e[p];\n };\n},\n _clean = function _clean(value, index, target, targets) {\n ScrollToPlugin_isFunction(value) && (value = value(index, target, targets));\n\n if (typeof value !== \"object\") {\n return ScrollToPlugin_isString(value) && value !== \"max\" && value.charAt(1) !== \"=\" ? {\n x: value,\n y: value\n } : {\n y: value\n }; //if we don't receive an object as the parameter, assume the user intends \"y\".\n } else if (value.nodeType) {\n return {\n y: value,\n x: value\n };\n } else {\n var result = {},\n p;\n\n for (p in value) {\n result[p] = p !== \"onAutoKill\" && ScrollToPlugin_isFunction(value[p]) ? value[p](index, target, targets) : value[p];\n }\n\n return result;\n }\n},\n _getOffset = function _getOffset(element, container) {\n element = ScrollToPlugin_toArray(element)[0];\n\n if (!element || !element.getBoundingClientRect) {\n return console.warn(\"scrollTo target doesn't exist. Using 0\") || {\n x: 0,\n y: 0\n };\n }\n\n var rect = element.getBoundingClientRect(),\n isRoot = !container || container === _window || container === ScrollToPlugin_body,\n cRect = isRoot ? {\n top: ScrollToPlugin_docEl.clientTop - (_window.pageYOffset || ScrollToPlugin_docEl.scrollTop || ScrollToPlugin_body.scrollTop || 0),\n left: ScrollToPlugin_docEl.clientLeft - (_window.pageXOffset || ScrollToPlugin_docEl.scrollLeft || ScrollToPlugin_body.scrollLeft || 0)\n } : container.getBoundingClientRect(),\n offsets = {\n x: rect.left - cRect.left,\n y: rect.top - cRect.top\n };\n\n if (!isRoot && container) {\n //only add the current scroll position if it's not the window/body.\n offsets.x += _buildGetter(container, \"x\")();\n offsets.y += _buildGetter(container, \"y\")();\n }\n\n return offsets;\n},\n _parseVal = function _parseVal(value, target, axis, currentVal, offset) {\n return !isNaN(value) && typeof value !== \"object\" ? parseFloat(value) - offset : ScrollToPlugin_isString(value) && value.charAt(1) === \"=\" ? parseFloat(value.substr(2)) * (value.charAt(0) === \"-\" ? -1 : 1) + currentVal - offset : value === \"max\" ? _max(target, axis) - offset : Math.min(_max(target, axis), _getOffset(value, target)[axis] - offset);\n},\n ScrollToPlugin_initCore = function _initCore() {\n ScrollToPlugin_gsap = ScrollToPlugin_getGSAP();\n\n if (ScrollToPlugin_windowExists() && ScrollToPlugin_gsap && typeof document !== \"undefined\" && document.body) {\n _window = window;\n ScrollToPlugin_body = document.body;\n ScrollToPlugin_docEl = document.documentElement;\n ScrollToPlugin_toArray = ScrollToPlugin_gsap.utils.toArray;\n ScrollToPlugin_gsap.config({\n autoKillThreshold: 7\n });\n ScrollToPlugin_config = ScrollToPlugin_gsap.config();\n ScrollToPlugin_coreInitted = 1;\n }\n};\n\nvar ScrollToPlugin = {\n version: \"3.12.5\",\n name: \"scrollTo\",\n rawVars: 1,\n register: function register(core) {\n ScrollToPlugin_gsap = core;\n\n ScrollToPlugin_initCore();\n },\n init: function init(target, value, tween, index, targets) {\n ScrollToPlugin_coreInitted || ScrollToPlugin_initCore();\n var data = this,\n snapType = ScrollToPlugin_gsap.getProperty(target, \"scrollSnapType\");\n data.isWin = target === _window;\n data.target = target;\n data.tween = tween;\n value = _clean(value, index, target, targets);\n data.vars = value;\n data.autoKill = !!value.autoKill;\n data.getX = _buildGetter(target, \"x\");\n data.getY = _buildGetter(target, \"y\");\n data.x = data.xPrev = data.getX();\n data.y = data.yPrev = data.getY();\n ScrollToPlugin_ScrollTrigger || (ScrollToPlugin_ScrollTrigger = ScrollToPlugin_gsap.core.globals().ScrollTrigger);\n ScrollToPlugin_gsap.getProperty(target, \"scrollBehavior\") === \"smooth\" && ScrollToPlugin_gsap.set(target, {\n scrollBehavior: \"auto\"\n });\n\n if (snapType && snapType !== \"none\") {\n // disable scroll snapping to avoid strange behavior\n data.snap = 1;\n data.snapInline = target.style.scrollSnapType;\n target.style.scrollSnapType = \"none\";\n }\n\n if (value.x != null) {\n data.add(data, \"x\", data.x, _parseVal(value.x, target, \"x\", data.x, value.offsetX || 0), index, targets);\n\n data._props.push(\"scrollTo_x\");\n } else {\n data.skipX = 1;\n }\n\n if (value.y != null) {\n data.add(data, \"y\", data.y, _parseVal(value.y, target, \"y\", data.y, value.offsetY || 0), index, targets);\n\n data._props.push(\"scrollTo_y\");\n } else {\n data.skipY = 1;\n }\n },\n render: function render(ratio, data) {\n var pt = data._pt,\n target = data.target,\n tween = data.tween,\n autoKill = data.autoKill,\n xPrev = data.xPrev,\n yPrev = data.yPrev,\n isWin = data.isWin,\n snap = data.snap,\n snapInline = data.snapInline,\n x,\n y,\n yDif,\n xDif,\n threshold;\n\n while (pt) {\n pt.r(ratio, pt.d);\n pt = pt._next;\n }\n\n x = isWin || !data.skipX ? data.getX() : xPrev;\n y = isWin || !data.skipY ? data.getY() : yPrev;\n yDif = y - yPrev;\n xDif = x - xPrev;\n threshold = ScrollToPlugin_config.autoKillThreshold;\n\n if (data.x < 0) {\n //can't scroll to a position less than 0! Might happen if someone uses a Back.easeOut or Elastic.easeOut when scrolling back to the top of the page (for example)\n data.x = 0;\n }\n\n if (data.y < 0) {\n data.y = 0;\n }\n\n if (autoKill) {\n //note: iOS has a bug that throws off the scroll by several pixels, so we need to check if it's within 7 pixels of the previous one that we set instead of just looking for an exact match.\n if (!data.skipX && (xDif > threshold || xDif < -threshold) && x < _max(target, \"x\")) {\n data.skipX = 1; //if the user scrolls separately, we should stop tweening!\n }\n\n if (!data.skipY && (yDif > threshold || yDif < -threshold) && y < _max(target, \"y\")) {\n data.skipY = 1; //if the user scrolls separately, we should stop tweening!\n }\n\n if (data.skipX && data.skipY) {\n tween.kill();\n data.vars.onAutoKill && data.vars.onAutoKill.apply(tween, data.vars.onAutoKillParams || []);\n }\n }\n\n if (isWin) {\n _window.scrollTo(!data.skipX ? data.x : x, !data.skipY ? data.y : y);\n } else {\n data.skipY || (target.scrollTop = data.y);\n data.skipX || (target.scrollLeft = data.x);\n }\n\n if (snap && (ratio === 1 || ratio === 0)) {\n y = target.scrollTop;\n x = target.scrollLeft;\n snapInline ? target.style.scrollSnapType = snapInline : target.style.removeProperty(\"scroll-snap-type\");\n target.scrollTop = y + 1; // bug in Safari causes the element to totally reset its scroll position when scroll-snap-type changes, so we need to set it to a slightly different value and then back again to work around this bug.\n\n target.scrollLeft = x + 1;\n target.scrollTop = y;\n target.scrollLeft = x;\n }\n\n data.xPrev = data.x;\n data.yPrev = data.y;\n ScrollToPlugin_ScrollTrigger && ScrollToPlugin_ScrollTrigger.update();\n },\n kill: function kill(property) {\n var both = property === \"scrollTo\",\n i = this._props.indexOf(property);\n\n if (both || property === \"scrollTo_x\") {\n this.skipX = 1;\n }\n\n if (both || property === \"scrollTo_y\") {\n this.skipY = 1;\n }\n\n i > -1 && this._props.splice(i, 1);\n return !this._props.length;\n }\n};\nScrollToPlugin.max = _max;\nScrollToPlugin.getOffset = _getOffset;\nScrollToPlugin.buildGetter = _buildGetter;\nScrollToPlugin_getGSAP() && ScrollToPlugin_gsap.registerPlugin(ScrollToPlugin);\n\n// EXTERNAL MODULE: ./node_modules/scrollmagic/scrollmagic/uncompressed/ScrollMagic.js\nvar ScrollMagic = __webpack_require__(131);\n// EXTERNAL MODULE: ./node_modules/scrollmagic-plugin-gsap/index.js\nvar scrollmagic_plugin_gsap = __webpack_require__(19);\n;// CONCATENATED MODULE: ./src/components/navbar/navbar.js\n\n\n\n\ngsapWithCSS.registerPlugin(ScrollToPlugin);\nlet navbar, lang;\nconst controller = new ScrollMagic.Controller();\nconst vw = window.innerWidth;\nconst activePage = window.location.pathname.split('allagrande-pirelli/')[1].replace('.html', '');\nconst navbarMenuBehaviors = () => {\n const navbarWrapper = navbar.querySelector('.navbar_wrapper');\n const navbarLogo = navbarWrapper.querySelector('.navbar_wrapper-logos .allagrande');\n const navbarMenu = navbarWrapper.querySelector('.navbar_wrapper-menu');\n const navbarMenuLink = navbarMenu.querySelectorAll('.navbar_wrapper-menu--navigationMenu_link');\n navbarLogo.addEventListener('click', () => {\n let homeUrl = '';\n // if (document.querySelector('.main.isBuildedProd')) {\n // homeUrl = 'index.html';\n // } else {\n // homeUrl = '';\n // }\n if (lang === 'it') {\n window.location.href = `/global/it-it/allagrande-pirelli/${homeUrl}`;\n } else if (lang === 'en') {\n window.location.href = `/global/en-ww/allagrande-pirelli/${homeUrl}`;\n }\n });\n navbarMenuLink.forEach(link => {\n const linkAnchor = link.getAttribute('href');\n if (document.querySelector(linkAnchor)) {\n link.addEventListener('click', e => {\n e.preventDefault();\n if (document.querySelector('.chapterModal .sectionChapter')) {\n closeChapterModal();\n }\n scrollTo(linkAnchor);\n });\n } else {\n link.addEventListener('click', e => {\n if (linkAnchor !== 'voyages' && linkAnchor !== 'voyages.html') {\n e.preventDefault();\n sessionStorage.setItem('anchor', linkAnchor);\n navbarLogo.click();\n }\n });\n }\n });\n if (activePage === '' || activePage === 'index' || activePage === 'index.html') {\n new ScrollMagic.Scene({\n triggerElement: '#' + document.querySelector('.sectionVisual').closest('section').nextElementSibling.getAttribute('id'),\n triggerHook: 0.3,\n reverse: true\n }).setClassToggle(navbar, 'hidden').addTo(controller);\n } else if (activePage !== 'voyages' && activePage !== 'voyages.html') {\n navbar.querySelectorAll('.navbar_wrapper-menu--navigationMenu_link')[1].classList.add('active');\n } else {\n navbar.querySelector(`.navbar_wrapper-menu--navigationMenu_link[href=\"${activePage}\"]`).classList.add('active');\n }\n};\nconst navbarBurgerClick = () => {\n const navbarBurger = navbar.querySelector('.navbar_wrapper-burger');\n navbarBurger.addEventListener('click', () => {\n if (navbar.classList.contains('navbar--open')) {\n navbar.classList.remove('navbar--open');\n } else {\n navbar.classList.add('navbar--open');\n }\n });\n};\nconst langSuggestionOpen = () => {\n const langSelect = navbar.querySelector('.langSelect');\n const langSelectSelected = langSelect.querySelector('.langSelect-selected span');\n const langSuggestions = langSelect.querySelector('.langSelect-suggestions');\n const langSuggestionsOptions = langSuggestions.querySelectorAll('.langSelect-suggestions--lang');\n const langSuggestionsOptionsHeight = langSuggestionsOptions[0].clientHeight;\n const langSuggestionsOptionsLength = langSuggestionsOptions.length;\n langSelect.addEventListener('click', e => {\n if (langSelectSelected.parentNode.classList.contains('open')) {\n langSelectSelected.parentNode.classList.remove('open');\n langSuggestions.style.height = 0;\n } else {\n langSelectSelected.parentNode.classList.add('open');\n langSuggestions.style.height = langSuggestionsOptionsHeight * langSuggestionsOptionsLength + 'px';\n }\n });\n langSuggestionsOptions.forEach(option => {\n option.addEventListener('click', e => {\n e.preventDefault();\n if (lang === 'it' && window.location.pathname.indexOf('en-ww') === -1) {\n window.location.href = `/global/en-ww/allagrande-pirelli/${activePage}`;\n } else if (lang === 'en' && window.location.pathname.indexOf('it-it') === -1) {\n window.location.href = `/global/it-it/allagrande-pirelli/${activePage}`;\n }\n });\n });\n};\nconst showNavbar = () => {\n navbar.classList.remove('hidden');\n};\nconst hideNavbar = () => {\n navbar.classList.add('hidden');\n};\nif (window.location.pathname.indexOf('it-it') > -1) {\n lang = 'it';\n} else if (window.location.pathname.indexOf('en-ww') > -1) {\n lang = 'en';\n}\ndocument.querySelector('.langSelect-selected span').innerHTML = lang;\ndocument.addEventListener('DOMContentLoaded', () => {\n if (document.querySelector('.navbar')) {\n navbar = document.querySelector('.navbar');\n navbarMenuBehaviors();\n navbarBurgerClick();\n langSuggestionOpen();\n }\n});\n\n;// CONCATENATED MODULE: ./src/components/chapterModal/chapterModal.js\n//Vendor scripts\n\n\n\n\nconst chapterModal_vw = window.outerWidth;\nlet chapterModal;\nconst chapterModalBuild = url => {\n const body = document.querySelector('body');\n body.classList.add('animating');\n gsapWithCSS.to(chapterModal, {\n top: 0,\n opacity: 1,\n scale: 1,\n duration: 1,\n ease: Expo.easeInOut,\n onComplete: () => {\n blockDocumentScroll();\n }\n });\n showNavbar();\n if (!window.XMLHttpRequest) return;\n let xhr = new XMLHttpRequest();\n const urlToCall = window.location.host !== 'localhost:4000' ? url : `${url}.html`;\n xhr.open('GET', urlToCall);\n xhr.addEventListener('load', () => {\n const contentToInjectTitle = xhr.response.querySelector('title').innerHTML;\n const contentToInject = xhr.response.querySelector('#toInject').innerHTML;\n chapterModal.innerHTML = contentToInject;\n window.history.pushState(null, contentToInjectTitle, url);\n document.title = contentToInjectTitle;\n chapterOpenClick();\n window.dispatchEvent(new Event('popstate'));\n body.classList.remove('animating');\n });\n xhr.responseType = 'document';\n xhr.send();\n window.addEventListener('popstate', e => {\n console.log(e);\n if (!body.classList.contains('animating')) {\n closeChapterModal();\n }\n });\n};\nwindow.addEventListener('DOMContentLoaded', () => {\n if (document.querySelector('.chapterModal')) {\n chapterModal = document.querySelector('.chapterModal');\n }\n});\n/* harmony default export */ const chapterModal_chapterModal = (chapterModalBuild);\n;// CONCATENATED MODULE: ./src/components/chapter/chapter.js\n//Vendor scripts\n\n\nconst YTPlayer = __webpack_require__(474);\nconst chapterOpenHandler = chapterName => {\n let path;\n const activePage = window.location.pathname.split('allagrande-pirelli/')[1];\n if (window.location.href.indexOf('en-ww') > -1) {\n path = `/global/en-ww/allagrande-pirelli/${chapterName}`;\n } else if (window.location.href.indexOf('it-it') > -1) {\n path = `/global/it-it/allagrande-pirelli/${chapterName}`;\n }\n if (activePage === '' || activePage === 'index' || activePage === 'index.html') {\n chapterModal_chapterModal(chapterName);\n } else {\n if (document.querySelector('.chapterModal')) {\n closeChapterModal();\n }\n window.location.href = path;\n }\n};\nconst chapterOpenClick = () => {\n const chapterNavigationPrev = document.querySelector('.sectionChapter_navigation-prev');\n if (chapterNavigationPrev) {\n const chapterNavigationPrevName = chapterNavigationPrev.getAttribute('data-name');\n chapterNavigationPrev.addEventListener('click', () => {\n let chapterName;\n if (window.location.host != \"localhost:3000\") {\n chapterName = `${chapterNavigationPrevName}`;\n } else {\n chapterName = `${chapterNavigationPrevName}.html`;\n }\n chapterOpenHandler(chapterName);\n });\n }\n const chapterNavigationNext = document.querySelector('.sectionChapter_navigation-next');\n if (chapterNavigationNext) {\n const chapterNavigationNextName = chapterNavigationNext?.getAttribute('data-name');\n chapterNavigationNext.addEventListener('click', () => {\n let chapterName;\n if (window.location.host != \"localhost:3000\") {\n chapterName = `${chapterNavigationNextName}`;\n } else {\n chapterName = `${chapterNavigationNextName}.html`;\n }\n chapterOpenHandler(chapterName);\n });\n }\n};\nconst playerInit = () => {\n const chapter = document.querySelector('.sectionChapter');\n const videoRow = chapter.querySelector('.sectionChapter_row-img.video');\n const videoPlayer = videoRow.querySelector('.videoPlayer');\n const videoPlayerID = videoPlayer.getAttribute('data-url-id');\n const player = new YTPlayer(videoPlayer, {\n height: '100%',\n width: '100%'\n });\n player.load(videoPlayerID);\n player.setVolume(30);\n const playButton = chapter.querySelector('.playButton');\n playButton.addEventListener('click', () => {\n videoRow.classList.add('playingVideo');\n player.play();\n });\n player.on('paused', () => {\n videoRow.classList.remove('playingVideo');\n });\n};\nconst checkEmptyChapter = () => {\n const chapter = document.querySelector('.sectionChapter');\n const chapterNavigation = chapter.querySelector('.sectionChapter_navigation');\n const prevChapter = chapterNavigation.querySelector('.sectionChapter_navigation-prev');\n const nextChapter = chapterNavigation.querySelector('.sectionChapter_navigation-next');\n if (prevChapter.getAttribute('data-name') === '') {\n prevChapter.style.opacity = 0;\n prevChapter.style.visibility = 'hidden';\n }\n if (nextChapter.getAttribute('data-name') === '') {\n nextChapter.style.opacity = 0;\n nextChapter.style.visibility = 'hidden';\n }\n};\nwindow.addEventListener('DOMContentLoaded', () => {\n if (document.querySelector('.sectionChapter')) {\n chapterOpenClick();\n playerInit();\n checkEmptyChapter();\n }\n});\n\n;// CONCATENATED MODULE: ./src/assets/js/common.js\n//Vendor scripts\n\n\n\n\n\n//JSONBuild\n\n\n(0,scrollmagic_plugin_gsap.ScrollMagicPluginGsap)(ScrollMagic, gsapWithCSS);\ngsapWithCSS.registerPlugin(ScrollTrigger_ScrollTrigger);\ngsapWithCSS.registerPlugin(ScrollToPlugin);\nconst common_controller = new ScrollMagic.Controller();\nconst common_vw = window.outerWidth;\nconst vh = window.outerHeight;\nlet activeUrl;\nconst setRealViewHeight = () => {\n const windowHeight = document.documentElement.clientHeight;\n document.documentElement.style.setProperty('--vh', `${windowHeight}px`);\n};\nconst parallaxEffect = () => {\n if (document.querySelector('[data-speed]')) {\n const verticalElements = document.querySelectorAll('[data-speed]');\n verticalElements.forEach(el => {\n if (!el.classList.contains('sectionCredits_background')) {\n let direction, moltiplicator;\n if (el.classList.contains('sectionVisual-ship')) {\n direction = 'x';\n moltiplicator = 1;\n } else {\n direction = 'y';\n moltiplicator = -1;\n }\n let speed;\n if (common_vw < 456 && el.getAttribute(\"data-speed-mobile\")) {\n speed = el.getAttribute(\"data-speed-mobile\");\n } else {\n speed = el.getAttribute(\"data-speed\");\n }\n gsapWithCSS.to(el, {\n [direction]: moltiplicator * parseFloat(speed) * (el.offsetHeight / 3),\n ease: \"none\",\n scrollTrigger: {\n trigger: el.closest('section'),\n start: 30,\n end: \"bottom top\",\n invalidateOnRefresh: true,\n scrub: true\n }\n });\n } else {\n const tween = gsapWithCSS.to(el, {\n y: '+=300'\n });\n new ScrollMagic.Scene({\n triggerElement: document.querySelector('.sectionMap'),\n triggerHook: 0.9,\n duration: vh * 2\n }).setTween(tween).addTo(common_controller);\n }\n });\n }\n};\nconst horizontalParallaxEffect = () => {\n if (document.querySelector('.HorizontalParallax')) {\n const horizontalElements = document.querySelectorAll('.HorizontalParallax');\n horizontalElements.forEach(horizontalElement => {\n let xValue, spanXValuel;\n if (horizontalElement.closest('section').classList.contains('sectionSocial')) {\n xValue = \"-20%\";\n if (common_vw >= 1025) {\n spanXValuel = \"-50%\";\n } else {\n spanXValuel = \"0%\";\n }\n } else {\n if (common_vw >= 1025) {\n xValue = '-50%';\n spanXValuel = \"0\";\n } else {\n xValue = '0';\n spanXValuel = \"-20%\";\n }\n }\n gsapWithCSS.to(horizontalElement, {\n x: xValue,\n ease: \"none\",\n scrollTrigger: {\n trigger: horizontalElement,\n start: 'top bottom',\n end: \"bottom top\",\n invalidateOnRefresh: true,\n scrub: true\n }\n });\n if (horizontalElement.classList.contains('multiline')) {\n if (common_vw < 456 || horizontalElement.classList.contains('sectionSocial_title')) {\n const lastRow = horizontalElement.querySelector('span:last-of-type');\n gsapWithCSS.to(lastRow, {\n x: spanXValuel,\n ease: \"none\",\n scrollTrigger: {\n trigger: horizontalElement,\n start: 'top bottom',\n end: \"bottom top\",\n invalidateOnRefresh: true,\n scrub: true\n }\n });\n }\n }\n });\n }\n};\nconst goToNextSection = () => {\n const triggerElements = document.querySelectorAll('.ScrollTo');\n if (triggerElements) {\n triggerElements.forEach(trigger => {\n trigger.addEventListener('click', e => {\n e.preventDefault();\n const nextSection = trigger.closest('section').nextElementSibling;\n // let offset;\n // if (vw >= 769) {\n // offset = 100;\n // } else {\n // offset = 64;\n // }\n\n gsapWithCSS.to(window, {\n scrollTo: {\n y: nextSection,\n // offsetY: offset,\n autoKill: false\n },\n duration: 1,\n ease: Power2.easeInOut\n });\n });\n });\n }\n};\nconst scrollTo = anchor => {\n // let offset;\n // if (vw >= 1025) {\n // offset = 100;\n // } else {\n // offset = 64;\n // }\n gsapWithCSS.to(window, {\n scrollTo: {\n y: anchor,\n // offsetY: offset,\n autoKill: false\n },\n duration: 1,\n ease: Power2.easeInOut\n });\n};\nconst revealOnViewport = () => {\n const sectionsToReveal = document.querySelectorAll('.ToReveal');\n if (sectionsToReveal) {\n sectionsToReveal.forEach(reveal => {\n if (reveal.classList.contains('sectionChapter_row')) {\n setTimeout(() => {\n reveal.classList.add('visible');\n }, 600);\n } else {\n new ScrollMagic.Scene({\n triggerElement: reveal,\n duration: vh + reveal.clientHeight,\n triggerHook: .8,\n reverse: true\n }).setClassToggle(reveal, \"visible\").addTo(common_controller);\n }\n });\n }\n};\nconst blockDocumentScroll = () => {\n document.querySelector('body').classList.add('blockScroll');\n document.querySelector('body').addEventListener('touchmove', e => {\n if (document.querySelector('body').classList.contains('blockScroll')) {\n e.preventDefault();\n }\n });\n};\nconst enableDocumentScroll = () => {\n document.querySelector('body').classList.remove('blockScroll');\n};\nconst closeChapterModal = () => {\n const chapterModal = document.querySelector('.chapterModal');\n const navbar = document.querySelector('.navbar');\n gsapWithCSS.to(chapterModal, {\n top: '100vw',\n opacity: 0,\n scale: .9,\n duration: 1,\n ease: Expo.easeInOut\n });\n window.history.pushState(null, '', activeUrl);\n document.title = 'Pirelli | Allagrande';\n document.querySelector('.main').removeAttribute('style');\n navbar.querySelector('.active').classList.remove('active');\n hideNavbar();\n enableDocumentScroll();\n};\nconst backFunction = () => {\n if (document.querySelector('.arrow-link.reverse')) {\n const back = document.querySelector('.arrow-link.reverse');\n back.addEventListener('click', e => {\n e.preventDefault();\n if (document.querySelector('.chapterModal')) {\n closeChapterModal();\n } else {\n history.back();\n }\n });\n }\n};\nconst sessionStorageCheck = () => {\n if (sessionStorage.anchor) {\n scrollTo(sessionStorage.anchor);\n sessionStorage.removeItem('anchor');\n }\n};\nwindow.addEventListener('DOMContentLoaded', () => {\n let lang;\n if (window.location.pathname.indexOf('it-it') > -1) {\n lang = 'it';\n activeUrl = '/global/it-it/allagrande-pirelli/';\n } else if (window.location.pathname.indexOf('en-ww') > -1) {\n lang = 'en';\n activeUrl = '/global/en-ww/allagrande-pirelli/';\n }\n setRealViewHeight();\n parallaxEffect();\n horizontalParallaxEffect();\n goToNextSection();\n revealOnViewport();\n backFunction();\n sessionStorageCheck();\n});\nwindow.addEventListener('popstate', e => {\n const navbar = document.querySelector('.navbar');\n if (document.querySelector('.chapterModal .sectionChapter')) {\n revealOnViewport();\n backFunction();\n setTimeout(() => {\n playerInit();\n }, 1000);\n const mapId = document.querySelector('.sectionMap').getAttribute('id');\n navbar.querySelector(`[href=\"#${mapId}\"]`).classList.add('active');\n }\n window.addEventListener('onbeforeunload', () => {\n closeChapterModal();\n });\n});\nwindow.addEventListener('resize', () => {\n setRealViewHeight();\n});\n// document.addEventListener('lazybeforeunveil', function(e){\n// horizontalParallaxEffect();\n// });\n\n\n;// CONCATENATED MODULE: ./src/components/visual/visual.js\n//Vendor scripts\n\nlet visual_vw = window.outerWidth;\nlet visual;\nconst textFadeIn = () => {\n const transtitionTiming = 1;\n let visualTimeline = gsapWithCSS.timeline();\n let visualCanvas;\n if (visual_vw < 456) {\n visualCanvas = document.querySelector('.sectionVisual-canvas--mobile');\n } else {\n visualCanvas = document.querySelector('.sectionVisual-canvas--desktop');\n }\n const visualShip = document.querySelector('.sectionVisual-ship');\n const visualEngHeader = visual.querySelector('.sectionVisual-engHeader');\n const visualSubtitle = visual.querySelector('.sectionVisual-subtitle');\n const visualHeading = visual.querySelector('.sectionVisual-heading');\n const visualHeadingSpan = visualHeading.querySelectorAll('span');\n const visualscrollTrigger = visual.querySelector('.sectionVisual-scrollTrigger');\n visualTimeline.to(visualCanvas, {\n opacity: 1,\n duration: transtitionTiming * 2\n }, 0).to(visualShip, {\n opacity: 1,\n duration: transtitionTiming * 2\n }, 0).to(visualEngHeader, {\n opacity: 1,\n duration: transtitionTiming * 2\n }, transtitionTiming * 2).to(visualSubtitle, {\n opacity: 1,\n duration: transtitionTiming * 2\n }, transtitionTiming * 2);\n visualHeadingSpan.forEach((visualSpan, i) => {\n visualTimeline.to(visualSpan, {\n opacity: 1,\n y: 0,\n duration: transtitionTiming\n }, transtitionTiming / 2 * i);\n });\n visualTimeline.to(visualscrollTrigger, {\n opacity: 1,\n duration: transtitionTiming * 2\n }, transtitionTiming * 2);\n visualTimeline.play();\n};\nconst aquarelleInit = () => {\n let image;\n if (visual_vw < 456) {\n image = document.querySelector('.sectionVisual-canvas--mobile');\n } else {\n image = document.querySelector('.sectionVisual-canvas--desktop');\n }\n const imageMask = visual.querySelector('.sectionVisual-mask').getAttribute('src');\n let direction = 'forward';\n let aquarelle = new Aquarelle(image, imageMask, {\n autoplay: true,\n fromAmplitude: 10,\n toAmplitude: 10,\n fromOffset: 100,\n fromFrequency: 4,\n toFrequency: 5\n });\n aquarelle.addEventListener('created', function () {\n var canvas = this.getCanvas();\n if (visual_vw < 456) {\n canvas.classList.add('sectionVisual-canvas--mobile');\n } else {\n canvas.classList.add('sectionVisual-canvas--desktop');\n }\n canvas.removeAttribute('style');\n image.parentNode.insertBefore(canvas, image.nextSibling);\n image.parentNode.removeChild(image);\n });\n\n //Simluate loop\n aquarelle.addEventListener('stopped', function () {\n if (direction === 'forward') {\n aquarelle.reverse();\n aquarelle.play();\n direction = 'backward';\n } else {\n aquarelle.reverse();\n aquarelle.play();\n direction = 'forward';\n }\n });\n aquarelle.addEventListener('created', () => {\n textFadeIn();\n });\n};\nwindow.addEventListener('DOMContentLoaded', () => {\n if (document.querySelector('.sectionVisual')) {\n visual = document.querySelector('.sectionVisual');\n textFadeIn();\n aquarelleInit();\n }\n});\nwindow.addEventListener('resize', () => {\n if (document.querySelector('.sectionVisual')) {\n visual_vw = window.outerWidth;\n aquarelleInit();\n }\n});\n;// CONCATENATED MODULE: ./src/components/alternate/alternate.js\n//Vendor scripts\n\n\nconst alternate_YTPlayer = __webpack_require__(474);\nconst alternate_controller = new ScrollMagic.Controller();\nlet alternate_vw = window.outerWidth;\nlet alternate_vh = window.outerHeight;\nconst bedgeCustomReveal = alternateSection => {\n const bedge = alternateSection.querySelector('.sectionAlternate_badge');\n if (bedge) {\n new ScrollMagic.Scene({\n triggerElement: bedge,\n triggerHook: .9,\n duration: alternate_vh - bedge.clientHeight,\n reverse: true\n }).setClassToggle(bedge, \"visible\").addTo(alternate_controller);\n }\n};\nconst playVideo = alternateSection => {\n const alternateSectionWrapper = alternateSection.querySelector('.sectionAlternate_wrapper');\n const videoPlayer = alternateSection.querySelector('.videoPlayer');\n if (videoPlayer) {\n const playButton = alternateSection.querySelector('.playButton');\n const videoTrigger = alternateSection.querySelector('.videoTrigger');\n const closeButton = alternateSection.querySelector('.closeButton');\n const videoId = videoPlayer.getAttribute('data-url-id');\n const alternateSectionWrapperImage = alternateSectionWrapper.querySelector('.sectionAlternate_wrapper-image');\n const alternateSectionWrapperImageBg = alternateSectionWrapperImage.querySelector('img');\n const alternateSectionWrapperText = alternateSectionWrapper.querySelector('.sectionAlternate_wrapper-text');\n const player = new alternate_YTPlayer(videoPlayer, {\n height: '100%',\n width: '100%'\n });\n player.load(videoId);\n player.setVolume(30);\n let videoRevealTimeline = '';\n const timelineBuild = type => {\n if (type === 'resize') {\n videoRevealTimeline = '';\n }\n if (videoRevealTimeline === '') {\n const animationTime = 1;\n const alternateSectionWrapperWidth = alternateSectionWrapper.clientWidth;\n const alternateSectionWrapperHeight = alternateSectionWrapper.clientHeight;\n const alternateSectionWrapperImageWidth = alternateSectionWrapperImage.clientWidth;\n const alternateSectionWrapperImageHeight = alternateSectionWrapperImage.clientHeight;\n const alternateSectionWrapperTextHeight = alternateSectionWrapperText.clientHeight;\n const videoWrapper = alternateSection.querySelector('.videoPlayer');\n videoRevealTimeline = gsapWithCSS.timeline({\n paused: true\n });\n if (vw >= 1025) {\n videoRevealTimeline.set(alternateSectionWrapperImage, {\n width: alternateSectionWrapperImageWidth,\n flex: 'none'\n }).set(videoWrapper, {\n width: alternateSectionWrapperImageWidth - 32,\n height: alternateSectionWrapperImageHeight\n }, 0).to(playButton, {\n opacity: 0,\n visibility: 'hidden',\n duration: animationTime / 2,\n ease: Circ.easeInOut\n }, 0).to(alternateSectionWrapperText, {\n x: '100%',\n height: alternateSectionWrapperTextHeight,\n opacity: 0,\n duration: animationTime,\n ease: Circ.easeInOut\n }, 0).to(closeButton, {\n opacity: 1,\n visibility: 'visible',\n duration: animationTime / 2,\n ease: Circ.easeInOut\n }, animationTime / 2).to(alternateSectionWrapperImage, {\n width: alternateSectionWrapperWidth,\n height: alternateSectionWrapperImageHeight,\n padding: 0,\n flex: 'none',\n duration: animationTime,\n ease: Circ.easeInOut\n }, animationTime / 2).to(alternateSectionWrapperImageBg, {\n filter: \"blur(3px)\",\n duration: animationTime,\n ease: Circ.easeInOut\n }, animationTime / 2).to(videoWrapper, {\n opacity: 1,\n visibility: 'visible',\n duration: animationTime,\n ease: Circ.easeInOut\n }, animationTime / 2);\n } else {\n videoRevealTimeline.set(alternateSectionWrapperImage, {\n width: alternateSectionWrapperImageWidth,\n flex: 'none'\n }).set(videoWrapper, {\n width: alternateSectionWrapperImageWidth,\n height: alternateSectionWrapperImageHeight\n }, 0).to(playButton, {\n opacity: 0,\n visibility: 'hidden',\n duration: animationTime / 2,\n ease: Circ.easeInOut\n }, 0).to(closeButton, {\n opacity: 1,\n visibility: 'visible',\n duration: animationTime / 2,\n ease: Circ.easeInOut\n }, 0).to(alternateSectionWrapperText, {\n y: '-100%',\n opacity: 0,\n duration: animationTime,\n ease: Circ.easeInOut\n }, 0).to(alternateSectionWrapperImage, {\n padding: 0,\n height: alternateSectionWrapperHeight,\n flex: 'none',\n duration: animationTime,\n ease: Circ.easeInOut\n }, 0).to(alternateSectionWrapperImageBg, {\n filter: \"blur(3px)\",\n height: alternateSectionWrapperHeight,\n width: 'auto',\n duration: animationTime,\n ease: Circ.easeInOut\n }, 0).to(videoWrapper, {\n opacity: 1,\n visibility: 'visible',\n duration: animationTime,\n ease: Circ.easeInOut\n }, 0);\n }\n }\n };\n player.on('unstarted', () => {\n timelineBuild();\n });\n playButton.addEventListener('click', () => {\n videoRevealTimeline.play();\n player.play();\n });\n closeButton.addEventListener('click', () => {\n videoRevealTimeline.reverse();\n player.pause();\n });\n videoTrigger.addEventListener('click', e => {\n e.preventDefault();\n playButton.click();\n });\n player.on('ended', () => {\n videoRevealTimeline.reverse();\n videoRevealTimeline = '';\n player.pause();\n player.seek(0);\n });\n const vw = window.innerWidth;\n window.addEventListener('resize', () => {\n if (window.innerWidth !== vw) {\n alternateSectionWrapperImage.removeAttribute('style');\n alternateSectionWrapperImageBg.removeAttribute('style');\n alternateSectionWrapperText.removeAttribute('style');\n playButton.removeAttribute('style');\n closeButton.removeAttribute('style');\n alternateSection.querySelector('.videoPlayer').removeAttribute('style');\n timelineBuild('resize');\n }\n });\n }\n};\ndocument.addEventListener('DOMContentLoaded', () => {\n if (document.querySelectorAll('.sectionAlternate')) {\n const alternateSections = document.querySelectorAll('.sectionAlternate');\n alternateSections.forEach(alternateSection => {\n bedgeCustomReveal(alternateSection);\n playVideo(alternateSection);\n });\n }\n});\nwindow.addEventListener('resize', () => {\n alternate_vw = window.outerWidth;\n});\n/* harmony default export */ const alternate = ((/* unused pure expression or super */ null && (playVideo)));\n;// CONCATENATED MODULE: ./src/components/map/map.js\n\n\n\ngsapWithCSS.registerPlugin(ScrollToPlugin);\nlet map;\nconst chaptersClick = () => {\n const mapWrapper = map.querySelector('.sectionMap_background-wrapper');\n const mapWrapperChapters = mapWrapper.querySelectorAll('.sectionMap_background-wrapper-chapter');\n mapWrapperChapters.forEach(chapter => {\n chapter.addEventListener('click', e => {\n e.preventDefault();\n let chapterName;\n if (window.location.host != \"localhost:3000\") {\n chapterName = `${chapter.getAttribute('data-chapter')}`;\n } else {\n chapterName = `${chapter.getAttribute('data-chapter')}.html`;\n }\n chapterOpenHandler(chapterName);\n });\n });\n};\n\n// const mapBuild = (data) => {\n// const mapWrapper = map.querySelector('.sectionMap_background-wrapper');\n\n// let mapChapterMarkup = '';\n// data.map.chapters.forEach((chapter, i) => {\n// mapChapterMarkup += `\n//
\n//

${chapter.title}

\n//
\n// \n// \n// \n//
\n//
\n// \n//
\n//
\n// `;\n// });\n// mapWrapper.innerHTML = mapChapterMarkup;\n// chaptersClick();\n// }\n\nwindow.addEventListener('DOMContentLoaded', () => {\n if (document.querySelector('.sectionMap')) {\n map = document.querySelector('.sectionMap');\n chaptersClick();\n }\n});\n\n// export default mapBuild;\n;// CONCATENATED MODULE: ./node_modules/ssr-window/ssr-window.esm.js\n/**\n * SSR Window 4.0.2\n * Better handling for window object in SSR environment\n * https://github.com/nolimits4web/ssr-window\n *\n * Copyright 2021, Vladimir Kharlampidi\n *\n * Licensed under MIT\n *\n * Released on: December 13, 2021\n */\n/* eslint-disable no-param-reassign */\nfunction ssr_window_esm_isObject(obj) {\n return (obj !== null &&\n typeof obj === 'object' &&\n 'constructor' in obj &&\n obj.constructor === Object);\n}\nfunction extend(target = {}, src = {}) {\n Object.keys(src).forEach((key) => {\n if (typeof target[key] === 'undefined')\n target[key] = src[key];\n else if (ssr_window_esm_isObject(src[key]) &&\n ssr_window_esm_isObject(target[key]) &&\n Object.keys(src[key]).length > 0) {\n extend(target[key], src[key]);\n }\n });\n}\n\nconst ssrDocument = {\n body: {},\n addEventListener() { },\n removeEventListener() { },\n activeElement: {\n blur() { },\n nodeName: '',\n },\n querySelector() {\n return null;\n },\n querySelectorAll() {\n return [];\n },\n getElementById() {\n return null;\n },\n createEvent() {\n return {\n initEvent() { },\n };\n },\n createElement() {\n return {\n children: [],\n childNodes: [],\n style: {},\n setAttribute() { },\n getElementsByTagName() {\n return [];\n },\n };\n },\n createElementNS() {\n return {};\n },\n importNode() {\n return null;\n },\n location: {\n hash: '',\n host: '',\n hostname: '',\n href: '',\n origin: '',\n pathname: '',\n protocol: '',\n search: '',\n },\n};\nfunction ssr_window_esm_getDocument() {\n const doc = typeof document !== 'undefined' ? document : {};\n extend(doc, ssrDocument);\n return doc;\n}\n\nconst ssrWindow = {\n document: ssrDocument,\n navigator: {\n userAgent: '',\n },\n location: {\n hash: '',\n host: '',\n hostname: '',\n href: '',\n origin: '',\n pathname: '',\n protocol: '',\n search: '',\n },\n history: {\n replaceState() { },\n pushState() { },\n go() { },\n back() { },\n },\n CustomEvent: function CustomEvent() {\n return this;\n },\n addEventListener() { },\n removeEventListener() { },\n getComputedStyle() {\n return {\n getPropertyValue() {\n return '';\n },\n };\n },\n Image() { },\n Date() { },\n screen: {},\n setTimeout() { },\n clearTimeout() { },\n matchMedia() {\n return {};\n },\n requestAnimationFrame(callback) {\n if (typeof setTimeout === 'undefined') {\n callback();\n return null;\n }\n return setTimeout(callback, 0);\n },\n cancelAnimationFrame(id) {\n if (typeof setTimeout === 'undefined') {\n return;\n }\n clearTimeout(id);\n },\n};\nfunction ssr_window_esm_getWindow() {\n const win = typeof window !== 'undefined' ? window : {};\n extend(win, ssrWindow);\n return win;\n}\n\n\n\n;// CONCATENATED MODULE: ./node_modules/dom7/dom7.esm.js\n/**\n * Dom7 4.0.6\n * Minimalistic JavaScript library for DOM manipulation, with a jQuery-compatible API\n * https://framework7.io/docs/dom7.html\n *\n * Copyright 2023, Vladimir Kharlampidi\n *\n * Licensed under MIT\n *\n * Released on: February 2, 2023\n */\n\n\n/* eslint-disable no-proto */\nfunction makeReactive(obj) {\n const proto = obj.__proto__;\n Object.defineProperty(obj, '__proto__', {\n get() {\n return proto;\n },\n\n set(value) {\n proto.__proto__ = value;\n }\n\n });\n}\n\nclass Dom7 extends Array {\n constructor(items) {\n if (typeof items === 'number') {\n super(items);\n } else {\n super(...(items || []));\n makeReactive(this);\n }\n }\n\n}\n\nfunction arrayFlat(arr = []) {\n const res = [];\n arr.forEach(el => {\n if (Array.isArray(el)) {\n res.push(...arrayFlat(el));\n } else {\n res.push(el);\n }\n });\n return res;\n}\nfunction arrayFilter(arr, callback) {\n return Array.prototype.filter.call(arr, callback);\n}\nfunction arrayUnique(arr) {\n const uniqueArray = [];\n\n for (let i = 0; i < arr.length; i += 1) {\n if (uniqueArray.indexOf(arr[i]) === -1) uniqueArray.push(arr[i]);\n }\n\n return uniqueArray;\n}\nfunction toCamelCase(string) {\n return string.toLowerCase().replace(/-(.)/g, (match, group) => group.toUpperCase());\n}\n\n// eslint-disable-next-line\n\nfunction qsa(selector, context) {\n if (typeof selector !== 'string') {\n return [selector];\n }\n\n const a = [];\n const res = context.querySelectorAll(selector);\n\n for (let i = 0; i < res.length; i += 1) {\n a.push(res[i]);\n }\n\n return a;\n}\n\nfunction dom7_esm_$(selector, context) {\n const window = ssr_window_esm_getWindow();\n const document = ssr_window_esm_getDocument();\n let arr = [];\n\n if (!context && selector instanceof Dom7) {\n return selector;\n }\n\n if (!selector) {\n return new Dom7(arr);\n }\n\n if (typeof selector === 'string') {\n const html = selector.trim();\n\n if (html.indexOf('<') >= 0 && html.indexOf('>') >= 0) {\n let toCreate = 'div';\n if (html.indexOf(' c.split(' ')));\n this.forEach(el => {\n el.classList.add(...classNames);\n });\n return this;\n}\n\nfunction removeClass(...classes) {\n const classNames = arrayFlat(classes.map(c => c.split(' ')));\n this.forEach(el => {\n el.classList.remove(...classNames);\n });\n return this;\n}\n\nfunction toggleClass(...classes) {\n const classNames = arrayFlat(classes.map(c => c.split(' ')));\n this.forEach(el => {\n classNames.forEach(className => {\n el.classList.toggle(className);\n });\n });\n}\n\nfunction hasClass(...classes) {\n const classNames = arrayFlat(classes.map(c => c.split(' ')));\n return arrayFilter(this, el => {\n return classNames.filter(className => el.classList.contains(className)).length > 0;\n }).length > 0;\n}\n\nfunction attr(attrs, value) {\n if (arguments.length === 1 && typeof attrs === 'string') {\n // Get attr\n if (this[0]) return this[0].getAttribute(attrs);\n return undefined;\n } // Set attrs\n\n\n for (let i = 0; i < this.length; i += 1) {\n if (arguments.length === 2) {\n // String\n this[i].setAttribute(attrs, value);\n } else {\n // Object\n for (const attrName in attrs) {\n this[i][attrName] = attrs[attrName];\n this[i].setAttribute(attrName, attrs[attrName]);\n }\n }\n }\n\n return this;\n}\n\nfunction removeAttr(attr) {\n for (let i = 0; i < this.length; i += 1) {\n this[i].removeAttribute(attr);\n }\n\n return this;\n}\n\nfunction prop(props, value) {\n if (arguments.length === 1 && typeof props === 'string') {\n // Get prop\n if (this[0]) return this[0][props];\n } else {\n // Set props\n for (let i = 0; i < this.length; i += 1) {\n if (arguments.length === 2) {\n // String\n this[i][props] = value;\n } else {\n // Object\n for (const propName in props) {\n this[i][propName] = props[propName];\n }\n }\n }\n\n return this;\n }\n\n return this;\n}\n\nfunction data(key, value) {\n let el;\n\n if (typeof value === 'undefined') {\n el = this[0];\n if (!el) return undefined; // Get value\n\n if (el.dom7ElementDataStorage && key in el.dom7ElementDataStorage) {\n return el.dom7ElementDataStorage[key];\n }\n\n const dataKey = el.getAttribute(`data-${key}`);\n\n if (dataKey) {\n return dataKey;\n }\n\n return undefined;\n } // Set value\n\n\n for (let i = 0; i < this.length; i += 1) {\n el = this[i];\n if (!el.dom7ElementDataStorage) el.dom7ElementDataStorage = {};\n el.dom7ElementDataStorage[key] = value;\n }\n\n return this;\n}\n\nfunction removeData(key) {\n for (let i = 0; i < this.length; i += 1) {\n const el = this[i];\n\n if (el.dom7ElementDataStorage && el.dom7ElementDataStorage[key]) {\n el.dom7ElementDataStorage[key] = null;\n delete el.dom7ElementDataStorage[key];\n }\n }\n}\n\nfunction dataset() {\n const el = this[0];\n if (!el) return undefined;\n const dataset = {}; // eslint-disable-line\n\n if (el.dataset) {\n for (const dataKey in el.dataset) {\n dataset[dataKey] = el.dataset[dataKey];\n }\n } else {\n for (let i = 0; i < el.attributes.length; i += 1) {\n const attr = el.attributes[i];\n\n if (attr.name.indexOf('data-') >= 0) {\n dataset[toCamelCase(attr.name.split('data-')[1])] = attr.value;\n }\n }\n }\n\n for (const key in dataset) {\n if (dataset[key] === 'false') dataset[key] = false;else if (dataset[key] === 'true') dataset[key] = true;else if (parseFloat(dataset[key]) === dataset[key] * 1) dataset[key] *= 1;\n }\n\n return dataset;\n}\n\nfunction val(value) {\n if (typeof value === 'undefined') {\n // get value\n const el = this[0];\n if (!el) return undefined;\n\n if (el.multiple && el.nodeName.toLowerCase() === 'select') {\n const values = [];\n\n for (let i = 0; i < el.selectedOptions.length; i += 1) {\n values.push(el.selectedOptions[i].value);\n }\n\n return values;\n }\n\n return el.value;\n } // set value\n\n\n for (let i = 0; i < this.length; i += 1) {\n const el = this[i];\n\n if (Array.isArray(value) && el.multiple && el.nodeName.toLowerCase() === 'select') {\n for (let j = 0; j < el.options.length; j += 1) {\n el.options[j].selected = value.indexOf(el.options[j].value) >= 0;\n }\n } else {\n el.value = value;\n }\n }\n\n return this;\n}\n\nfunction value(value) {\n return this.val(value);\n}\n\nfunction transform(transform) {\n for (let i = 0; i < this.length; i += 1) {\n this[i].style.transform = transform;\n }\n\n return this;\n}\n\nfunction transition(duration) {\n for (let i = 0; i < this.length; i += 1) {\n this[i].style.transitionDuration = typeof duration !== 'string' ? `${duration}ms` : duration;\n }\n\n return this;\n}\n\nfunction on(...args) {\n let [eventType, targetSelector, listener, capture] = args;\n\n if (typeof args[1] === 'function') {\n [eventType, listener, capture] = args;\n targetSelector = undefined;\n }\n\n if (!capture) capture = false;\n\n function handleLiveEvent(e) {\n const target = e.target;\n if (!target) return;\n const eventData = e.target.dom7EventData || [];\n\n if (eventData.indexOf(e) < 0) {\n eventData.unshift(e);\n }\n\n if (dom7_esm_$(target).is(targetSelector)) listener.apply(target, eventData);else {\n const parents = dom7_esm_$(target).parents(); // eslint-disable-line\n\n for (let k = 0; k < parents.length; k += 1) {\n if (dom7_esm_$(parents[k]).is(targetSelector)) listener.apply(parents[k], eventData);\n }\n }\n }\n\n function handleEvent(e) {\n const eventData = e && e.target ? e.target.dom7EventData || [] : [];\n\n if (eventData.indexOf(e) < 0) {\n eventData.unshift(e);\n }\n\n listener.apply(this, eventData);\n }\n\n const events = eventType.split(' ');\n let j;\n\n for (let i = 0; i < this.length; i += 1) {\n const el = this[i];\n\n if (!targetSelector) {\n for (j = 0; j < events.length; j += 1) {\n const event = events[j];\n if (!el.dom7Listeners) el.dom7Listeners = {};\n if (!el.dom7Listeners[event]) el.dom7Listeners[event] = [];\n el.dom7Listeners[event].push({\n listener,\n proxyListener: handleEvent\n });\n el.addEventListener(event, handleEvent, capture);\n }\n } else {\n // Live events\n for (j = 0; j < events.length; j += 1) {\n const event = events[j];\n if (!el.dom7LiveListeners) el.dom7LiveListeners = {};\n if (!el.dom7LiveListeners[event]) el.dom7LiveListeners[event] = [];\n el.dom7LiveListeners[event].push({\n listener,\n proxyListener: handleLiveEvent\n });\n el.addEventListener(event, handleLiveEvent, capture);\n }\n }\n }\n\n return this;\n}\n\nfunction off(...args) {\n let [eventType, targetSelector, listener, capture] = args;\n\n if (typeof args[1] === 'function') {\n [eventType, listener, capture] = args;\n targetSelector = undefined;\n }\n\n if (!capture) capture = false;\n const events = eventType.split(' ');\n\n for (let i = 0; i < events.length; i += 1) {\n const event = events[i];\n\n for (let j = 0; j < this.length; j += 1) {\n const el = this[j];\n let handlers;\n\n if (!targetSelector && el.dom7Listeners) {\n handlers = el.dom7Listeners[event];\n } else if (targetSelector && el.dom7LiveListeners) {\n handlers = el.dom7LiveListeners[event];\n }\n\n if (handlers && handlers.length) {\n for (let k = handlers.length - 1; k >= 0; k -= 1) {\n const handler = handlers[k];\n\n if (listener && handler.listener === listener) {\n el.removeEventListener(event, handler.proxyListener, capture);\n handlers.splice(k, 1);\n } else if (listener && handler.listener && handler.listener.dom7proxy && handler.listener.dom7proxy === listener) {\n el.removeEventListener(event, handler.proxyListener, capture);\n handlers.splice(k, 1);\n } else if (!listener) {\n el.removeEventListener(event, handler.proxyListener, capture);\n handlers.splice(k, 1);\n }\n }\n }\n }\n }\n\n return this;\n}\n\nfunction once(...args) {\n const dom = this;\n let [eventName, targetSelector, listener, capture] = args;\n\n if (typeof args[1] === 'function') {\n [eventName, listener, capture] = args;\n targetSelector = undefined;\n }\n\n function onceHandler(...eventArgs) {\n listener.apply(this, eventArgs);\n dom.off(eventName, targetSelector, onceHandler, capture);\n\n if (onceHandler.dom7proxy) {\n delete onceHandler.dom7proxy;\n }\n }\n\n onceHandler.dom7proxy = listener;\n return dom.on(eventName, targetSelector, onceHandler, capture);\n}\n\nfunction trigger(...args) {\n const window = ssr_window_esm_getWindow();\n const events = args[0].split(' ');\n const eventData = args[1];\n\n for (let i = 0; i < events.length; i += 1) {\n const event = events[i];\n\n for (let j = 0; j < this.length; j += 1) {\n const el = this[j];\n\n if (window.CustomEvent) {\n const evt = new window.CustomEvent(event, {\n detail: eventData,\n bubbles: true,\n cancelable: true\n });\n el.dom7EventData = args.filter((data, dataIndex) => dataIndex > 0);\n el.dispatchEvent(evt);\n el.dom7EventData = [];\n delete el.dom7EventData;\n }\n }\n }\n\n return this;\n}\n\nfunction transitionStart(callback) {\n const dom = this;\n\n function fireCallBack(e) {\n if (e.target !== this) return;\n callback.call(this, e);\n dom.off('transitionstart', fireCallBack);\n }\n\n if (callback) {\n dom.on('transitionstart', fireCallBack);\n }\n\n return this;\n}\n\nfunction transitionEnd(callback) {\n const dom = this;\n\n function fireCallBack(e) {\n if (e.target !== this) return;\n callback.call(this, e);\n dom.off('transitionend', fireCallBack);\n }\n\n if (callback) {\n dom.on('transitionend', fireCallBack);\n }\n\n return this;\n}\n\nfunction animationEnd(callback) {\n const dom = this;\n\n function fireCallBack(e) {\n if (e.target !== this) return;\n callback.call(this, e);\n dom.off('animationend', fireCallBack);\n }\n\n if (callback) {\n dom.on('animationend', fireCallBack);\n }\n\n return this;\n}\n\nfunction width() {\n const window = getWindow();\n\n if (this[0] === window) {\n return window.innerWidth;\n }\n\n if (this.length > 0) {\n return parseFloat(this.css('width'));\n }\n\n return null;\n}\n\nfunction dom7_esm_outerWidth(includeMargins) {\n if (this.length > 0) {\n if (includeMargins) {\n const styles = this.styles();\n return this[0].offsetWidth + parseFloat(styles.getPropertyValue('margin-right')) + parseFloat(styles.getPropertyValue('margin-left'));\n }\n\n return this[0].offsetWidth;\n }\n\n return null;\n}\n\nfunction height() {\n const window = getWindow();\n\n if (this[0] === window) {\n return window.innerHeight;\n }\n\n if (this.length > 0) {\n return parseFloat(this.css('height'));\n }\n\n return null;\n}\n\nfunction dom7_esm_outerHeight(includeMargins) {\n if (this.length > 0) {\n if (includeMargins) {\n const styles = this.styles();\n return this[0].offsetHeight + parseFloat(styles.getPropertyValue('margin-top')) + parseFloat(styles.getPropertyValue('margin-bottom'));\n }\n\n return this[0].offsetHeight;\n }\n\n return null;\n}\n\nfunction offset() {\n if (this.length > 0) {\n const window = ssr_window_esm_getWindow();\n const document = ssr_window_esm_getDocument();\n const el = this[0];\n const box = el.getBoundingClientRect();\n const body = document.body;\n const clientTop = el.clientTop || body.clientTop || 0;\n const clientLeft = el.clientLeft || body.clientLeft || 0;\n const scrollTop = el === window ? window.scrollY : el.scrollTop;\n const scrollLeft = el === window ? window.scrollX : el.scrollLeft;\n return {\n top: box.top + scrollTop - clientTop,\n left: box.left + scrollLeft - clientLeft\n };\n }\n\n return null;\n}\n\nfunction hide() {\n for (let i = 0; i < this.length; i += 1) {\n this[i].style.display = 'none';\n }\n\n return this;\n}\n\nfunction show() {\n const window = getWindow();\n\n for (let i = 0; i < this.length; i += 1) {\n const el = this[i];\n\n if (el.style.display === 'none') {\n el.style.display = '';\n }\n\n if (window.getComputedStyle(el, null).getPropertyValue('display') === 'none') {\n // Still not visible\n el.style.display = 'block';\n }\n }\n\n return this;\n}\n\nfunction styles() {\n const window = ssr_window_esm_getWindow();\n if (this[0]) return window.getComputedStyle(this[0], null);\n return {};\n}\n\nfunction css(props, value) {\n const window = ssr_window_esm_getWindow();\n let i;\n\n if (arguments.length === 1) {\n if (typeof props === 'string') {\n // .css('width')\n if (this[0]) return window.getComputedStyle(this[0], null).getPropertyValue(props);\n } else {\n // .css({ width: '100px' })\n for (i = 0; i < this.length; i += 1) {\n for (const prop in props) {\n this[i].style[prop] = props[prop];\n }\n }\n\n return this;\n }\n }\n\n if (arguments.length === 2 && typeof props === 'string') {\n // .css('width', '100px')\n for (i = 0; i < this.length; i += 1) {\n this[i].style[props] = value;\n }\n\n return this;\n }\n\n return this;\n}\n\nfunction each(callback) {\n if (!callback) return this;\n this.forEach((el, index) => {\n callback.apply(el, [el, index]);\n });\n return this;\n}\n\nfunction filter(callback) {\n const result = arrayFilter(this, callback);\n return dom7_esm_$(result);\n}\n\nfunction html(html) {\n if (typeof html === 'undefined') {\n return this[0] ? this[0].innerHTML : null;\n }\n\n for (let i = 0; i < this.length; i += 1) {\n this[i].innerHTML = html;\n }\n\n return this;\n}\n\nfunction dom7_esm_text(text) {\n if (typeof text === 'undefined') {\n return this[0] ? this[0].textContent.trim() : null;\n }\n\n for (let i = 0; i < this.length; i += 1) {\n this[i].textContent = text;\n }\n\n return this;\n}\n\nfunction is(selector) {\n const window = ssr_window_esm_getWindow();\n const document = ssr_window_esm_getDocument();\n const el = this[0];\n let compareWith;\n let i;\n if (!el || typeof selector === 'undefined') return false;\n\n if (typeof selector === 'string') {\n if (el.matches) return el.matches(selector);\n if (el.webkitMatchesSelector) return el.webkitMatchesSelector(selector);\n if (el.msMatchesSelector) return el.msMatchesSelector(selector);\n compareWith = dom7_esm_$(selector);\n\n for (i = 0; i < compareWith.length; i += 1) {\n if (compareWith[i] === el) return true;\n }\n\n return false;\n }\n\n if (selector === document) {\n return el === document;\n }\n\n if (selector === window) {\n return el === window;\n }\n\n if (selector.nodeType || selector instanceof Dom7) {\n compareWith = selector.nodeType ? [selector] : selector;\n\n for (i = 0; i < compareWith.length; i += 1) {\n if (compareWith[i] === el) return true;\n }\n\n return false;\n }\n\n return false;\n}\n\nfunction index() {\n let child = this[0];\n let i;\n\n if (child) {\n i = 0; // eslint-disable-next-line\n\n while ((child = child.previousSibling) !== null) {\n if (child.nodeType === 1) i += 1;\n }\n\n return i;\n }\n\n return undefined;\n}\n\nfunction eq(index) {\n if (typeof index === 'undefined') return this;\n const length = this.length;\n\n if (index > length - 1) {\n return dom7_esm_$([]);\n }\n\n if (index < 0) {\n const returnIndex = length + index;\n if (returnIndex < 0) return dom7_esm_$([]);\n return dom7_esm_$([this[returnIndex]]);\n }\n\n return dom7_esm_$([this[index]]);\n}\n\nfunction append(...els) {\n let newChild;\n const document = ssr_window_esm_getDocument();\n\n for (let k = 0; k < els.length; k += 1) {\n newChild = els[k];\n\n for (let i = 0; i < this.length; i += 1) {\n if (typeof newChild === 'string') {\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = newChild;\n\n while (tempDiv.firstChild) {\n this[i].appendChild(tempDiv.firstChild);\n }\n } else if (newChild instanceof Dom7) {\n for (let j = 0; j < newChild.length; j += 1) {\n this[i].appendChild(newChild[j]);\n }\n } else {\n this[i].appendChild(newChild);\n }\n }\n }\n\n return this;\n}\n\nfunction appendTo(parent) {\n dom7_esm_$(parent).append(this);\n return this;\n}\n\nfunction prepend(newChild) {\n const document = ssr_window_esm_getDocument();\n let i;\n let j;\n\n for (i = 0; i < this.length; i += 1) {\n if (typeof newChild === 'string') {\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = newChild;\n\n for (j = tempDiv.childNodes.length - 1; j >= 0; j -= 1) {\n this[i].insertBefore(tempDiv.childNodes[j], this[i].childNodes[0]);\n }\n } else if (newChild instanceof Dom7) {\n for (j = 0; j < newChild.length; j += 1) {\n this[i].insertBefore(newChild[j], this[i].childNodes[0]);\n }\n } else {\n this[i].insertBefore(newChild, this[i].childNodes[0]);\n }\n }\n\n return this;\n}\n\nfunction prependTo(parent) {\n dom7_esm_$(parent).prepend(this);\n return this;\n}\n\nfunction insertBefore(selector) {\n const before = dom7_esm_$(selector);\n\n for (let i = 0; i < this.length; i += 1) {\n if (before.length === 1) {\n before[0].parentNode.insertBefore(this[i], before[0]);\n } else if (before.length > 1) {\n for (let j = 0; j < before.length; j += 1) {\n before[j].parentNode.insertBefore(this[i].cloneNode(true), before[j]);\n }\n }\n }\n}\n\nfunction insertAfter(selector) {\n const after = dom7_esm_$(selector);\n\n for (let i = 0; i < this.length; i += 1) {\n if (after.length === 1) {\n after[0].parentNode.insertBefore(this[i], after[0].nextSibling);\n } else if (after.length > 1) {\n for (let j = 0; j < after.length; j += 1) {\n after[j].parentNode.insertBefore(this[i].cloneNode(true), after[j].nextSibling);\n }\n }\n }\n}\n\nfunction next(selector) {\n if (this.length > 0) {\n if (selector) {\n if (this[0].nextElementSibling && dom7_esm_$(this[0].nextElementSibling).is(selector)) {\n return dom7_esm_$([this[0].nextElementSibling]);\n }\n\n return dom7_esm_$([]);\n }\n\n if (this[0].nextElementSibling) return dom7_esm_$([this[0].nextElementSibling]);\n return dom7_esm_$([]);\n }\n\n return dom7_esm_$([]);\n}\n\nfunction nextAll(selector) {\n const nextEls = [];\n let el = this[0];\n if (!el) return dom7_esm_$([]);\n\n while (el.nextElementSibling) {\n const next = el.nextElementSibling; // eslint-disable-line\n\n if (selector) {\n if (dom7_esm_$(next).is(selector)) nextEls.push(next);\n } else nextEls.push(next);\n\n el = next;\n }\n\n return dom7_esm_$(nextEls);\n}\n\nfunction prev(selector) {\n if (this.length > 0) {\n const el = this[0];\n\n if (selector) {\n if (el.previousElementSibling && dom7_esm_$(el.previousElementSibling).is(selector)) {\n return dom7_esm_$([el.previousElementSibling]);\n }\n\n return dom7_esm_$([]);\n }\n\n if (el.previousElementSibling) return dom7_esm_$([el.previousElementSibling]);\n return dom7_esm_$([]);\n }\n\n return dom7_esm_$([]);\n}\n\nfunction prevAll(selector) {\n const prevEls = [];\n let el = this[0];\n if (!el) return dom7_esm_$([]);\n\n while (el.previousElementSibling) {\n const prev = el.previousElementSibling; // eslint-disable-line\n\n if (selector) {\n if (dom7_esm_$(prev).is(selector)) prevEls.push(prev);\n } else prevEls.push(prev);\n\n el = prev;\n }\n\n return dom7_esm_$(prevEls);\n}\n\nfunction siblings(selector) {\n return this.nextAll(selector).add(this.prevAll(selector));\n}\n\nfunction dom7_esm_parent(selector) {\n const parents = []; // eslint-disable-line\n\n for (let i = 0; i < this.length; i += 1) {\n if (this[i].parentNode !== null) {\n if (selector) {\n if (dom7_esm_$(this[i].parentNode).is(selector)) parents.push(this[i].parentNode);\n } else {\n parents.push(this[i].parentNode);\n }\n }\n }\n\n return dom7_esm_$(parents);\n}\n\nfunction parents(selector) {\n const parents = []; // eslint-disable-line\n\n for (let i = 0; i < this.length; i += 1) {\n let parent = this[i].parentNode; // eslint-disable-line\n\n while (parent) {\n if (selector) {\n if (dom7_esm_$(parent).is(selector)) parents.push(parent);\n } else {\n parents.push(parent);\n }\n\n parent = parent.parentNode;\n }\n }\n\n return dom7_esm_$(parents);\n}\n\nfunction closest(selector) {\n let closest = this; // eslint-disable-line\n\n if (typeof selector === 'undefined') {\n return dom7_esm_$([]);\n }\n\n if (!closest.is(selector)) {\n closest = closest.parents(selector).eq(0);\n }\n\n return closest;\n}\n\nfunction find(selector) {\n const foundElements = [];\n\n for (let i = 0; i < this.length; i += 1) {\n const found = this[i].querySelectorAll(selector);\n\n for (let j = 0; j < found.length; j += 1) {\n foundElements.push(found[j]);\n }\n }\n\n return dom7_esm_$(foundElements);\n}\n\nfunction children(selector) {\n const children = []; // eslint-disable-line\n\n for (let i = 0; i < this.length; i += 1) {\n const childNodes = this[i].children;\n\n for (let j = 0; j < childNodes.length; j += 1) {\n if (!selector || dom7_esm_$(childNodes[j]).is(selector)) {\n children.push(childNodes[j]);\n }\n }\n }\n\n return dom7_esm_$(children);\n}\n\nfunction remove() {\n for (let i = 0; i < this.length; i += 1) {\n if (this[i].parentNode) this[i].parentNode.removeChild(this[i]);\n }\n\n return this;\n}\n\nfunction detach() {\n return this.remove();\n}\n\nfunction add(...els) {\n const dom = this;\n let i;\n let j;\n\n for (i = 0; i < els.length; i += 1) {\n const toAdd = dom7_esm_$(els[i]);\n\n for (j = 0; j < toAdd.length; j += 1) {\n dom.push(toAdd[j]);\n }\n }\n\n return dom;\n}\n\nfunction empty() {\n for (let i = 0; i < this.length; i += 1) {\n const el = this[i];\n\n if (el.nodeType === 1) {\n for (let j = 0; j < el.childNodes.length; j += 1) {\n if (el.childNodes[j].parentNode) {\n el.childNodes[j].parentNode.removeChild(el.childNodes[j]);\n }\n }\n\n el.textContent = '';\n }\n }\n\n return this;\n}\n\n// eslint-disable-next-line\n\nfunction dom7_esm_scrollTo(...args) {\n const window = getWindow();\n let [left, top, duration, easing, callback] = args;\n\n if (args.length === 4 && typeof easing === 'function') {\n callback = easing;\n [left, top, duration, callback, easing] = args;\n }\n\n if (typeof easing === 'undefined') easing = 'swing';\n return this.each(function animate() {\n const el = this;\n let currentTop;\n let currentLeft;\n let maxTop;\n let maxLeft;\n let newTop;\n let newLeft;\n let scrollTop; // eslint-disable-line\n\n let scrollLeft; // eslint-disable-line\n\n let animateTop = top > 0 || top === 0;\n let animateLeft = left > 0 || left === 0;\n\n if (typeof easing === 'undefined') {\n easing = 'swing';\n }\n\n if (animateTop) {\n currentTop = el.scrollTop;\n\n if (!duration) {\n el.scrollTop = top;\n }\n }\n\n if (animateLeft) {\n currentLeft = el.scrollLeft;\n\n if (!duration) {\n el.scrollLeft = left;\n }\n }\n\n if (!duration) return;\n\n if (animateTop) {\n maxTop = el.scrollHeight - el.offsetHeight;\n newTop = Math.max(Math.min(top, maxTop), 0);\n }\n\n if (animateLeft) {\n maxLeft = el.scrollWidth - el.offsetWidth;\n newLeft = Math.max(Math.min(left, maxLeft), 0);\n }\n\n let startTime = null;\n if (animateTop && newTop === currentTop) animateTop = false;\n if (animateLeft && newLeft === currentLeft) animateLeft = false;\n\n function render(time = new Date().getTime()) {\n if (startTime === null) {\n startTime = time;\n }\n\n const progress = Math.max(Math.min((time - startTime) / duration, 1), 0);\n const easeProgress = easing === 'linear' ? progress : 0.5 - Math.cos(progress * Math.PI) / 2;\n let done;\n if (animateTop) scrollTop = currentTop + easeProgress * (newTop - currentTop);\n if (animateLeft) scrollLeft = currentLeft + easeProgress * (newLeft - currentLeft);\n\n if (animateTop && newTop > currentTop && scrollTop >= newTop) {\n el.scrollTop = newTop;\n done = true;\n }\n\n if (animateTop && newTop < currentTop && scrollTop <= newTop) {\n el.scrollTop = newTop;\n done = true;\n }\n\n if (animateLeft && newLeft > currentLeft && scrollLeft >= newLeft) {\n el.scrollLeft = newLeft;\n done = true;\n }\n\n if (animateLeft && newLeft < currentLeft && scrollLeft <= newLeft) {\n el.scrollLeft = newLeft;\n done = true;\n }\n\n if (done) {\n if (callback) callback();\n return;\n }\n\n if (animateTop) el.scrollTop = scrollTop;\n if (animateLeft) el.scrollLeft = scrollLeft;\n window.requestAnimationFrame(render);\n }\n\n window.requestAnimationFrame(render);\n });\n} // scrollTop(top, duration, easing, callback) {\n\n\nfunction scrollTop(...args) {\n let [top, duration, easing, callback] = args;\n\n if (args.length === 3 && typeof easing === 'function') {\n [top, duration, callback, easing] = args;\n }\n\n const dom = this;\n\n if (typeof top === 'undefined') {\n if (dom.length > 0) return dom[0].scrollTop;\n return null;\n }\n\n return dom.scrollTo(undefined, top, duration, easing, callback);\n}\n\nfunction scrollLeft(...args) {\n let [left, duration, easing, callback] = args;\n\n if (args.length === 3 && typeof easing === 'function') {\n [left, duration, callback, easing] = args;\n }\n\n const dom = this;\n\n if (typeof left === 'undefined') {\n if (dom.length > 0) return dom[0].scrollLeft;\n return null;\n }\n\n return dom.scrollTo(left, undefined, duration, easing, callback);\n}\n\n// eslint-disable-next-line\n\nfunction animate(initialProps, initialParams) {\n const window = getWindow();\n const els = this;\n const a = {\n props: Object.assign({}, initialProps),\n params: Object.assign({\n duration: 300,\n easing: 'swing' // or 'linear'\n\n /* Callbacks\n begin(elements)\n complete(elements)\n progress(elements, complete, remaining, start, tweenValue)\n */\n\n }, initialParams),\n elements: els,\n animating: false,\n que: [],\n\n easingProgress(easing, progress) {\n if (easing === 'swing') {\n return 0.5 - Math.cos(progress * Math.PI) / 2;\n }\n\n if (typeof easing === 'function') {\n return easing(progress);\n }\n\n return progress;\n },\n\n stop() {\n if (a.frameId) {\n window.cancelAnimationFrame(a.frameId);\n }\n\n a.animating = false;\n a.elements.each(el => {\n const element = el;\n delete element.dom7AnimateInstance;\n });\n a.que = [];\n },\n\n done(complete) {\n a.animating = false;\n a.elements.each(el => {\n const element = el;\n delete element.dom7AnimateInstance;\n });\n if (complete) complete(els);\n\n if (a.que.length > 0) {\n const que = a.que.shift();\n a.animate(que[0], que[1]);\n }\n },\n\n animate(props, params) {\n if (a.animating) {\n a.que.push([props, params]);\n return a;\n }\n\n const elements = []; // Define & Cache Initials & Units\n\n a.elements.each((el, index) => {\n let initialFullValue;\n let initialValue;\n let unit;\n let finalValue;\n let finalFullValue;\n if (!el.dom7AnimateInstance) a.elements[index].dom7AnimateInstance = a;\n elements[index] = {\n container: el\n };\n Object.keys(props).forEach(prop => {\n initialFullValue = window.getComputedStyle(el, null).getPropertyValue(prop).replace(',', '.');\n initialValue = parseFloat(initialFullValue);\n unit = initialFullValue.replace(initialValue, '');\n finalValue = parseFloat(props[prop]);\n finalFullValue = props[prop] + unit;\n elements[index][prop] = {\n initialFullValue,\n initialValue,\n unit,\n finalValue,\n finalFullValue,\n currentValue: initialValue\n };\n });\n });\n let startTime = null;\n let time;\n let elementsDone = 0;\n let propsDone = 0;\n let done;\n let began = false;\n a.animating = true;\n\n function render() {\n time = new Date().getTime();\n let progress;\n let easeProgress; // let el;\n\n if (!began) {\n began = true;\n if (params.begin) params.begin(els);\n }\n\n if (startTime === null) {\n startTime = time;\n }\n\n if (params.progress) {\n // eslint-disable-next-line\n params.progress(els, Math.max(Math.min((time - startTime) / params.duration, 1), 0), startTime + params.duration - time < 0 ? 0 : startTime + params.duration - time, startTime);\n }\n\n elements.forEach(element => {\n const el = element;\n if (done || el.done) return;\n Object.keys(props).forEach(prop => {\n if (done || el.done) return;\n progress = Math.max(Math.min((time - startTime) / params.duration, 1), 0);\n easeProgress = a.easingProgress(params.easing, progress);\n const {\n initialValue,\n finalValue,\n unit\n } = el[prop];\n el[prop].currentValue = initialValue + easeProgress * (finalValue - initialValue);\n const currentValue = el[prop].currentValue;\n\n if (finalValue > initialValue && currentValue >= finalValue || finalValue < initialValue && currentValue <= finalValue) {\n el.container.style[prop] = finalValue + unit;\n propsDone += 1;\n\n if (propsDone === Object.keys(props).length) {\n el.done = true;\n elementsDone += 1;\n }\n\n if (elementsDone === elements.length) {\n done = true;\n }\n }\n\n if (done) {\n a.done(params.complete);\n return;\n }\n\n el.container.style[prop] = currentValue + unit;\n });\n });\n if (done) return; // Then call\n\n a.frameId = window.requestAnimationFrame(render);\n }\n\n a.frameId = window.requestAnimationFrame(render);\n return a;\n }\n\n };\n\n if (a.elements.length === 0) {\n return els;\n }\n\n let animateInstance;\n\n for (let i = 0; i < a.elements.length; i += 1) {\n if (a.elements[i].dom7AnimateInstance) {\n animateInstance = a.elements[i].dom7AnimateInstance;\n } else a.elements[i].dom7AnimateInstance = a;\n }\n\n if (!animateInstance) {\n animateInstance = a;\n }\n\n if (initialProps === 'stop') {\n animateInstance.stop();\n } else {\n animateInstance.animate(a.props, a.params);\n }\n\n return els;\n}\n\nfunction stop() {\n const els = this;\n\n for (let i = 0; i < els.length; i += 1) {\n if (els[i].dom7AnimateInstance) {\n els[i].dom7AnimateInstance.stop();\n }\n }\n}\n\nconst noTrigger = 'resize scroll'.split(' ');\n\nfunction shortcut(name) {\n function eventHandler(...args) {\n if (typeof args[0] === 'undefined') {\n for (let i = 0; i < this.length; i += 1) {\n if (noTrigger.indexOf(name) < 0) {\n if (name in this[i]) this[i][name]();else {\n dom7_esm_$(this[i]).trigger(name);\n }\n }\n }\n\n return this;\n }\n\n return this.on(name, ...args);\n }\n\n return eventHandler;\n}\n\nconst click = shortcut('click');\nconst dom7_esm_blur = shortcut('blur');\nconst dom7_esm_focus = shortcut('focus');\nconst focusin = shortcut('focusin');\nconst focusout = shortcut('focusout');\nconst keyup = shortcut('keyup');\nconst keydown = shortcut('keydown');\nconst keypress = shortcut('keypress');\nconst dom7_esm_submit = shortcut('submit');\nconst change = shortcut('change');\nconst mousedown = shortcut('mousedown');\nconst mousemove = shortcut('mousemove');\nconst mouseup = shortcut('mouseup');\nconst mouseenter = shortcut('mouseenter');\nconst mouseleave = shortcut('mouseleave');\nconst mouseout = shortcut('mouseout');\nconst mouseover = shortcut('mouseover');\nconst touchstart = shortcut('touchstart');\nconst touchend = shortcut('touchend');\nconst touchmove = shortcut('touchmove');\nconst resize = shortcut('resize');\nconst dom7_esm_scroll = shortcut('scroll');\n\n/* harmony default export */ const dom7_esm = ((/* unused pure expression or super */ null && (dom7_esm_$)));\n\n\n;// CONCATENATED MODULE: ./node_modules/swiper/shared/dom.js\n\nconst Methods = {\n addClass: addClass,\n removeClass: removeClass,\n hasClass: hasClass,\n toggleClass: toggleClass,\n attr: attr,\n removeAttr: removeAttr,\n transform: transform,\n transition: transition,\n on: on,\n off: off,\n trigger: trigger,\n transitionEnd: transitionEnd,\n outerWidth: dom7_esm_outerWidth,\n outerHeight: dom7_esm_outerHeight,\n styles: styles,\n offset: offset,\n css: css,\n each: each,\n html: html,\n text: dom7_esm_text,\n is: is,\n index: index,\n eq: eq,\n append: append,\n prepend: prepend,\n next: next,\n nextAll: nextAll,\n prev: prev,\n prevAll: prevAll,\n parent: dom7_esm_parent,\n parents: parents,\n closest: closest,\n find: find,\n children: children,\n filter: filter,\n remove: remove\n};\nObject.keys(Methods).forEach(methodName => {\n Object.defineProperty(dom7_esm_$.fn, methodName, {\n value: Methods[methodName],\n writable: true\n });\n});\n/* harmony default export */ const dom = (dom7_esm_$);\n;// CONCATENATED MODULE: ./node_modules/swiper/shared/utils.js\n\n\nfunction deleteProps(obj) {\n const object = obj;\n Object.keys(object).forEach(key => {\n try {\n object[key] = null;\n } catch (e) {// no getter for object\n }\n\n try {\n delete object[key];\n } catch (e) {// something got wrong\n }\n });\n}\n\nfunction utils_nextTick(callback, delay = 0) {\n return setTimeout(callback, delay);\n}\n\nfunction utils_now() {\n return Date.now();\n}\n\nfunction utils_getComputedStyle(el) {\n const window = ssr_window_esm_getWindow();\n let style;\n\n if (window.getComputedStyle) {\n style = window.getComputedStyle(el, null);\n }\n\n if (!style && el.currentStyle) {\n style = el.currentStyle;\n }\n\n if (!style) {\n style = el.style;\n }\n\n return style;\n}\n\nfunction utils_getTranslate(el, axis = 'x') {\n const window = ssr_window_esm_getWindow();\n let matrix;\n let curTransform;\n let transformMatrix;\n const curStyle = utils_getComputedStyle(el, null);\n\n if (window.WebKitCSSMatrix) {\n curTransform = curStyle.transform || curStyle.webkitTransform;\n\n if (curTransform.split(',').length > 6) {\n curTransform = curTransform.split(', ').map(a => a.replace(',', '.')).join(', ');\n } // Some old versions of Webkit choke when 'none' is passed; pass\n // empty string instead in this case\n\n\n transformMatrix = new window.WebKitCSSMatrix(curTransform === 'none' ? '' : curTransform);\n } else {\n transformMatrix = curStyle.MozTransform || curStyle.OTransform || curStyle.MsTransform || curStyle.msTransform || curStyle.transform || curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,');\n matrix = transformMatrix.toString().split(',');\n }\n\n if (axis === 'x') {\n // Latest Chrome and webkits Fix\n if (window.WebKitCSSMatrix) curTransform = transformMatrix.m41; // Crazy IE10 Matrix\n else if (matrix.length === 16) curTransform = parseFloat(matrix[12]); // Normal Browsers\n else curTransform = parseFloat(matrix[4]);\n }\n\n if (axis === 'y') {\n // Latest Chrome and webkits Fix\n if (window.WebKitCSSMatrix) curTransform = transformMatrix.m42; // Crazy IE10 Matrix\n else if (matrix.length === 16) curTransform = parseFloat(matrix[13]); // Normal Browsers\n else curTransform = parseFloat(matrix[5]);\n }\n\n return curTransform || 0;\n}\n\nfunction utils_isObject(o) {\n return typeof o === 'object' && o !== null && o.constructor && Object.prototype.toString.call(o).slice(8, -1) === 'Object';\n}\n\nfunction isNode(node) {\n // eslint-disable-next-line\n if (typeof window !== 'undefined' && typeof window.HTMLElement !== 'undefined') {\n return node instanceof HTMLElement;\n }\n\n return node && (node.nodeType === 1 || node.nodeType === 11);\n}\n\nfunction utils_extend(...args) {\n const to = Object(args[0]);\n const noExtend = ['__proto__', 'constructor', 'prototype'];\n\n for (let i = 1; i < args.length; i += 1) {\n const nextSource = args[i];\n\n if (nextSource !== undefined && nextSource !== null && !isNode(nextSource)) {\n const keysArray = Object.keys(Object(nextSource)).filter(key => noExtend.indexOf(key) < 0);\n\n for (let nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex += 1) {\n const nextKey = keysArray[nextIndex];\n const desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);\n\n if (desc !== undefined && desc.enumerable) {\n if (utils_isObject(to[nextKey]) && utils_isObject(nextSource[nextKey])) {\n if (nextSource[nextKey].__swiper__) {\n to[nextKey] = nextSource[nextKey];\n } else {\n utils_extend(to[nextKey], nextSource[nextKey]);\n }\n } else if (!utils_isObject(to[nextKey]) && utils_isObject(nextSource[nextKey])) {\n to[nextKey] = {};\n\n if (nextSource[nextKey].__swiper__) {\n to[nextKey] = nextSource[nextKey];\n } else {\n utils_extend(to[nextKey], nextSource[nextKey]);\n }\n } else {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n }\n }\n\n return to;\n}\n\nfunction utils_setCSSProperty(el, varName, varValue) {\n el.style.setProperty(varName, varValue);\n}\n\nfunction animateCSSModeScroll({\n swiper,\n targetPosition,\n side\n}) {\n const window = ssr_window_esm_getWindow();\n const startPosition = -swiper.translate;\n let startTime = null;\n let time;\n const duration = swiper.params.speed;\n swiper.wrapperEl.style.scrollSnapType = 'none';\n window.cancelAnimationFrame(swiper.cssModeFrameID);\n const dir = targetPosition > startPosition ? 'next' : 'prev';\n\n const isOutOfBound = (current, target) => {\n return dir === 'next' && current >= target || dir === 'prev' && current <= target;\n };\n\n const animate = () => {\n time = new Date().getTime();\n\n if (startTime === null) {\n startTime = time;\n }\n\n const progress = Math.max(Math.min((time - startTime) / duration, 1), 0);\n const easeProgress = 0.5 - Math.cos(progress * Math.PI) / 2;\n let currentPosition = startPosition + easeProgress * (targetPosition - startPosition);\n\n if (isOutOfBound(currentPosition, targetPosition)) {\n currentPosition = targetPosition;\n }\n\n swiper.wrapperEl.scrollTo({\n [side]: currentPosition\n });\n\n if (isOutOfBound(currentPosition, targetPosition)) {\n swiper.wrapperEl.style.overflow = 'hidden';\n swiper.wrapperEl.style.scrollSnapType = '';\n setTimeout(() => {\n swiper.wrapperEl.style.overflow = '';\n swiper.wrapperEl.scrollTo({\n [side]: currentPosition\n });\n });\n window.cancelAnimationFrame(swiper.cssModeFrameID);\n return;\n }\n\n swiper.cssModeFrameID = window.requestAnimationFrame(animate);\n };\n\n animate();\n}\n\n\n;// CONCATENATED MODULE: ./node_modules/swiper/shared/get-support.js\n\nlet support;\n\nfunction calcSupport() {\n const window = ssr_window_esm_getWindow();\n const document = ssr_window_esm_getDocument();\n return {\n smoothScroll: document.documentElement && 'scrollBehavior' in document.documentElement.style,\n touch: !!('ontouchstart' in window || window.DocumentTouch && document instanceof window.DocumentTouch),\n passiveListener: function checkPassiveListener() {\n let supportsPassive = false;\n\n try {\n const opts = Object.defineProperty({}, 'passive', {\n // eslint-disable-next-line\n get() {\n supportsPassive = true;\n }\n\n });\n window.addEventListener('testPassiveListener', null, opts);\n } catch (e) {// No support\n }\n\n return supportsPassive;\n }(),\n gestures: function checkGestures() {\n return 'ongesturestart' in window;\n }()\n };\n}\n\nfunction getSupport() {\n if (!support) {\n support = calcSupport();\n }\n\n return support;\n}\n\n\n;// CONCATENATED MODULE: ./node_modules/swiper/shared/get-device.js\n\n\nlet deviceCached;\n\nfunction calcDevice({\n userAgent\n} = {}) {\n const support = getSupport();\n const window = ssr_window_esm_getWindow();\n const platform = window.navigator.platform;\n const ua = userAgent || window.navigator.userAgent;\n const device = {\n ios: false,\n android: false\n };\n const screenWidth = window.screen.width;\n const screenHeight = window.screen.height;\n const android = ua.match(/(Android);?[\\s\\/]+([\\d.]+)?/); // eslint-disable-line\n\n let ipad = ua.match(/(iPad).*OS\\s([\\d_]+)/);\n const ipod = ua.match(/(iPod)(.*OS\\s([\\d_]+))?/);\n const iphone = !ipad && ua.match(/(iPhone\\sOS|iOS)\\s([\\d_]+)/);\n const windows = platform === 'Win32';\n let macos = platform === 'MacIntel'; // iPadOs 13 fix\n\n const iPadScreens = ['1024x1366', '1366x1024', '834x1194', '1194x834', '834x1112', '1112x834', '768x1024', '1024x768', '820x1180', '1180x820', '810x1080', '1080x810'];\n\n if (!ipad && macos && support.touch && iPadScreens.indexOf(`${screenWidth}x${screenHeight}`) >= 0) {\n ipad = ua.match(/(Version)\\/([\\d.]+)/);\n if (!ipad) ipad = [0, 1, '13_0_0'];\n macos = false;\n } // Android\n\n\n if (android && !windows) {\n device.os = 'android';\n device.android = true;\n }\n\n if (ipad || iphone || ipod) {\n device.os = 'ios';\n device.ios = true;\n } // Export object\n\n\n return device;\n}\n\nfunction getDevice(overrides = {}) {\n if (!deviceCached) {\n deviceCached = calcDevice(overrides);\n }\n\n return deviceCached;\n}\n\n\n;// CONCATENATED MODULE: ./node_modules/swiper/shared/get-browser.js\n\nlet browser;\n\nfunction calcBrowser() {\n const window = ssr_window_esm_getWindow();\n\n function isSafari() {\n const ua = window.navigator.userAgent.toLowerCase();\n return ua.indexOf('safari') >= 0 && ua.indexOf('chrome') < 0 && ua.indexOf('android') < 0;\n }\n\n return {\n isSafari: isSafari(),\n isWebView: /(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(window.navigator.userAgent)\n };\n}\n\nfunction getBrowser() {\n if (!browser) {\n browser = calcBrowser();\n }\n\n return browser;\n}\n\n\n;// CONCATENATED MODULE: ./node_modules/swiper/core/modules/resize/resize.js\n\nfunction Resize({\n swiper,\n on,\n emit\n}) {\n const window = ssr_window_esm_getWindow();\n let observer = null;\n let animationFrame = null;\n\n const resizeHandler = () => {\n if (!swiper || swiper.destroyed || !swiper.initialized) return;\n emit('beforeResize');\n emit('resize');\n };\n\n const createObserver = () => {\n if (!swiper || swiper.destroyed || !swiper.initialized) return;\n observer = new ResizeObserver(entries => {\n animationFrame = window.requestAnimationFrame(() => {\n const {\n width,\n height\n } = swiper;\n let newWidth = width;\n let newHeight = height;\n entries.forEach(({\n contentBoxSize,\n contentRect,\n target\n }) => {\n if (target && target !== swiper.el) return;\n newWidth = contentRect ? contentRect.width : (contentBoxSize[0] || contentBoxSize).inlineSize;\n newHeight = contentRect ? contentRect.height : (contentBoxSize[0] || contentBoxSize).blockSize;\n });\n\n if (newWidth !== width || newHeight !== height) {\n resizeHandler();\n }\n });\n });\n observer.observe(swiper.el);\n };\n\n const removeObserver = () => {\n if (animationFrame) {\n window.cancelAnimationFrame(animationFrame);\n }\n\n if (observer && observer.unobserve && swiper.el) {\n observer.unobserve(swiper.el);\n observer = null;\n }\n };\n\n const orientationChangeHandler = () => {\n if (!swiper || swiper.destroyed || !swiper.initialized) return;\n emit('orientationchange');\n };\n\n on('init', () => {\n if (swiper.params.resizeObserver && typeof window.ResizeObserver !== 'undefined') {\n createObserver();\n return;\n }\n\n window.addEventListener('resize', resizeHandler);\n window.addEventListener('orientationchange', orientationChangeHandler);\n });\n on('destroy', () => {\n removeObserver();\n window.removeEventListener('resize', resizeHandler);\n window.removeEventListener('orientationchange', orientationChangeHandler);\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/modules/observer/observer.js\n\nfunction observer_Observer({\n swiper,\n extendParams,\n on,\n emit\n}) {\n const observers = [];\n const window = ssr_window_esm_getWindow();\n\n const attach = (target, options = {}) => {\n const ObserverFunc = window.MutationObserver || window.WebkitMutationObserver;\n const observer = new ObserverFunc(mutations => {\n // The observerUpdate event should only be triggered\n // once despite the number of mutations. Additional\n // triggers are redundant and are very costly\n if (mutations.length === 1) {\n emit('observerUpdate', mutations[0]);\n return;\n }\n\n const observerUpdate = function observerUpdate() {\n emit('observerUpdate', mutations[0]);\n };\n\n if (window.requestAnimationFrame) {\n window.requestAnimationFrame(observerUpdate);\n } else {\n window.setTimeout(observerUpdate, 0);\n }\n });\n observer.observe(target, {\n attributes: typeof options.attributes === 'undefined' ? true : options.attributes,\n childList: typeof options.childList === 'undefined' ? true : options.childList,\n characterData: typeof options.characterData === 'undefined' ? true : options.characterData\n });\n observers.push(observer);\n };\n\n const init = () => {\n if (!swiper.params.observer) return;\n\n if (swiper.params.observeParents) {\n const containerParents = swiper.$el.parents();\n\n for (let i = 0; i < containerParents.length; i += 1) {\n attach(containerParents[i]);\n }\n } // Observe container\n\n\n attach(swiper.$el[0], {\n childList: swiper.params.observeSlideChildren\n }); // Observe wrapper\n\n attach(swiper.$wrapperEl[0], {\n attributes: false\n });\n };\n\n const destroy = () => {\n observers.forEach(observer => {\n observer.disconnect();\n });\n observers.splice(0, observers.length);\n };\n\n extendParams({\n observer: false,\n observeParents: false,\n observeSlideChildren: false\n });\n on('init', init);\n on('destroy', destroy);\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/events-emitter.js\n/* eslint-disable no-underscore-dangle */\n/* harmony default export */ const events_emitter = ({\n on(events, handler, priority) {\n const self = this;\n if (!self.eventsListeners || self.destroyed) return self;\n if (typeof handler !== 'function') return self;\n const method = priority ? 'unshift' : 'push';\n events.split(' ').forEach(event => {\n if (!self.eventsListeners[event]) self.eventsListeners[event] = [];\n self.eventsListeners[event][method](handler);\n });\n return self;\n },\n\n once(events, handler, priority) {\n const self = this;\n if (!self.eventsListeners || self.destroyed) return self;\n if (typeof handler !== 'function') return self;\n\n function onceHandler(...args) {\n self.off(events, onceHandler);\n\n if (onceHandler.__emitterProxy) {\n delete onceHandler.__emitterProxy;\n }\n\n handler.apply(self, args);\n }\n\n onceHandler.__emitterProxy = handler;\n return self.on(events, onceHandler, priority);\n },\n\n onAny(handler, priority) {\n const self = this;\n if (!self.eventsListeners || self.destroyed) return self;\n if (typeof handler !== 'function') return self;\n const method = priority ? 'unshift' : 'push';\n\n if (self.eventsAnyListeners.indexOf(handler) < 0) {\n self.eventsAnyListeners[method](handler);\n }\n\n return self;\n },\n\n offAny(handler) {\n const self = this;\n if (!self.eventsListeners || self.destroyed) return self;\n if (!self.eventsAnyListeners) return self;\n const index = self.eventsAnyListeners.indexOf(handler);\n\n if (index >= 0) {\n self.eventsAnyListeners.splice(index, 1);\n }\n\n return self;\n },\n\n off(events, handler) {\n const self = this;\n if (!self.eventsListeners || self.destroyed) return self;\n if (!self.eventsListeners) return self;\n events.split(' ').forEach(event => {\n if (typeof handler === 'undefined') {\n self.eventsListeners[event] = [];\n } else if (self.eventsListeners[event]) {\n self.eventsListeners[event].forEach((eventHandler, index) => {\n if (eventHandler === handler || eventHandler.__emitterProxy && eventHandler.__emitterProxy === handler) {\n self.eventsListeners[event].splice(index, 1);\n }\n });\n }\n });\n return self;\n },\n\n emit(...args) {\n const self = this;\n if (!self.eventsListeners || self.destroyed) return self;\n if (!self.eventsListeners) return self;\n let events;\n let data;\n let context;\n\n if (typeof args[0] === 'string' || Array.isArray(args[0])) {\n events = args[0];\n data = args.slice(1, args.length);\n context = self;\n } else {\n events = args[0].events;\n data = args[0].data;\n context = args[0].context || self;\n }\n\n data.unshift(context);\n const eventsArray = Array.isArray(events) ? events : events.split(' ');\n eventsArray.forEach(event => {\n if (self.eventsAnyListeners && self.eventsAnyListeners.length) {\n self.eventsAnyListeners.forEach(eventHandler => {\n eventHandler.apply(context, [event, ...data]);\n });\n }\n\n if (self.eventsListeners && self.eventsListeners[event]) {\n self.eventsListeners[event].forEach(eventHandler => {\n eventHandler.apply(context, data);\n });\n }\n });\n return self;\n }\n\n});\n;// CONCATENATED MODULE: ./node_modules/swiper/core/update/updateSize.js\nfunction updateSize() {\n const swiper = this;\n let width;\n let height;\n const $el = swiper.$el;\n\n if (typeof swiper.params.width !== 'undefined' && swiper.params.width !== null) {\n width = swiper.params.width;\n } else {\n width = $el[0].clientWidth;\n }\n\n if (typeof swiper.params.height !== 'undefined' && swiper.params.height !== null) {\n height = swiper.params.height;\n } else {\n height = $el[0].clientHeight;\n }\n\n if (width === 0 && swiper.isHorizontal() || height === 0 && swiper.isVertical()) {\n return;\n } // Subtract paddings\n\n\n width = width - parseInt($el.css('padding-left') || 0, 10) - parseInt($el.css('padding-right') || 0, 10);\n height = height - parseInt($el.css('padding-top') || 0, 10) - parseInt($el.css('padding-bottom') || 0, 10);\n if (Number.isNaN(width)) width = 0;\n if (Number.isNaN(height)) height = 0;\n Object.assign(swiper, {\n width,\n height,\n size: swiper.isHorizontal() ? width : height\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/update/updateSlides.js\n\nfunction updateSlides() {\n const swiper = this;\n\n function getDirectionLabel(property) {\n if (swiper.isHorizontal()) {\n return property;\n } // prettier-ignore\n\n\n return {\n 'width': 'height',\n 'margin-top': 'margin-left',\n 'margin-bottom ': 'margin-right',\n 'margin-left': 'margin-top',\n 'margin-right': 'margin-bottom',\n 'padding-left': 'padding-top',\n 'padding-right': 'padding-bottom',\n 'marginRight': 'marginBottom'\n }[property];\n }\n\n function getDirectionPropertyValue(node, label) {\n return parseFloat(node.getPropertyValue(getDirectionLabel(label)) || 0);\n }\n\n const params = swiper.params;\n const {\n $wrapperEl,\n size: swiperSize,\n rtlTranslate: rtl,\n wrongRTL\n } = swiper;\n const isVirtual = swiper.virtual && params.virtual.enabled;\n const previousSlidesLength = isVirtual ? swiper.virtual.slides.length : swiper.slides.length;\n const slides = $wrapperEl.children(`.${swiper.params.slideClass}`);\n const slidesLength = isVirtual ? swiper.virtual.slides.length : slides.length;\n let snapGrid = [];\n const slidesGrid = [];\n const slidesSizesGrid = [];\n let offsetBefore = params.slidesOffsetBefore;\n\n if (typeof offsetBefore === 'function') {\n offsetBefore = params.slidesOffsetBefore.call(swiper);\n }\n\n let offsetAfter = params.slidesOffsetAfter;\n\n if (typeof offsetAfter === 'function') {\n offsetAfter = params.slidesOffsetAfter.call(swiper);\n }\n\n const previousSnapGridLength = swiper.snapGrid.length;\n const previousSlidesGridLength = swiper.slidesGrid.length;\n let spaceBetween = params.spaceBetween;\n let slidePosition = -offsetBefore;\n let prevSlideSize = 0;\n let index = 0;\n\n if (typeof swiperSize === 'undefined') {\n return;\n }\n\n if (typeof spaceBetween === 'string' && spaceBetween.indexOf('%') >= 0) {\n spaceBetween = parseFloat(spaceBetween.replace('%', '')) / 100 * swiperSize;\n }\n\n swiper.virtualSize = -spaceBetween; // reset margins\n\n if (rtl) slides.css({\n marginLeft: '',\n marginBottom: '',\n marginTop: ''\n });else slides.css({\n marginRight: '',\n marginBottom: '',\n marginTop: ''\n }); // reset cssMode offsets\n\n if (params.centeredSlides && params.cssMode) {\n utils_setCSSProperty(swiper.wrapperEl, '--swiper-centered-offset-before', '');\n utils_setCSSProperty(swiper.wrapperEl, '--swiper-centered-offset-after', '');\n }\n\n const gridEnabled = params.grid && params.grid.rows > 1 && swiper.grid;\n\n if (gridEnabled) {\n swiper.grid.initSlides(slidesLength);\n } // Calc slides\n\n\n let slideSize;\n const shouldResetSlideSize = params.slidesPerView === 'auto' && params.breakpoints && Object.keys(params.breakpoints).filter(key => {\n return typeof params.breakpoints[key].slidesPerView !== 'undefined';\n }).length > 0;\n\n for (let i = 0; i < slidesLength; i += 1) {\n slideSize = 0;\n const slide = slides.eq(i);\n\n if (gridEnabled) {\n swiper.grid.updateSlide(i, slide, slidesLength, getDirectionLabel);\n }\n\n if (slide.css('display') === 'none') continue; // eslint-disable-line\n\n if (params.slidesPerView === 'auto') {\n if (shouldResetSlideSize) {\n slides[i].style[getDirectionLabel('width')] = ``;\n }\n\n const slideStyles = getComputedStyle(slide[0]);\n const currentTransform = slide[0].style.transform;\n const currentWebKitTransform = slide[0].style.webkitTransform;\n\n if (currentTransform) {\n slide[0].style.transform = 'none';\n }\n\n if (currentWebKitTransform) {\n slide[0].style.webkitTransform = 'none';\n }\n\n if (params.roundLengths) {\n slideSize = swiper.isHorizontal() ? slide.outerWidth(true) : slide.outerHeight(true);\n } else {\n // eslint-disable-next-line\n const width = getDirectionPropertyValue(slideStyles, 'width');\n const paddingLeft = getDirectionPropertyValue(slideStyles, 'padding-left');\n const paddingRight = getDirectionPropertyValue(slideStyles, 'padding-right');\n const marginLeft = getDirectionPropertyValue(slideStyles, 'margin-left');\n const marginRight = getDirectionPropertyValue(slideStyles, 'margin-right');\n const boxSizing = slideStyles.getPropertyValue('box-sizing');\n\n if (boxSizing && boxSizing === 'border-box') {\n slideSize = width + marginLeft + marginRight;\n } else {\n const {\n clientWidth,\n offsetWidth\n } = slide[0];\n slideSize = width + paddingLeft + paddingRight + marginLeft + marginRight + (offsetWidth - clientWidth);\n }\n }\n\n if (currentTransform) {\n slide[0].style.transform = currentTransform;\n }\n\n if (currentWebKitTransform) {\n slide[0].style.webkitTransform = currentWebKitTransform;\n }\n\n if (params.roundLengths) slideSize = Math.floor(slideSize);\n } else {\n slideSize = (swiperSize - (params.slidesPerView - 1) * spaceBetween) / params.slidesPerView;\n if (params.roundLengths) slideSize = Math.floor(slideSize);\n\n if (slides[i]) {\n slides[i].style[getDirectionLabel('width')] = `${slideSize}px`;\n }\n }\n\n if (slides[i]) {\n slides[i].swiperSlideSize = slideSize;\n }\n\n slidesSizesGrid.push(slideSize);\n\n if (params.centeredSlides) {\n slidePosition = slidePosition + slideSize / 2 + prevSlideSize / 2 + spaceBetween;\n if (prevSlideSize === 0 && i !== 0) slidePosition = slidePosition - swiperSize / 2 - spaceBetween;\n if (i === 0) slidePosition = slidePosition - swiperSize / 2 - spaceBetween;\n if (Math.abs(slidePosition) < 1 / 1000) slidePosition = 0;\n if (params.roundLengths) slidePosition = Math.floor(slidePosition);\n if (index % params.slidesPerGroup === 0) snapGrid.push(slidePosition);\n slidesGrid.push(slidePosition);\n } else {\n if (params.roundLengths) slidePosition = Math.floor(slidePosition);\n if ((index - Math.min(swiper.params.slidesPerGroupSkip, index)) % swiper.params.slidesPerGroup === 0) snapGrid.push(slidePosition);\n slidesGrid.push(slidePosition);\n slidePosition = slidePosition + slideSize + spaceBetween;\n }\n\n swiper.virtualSize += slideSize + spaceBetween;\n prevSlideSize = slideSize;\n index += 1;\n }\n\n swiper.virtualSize = Math.max(swiper.virtualSize, swiperSize) + offsetAfter;\n\n if (rtl && wrongRTL && (params.effect === 'slide' || params.effect === 'coverflow')) {\n $wrapperEl.css({\n width: `${swiper.virtualSize + params.spaceBetween}px`\n });\n }\n\n if (params.setWrapperSize) {\n $wrapperEl.css({\n [getDirectionLabel('width')]: `${swiper.virtualSize + params.spaceBetween}px`\n });\n }\n\n if (gridEnabled) {\n swiper.grid.updateWrapperSize(slideSize, snapGrid, getDirectionLabel);\n } // Remove last grid elements depending on width\n\n\n if (!params.centeredSlides) {\n const newSlidesGrid = [];\n\n for (let i = 0; i < snapGrid.length; i += 1) {\n let slidesGridItem = snapGrid[i];\n if (params.roundLengths) slidesGridItem = Math.floor(slidesGridItem);\n\n if (snapGrid[i] <= swiper.virtualSize - swiperSize) {\n newSlidesGrid.push(slidesGridItem);\n }\n }\n\n snapGrid = newSlidesGrid;\n\n if (Math.floor(swiper.virtualSize - swiperSize) - Math.floor(snapGrid[snapGrid.length - 1]) > 1) {\n snapGrid.push(swiper.virtualSize - swiperSize);\n }\n }\n\n if (snapGrid.length === 0) snapGrid = [0];\n\n if (params.spaceBetween !== 0) {\n const key = swiper.isHorizontal() && rtl ? 'marginLeft' : getDirectionLabel('marginRight');\n slides.filter((_, slideIndex) => {\n if (!params.cssMode) return true;\n\n if (slideIndex === slides.length - 1) {\n return false;\n }\n\n return true;\n }).css({\n [key]: `${spaceBetween}px`\n });\n }\n\n if (params.centeredSlides && params.centeredSlidesBounds) {\n let allSlidesSize = 0;\n slidesSizesGrid.forEach(slideSizeValue => {\n allSlidesSize += slideSizeValue + (params.spaceBetween ? params.spaceBetween : 0);\n });\n allSlidesSize -= params.spaceBetween;\n const maxSnap = allSlidesSize - swiperSize;\n snapGrid = snapGrid.map(snap => {\n if (snap < 0) return -offsetBefore;\n if (snap > maxSnap) return maxSnap + offsetAfter;\n return snap;\n });\n }\n\n if (params.centerInsufficientSlides) {\n let allSlidesSize = 0;\n slidesSizesGrid.forEach(slideSizeValue => {\n allSlidesSize += slideSizeValue + (params.spaceBetween ? params.spaceBetween : 0);\n });\n allSlidesSize -= params.spaceBetween;\n\n if (allSlidesSize < swiperSize) {\n const allSlidesOffset = (swiperSize - allSlidesSize) / 2;\n snapGrid.forEach((snap, snapIndex) => {\n snapGrid[snapIndex] = snap - allSlidesOffset;\n });\n slidesGrid.forEach((snap, snapIndex) => {\n slidesGrid[snapIndex] = snap + allSlidesOffset;\n });\n }\n }\n\n Object.assign(swiper, {\n slides,\n snapGrid,\n slidesGrid,\n slidesSizesGrid\n });\n\n if (params.centeredSlides && params.cssMode && !params.centeredSlidesBounds) {\n utils_setCSSProperty(swiper.wrapperEl, '--swiper-centered-offset-before', `${-snapGrid[0]}px`);\n utils_setCSSProperty(swiper.wrapperEl, '--swiper-centered-offset-after', `${swiper.size / 2 - slidesSizesGrid[slidesSizesGrid.length - 1] / 2}px`);\n const addToSnapGrid = -swiper.snapGrid[0];\n const addToSlidesGrid = -swiper.slidesGrid[0];\n swiper.snapGrid = swiper.snapGrid.map(v => v + addToSnapGrid);\n swiper.slidesGrid = swiper.slidesGrid.map(v => v + addToSlidesGrid);\n }\n\n if (slidesLength !== previousSlidesLength) {\n swiper.emit('slidesLengthChange');\n }\n\n if (snapGrid.length !== previousSnapGridLength) {\n if (swiper.params.watchOverflow) swiper.checkOverflow();\n swiper.emit('snapGridLengthChange');\n }\n\n if (slidesGrid.length !== previousSlidesGridLength) {\n swiper.emit('slidesGridLengthChange');\n }\n\n if (params.watchSlidesProgress) {\n swiper.updateSlidesOffset();\n }\n\n if (!isVirtual && !params.cssMode && (params.effect === 'slide' || params.effect === 'fade')) {\n const backFaceHiddenClass = `${params.containerModifierClass}backface-hidden`;\n const hasClassBackfaceClassAdded = swiper.$el.hasClass(backFaceHiddenClass);\n\n if (slidesLength <= params.maxBackfaceHiddenSlides) {\n if (!hasClassBackfaceClassAdded) swiper.$el.addClass(backFaceHiddenClass);\n } else if (hasClassBackfaceClassAdded) {\n swiper.$el.removeClass(backFaceHiddenClass);\n }\n }\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/update/updateAutoHeight.js\n\nfunction updateAutoHeight(speed) {\n const swiper = this;\n const activeSlides = [];\n const isVirtual = swiper.virtual && swiper.params.virtual.enabled;\n let newHeight = 0;\n let i;\n\n if (typeof speed === 'number') {\n swiper.setTransition(speed);\n } else if (speed === true) {\n swiper.setTransition(swiper.params.speed);\n }\n\n const getSlideByIndex = index => {\n if (isVirtual) {\n return swiper.slides.filter(el => parseInt(el.getAttribute('data-swiper-slide-index'), 10) === index)[0];\n }\n\n return swiper.slides.eq(index)[0];\n }; // Find slides currently in view\n\n\n if (swiper.params.slidesPerView !== 'auto' && swiper.params.slidesPerView > 1) {\n if (swiper.params.centeredSlides) {\n (swiper.visibleSlides || dom([])).each(slide => {\n activeSlides.push(slide);\n });\n } else {\n for (i = 0; i < Math.ceil(swiper.params.slidesPerView); i += 1) {\n const index = swiper.activeIndex + i;\n if (index > swiper.slides.length && !isVirtual) break;\n activeSlides.push(getSlideByIndex(index));\n }\n }\n } else {\n activeSlides.push(getSlideByIndex(swiper.activeIndex));\n } // Find new height from highest slide in view\n\n\n for (i = 0; i < activeSlides.length; i += 1) {\n if (typeof activeSlides[i] !== 'undefined') {\n const height = activeSlides[i].offsetHeight;\n newHeight = height > newHeight ? height : newHeight;\n }\n } // Update Height\n\n\n if (newHeight || newHeight === 0) swiper.$wrapperEl.css('height', `${newHeight}px`);\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/update/updateSlidesOffset.js\nfunction updateSlidesOffset() {\n const swiper = this;\n const slides = swiper.slides;\n\n for (let i = 0; i < slides.length; i += 1) {\n slides[i].swiperSlideOffset = swiper.isHorizontal() ? slides[i].offsetLeft : slides[i].offsetTop;\n }\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/update/updateSlidesProgress.js\n\nfunction updateSlidesProgress(translate = this && this.translate || 0) {\n const swiper = this;\n const params = swiper.params;\n const {\n slides,\n rtlTranslate: rtl,\n snapGrid\n } = swiper;\n if (slides.length === 0) return;\n if (typeof slides[0].swiperSlideOffset === 'undefined') swiper.updateSlidesOffset();\n let offsetCenter = -translate;\n if (rtl) offsetCenter = translate; // Visible Slides\n\n slides.removeClass(params.slideVisibleClass);\n swiper.visibleSlidesIndexes = [];\n swiper.visibleSlides = [];\n\n for (let i = 0; i < slides.length; i += 1) {\n const slide = slides[i];\n let slideOffset = slide.swiperSlideOffset;\n\n if (params.cssMode && params.centeredSlides) {\n slideOffset -= slides[0].swiperSlideOffset;\n }\n\n const slideProgress = (offsetCenter + (params.centeredSlides ? swiper.minTranslate() : 0) - slideOffset) / (slide.swiperSlideSize + params.spaceBetween);\n const originalSlideProgress = (offsetCenter - snapGrid[0] + (params.centeredSlides ? swiper.minTranslate() : 0) - slideOffset) / (slide.swiperSlideSize + params.spaceBetween);\n const slideBefore = -(offsetCenter - slideOffset);\n const slideAfter = slideBefore + swiper.slidesSizesGrid[i];\n const isVisible = slideBefore >= 0 && slideBefore < swiper.size - 1 || slideAfter > 1 && slideAfter <= swiper.size || slideBefore <= 0 && slideAfter >= swiper.size;\n\n if (isVisible) {\n swiper.visibleSlides.push(slide);\n swiper.visibleSlidesIndexes.push(i);\n slides.eq(i).addClass(params.slideVisibleClass);\n }\n\n slide.progress = rtl ? -slideProgress : slideProgress;\n slide.originalProgress = rtl ? -originalSlideProgress : originalSlideProgress;\n }\n\n swiper.visibleSlides = dom(swiper.visibleSlides);\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/update/updateProgress.js\nfunction updateProgress(translate) {\n const swiper = this;\n\n if (typeof translate === 'undefined') {\n const multiplier = swiper.rtlTranslate ? -1 : 1; // eslint-disable-next-line\n\n translate = swiper && swiper.translate && swiper.translate * multiplier || 0;\n }\n\n const params = swiper.params;\n const translatesDiff = swiper.maxTranslate() - swiper.minTranslate();\n let {\n progress,\n isBeginning,\n isEnd\n } = swiper;\n const wasBeginning = isBeginning;\n const wasEnd = isEnd;\n\n if (translatesDiff === 0) {\n progress = 0;\n isBeginning = true;\n isEnd = true;\n } else {\n progress = (translate - swiper.minTranslate()) / translatesDiff;\n isBeginning = progress <= 0;\n isEnd = progress >= 1;\n }\n\n Object.assign(swiper, {\n progress,\n isBeginning,\n isEnd\n });\n if (params.watchSlidesProgress || params.centeredSlides && params.autoHeight) swiper.updateSlidesProgress(translate);\n\n if (isBeginning && !wasBeginning) {\n swiper.emit('reachBeginning toEdge');\n }\n\n if (isEnd && !wasEnd) {\n swiper.emit('reachEnd toEdge');\n }\n\n if (wasBeginning && !isBeginning || wasEnd && !isEnd) {\n swiper.emit('fromEdge');\n }\n\n swiper.emit('progress', progress);\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/update/updateSlidesClasses.js\nfunction updateSlidesClasses() {\n const swiper = this;\n const {\n slides,\n params,\n $wrapperEl,\n activeIndex,\n realIndex\n } = swiper;\n const isVirtual = swiper.virtual && params.virtual.enabled;\n slides.removeClass(`${params.slideActiveClass} ${params.slideNextClass} ${params.slidePrevClass} ${params.slideDuplicateActiveClass} ${params.slideDuplicateNextClass} ${params.slideDuplicatePrevClass}`);\n let activeSlide;\n\n if (isVirtual) {\n activeSlide = swiper.$wrapperEl.find(`.${params.slideClass}[data-swiper-slide-index=\"${activeIndex}\"]`);\n } else {\n activeSlide = slides.eq(activeIndex);\n } // Active classes\n\n\n activeSlide.addClass(params.slideActiveClass);\n\n if (params.loop) {\n // Duplicate to all looped slides\n if (activeSlide.hasClass(params.slideDuplicateClass)) {\n $wrapperEl.children(`.${params.slideClass}:not(.${params.slideDuplicateClass})[data-swiper-slide-index=\"${realIndex}\"]`).addClass(params.slideDuplicateActiveClass);\n } else {\n $wrapperEl.children(`.${params.slideClass}.${params.slideDuplicateClass}[data-swiper-slide-index=\"${realIndex}\"]`).addClass(params.slideDuplicateActiveClass);\n }\n } // Next Slide\n\n\n let nextSlide = activeSlide.nextAll(`.${params.slideClass}`).eq(0).addClass(params.slideNextClass);\n\n if (params.loop && nextSlide.length === 0) {\n nextSlide = slides.eq(0);\n nextSlide.addClass(params.slideNextClass);\n } // Prev Slide\n\n\n let prevSlide = activeSlide.prevAll(`.${params.slideClass}`).eq(0).addClass(params.slidePrevClass);\n\n if (params.loop && prevSlide.length === 0) {\n prevSlide = slides.eq(-1);\n prevSlide.addClass(params.slidePrevClass);\n }\n\n if (params.loop) {\n // Duplicate to all looped slides\n if (nextSlide.hasClass(params.slideDuplicateClass)) {\n $wrapperEl.children(`.${params.slideClass}:not(.${params.slideDuplicateClass})[data-swiper-slide-index=\"${nextSlide.attr('data-swiper-slide-index')}\"]`).addClass(params.slideDuplicateNextClass);\n } else {\n $wrapperEl.children(`.${params.slideClass}.${params.slideDuplicateClass}[data-swiper-slide-index=\"${nextSlide.attr('data-swiper-slide-index')}\"]`).addClass(params.slideDuplicateNextClass);\n }\n\n if (prevSlide.hasClass(params.slideDuplicateClass)) {\n $wrapperEl.children(`.${params.slideClass}:not(.${params.slideDuplicateClass})[data-swiper-slide-index=\"${prevSlide.attr('data-swiper-slide-index')}\"]`).addClass(params.slideDuplicatePrevClass);\n } else {\n $wrapperEl.children(`.${params.slideClass}.${params.slideDuplicateClass}[data-swiper-slide-index=\"${prevSlide.attr('data-swiper-slide-index')}\"]`).addClass(params.slideDuplicatePrevClass);\n }\n }\n\n swiper.emitSlidesClasses();\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/update/updateActiveIndex.js\nfunction updateActiveIndex(newActiveIndex) {\n const swiper = this;\n const translate = swiper.rtlTranslate ? swiper.translate : -swiper.translate;\n const {\n slidesGrid,\n snapGrid,\n params,\n activeIndex: previousIndex,\n realIndex: previousRealIndex,\n snapIndex: previousSnapIndex\n } = swiper;\n let activeIndex = newActiveIndex;\n let snapIndex;\n\n if (typeof activeIndex === 'undefined') {\n for (let i = 0; i < slidesGrid.length; i += 1) {\n if (typeof slidesGrid[i + 1] !== 'undefined') {\n if (translate >= slidesGrid[i] && translate < slidesGrid[i + 1] - (slidesGrid[i + 1] - slidesGrid[i]) / 2) {\n activeIndex = i;\n } else if (translate >= slidesGrid[i] && translate < slidesGrid[i + 1]) {\n activeIndex = i + 1;\n }\n } else if (translate >= slidesGrid[i]) {\n activeIndex = i;\n }\n } // Normalize slideIndex\n\n\n if (params.normalizeSlideIndex) {\n if (activeIndex < 0 || typeof activeIndex === 'undefined') activeIndex = 0;\n }\n }\n\n if (snapGrid.indexOf(translate) >= 0) {\n snapIndex = snapGrid.indexOf(translate);\n } else {\n const skip = Math.min(params.slidesPerGroupSkip, activeIndex);\n snapIndex = skip + Math.floor((activeIndex - skip) / params.slidesPerGroup);\n }\n\n if (snapIndex >= snapGrid.length) snapIndex = snapGrid.length - 1;\n\n if (activeIndex === previousIndex) {\n if (snapIndex !== previousSnapIndex) {\n swiper.snapIndex = snapIndex;\n swiper.emit('snapIndexChange');\n }\n\n return;\n } // Get real index\n\n\n const realIndex = parseInt(swiper.slides.eq(activeIndex).attr('data-swiper-slide-index') || activeIndex, 10);\n Object.assign(swiper, {\n snapIndex,\n realIndex,\n previousIndex,\n activeIndex\n });\n swiper.emit('activeIndexChange');\n swiper.emit('snapIndexChange');\n\n if (previousRealIndex !== realIndex) {\n swiper.emit('realIndexChange');\n }\n\n if (swiper.initialized || swiper.params.runCallbacksOnInit) {\n swiper.emit('slideChange');\n }\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/update/updateClickedSlide.js\n\nfunction updateClickedSlide(e) {\n const swiper = this;\n const params = swiper.params;\n const slide = dom(e).closest(`.${params.slideClass}`)[0];\n let slideFound = false;\n let slideIndex;\n\n if (slide) {\n for (let i = 0; i < swiper.slides.length; i += 1) {\n if (swiper.slides[i] === slide) {\n slideFound = true;\n slideIndex = i;\n break;\n }\n }\n }\n\n if (slide && slideFound) {\n swiper.clickedSlide = slide;\n\n if (swiper.virtual && swiper.params.virtual.enabled) {\n swiper.clickedIndex = parseInt(dom(slide).attr('data-swiper-slide-index'), 10);\n } else {\n swiper.clickedIndex = slideIndex;\n }\n } else {\n swiper.clickedSlide = undefined;\n swiper.clickedIndex = undefined;\n return;\n }\n\n if (params.slideToClickedSlide && swiper.clickedIndex !== undefined && swiper.clickedIndex !== swiper.activeIndex) {\n swiper.slideToClickedSlide();\n }\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/update/index.js\n\n\n\n\n\n\n\n\n\n/* harmony default export */ const update = ({\n updateSize: updateSize,\n updateSlides: updateSlides,\n updateAutoHeight: updateAutoHeight,\n updateSlidesOffset: updateSlidesOffset,\n updateSlidesProgress: updateSlidesProgress,\n updateProgress: updateProgress,\n updateSlidesClasses: updateSlidesClasses,\n updateActiveIndex: updateActiveIndex,\n updateClickedSlide: updateClickedSlide\n});\n;// CONCATENATED MODULE: ./node_modules/swiper/core/translate/getTranslate.js\n\nfunction getSwiperTranslate(axis = this.isHorizontal() ? 'x' : 'y') {\n const swiper = this;\n const {\n params,\n rtlTranslate: rtl,\n translate,\n $wrapperEl\n } = swiper;\n\n if (params.virtualTranslate) {\n return rtl ? -translate : translate;\n }\n\n if (params.cssMode) {\n return translate;\n }\n\n let currentTranslate = utils_getTranslate($wrapperEl[0], axis);\n if (rtl) currentTranslate = -currentTranslate;\n return currentTranslate || 0;\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/translate/setTranslate.js\nfunction setTranslate(translate, byController) {\n const swiper = this;\n const {\n rtlTranslate: rtl,\n params,\n $wrapperEl,\n wrapperEl,\n progress\n } = swiper;\n let x = 0;\n let y = 0;\n const z = 0;\n\n if (swiper.isHorizontal()) {\n x = rtl ? -translate : translate;\n } else {\n y = translate;\n }\n\n if (params.roundLengths) {\n x = Math.floor(x);\n y = Math.floor(y);\n }\n\n if (params.cssMode) {\n wrapperEl[swiper.isHorizontal() ? 'scrollLeft' : 'scrollTop'] = swiper.isHorizontal() ? -x : -y;\n } else if (!params.virtualTranslate) {\n $wrapperEl.transform(`translate3d(${x}px, ${y}px, ${z}px)`);\n }\n\n swiper.previousTranslate = swiper.translate;\n swiper.translate = swiper.isHorizontal() ? x : y; // Check if we need to update progress\n\n let newProgress;\n const translatesDiff = swiper.maxTranslate() - swiper.minTranslate();\n\n if (translatesDiff === 0) {\n newProgress = 0;\n } else {\n newProgress = (translate - swiper.minTranslate()) / translatesDiff;\n }\n\n if (newProgress !== progress) {\n swiper.updateProgress(translate);\n }\n\n swiper.emit('setTranslate', swiper.translate, byController);\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/translate/minTranslate.js\nfunction minTranslate() {\n return -this.snapGrid[0];\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/translate/maxTranslate.js\nfunction maxTranslate() {\n return -this.snapGrid[this.snapGrid.length - 1];\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/translate/translateTo.js\n\nfunction translateTo(translate = 0, speed = this.params.speed, runCallbacks = true, translateBounds = true, internal) {\n const swiper = this;\n const {\n params,\n wrapperEl\n } = swiper;\n\n if (swiper.animating && params.preventInteractionOnTransition) {\n return false;\n }\n\n const minTranslate = swiper.minTranslate();\n const maxTranslate = swiper.maxTranslate();\n let newTranslate;\n if (translateBounds && translate > minTranslate) newTranslate = minTranslate;else if (translateBounds && translate < maxTranslate) newTranslate = maxTranslate;else newTranslate = translate; // Update progress\n\n swiper.updateProgress(newTranslate);\n\n if (params.cssMode) {\n const isH = swiper.isHorizontal();\n\n if (speed === 0) {\n wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = -newTranslate;\n } else {\n if (!swiper.support.smoothScroll) {\n animateCSSModeScroll({\n swiper,\n targetPosition: -newTranslate,\n side: isH ? 'left' : 'top'\n });\n return true;\n }\n\n wrapperEl.scrollTo({\n [isH ? 'left' : 'top']: -newTranslate,\n behavior: 'smooth'\n });\n }\n\n return true;\n }\n\n if (speed === 0) {\n swiper.setTransition(0);\n swiper.setTranslate(newTranslate);\n\n if (runCallbacks) {\n swiper.emit('beforeTransitionStart', speed, internal);\n swiper.emit('transitionEnd');\n }\n } else {\n swiper.setTransition(speed);\n swiper.setTranslate(newTranslate);\n\n if (runCallbacks) {\n swiper.emit('beforeTransitionStart', speed, internal);\n swiper.emit('transitionStart');\n }\n\n if (!swiper.animating) {\n swiper.animating = true;\n\n if (!swiper.onTranslateToWrapperTransitionEnd) {\n swiper.onTranslateToWrapperTransitionEnd = function transitionEnd(e) {\n if (!swiper || swiper.destroyed) return;\n if (e.target !== this) return;\n swiper.$wrapperEl[0].removeEventListener('transitionend', swiper.onTranslateToWrapperTransitionEnd);\n swiper.$wrapperEl[0].removeEventListener('webkitTransitionEnd', swiper.onTranslateToWrapperTransitionEnd);\n swiper.onTranslateToWrapperTransitionEnd = null;\n delete swiper.onTranslateToWrapperTransitionEnd;\n\n if (runCallbacks) {\n swiper.emit('transitionEnd');\n }\n };\n }\n\n swiper.$wrapperEl[0].addEventListener('transitionend', swiper.onTranslateToWrapperTransitionEnd);\n swiper.$wrapperEl[0].addEventListener('webkitTransitionEnd', swiper.onTranslateToWrapperTransitionEnd);\n }\n }\n\n return true;\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/translate/index.js\n\n\n\n\n\n/* harmony default export */ const translate = ({\n getTranslate: getSwiperTranslate,\n setTranslate: setTranslate,\n minTranslate: minTranslate,\n maxTranslate: maxTranslate,\n translateTo: translateTo\n});\n;// CONCATENATED MODULE: ./node_modules/swiper/core/transition/setTransition.js\nfunction setTransition(duration, byController) {\n const swiper = this;\n\n if (!swiper.params.cssMode) {\n swiper.$wrapperEl.transition(duration);\n }\n\n swiper.emit('setTransition', duration, byController);\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/transition/transitionEmit.js\nfunction transitionEmit({\n swiper,\n runCallbacks,\n direction,\n step\n}) {\n const {\n activeIndex,\n previousIndex\n } = swiper;\n let dir = direction;\n\n if (!dir) {\n if (activeIndex > previousIndex) dir = 'next';else if (activeIndex < previousIndex) dir = 'prev';else dir = 'reset';\n }\n\n swiper.emit(`transition${step}`);\n\n if (runCallbacks && activeIndex !== previousIndex) {\n if (dir === 'reset') {\n swiper.emit(`slideResetTransition${step}`);\n return;\n }\n\n swiper.emit(`slideChangeTransition${step}`);\n\n if (dir === 'next') {\n swiper.emit(`slideNextTransition${step}`);\n } else {\n swiper.emit(`slidePrevTransition${step}`);\n }\n }\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/transition/transitionStart.js\n\nfunction transitionStart_transitionStart(runCallbacks = true, direction) {\n const swiper = this;\n const {\n params\n } = swiper;\n if (params.cssMode) return;\n\n if (params.autoHeight) {\n swiper.updateAutoHeight();\n }\n\n transitionEmit({\n swiper,\n runCallbacks,\n direction,\n step: 'Start'\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/transition/transitionEnd.js\n\nfunction transitionEnd_transitionEnd(runCallbacks = true, direction) {\n const swiper = this;\n const {\n params\n } = swiper;\n swiper.animating = false;\n if (params.cssMode) return;\n swiper.setTransition(0);\n transitionEmit({\n swiper,\n runCallbacks,\n direction,\n step: 'End'\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/transition/index.js\n\n\n\n/* harmony default export */ const core_transition = ({\n setTransition: setTransition,\n transitionStart: transitionStart_transitionStart,\n transitionEnd: transitionEnd_transitionEnd\n});\n;// CONCATENATED MODULE: ./node_modules/swiper/core/slide/slideTo.js\n\nfunction slideTo(index = 0, speed = this.params.speed, runCallbacks = true, internal, initial) {\n if (typeof index !== 'number' && typeof index !== 'string') {\n throw new Error(`The 'index' argument cannot have type other than 'number' or 'string'. [${typeof index}] given.`);\n }\n\n if (typeof index === 'string') {\n /**\n * The `index` argument converted from `string` to `number`.\n * @type {number}\n */\n const indexAsNumber = parseInt(index, 10);\n /**\n * Determines whether the `index` argument is a valid `number`\n * after being converted from the `string` type.\n * @type {boolean}\n */\n\n const isValidNumber = isFinite(indexAsNumber);\n\n if (!isValidNumber) {\n throw new Error(`The passed-in 'index' (string) couldn't be converted to 'number'. [${index}] given.`);\n } // Knowing that the converted `index` is a valid number,\n // we can update the original argument's value.\n\n\n index = indexAsNumber;\n }\n\n const swiper = this;\n let slideIndex = index;\n if (slideIndex < 0) slideIndex = 0;\n const {\n params,\n snapGrid,\n slidesGrid,\n previousIndex,\n activeIndex,\n rtlTranslate: rtl,\n wrapperEl,\n enabled\n } = swiper;\n\n if (swiper.animating && params.preventInteractionOnTransition || !enabled && !internal && !initial) {\n return false;\n }\n\n const skip = Math.min(swiper.params.slidesPerGroupSkip, slideIndex);\n let snapIndex = skip + Math.floor((slideIndex - skip) / swiper.params.slidesPerGroup);\n if (snapIndex >= snapGrid.length) snapIndex = snapGrid.length - 1;\n const translate = -snapGrid[snapIndex]; // Normalize slideIndex\n\n if (params.normalizeSlideIndex) {\n for (let i = 0; i < slidesGrid.length; i += 1) {\n const normalizedTranslate = -Math.floor(translate * 100);\n const normalizedGrid = Math.floor(slidesGrid[i] * 100);\n const normalizedGridNext = Math.floor(slidesGrid[i + 1] * 100);\n\n if (typeof slidesGrid[i + 1] !== 'undefined') {\n if (normalizedTranslate >= normalizedGrid && normalizedTranslate < normalizedGridNext - (normalizedGridNext - normalizedGrid) / 2) {\n slideIndex = i;\n } else if (normalizedTranslate >= normalizedGrid && normalizedTranslate < normalizedGridNext) {\n slideIndex = i + 1;\n }\n } else if (normalizedTranslate >= normalizedGrid) {\n slideIndex = i;\n }\n }\n } // Directions locks\n\n\n if (swiper.initialized && slideIndex !== activeIndex) {\n if (!swiper.allowSlideNext && translate < swiper.translate && translate < swiper.minTranslate()) {\n return false;\n }\n\n if (!swiper.allowSlidePrev && translate > swiper.translate && translate > swiper.maxTranslate()) {\n if ((activeIndex || 0) !== slideIndex) return false;\n }\n }\n\n if (slideIndex !== (previousIndex || 0) && runCallbacks) {\n swiper.emit('beforeSlideChangeStart');\n } // Update progress\n\n\n swiper.updateProgress(translate);\n let direction;\n if (slideIndex > activeIndex) direction = 'next';else if (slideIndex < activeIndex) direction = 'prev';else direction = 'reset'; // Update Index\n\n if (rtl && -translate === swiper.translate || !rtl && translate === swiper.translate) {\n swiper.updateActiveIndex(slideIndex); // Update Height\n\n if (params.autoHeight) {\n swiper.updateAutoHeight();\n }\n\n swiper.updateSlidesClasses();\n\n if (params.effect !== 'slide') {\n swiper.setTranslate(translate);\n }\n\n if (direction !== 'reset') {\n swiper.transitionStart(runCallbacks, direction);\n swiper.transitionEnd(runCallbacks, direction);\n }\n\n return false;\n }\n\n if (params.cssMode) {\n const isH = swiper.isHorizontal();\n const t = rtl ? translate : -translate;\n\n if (speed === 0) {\n const isVirtual = swiper.virtual && swiper.params.virtual.enabled;\n\n if (isVirtual) {\n swiper.wrapperEl.style.scrollSnapType = 'none';\n swiper._immediateVirtual = true;\n }\n\n wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = t;\n\n if (isVirtual) {\n requestAnimationFrame(() => {\n swiper.wrapperEl.style.scrollSnapType = '';\n swiper._swiperImmediateVirtual = false;\n });\n }\n } else {\n if (!swiper.support.smoothScroll) {\n animateCSSModeScroll({\n swiper,\n targetPosition: t,\n side: isH ? 'left' : 'top'\n });\n return true;\n }\n\n wrapperEl.scrollTo({\n [isH ? 'left' : 'top']: t,\n behavior: 'smooth'\n });\n }\n\n return true;\n }\n\n swiper.setTransition(speed);\n swiper.setTranslate(translate);\n swiper.updateActiveIndex(slideIndex);\n swiper.updateSlidesClasses();\n swiper.emit('beforeTransitionStart', speed, internal);\n swiper.transitionStart(runCallbacks, direction);\n\n if (speed === 0) {\n swiper.transitionEnd(runCallbacks, direction);\n } else if (!swiper.animating) {\n swiper.animating = true;\n\n if (!swiper.onSlideToWrapperTransitionEnd) {\n swiper.onSlideToWrapperTransitionEnd = function transitionEnd(e) {\n if (!swiper || swiper.destroyed) return;\n if (e.target !== this) return;\n swiper.$wrapperEl[0].removeEventListener('transitionend', swiper.onSlideToWrapperTransitionEnd);\n swiper.$wrapperEl[0].removeEventListener('webkitTransitionEnd', swiper.onSlideToWrapperTransitionEnd);\n swiper.onSlideToWrapperTransitionEnd = null;\n delete swiper.onSlideToWrapperTransitionEnd;\n swiper.transitionEnd(runCallbacks, direction);\n };\n }\n\n swiper.$wrapperEl[0].addEventListener('transitionend', swiper.onSlideToWrapperTransitionEnd);\n swiper.$wrapperEl[0].addEventListener('webkitTransitionEnd', swiper.onSlideToWrapperTransitionEnd);\n }\n\n return true;\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/slide/slideToLoop.js\nfunction slideToLoop(index = 0, speed = this.params.speed, runCallbacks = true, internal) {\n if (typeof index === 'string') {\n /**\n * The `index` argument converted from `string` to `number`.\n * @type {number}\n */\n const indexAsNumber = parseInt(index, 10);\n /**\n * Determines whether the `index` argument is a valid `number`\n * after being converted from the `string` type.\n * @type {boolean}\n */\n\n const isValidNumber = isFinite(indexAsNumber);\n\n if (!isValidNumber) {\n throw new Error(`The passed-in 'index' (string) couldn't be converted to 'number'. [${index}] given.`);\n } // Knowing that the converted `index` is a valid number,\n // we can update the original argument's value.\n\n\n index = indexAsNumber;\n }\n\n const swiper = this;\n let newIndex = index;\n\n if (swiper.params.loop) {\n newIndex += swiper.loopedSlides;\n }\n\n return swiper.slideTo(newIndex, speed, runCallbacks, internal);\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/slide/slideNext.js\n/* eslint no-unused-vars: \"off\" */\nfunction slideNext(speed = this.params.speed, runCallbacks = true, internal) {\n const swiper = this;\n const {\n animating,\n enabled,\n params\n } = swiper;\n if (!enabled) return swiper;\n let perGroup = params.slidesPerGroup;\n\n if (params.slidesPerView === 'auto' && params.slidesPerGroup === 1 && params.slidesPerGroupAuto) {\n perGroup = Math.max(swiper.slidesPerViewDynamic('current', true), 1);\n }\n\n const increment = swiper.activeIndex < params.slidesPerGroupSkip ? 1 : perGroup;\n\n if (params.loop) {\n if (animating && params.loopPreventsSlide) return false;\n swiper.loopFix(); // eslint-disable-next-line\n\n swiper._clientLeft = swiper.$wrapperEl[0].clientLeft;\n }\n\n if (params.rewind && swiper.isEnd) {\n return swiper.slideTo(0, speed, runCallbacks, internal);\n }\n\n return swiper.slideTo(swiper.activeIndex + increment, speed, runCallbacks, internal);\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/slide/slidePrev.js\n/* eslint no-unused-vars: \"off\" */\nfunction slidePrev(speed = this.params.speed, runCallbacks = true, internal) {\n const swiper = this;\n const {\n params,\n animating,\n snapGrid,\n slidesGrid,\n rtlTranslate,\n enabled\n } = swiper;\n if (!enabled) return swiper;\n\n if (params.loop) {\n if (animating && params.loopPreventsSlide) return false;\n swiper.loopFix(); // eslint-disable-next-line\n\n swiper._clientLeft = swiper.$wrapperEl[0].clientLeft;\n }\n\n const translate = rtlTranslate ? swiper.translate : -swiper.translate;\n\n function normalize(val) {\n if (val < 0) return -Math.floor(Math.abs(val));\n return Math.floor(val);\n }\n\n const normalizedTranslate = normalize(translate);\n const normalizedSnapGrid = snapGrid.map(val => normalize(val));\n let prevSnap = snapGrid[normalizedSnapGrid.indexOf(normalizedTranslate) - 1];\n\n if (typeof prevSnap === 'undefined' && params.cssMode) {\n let prevSnapIndex;\n snapGrid.forEach((snap, snapIndex) => {\n if (normalizedTranslate >= snap) {\n // prevSnap = snap;\n prevSnapIndex = snapIndex;\n }\n });\n\n if (typeof prevSnapIndex !== 'undefined') {\n prevSnap = snapGrid[prevSnapIndex > 0 ? prevSnapIndex - 1 : prevSnapIndex];\n }\n }\n\n let prevIndex = 0;\n\n if (typeof prevSnap !== 'undefined') {\n prevIndex = slidesGrid.indexOf(prevSnap);\n if (prevIndex < 0) prevIndex = swiper.activeIndex - 1;\n\n if (params.slidesPerView === 'auto' && params.slidesPerGroup === 1 && params.slidesPerGroupAuto) {\n prevIndex = prevIndex - swiper.slidesPerViewDynamic('previous', true) + 1;\n prevIndex = Math.max(prevIndex, 0);\n }\n }\n\n if (params.rewind && swiper.isBeginning) {\n const lastIndex = swiper.params.virtual && swiper.params.virtual.enabled && swiper.virtual ? swiper.virtual.slides.length - 1 : swiper.slides.length - 1;\n return swiper.slideTo(lastIndex, speed, runCallbacks, internal);\n }\n\n return swiper.slideTo(prevIndex, speed, runCallbacks, internal);\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/slide/slideReset.js\n/* eslint no-unused-vars: \"off\" */\nfunction slideReset(speed = this.params.speed, runCallbacks = true, internal) {\n const swiper = this;\n return swiper.slideTo(swiper.activeIndex, speed, runCallbacks, internal);\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/slide/slideToClosest.js\n/* eslint no-unused-vars: \"off\" */\nfunction slideToClosest(speed = this.params.speed, runCallbacks = true, internal, threshold = 0.5) {\n const swiper = this;\n let index = swiper.activeIndex;\n const skip = Math.min(swiper.params.slidesPerGroupSkip, index);\n const snapIndex = skip + Math.floor((index - skip) / swiper.params.slidesPerGroup);\n const translate = swiper.rtlTranslate ? swiper.translate : -swiper.translate;\n\n if (translate >= swiper.snapGrid[snapIndex]) {\n // The current translate is on or after the current snap index, so the choice\n // is between the current index and the one after it.\n const currentSnap = swiper.snapGrid[snapIndex];\n const nextSnap = swiper.snapGrid[snapIndex + 1];\n\n if (translate - currentSnap > (nextSnap - currentSnap) * threshold) {\n index += swiper.params.slidesPerGroup;\n }\n } else {\n // The current translate is before the current snap index, so the choice\n // is between the current index and the one before it.\n const prevSnap = swiper.snapGrid[snapIndex - 1];\n const currentSnap = swiper.snapGrid[snapIndex];\n\n if (translate - prevSnap <= (currentSnap - prevSnap) * threshold) {\n index -= swiper.params.slidesPerGroup;\n }\n }\n\n index = Math.max(index, 0);\n index = Math.min(index, swiper.slidesGrid.length - 1);\n return swiper.slideTo(index, speed, runCallbacks, internal);\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/slide/slideToClickedSlide.js\n\n\nfunction slideToClickedSlide() {\n const swiper = this;\n const {\n params,\n $wrapperEl\n } = swiper;\n const slidesPerView = params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : params.slidesPerView;\n let slideToIndex = swiper.clickedIndex;\n let realIndex;\n\n if (params.loop) {\n if (swiper.animating) return;\n realIndex = parseInt(dom(swiper.clickedSlide).attr('data-swiper-slide-index'), 10);\n\n if (params.centeredSlides) {\n if (slideToIndex < swiper.loopedSlides - slidesPerView / 2 || slideToIndex > swiper.slides.length - swiper.loopedSlides + slidesPerView / 2) {\n swiper.loopFix();\n slideToIndex = $wrapperEl.children(`.${params.slideClass}[data-swiper-slide-index=\"${realIndex}\"]:not(.${params.slideDuplicateClass})`).eq(0).index();\n utils_nextTick(() => {\n swiper.slideTo(slideToIndex);\n });\n } else {\n swiper.slideTo(slideToIndex);\n }\n } else if (slideToIndex > swiper.slides.length - slidesPerView) {\n swiper.loopFix();\n slideToIndex = $wrapperEl.children(`.${params.slideClass}[data-swiper-slide-index=\"${realIndex}\"]:not(.${params.slideDuplicateClass})`).eq(0).index();\n utils_nextTick(() => {\n swiper.slideTo(slideToIndex);\n });\n } else {\n swiper.slideTo(slideToIndex);\n }\n } else {\n swiper.slideTo(slideToIndex);\n }\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/slide/index.js\n\n\n\n\n\n\n\n/* harmony default export */ const slide = ({\n slideTo: slideTo,\n slideToLoop: slideToLoop,\n slideNext: slideNext,\n slidePrev: slidePrev,\n slideReset: slideReset,\n slideToClosest: slideToClosest,\n slideToClickedSlide: slideToClickedSlide\n});\n;// CONCATENATED MODULE: ./node_modules/swiper/core/loop/loopCreate.js\n\n\nfunction loopCreate() {\n const swiper = this;\n const document = ssr_window_esm_getDocument();\n const {\n params,\n $wrapperEl\n } = swiper; // Remove duplicated slides\n\n const $selector = $wrapperEl.children().length > 0 ? dom($wrapperEl.children()[0].parentNode) : $wrapperEl;\n $selector.children(`.${params.slideClass}.${params.slideDuplicateClass}`).remove();\n let slides = $selector.children(`.${params.slideClass}`);\n\n if (params.loopFillGroupWithBlank) {\n const blankSlidesNum = params.slidesPerGroup - slides.length % params.slidesPerGroup;\n\n if (blankSlidesNum !== params.slidesPerGroup) {\n for (let i = 0; i < blankSlidesNum; i += 1) {\n const blankNode = dom(document.createElement('div')).addClass(`${params.slideClass} ${params.slideBlankClass}`);\n $selector.append(blankNode);\n }\n\n slides = $selector.children(`.${params.slideClass}`);\n }\n }\n\n if (params.slidesPerView === 'auto' && !params.loopedSlides) params.loopedSlides = slides.length;\n swiper.loopedSlides = Math.ceil(parseFloat(params.loopedSlides || params.slidesPerView, 10));\n swiper.loopedSlides += params.loopAdditionalSlides;\n\n if (swiper.loopedSlides > slides.length && swiper.params.loopedSlidesLimit) {\n swiper.loopedSlides = slides.length;\n }\n\n const prependSlides = [];\n const appendSlides = [];\n slides.each((el, index) => {\n const slide = dom(el);\n slide.attr('data-swiper-slide-index', index);\n });\n\n for (let i = 0; i < swiper.loopedSlides; i += 1) {\n const index = i - Math.floor(i / slides.length) * slides.length;\n appendSlides.push(slides.eq(index)[0]);\n prependSlides.unshift(slides.eq(slides.length - index - 1)[0]);\n }\n\n for (let i = 0; i < appendSlides.length; i += 1) {\n $selector.append(dom(appendSlides[i].cloneNode(true)).addClass(params.slideDuplicateClass));\n }\n\n for (let i = prependSlides.length - 1; i >= 0; i -= 1) {\n $selector.prepend(dom(prependSlides[i].cloneNode(true)).addClass(params.slideDuplicateClass));\n }\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/loop/loopFix.js\nfunction loopFix() {\n const swiper = this;\n swiper.emit('beforeLoopFix');\n const {\n activeIndex,\n slides,\n loopedSlides,\n allowSlidePrev,\n allowSlideNext,\n snapGrid,\n rtlTranslate: rtl\n } = swiper;\n let newIndex;\n swiper.allowSlidePrev = true;\n swiper.allowSlideNext = true;\n const snapTranslate = -snapGrid[activeIndex];\n const diff = snapTranslate - swiper.getTranslate(); // Fix For Negative Oversliding\n\n if (activeIndex < loopedSlides) {\n newIndex = slides.length - loopedSlides * 3 + activeIndex;\n newIndex += loopedSlides;\n const slideChanged = swiper.slideTo(newIndex, 0, false, true);\n\n if (slideChanged && diff !== 0) {\n swiper.setTranslate((rtl ? -swiper.translate : swiper.translate) - diff);\n }\n } else if (activeIndex >= slides.length - loopedSlides) {\n // Fix For Positive Oversliding\n newIndex = -slides.length + activeIndex + loopedSlides;\n newIndex += loopedSlides;\n const slideChanged = swiper.slideTo(newIndex, 0, false, true);\n\n if (slideChanged && diff !== 0) {\n swiper.setTranslate((rtl ? -swiper.translate : swiper.translate) - diff);\n }\n }\n\n swiper.allowSlidePrev = allowSlidePrev;\n swiper.allowSlideNext = allowSlideNext;\n swiper.emit('loopFix');\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/loop/loopDestroy.js\nfunction loopDestroy() {\n const swiper = this;\n const {\n $wrapperEl,\n params,\n slides\n } = swiper;\n $wrapperEl.children(`.${params.slideClass}.${params.slideDuplicateClass},.${params.slideClass}.${params.slideBlankClass}`).remove();\n slides.removeAttr('data-swiper-slide-index');\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/loop/index.js\n\n\n\n/* harmony default export */ const loop = ({\n loopCreate: loopCreate,\n loopFix: loopFix,\n loopDestroy: loopDestroy\n});\n;// CONCATENATED MODULE: ./node_modules/swiper/core/grab-cursor/setGrabCursor.js\nfunction setGrabCursor(moving) {\n const swiper = this;\n if (swiper.support.touch || !swiper.params.simulateTouch || swiper.params.watchOverflow && swiper.isLocked || swiper.params.cssMode) return;\n const el = swiper.params.touchEventsTarget === 'container' ? swiper.el : swiper.wrapperEl;\n el.style.cursor = 'move';\n el.style.cursor = moving ? 'grabbing' : 'grab';\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/grab-cursor/unsetGrabCursor.js\nfunction unsetGrabCursor() {\n const swiper = this;\n\n if (swiper.support.touch || swiper.params.watchOverflow && swiper.isLocked || swiper.params.cssMode) {\n return;\n }\n\n swiper[swiper.params.touchEventsTarget === 'container' ? 'el' : 'wrapperEl'].style.cursor = '';\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/grab-cursor/index.js\n\n\n/* harmony default export */ const grab_cursor = ({\n setGrabCursor: setGrabCursor,\n unsetGrabCursor: unsetGrabCursor\n});\n;// CONCATENATED MODULE: ./node_modules/swiper/core/events/onTouchStart.js\n\n\n // Modified from https://stackoverflow.com/questions/54520554/custom-element-getrootnode-closest-function-crossing-multiple-parent-shadowd\n\nfunction closestElement(selector, base = this) {\n function __closestFrom(el) {\n if (!el || el === ssr_window_esm_getDocument() || el === ssr_window_esm_getWindow()) return null;\n if (el.assignedSlot) el = el.assignedSlot;\n const found = el.closest(selector);\n\n if (!found && !el.getRootNode) {\n return null;\n }\n\n return found || __closestFrom(el.getRootNode().host);\n }\n\n return __closestFrom(base);\n}\n\nfunction onTouchStart(event) {\n const swiper = this;\n const document = ssr_window_esm_getDocument();\n const window = ssr_window_esm_getWindow();\n const data = swiper.touchEventsData;\n const {\n params,\n touches,\n enabled\n } = swiper;\n if (!enabled) return;\n\n if (swiper.animating && params.preventInteractionOnTransition) {\n return;\n }\n\n if (!swiper.animating && params.cssMode && params.loop) {\n swiper.loopFix();\n }\n\n let e = event;\n if (e.originalEvent) e = e.originalEvent;\n let $targetEl = dom(e.target);\n\n if (params.touchEventsTarget === 'wrapper') {\n if (!$targetEl.closest(swiper.wrapperEl).length) return;\n }\n\n data.isTouchEvent = e.type === 'touchstart';\n if (!data.isTouchEvent && 'which' in e && e.which === 3) return;\n if (!data.isTouchEvent && 'button' in e && e.button > 0) return;\n if (data.isTouched && data.isMoved) return; // change target el for shadow root component\n\n const swipingClassHasValue = !!params.noSwipingClass && params.noSwipingClass !== ''; // eslint-disable-next-line\n\n const eventPath = event.composedPath ? event.composedPath() : event.path;\n\n if (swipingClassHasValue && e.target && e.target.shadowRoot && eventPath) {\n $targetEl = dom(eventPath[0]);\n }\n\n const noSwipingSelector = params.noSwipingSelector ? params.noSwipingSelector : `.${params.noSwipingClass}`;\n const isTargetShadow = !!(e.target && e.target.shadowRoot); // use closestElement for shadow root element to get the actual closest for nested shadow root element\n\n if (params.noSwiping && (isTargetShadow ? closestElement(noSwipingSelector, $targetEl[0]) : $targetEl.closest(noSwipingSelector)[0])) {\n swiper.allowClick = true;\n return;\n }\n\n if (params.swipeHandler) {\n if (!$targetEl.closest(params.swipeHandler)[0]) return;\n }\n\n touches.currentX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;\n touches.currentY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;\n const startX = touches.currentX;\n const startY = touches.currentY; // Do NOT start if iOS edge swipe is detected. Otherwise iOS app cannot swipe-to-go-back anymore\n\n const edgeSwipeDetection = params.edgeSwipeDetection || params.iOSEdgeSwipeDetection;\n const edgeSwipeThreshold = params.edgeSwipeThreshold || params.iOSEdgeSwipeThreshold;\n\n if (edgeSwipeDetection && (startX <= edgeSwipeThreshold || startX >= window.innerWidth - edgeSwipeThreshold)) {\n if (edgeSwipeDetection === 'prevent') {\n event.preventDefault();\n } else {\n return;\n }\n }\n\n Object.assign(data, {\n isTouched: true,\n isMoved: false,\n allowTouchCallbacks: true,\n isScrolling: undefined,\n startMoving: undefined\n });\n touches.startX = startX;\n touches.startY = startY;\n data.touchStartTime = utils_now();\n swiper.allowClick = true;\n swiper.updateSize();\n swiper.swipeDirection = undefined;\n if (params.threshold > 0) data.allowThresholdMove = false;\n\n if (e.type !== 'touchstart') {\n let preventDefault = true;\n\n if ($targetEl.is(data.focusableElements)) {\n preventDefault = false;\n\n if ($targetEl[0].nodeName === 'SELECT') {\n data.isTouched = false;\n }\n }\n\n if (document.activeElement && dom(document.activeElement).is(data.focusableElements) && document.activeElement !== $targetEl[0]) {\n document.activeElement.blur();\n }\n\n const shouldPreventDefault = preventDefault && swiper.allowTouchMove && params.touchStartPreventDefault;\n\n if ((params.touchStartForcePreventDefault || shouldPreventDefault) && !$targetEl[0].isContentEditable) {\n e.preventDefault();\n }\n }\n\n if (swiper.params.freeMode && swiper.params.freeMode.enabled && swiper.freeMode && swiper.animating && !params.cssMode) {\n swiper.freeMode.onTouchStart();\n }\n\n swiper.emit('touchStart', e);\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/events/onTouchMove.js\n\n\n\nfunction onTouchMove(event) {\n const document = ssr_window_esm_getDocument();\n const swiper = this;\n const data = swiper.touchEventsData;\n const {\n params,\n touches,\n rtlTranslate: rtl,\n enabled\n } = swiper;\n if (!enabled) return;\n let e = event;\n if (e.originalEvent) e = e.originalEvent;\n\n if (!data.isTouched) {\n if (data.startMoving && data.isScrolling) {\n swiper.emit('touchMoveOpposite', e);\n }\n\n return;\n }\n\n if (data.isTouchEvent && e.type !== 'touchmove') return;\n const targetTouch = e.type === 'touchmove' && e.targetTouches && (e.targetTouches[0] || e.changedTouches[0]);\n const pageX = e.type === 'touchmove' ? targetTouch.pageX : e.pageX;\n const pageY = e.type === 'touchmove' ? targetTouch.pageY : e.pageY;\n\n if (e.preventedByNestedSwiper) {\n touches.startX = pageX;\n touches.startY = pageY;\n return;\n }\n\n if (!swiper.allowTouchMove) {\n if (!dom(e.target).is(data.focusableElements)) {\n swiper.allowClick = false;\n }\n\n if (data.isTouched) {\n Object.assign(touches, {\n startX: pageX,\n startY: pageY,\n currentX: pageX,\n currentY: pageY\n });\n data.touchStartTime = utils_now();\n }\n\n return;\n }\n\n if (data.isTouchEvent && params.touchReleaseOnEdges && !params.loop) {\n if (swiper.isVertical()) {\n // Vertical\n if (pageY < touches.startY && swiper.translate <= swiper.maxTranslate() || pageY > touches.startY && swiper.translate >= swiper.minTranslate()) {\n data.isTouched = false;\n data.isMoved = false;\n return;\n }\n } else if (pageX < touches.startX && swiper.translate <= swiper.maxTranslate() || pageX > touches.startX && swiper.translate >= swiper.minTranslate()) {\n return;\n }\n }\n\n if (data.isTouchEvent && document.activeElement) {\n if (e.target === document.activeElement && dom(e.target).is(data.focusableElements)) {\n data.isMoved = true;\n swiper.allowClick = false;\n return;\n }\n }\n\n if (data.allowTouchCallbacks) {\n swiper.emit('touchMove', e);\n }\n\n if (e.targetTouches && e.targetTouches.length > 1) return;\n touches.currentX = pageX;\n touches.currentY = pageY;\n const diffX = touches.currentX - touches.startX;\n const diffY = touches.currentY - touches.startY;\n if (swiper.params.threshold && Math.sqrt(diffX ** 2 + diffY ** 2) < swiper.params.threshold) return;\n\n if (typeof data.isScrolling === 'undefined') {\n let touchAngle;\n\n if (swiper.isHorizontal() && touches.currentY === touches.startY || swiper.isVertical() && touches.currentX === touches.startX) {\n data.isScrolling = false;\n } else {\n // eslint-disable-next-line\n if (diffX * diffX + diffY * diffY >= 25) {\n touchAngle = Math.atan2(Math.abs(diffY), Math.abs(diffX)) * 180 / Math.PI;\n data.isScrolling = swiper.isHorizontal() ? touchAngle > params.touchAngle : 90 - touchAngle > params.touchAngle;\n }\n }\n }\n\n if (data.isScrolling) {\n swiper.emit('touchMoveOpposite', e);\n }\n\n if (typeof data.startMoving === 'undefined') {\n if (touches.currentX !== touches.startX || touches.currentY !== touches.startY) {\n data.startMoving = true;\n }\n }\n\n if (data.isScrolling) {\n data.isTouched = false;\n return;\n }\n\n if (!data.startMoving) {\n return;\n }\n\n swiper.allowClick = false;\n\n if (!params.cssMode && e.cancelable) {\n e.preventDefault();\n }\n\n if (params.touchMoveStopPropagation && !params.nested) {\n e.stopPropagation();\n }\n\n if (!data.isMoved) {\n if (params.loop && !params.cssMode) {\n swiper.loopFix();\n }\n\n data.startTranslate = swiper.getTranslate();\n swiper.setTransition(0);\n\n if (swiper.animating) {\n swiper.$wrapperEl.trigger('webkitTransitionEnd transitionend');\n }\n\n data.allowMomentumBounce = false; // Grab Cursor\n\n if (params.grabCursor && (swiper.allowSlideNext === true || swiper.allowSlidePrev === true)) {\n swiper.setGrabCursor(true);\n }\n\n swiper.emit('sliderFirstMove', e);\n }\n\n swiper.emit('sliderMove', e);\n data.isMoved = true;\n let diff = swiper.isHorizontal() ? diffX : diffY;\n touches.diff = diff;\n diff *= params.touchRatio;\n if (rtl) diff = -diff;\n swiper.swipeDirection = diff > 0 ? 'prev' : 'next';\n data.currentTranslate = diff + data.startTranslate;\n let disableParentSwiper = true;\n let resistanceRatio = params.resistanceRatio;\n\n if (params.touchReleaseOnEdges) {\n resistanceRatio = 0;\n }\n\n if (diff > 0 && data.currentTranslate > swiper.minTranslate()) {\n disableParentSwiper = false;\n if (params.resistance) data.currentTranslate = swiper.minTranslate() - 1 + (-swiper.minTranslate() + data.startTranslate + diff) ** resistanceRatio;\n } else if (diff < 0 && data.currentTranslate < swiper.maxTranslate()) {\n disableParentSwiper = false;\n if (params.resistance) data.currentTranslate = swiper.maxTranslate() + 1 - (swiper.maxTranslate() - data.startTranslate - diff) ** resistanceRatio;\n }\n\n if (disableParentSwiper) {\n e.preventedByNestedSwiper = true;\n } // Directions locks\n\n\n if (!swiper.allowSlideNext && swiper.swipeDirection === 'next' && data.currentTranslate < data.startTranslate) {\n data.currentTranslate = data.startTranslate;\n }\n\n if (!swiper.allowSlidePrev && swiper.swipeDirection === 'prev' && data.currentTranslate > data.startTranslate) {\n data.currentTranslate = data.startTranslate;\n }\n\n if (!swiper.allowSlidePrev && !swiper.allowSlideNext) {\n data.currentTranslate = data.startTranslate;\n } // Threshold\n\n\n if (params.threshold > 0) {\n if (Math.abs(diff) > params.threshold || data.allowThresholdMove) {\n if (!data.allowThresholdMove) {\n data.allowThresholdMove = true;\n touches.startX = touches.currentX;\n touches.startY = touches.currentY;\n data.currentTranslate = data.startTranslate;\n touches.diff = swiper.isHorizontal() ? touches.currentX - touches.startX : touches.currentY - touches.startY;\n return;\n }\n } else {\n data.currentTranslate = data.startTranslate;\n return;\n }\n }\n\n if (!params.followFinger || params.cssMode) return; // Update active index in free mode\n\n if (params.freeMode && params.freeMode.enabled && swiper.freeMode || params.watchSlidesProgress) {\n swiper.updateActiveIndex();\n swiper.updateSlidesClasses();\n }\n\n if (swiper.params.freeMode && params.freeMode.enabled && swiper.freeMode) {\n swiper.freeMode.onTouchMove();\n } // Update progress\n\n\n swiper.updateProgress(data.currentTranslate); // Update translate\n\n swiper.setTranslate(data.currentTranslate);\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/events/onTouchEnd.js\n\nfunction onTouchEnd(event) {\n const swiper = this;\n const data = swiper.touchEventsData;\n const {\n params,\n touches,\n rtlTranslate: rtl,\n slidesGrid,\n enabled\n } = swiper;\n if (!enabled) return;\n let e = event;\n if (e.originalEvent) e = e.originalEvent;\n\n if (data.allowTouchCallbacks) {\n swiper.emit('touchEnd', e);\n }\n\n data.allowTouchCallbacks = false;\n\n if (!data.isTouched) {\n if (data.isMoved && params.grabCursor) {\n swiper.setGrabCursor(false);\n }\n\n data.isMoved = false;\n data.startMoving = false;\n return;\n } // Return Grab Cursor\n\n\n if (params.grabCursor && data.isMoved && data.isTouched && (swiper.allowSlideNext === true || swiper.allowSlidePrev === true)) {\n swiper.setGrabCursor(false);\n } // Time diff\n\n\n const touchEndTime = utils_now();\n const timeDiff = touchEndTime - data.touchStartTime; // Tap, doubleTap, Click\n\n if (swiper.allowClick) {\n const pathTree = e.path || e.composedPath && e.composedPath();\n swiper.updateClickedSlide(pathTree && pathTree[0] || e.target);\n swiper.emit('tap click', e);\n\n if (timeDiff < 300 && touchEndTime - data.lastClickTime < 300) {\n swiper.emit('doubleTap doubleClick', e);\n }\n }\n\n data.lastClickTime = utils_now();\n utils_nextTick(() => {\n if (!swiper.destroyed) swiper.allowClick = true;\n });\n\n if (!data.isTouched || !data.isMoved || !swiper.swipeDirection || touches.diff === 0 || data.currentTranslate === data.startTranslate) {\n data.isTouched = false;\n data.isMoved = false;\n data.startMoving = false;\n return;\n }\n\n data.isTouched = false;\n data.isMoved = false;\n data.startMoving = false;\n let currentPos;\n\n if (params.followFinger) {\n currentPos = rtl ? swiper.translate : -swiper.translate;\n } else {\n currentPos = -data.currentTranslate;\n }\n\n if (params.cssMode) {\n return;\n }\n\n if (swiper.params.freeMode && params.freeMode.enabled) {\n swiper.freeMode.onTouchEnd({\n currentPos\n });\n return;\n } // Find current slide\n\n\n let stopIndex = 0;\n let groupSize = swiper.slidesSizesGrid[0];\n\n for (let i = 0; i < slidesGrid.length; i += i < params.slidesPerGroupSkip ? 1 : params.slidesPerGroup) {\n const increment = i < params.slidesPerGroupSkip - 1 ? 1 : params.slidesPerGroup;\n\n if (typeof slidesGrid[i + increment] !== 'undefined') {\n if (currentPos >= slidesGrid[i] && currentPos < slidesGrid[i + increment]) {\n stopIndex = i;\n groupSize = slidesGrid[i + increment] - slidesGrid[i];\n }\n } else if (currentPos >= slidesGrid[i]) {\n stopIndex = i;\n groupSize = slidesGrid[slidesGrid.length - 1] - slidesGrid[slidesGrid.length - 2];\n }\n }\n\n let rewindFirstIndex = null;\n let rewindLastIndex = null;\n\n if (params.rewind) {\n if (swiper.isBeginning) {\n rewindLastIndex = swiper.params.virtual && swiper.params.virtual.enabled && swiper.virtual ? swiper.virtual.slides.length - 1 : swiper.slides.length - 1;\n } else if (swiper.isEnd) {\n rewindFirstIndex = 0;\n }\n } // Find current slide size\n\n\n const ratio = (currentPos - slidesGrid[stopIndex]) / groupSize;\n const increment = stopIndex < params.slidesPerGroupSkip - 1 ? 1 : params.slidesPerGroup;\n\n if (timeDiff > params.longSwipesMs) {\n // Long touches\n if (!params.longSwipes) {\n swiper.slideTo(swiper.activeIndex);\n return;\n }\n\n if (swiper.swipeDirection === 'next') {\n if (ratio >= params.longSwipesRatio) swiper.slideTo(params.rewind && swiper.isEnd ? rewindFirstIndex : stopIndex + increment);else swiper.slideTo(stopIndex);\n }\n\n if (swiper.swipeDirection === 'prev') {\n if (ratio > 1 - params.longSwipesRatio) {\n swiper.slideTo(stopIndex + increment);\n } else if (rewindLastIndex !== null && ratio < 0 && Math.abs(ratio) > params.longSwipesRatio) {\n swiper.slideTo(rewindLastIndex);\n } else {\n swiper.slideTo(stopIndex);\n }\n }\n } else {\n // Short swipes\n if (!params.shortSwipes) {\n swiper.slideTo(swiper.activeIndex);\n return;\n }\n\n const isNavButtonTarget = swiper.navigation && (e.target === swiper.navigation.nextEl || e.target === swiper.navigation.prevEl);\n\n if (!isNavButtonTarget) {\n if (swiper.swipeDirection === 'next') {\n swiper.slideTo(rewindFirstIndex !== null ? rewindFirstIndex : stopIndex + increment);\n }\n\n if (swiper.swipeDirection === 'prev') {\n swiper.slideTo(rewindLastIndex !== null ? rewindLastIndex : stopIndex);\n }\n } else if (e.target === swiper.navigation.nextEl) {\n swiper.slideTo(stopIndex + increment);\n } else {\n swiper.slideTo(stopIndex);\n }\n }\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/events/onResize.js\nfunction onResize() {\n const swiper = this;\n const {\n params,\n el\n } = swiper;\n if (el && el.offsetWidth === 0) return; // Breakpoints\n\n if (params.breakpoints) {\n swiper.setBreakpoint();\n } // Save locks\n\n\n const {\n allowSlideNext,\n allowSlidePrev,\n snapGrid\n } = swiper; // Disable locks on resize\n\n swiper.allowSlideNext = true;\n swiper.allowSlidePrev = true;\n swiper.updateSize();\n swiper.updateSlides();\n swiper.updateSlidesClasses();\n\n if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !swiper.isBeginning && !swiper.params.centeredSlides) {\n swiper.slideTo(swiper.slides.length - 1, 0, false, true);\n } else {\n swiper.slideTo(swiper.activeIndex, 0, false, true);\n }\n\n if (swiper.autoplay && swiper.autoplay.running && swiper.autoplay.paused) {\n swiper.autoplay.run();\n } // Return locks after resize\n\n\n swiper.allowSlidePrev = allowSlidePrev;\n swiper.allowSlideNext = allowSlideNext;\n\n if (swiper.params.watchOverflow && snapGrid !== swiper.snapGrid) {\n swiper.checkOverflow();\n }\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/events/onClick.js\nfunction onClick(e) {\n const swiper = this;\n if (!swiper.enabled) return;\n\n if (!swiper.allowClick) {\n if (swiper.params.preventClicks) e.preventDefault();\n\n if (swiper.params.preventClicksPropagation && swiper.animating) {\n e.stopPropagation();\n e.stopImmediatePropagation();\n }\n }\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/events/onScroll.js\nfunction onScroll() {\n const swiper = this;\n const {\n wrapperEl,\n rtlTranslate,\n enabled\n } = swiper;\n if (!enabled) return;\n swiper.previousTranslate = swiper.translate;\n\n if (swiper.isHorizontal()) {\n swiper.translate = -wrapperEl.scrollLeft;\n } else {\n swiper.translate = -wrapperEl.scrollTop;\n } // eslint-disable-next-line\n\n\n if (swiper.translate === 0) swiper.translate = 0;\n swiper.updateActiveIndex();\n swiper.updateSlidesClasses();\n let newProgress;\n const translatesDiff = swiper.maxTranslate() - swiper.minTranslate();\n\n if (translatesDiff === 0) {\n newProgress = 0;\n } else {\n newProgress = (swiper.translate - swiper.minTranslate()) / translatesDiff;\n }\n\n if (newProgress !== swiper.progress) {\n swiper.updateProgress(rtlTranslate ? -swiper.translate : swiper.translate);\n }\n\n swiper.emit('setTranslate', swiper.translate, false);\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/events/index.js\n\n\n\n\n\n\n\nlet dummyEventAttached = false;\n\nfunction dummyEventListener() {}\n\nconst events = (swiper, method) => {\n const document = ssr_window_esm_getDocument();\n const {\n params,\n touchEvents,\n el,\n wrapperEl,\n device,\n support\n } = swiper;\n const capture = !!params.nested;\n const domMethod = method === 'on' ? 'addEventListener' : 'removeEventListener';\n const swiperMethod = method; // Touch Events\n\n if (!support.touch) {\n el[domMethod](touchEvents.start, swiper.onTouchStart, false);\n document[domMethod](touchEvents.move, swiper.onTouchMove, capture);\n document[domMethod](touchEvents.end, swiper.onTouchEnd, false);\n } else {\n const passiveListener = touchEvents.start === 'touchstart' && support.passiveListener && params.passiveListeners ? {\n passive: true,\n capture: false\n } : false;\n el[domMethod](touchEvents.start, swiper.onTouchStart, passiveListener);\n el[domMethod](touchEvents.move, swiper.onTouchMove, support.passiveListener ? {\n passive: false,\n capture\n } : capture);\n el[domMethod](touchEvents.end, swiper.onTouchEnd, passiveListener);\n\n if (touchEvents.cancel) {\n el[domMethod](touchEvents.cancel, swiper.onTouchEnd, passiveListener);\n }\n } // Prevent Links Clicks\n\n\n if (params.preventClicks || params.preventClicksPropagation) {\n el[domMethod]('click', swiper.onClick, true);\n }\n\n if (params.cssMode) {\n wrapperEl[domMethod]('scroll', swiper.onScroll);\n } // Resize handler\n\n\n if (params.updateOnWindowResize) {\n swiper[swiperMethod](device.ios || device.android ? 'resize orientationchange observerUpdate' : 'resize observerUpdate', onResize, true);\n } else {\n swiper[swiperMethod]('observerUpdate', onResize, true);\n }\n};\n\nfunction attachEvents() {\n const swiper = this;\n const document = ssr_window_esm_getDocument();\n const {\n params,\n support\n } = swiper;\n swiper.onTouchStart = onTouchStart.bind(swiper);\n swiper.onTouchMove = onTouchMove.bind(swiper);\n swiper.onTouchEnd = onTouchEnd.bind(swiper);\n\n if (params.cssMode) {\n swiper.onScroll = onScroll.bind(swiper);\n }\n\n swiper.onClick = onClick.bind(swiper);\n\n if (support.touch && !dummyEventAttached) {\n document.addEventListener('touchstart', dummyEventListener);\n dummyEventAttached = true;\n }\n\n events(swiper, 'on');\n}\n\nfunction detachEvents() {\n const swiper = this;\n events(swiper, 'off');\n}\n\n/* harmony default export */ const core_events = ({\n attachEvents,\n detachEvents\n});\n;// CONCATENATED MODULE: ./node_modules/swiper/core/breakpoints/setBreakpoint.js\n\n\nconst isGridEnabled = (swiper, params) => {\n return swiper.grid && params.grid && params.grid.rows > 1;\n};\n\nfunction setBreakpoint() {\n const swiper = this;\n const {\n activeIndex,\n initialized,\n loopedSlides = 0,\n params,\n $el\n } = swiper;\n const breakpoints = params.breakpoints;\n if (!breakpoints || breakpoints && Object.keys(breakpoints).length === 0) return; // Get breakpoint for window width and update parameters\n\n const breakpoint = swiper.getBreakpoint(breakpoints, swiper.params.breakpointsBase, swiper.el);\n if (!breakpoint || swiper.currentBreakpoint === breakpoint) return;\n const breakpointOnlyParams = breakpoint in breakpoints ? breakpoints[breakpoint] : undefined;\n const breakpointParams = breakpointOnlyParams || swiper.originalParams;\n const wasMultiRow = isGridEnabled(swiper, params);\n const isMultiRow = isGridEnabled(swiper, breakpointParams);\n const wasEnabled = params.enabled;\n\n if (wasMultiRow && !isMultiRow) {\n $el.removeClass(`${params.containerModifierClass}grid ${params.containerModifierClass}grid-column`);\n swiper.emitContainerClasses();\n } else if (!wasMultiRow && isMultiRow) {\n $el.addClass(`${params.containerModifierClass}grid`);\n\n if (breakpointParams.grid.fill && breakpointParams.grid.fill === 'column' || !breakpointParams.grid.fill && params.grid.fill === 'column') {\n $el.addClass(`${params.containerModifierClass}grid-column`);\n }\n\n swiper.emitContainerClasses();\n } // Toggle navigation, pagination, scrollbar\n\n\n ['navigation', 'pagination', 'scrollbar'].forEach(prop => {\n const wasModuleEnabled = params[prop] && params[prop].enabled;\n const isModuleEnabled = breakpointParams[prop] && breakpointParams[prop].enabled;\n\n if (wasModuleEnabled && !isModuleEnabled) {\n swiper[prop].disable();\n }\n\n if (!wasModuleEnabled && isModuleEnabled) {\n swiper[prop].enable();\n }\n });\n const directionChanged = breakpointParams.direction && breakpointParams.direction !== params.direction;\n const needsReLoop = params.loop && (breakpointParams.slidesPerView !== params.slidesPerView || directionChanged);\n\n if (directionChanged && initialized) {\n swiper.changeDirection();\n }\n\n utils_extend(swiper.params, breakpointParams);\n const isEnabled = swiper.params.enabled;\n Object.assign(swiper, {\n allowTouchMove: swiper.params.allowTouchMove,\n allowSlideNext: swiper.params.allowSlideNext,\n allowSlidePrev: swiper.params.allowSlidePrev\n });\n\n if (wasEnabled && !isEnabled) {\n swiper.disable();\n } else if (!wasEnabled && isEnabled) {\n swiper.enable();\n }\n\n swiper.currentBreakpoint = breakpoint;\n swiper.emit('_beforeBreakpoint', breakpointParams);\n\n if (needsReLoop && initialized) {\n swiper.loopDestroy();\n swiper.loopCreate();\n swiper.updateSlides();\n swiper.slideTo(activeIndex - loopedSlides + swiper.loopedSlides, 0, false);\n }\n\n swiper.emit('breakpoint', breakpointParams);\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/breakpoints/getBreakpoint.js\n\nfunction getBreakpoint(breakpoints, base = 'window', containerEl) {\n if (!breakpoints || base === 'container' && !containerEl) return undefined;\n let breakpoint = false;\n const window = ssr_window_esm_getWindow();\n const currentHeight = base === 'window' ? window.innerHeight : containerEl.clientHeight;\n const points = Object.keys(breakpoints).map(point => {\n if (typeof point === 'string' && point.indexOf('@') === 0) {\n const minRatio = parseFloat(point.substr(1));\n const value = currentHeight * minRatio;\n return {\n value,\n point\n };\n }\n\n return {\n value: point,\n point\n };\n });\n points.sort((a, b) => parseInt(a.value, 10) - parseInt(b.value, 10));\n\n for (let i = 0; i < points.length; i += 1) {\n const {\n point,\n value\n } = points[i];\n\n if (base === 'window') {\n if (window.matchMedia(`(min-width: ${value}px)`).matches) {\n breakpoint = point;\n }\n } else if (value <= containerEl.clientWidth) {\n breakpoint = point;\n }\n }\n\n return breakpoint || 'max';\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/breakpoints/index.js\n\n\n/* harmony default export */ const breakpoints = ({\n setBreakpoint: setBreakpoint,\n getBreakpoint: getBreakpoint\n});\n;// CONCATENATED MODULE: ./node_modules/swiper/core/classes/addClasses.js\nfunction prepareClasses(entries, prefix) {\n const resultClasses = [];\n entries.forEach(item => {\n if (typeof item === 'object') {\n Object.keys(item).forEach(classNames => {\n if (item[classNames]) {\n resultClasses.push(prefix + classNames);\n }\n });\n } else if (typeof item === 'string') {\n resultClasses.push(prefix + item);\n }\n });\n return resultClasses;\n}\n\nfunction addClasses() {\n const swiper = this;\n const {\n classNames,\n params,\n rtl,\n $el,\n device,\n support\n } = swiper; // prettier-ignore\n\n const suffixes = prepareClasses(['initialized', params.direction, {\n 'pointer-events': !support.touch\n }, {\n 'free-mode': swiper.params.freeMode && params.freeMode.enabled\n }, {\n 'autoheight': params.autoHeight\n }, {\n 'rtl': rtl\n }, {\n 'grid': params.grid && params.grid.rows > 1\n }, {\n 'grid-column': params.grid && params.grid.rows > 1 && params.grid.fill === 'column'\n }, {\n 'android': device.android\n }, {\n 'ios': device.ios\n }, {\n 'css-mode': params.cssMode\n }, {\n 'centered': params.cssMode && params.centeredSlides\n }, {\n 'watch-progress': params.watchSlidesProgress\n }], params.containerModifierClass);\n classNames.push(...suffixes);\n $el.addClass([...classNames].join(' '));\n swiper.emitContainerClasses();\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/classes/removeClasses.js\nfunction removeClasses() {\n const swiper = this;\n const {\n $el,\n classNames\n } = swiper;\n $el.removeClass(classNames.join(' '));\n swiper.emitContainerClasses();\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/classes/index.js\n\n\n/* harmony default export */ const classes = ({\n addClasses: addClasses,\n removeClasses: removeClasses\n});\n;// CONCATENATED MODULE: ./node_modules/swiper/core/images/loadImage.js\n\n\nfunction loadImage(imageEl, src, srcset, sizes, checkForComplete, callback) {\n const window = ssr_window_esm_getWindow();\n let image;\n\n function onReady() {\n if (callback) callback();\n }\n\n const isPicture = dom(imageEl).parent('picture')[0];\n\n if (!isPicture && (!imageEl.complete || !checkForComplete)) {\n if (src) {\n image = new window.Image();\n image.onload = onReady;\n image.onerror = onReady;\n\n if (sizes) {\n image.sizes = sizes;\n }\n\n if (srcset) {\n image.srcset = srcset;\n }\n\n if (src) {\n image.src = src;\n }\n } else {\n onReady();\n }\n } else {\n // image already loaded...\n onReady();\n }\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/images/preloadImages.js\nfunction preloadImages() {\n const swiper = this;\n swiper.imagesToLoad = swiper.$el.find('img');\n\n function onReady() {\n if (typeof swiper === 'undefined' || swiper === null || !swiper || swiper.destroyed) return;\n if (swiper.imagesLoaded !== undefined) swiper.imagesLoaded += 1;\n\n if (swiper.imagesLoaded === swiper.imagesToLoad.length) {\n if (swiper.params.updateOnImagesReady) swiper.update();\n swiper.emit('imagesReady');\n }\n }\n\n for (let i = 0; i < swiper.imagesToLoad.length; i += 1) {\n const imageEl = swiper.imagesToLoad[i];\n swiper.loadImage(imageEl, imageEl.currentSrc || imageEl.getAttribute('src'), imageEl.srcset || imageEl.getAttribute('srcset'), imageEl.sizes || imageEl.getAttribute('sizes'), true, onReady);\n }\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/images/index.js\n\n\n/* harmony default export */ const core_images = ({\n loadImage: loadImage,\n preloadImages: preloadImages\n});\n;// CONCATENATED MODULE: ./node_modules/swiper/core/check-overflow/index.js\nfunction checkOverflow() {\n const swiper = this;\n const {\n isLocked: wasLocked,\n params\n } = swiper;\n const {\n slidesOffsetBefore\n } = params;\n\n if (slidesOffsetBefore) {\n const lastSlideIndex = swiper.slides.length - 1;\n const lastSlideRightEdge = swiper.slidesGrid[lastSlideIndex] + swiper.slidesSizesGrid[lastSlideIndex] + slidesOffsetBefore * 2;\n swiper.isLocked = swiper.size > lastSlideRightEdge;\n } else {\n swiper.isLocked = swiper.snapGrid.length === 1;\n }\n\n if (params.allowSlideNext === true) {\n swiper.allowSlideNext = !swiper.isLocked;\n }\n\n if (params.allowSlidePrev === true) {\n swiper.allowSlidePrev = !swiper.isLocked;\n }\n\n if (wasLocked && wasLocked !== swiper.isLocked) {\n swiper.isEnd = false;\n }\n\n if (wasLocked !== swiper.isLocked) {\n swiper.emit(swiper.isLocked ? 'lock' : 'unlock');\n }\n}\n\n/* harmony default export */ const check_overflow = ({\n checkOverflow\n});\n;// CONCATENATED MODULE: ./node_modules/swiper/core/defaults.js\n/* harmony default export */ const defaults = ({\n init: true,\n direction: 'horizontal',\n touchEventsTarget: 'wrapper',\n initialSlide: 0,\n speed: 300,\n cssMode: false,\n updateOnWindowResize: true,\n resizeObserver: true,\n nested: false,\n createElements: false,\n enabled: true,\n focusableElements: 'input, select, option, textarea, button, video, label',\n // Overrides\n width: null,\n height: null,\n //\n preventInteractionOnTransition: false,\n // ssr\n userAgent: null,\n url: null,\n // To support iOS's swipe-to-go-back gesture (when being used in-app).\n edgeSwipeDetection: false,\n edgeSwipeThreshold: 20,\n // Autoheight\n autoHeight: false,\n // Set wrapper width\n setWrapperSize: false,\n // Virtual Translate\n virtualTranslate: false,\n // Effects\n effect: 'slide',\n // 'slide' or 'fade' or 'cube' or 'coverflow' or 'flip'\n // Breakpoints\n breakpoints: undefined,\n breakpointsBase: 'window',\n // Slides grid\n spaceBetween: 0,\n slidesPerView: 1,\n slidesPerGroup: 1,\n slidesPerGroupSkip: 0,\n slidesPerGroupAuto: false,\n centeredSlides: false,\n centeredSlidesBounds: false,\n slidesOffsetBefore: 0,\n // in px\n slidesOffsetAfter: 0,\n // in px\n normalizeSlideIndex: true,\n centerInsufficientSlides: false,\n // Disable swiper and hide navigation when container not overflow\n watchOverflow: true,\n // Round length\n roundLengths: false,\n // Touches\n touchRatio: 1,\n touchAngle: 45,\n simulateTouch: true,\n shortSwipes: true,\n longSwipes: true,\n longSwipesRatio: 0.5,\n longSwipesMs: 300,\n followFinger: true,\n allowTouchMove: true,\n threshold: 0,\n touchMoveStopPropagation: false,\n touchStartPreventDefault: true,\n touchStartForcePreventDefault: false,\n touchReleaseOnEdges: false,\n // Unique Navigation Elements\n uniqueNavElements: true,\n // Resistance\n resistance: true,\n resistanceRatio: 0.85,\n // Progress\n watchSlidesProgress: false,\n // Cursor\n grabCursor: false,\n // Clicks\n preventClicks: true,\n preventClicksPropagation: true,\n slideToClickedSlide: false,\n // Images\n preloadImages: true,\n updateOnImagesReady: true,\n // loop\n loop: false,\n loopAdditionalSlides: 0,\n loopedSlides: null,\n loopedSlidesLimit: true,\n loopFillGroupWithBlank: false,\n loopPreventsSlide: true,\n // rewind\n rewind: false,\n // Swiping/no swiping\n allowSlidePrev: true,\n allowSlideNext: true,\n swipeHandler: null,\n // '.swipe-handler',\n noSwiping: true,\n noSwipingClass: 'swiper-no-swiping',\n noSwipingSelector: null,\n // Passive Listeners\n passiveListeners: true,\n maxBackfaceHiddenSlides: 10,\n // NS\n containerModifierClass: 'swiper-',\n // NEW\n slideClass: 'swiper-slide',\n slideBlankClass: 'swiper-slide-invisible-blank',\n slideActiveClass: 'swiper-slide-active',\n slideDuplicateActiveClass: 'swiper-slide-duplicate-active',\n slideVisibleClass: 'swiper-slide-visible',\n slideDuplicateClass: 'swiper-slide-duplicate',\n slideNextClass: 'swiper-slide-next',\n slideDuplicateNextClass: 'swiper-slide-duplicate-next',\n slidePrevClass: 'swiper-slide-prev',\n slideDuplicatePrevClass: 'swiper-slide-duplicate-prev',\n wrapperClass: 'swiper-wrapper',\n // Callbacks\n runCallbacksOnInit: true,\n // Internals\n _emitClasses: false\n});\n;// CONCATENATED MODULE: ./node_modules/swiper/core/moduleExtendParams.js\n\nfunction moduleExtendParams(params, allModulesParams) {\n return function extendParams(obj = {}) {\n const moduleParamName = Object.keys(obj)[0];\n const moduleParams = obj[moduleParamName];\n\n if (typeof moduleParams !== 'object' || moduleParams === null) {\n utils_extend(allModulesParams, obj);\n return;\n }\n\n if (['navigation', 'pagination', 'scrollbar'].indexOf(moduleParamName) >= 0 && params[moduleParamName] === true) {\n params[moduleParamName] = {\n auto: true\n };\n }\n\n if (!(moduleParamName in params && 'enabled' in moduleParams)) {\n utils_extend(allModulesParams, obj);\n return;\n }\n\n if (params[moduleParamName] === true) {\n params[moduleParamName] = {\n enabled: true\n };\n }\n\n if (typeof params[moduleParamName] === 'object' && !('enabled' in params[moduleParamName])) {\n params[moduleParamName].enabled = true;\n }\n\n if (!params[moduleParamName]) params[moduleParamName] = {\n enabled: false\n };\n utils_extend(allModulesParams, obj);\n };\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/core/core.js\n/* eslint no-param-reassign: \"off\" */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst prototypes = {\n eventsEmitter: events_emitter,\n update: update,\n translate: translate,\n transition: core_transition,\n slide: slide,\n loop: loop,\n grabCursor: grab_cursor,\n events: core_events,\n breakpoints: breakpoints,\n checkOverflow: check_overflow,\n classes: classes,\n images: core_images\n};\nconst extendedDefaults = {};\n\nclass Swiper {\n constructor(...args) {\n let el;\n let params;\n\n if (args.length === 1 && args[0].constructor && Object.prototype.toString.call(args[0]).slice(8, -1) === 'Object') {\n params = args[0];\n } else {\n [el, params] = args;\n }\n\n if (!params) params = {};\n params = utils_extend({}, params);\n if (el && !params.el) params.el = el;\n\n if (params.el && dom(params.el).length > 1) {\n const swipers = [];\n dom(params.el).each(containerEl => {\n const newParams = utils_extend({}, params, {\n el: containerEl\n });\n swipers.push(new Swiper(newParams));\n }); // eslint-disable-next-line no-constructor-return\n\n return swipers;\n } // Swiper Instance\n\n\n const swiper = this;\n swiper.__swiper__ = true;\n swiper.support = getSupport();\n swiper.device = getDevice({\n userAgent: params.userAgent\n });\n swiper.browser = getBrowser();\n swiper.eventsListeners = {};\n swiper.eventsAnyListeners = [];\n swiper.modules = [...swiper.__modules__];\n\n if (params.modules && Array.isArray(params.modules)) {\n swiper.modules.push(...params.modules);\n }\n\n const allModulesParams = {};\n swiper.modules.forEach(mod => {\n mod({\n swiper,\n extendParams: moduleExtendParams(params, allModulesParams),\n on: swiper.on.bind(swiper),\n once: swiper.once.bind(swiper),\n off: swiper.off.bind(swiper),\n emit: swiper.emit.bind(swiper)\n });\n }); // Extend defaults with modules params\n\n const swiperParams = utils_extend({}, defaults, allModulesParams); // Extend defaults with passed params\n\n swiper.params = utils_extend({}, swiperParams, extendedDefaults, params);\n swiper.originalParams = utils_extend({}, swiper.params);\n swiper.passedParams = utils_extend({}, params); // add event listeners\n\n if (swiper.params && swiper.params.on) {\n Object.keys(swiper.params.on).forEach(eventName => {\n swiper.on(eventName, swiper.params.on[eventName]);\n });\n }\n\n if (swiper.params && swiper.params.onAny) {\n swiper.onAny(swiper.params.onAny);\n } // Save Dom lib\n\n\n swiper.$ = dom; // Extend Swiper\n\n Object.assign(swiper, {\n enabled: swiper.params.enabled,\n el,\n // Classes\n classNames: [],\n // Slides\n slides: dom(),\n slidesGrid: [],\n snapGrid: [],\n slidesSizesGrid: [],\n\n // isDirection\n isHorizontal() {\n return swiper.params.direction === 'horizontal';\n },\n\n isVertical() {\n return swiper.params.direction === 'vertical';\n },\n\n // Indexes\n activeIndex: 0,\n realIndex: 0,\n //\n isBeginning: true,\n isEnd: false,\n // Props\n translate: 0,\n previousTranslate: 0,\n progress: 0,\n velocity: 0,\n animating: false,\n // Locks\n allowSlideNext: swiper.params.allowSlideNext,\n allowSlidePrev: swiper.params.allowSlidePrev,\n // Touch Events\n touchEvents: function touchEvents() {\n const touch = ['touchstart', 'touchmove', 'touchend', 'touchcancel'];\n const desktop = ['pointerdown', 'pointermove', 'pointerup'];\n swiper.touchEventsTouch = {\n start: touch[0],\n move: touch[1],\n end: touch[2],\n cancel: touch[3]\n };\n swiper.touchEventsDesktop = {\n start: desktop[0],\n move: desktop[1],\n end: desktop[2]\n };\n return swiper.support.touch || !swiper.params.simulateTouch ? swiper.touchEventsTouch : swiper.touchEventsDesktop;\n }(),\n touchEventsData: {\n isTouched: undefined,\n isMoved: undefined,\n allowTouchCallbacks: undefined,\n touchStartTime: undefined,\n isScrolling: undefined,\n currentTranslate: undefined,\n startTranslate: undefined,\n allowThresholdMove: undefined,\n // Form elements to match\n focusableElements: swiper.params.focusableElements,\n // Last click time\n lastClickTime: utils_now(),\n clickTimeout: undefined,\n // Velocities\n velocities: [],\n allowMomentumBounce: undefined,\n isTouchEvent: undefined,\n startMoving: undefined\n },\n // Clicks\n allowClick: true,\n // Touches\n allowTouchMove: swiper.params.allowTouchMove,\n touches: {\n startX: 0,\n startY: 0,\n currentX: 0,\n currentY: 0,\n diff: 0\n },\n // Images\n imagesToLoad: [],\n imagesLoaded: 0\n });\n swiper.emit('_swiper'); // Init\n\n if (swiper.params.init) {\n swiper.init();\n } // Return app instance\n // eslint-disable-next-line no-constructor-return\n\n\n return swiper;\n }\n\n enable() {\n const swiper = this;\n if (swiper.enabled) return;\n swiper.enabled = true;\n\n if (swiper.params.grabCursor) {\n swiper.setGrabCursor();\n }\n\n swiper.emit('enable');\n }\n\n disable() {\n const swiper = this;\n if (!swiper.enabled) return;\n swiper.enabled = false;\n\n if (swiper.params.grabCursor) {\n swiper.unsetGrabCursor();\n }\n\n swiper.emit('disable');\n }\n\n setProgress(progress, speed) {\n const swiper = this;\n progress = Math.min(Math.max(progress, 0), 1);\n const min = swiper.minTranslate();\n const max = swiper.maxTranslate();\n const current = (max - min) * progress + min;\n swiper.translateTo(current, typeof speed === 'undefined' ? 0 : speed);\n swiper.updateActiveIndex();\n swiper.updateSlidesClasses();\n }\n\n emitContainerClasses() {\n const swiper = this;\n if (!swiper.params._emitClasses || !swiper.el) return;\n const cls = swiper.el.className.split(' ').filter(className => {\n return className.indexOf('swiper') === 0 || className.indexOf(swiper.params.containerModifierClass) === 0;\n });\n swiper.emit('_containerClasses', cls.join(' '));\n }\n\n getSlideClasses(slideEl) {\n const swiper = this;\n if (swiper.destroyed) return '';\n return slideEl.className.split(' ').filter(className => {\n return className.indexOf('swiper-slide') === 0 || className.indexOf(swiper.params.slideClass) === 0;\n }).join(' ');\n }\n\n emitSlidesClasses() {\n const swiper = this;\n if (!swiper.params._emitClasses || !swiper.el) return;\n const updates = [];\n swiper.slides.each(slideEl => {\n const classNames = swiper.getSlideClasses(slideEl);\n updates.push({\n slideEl,\n classNames\n });\n swiper.emit('_slideClass', slideEl, classNames);\n });\n swiper.emit('_slideClasses', updates);\n }\n\n slidesPerViewDynamic(view = 'current', exact = false) {\n const swiper = this;\n const {\n params,\n slides,\n slidesGrid,\n slidesSizesGrid,\n size: swiperSize,\n activeIndex\n } = swiper;\n let spv = 1;\n\n if (params.centeredSlides) {\n let slideSize = slides[activeIndex].swiperSlideSize;\n let breakLoop;\n\n for (let i = activeIndex + 1; i < slides.length; i += 1) {\n if (slides[i] && !breakLoop) {\n slideSize += slides[i].swiperSlideSize;\n spv += 1;\n if (slideSize > swiperSize) breakLoop = true;\n }\n }\n\n for (let i = activeIndex - 1; i >= 0; i -= 1) {\n if (slides[i] && !breakLoop) {\n slideSize += slides[i].swiperSlideSize;\n spv += 1;\n if (slideSize > swiperSize) breakLoop = true;\n }\n }\n } else {\n // eslint-disable-next-line\n if (view === 'current') {\n for (let i = activeIndex + 1; i < slides.length; i += 1) {\n const slideInView = exact ? slidesGrid[i] + slidesSizesGrid[i] - slidesGrid[activeIndex] < swiperSize : slidesGrid[i] - slidesGrid[activeIndex] < swiperSize;\n\n if (slideInView) {\n spv += 1;\n }\n }\n } else {\n // previous\n for (let i = activeIndex - 1; i >= 0; i -= 1) {\n const slideInView = slidesGrid[activeIndex] - slidesGrid[i] < swiperSize;\n\n if (slideInView) {\n spv += 1;\n }\n }\n }\n }\n\n return spv;\n }\n\n update() {\n const swiper = this;\n if (!swiper || swiper.destroyed) return;\n const {\n snapGrid,\n params\n } = swiper; // Breakpoints\n\n if (params.breakpoints) {\n swiper.setBreakpoint();\n }\n\n swiper.updateSize();\n swiper.updateSlides();\n swiper.updateProgress();\n swiper.updateSlidesClasses();\n\n function setTranslate() {\n const translateValue = swiper.rtlTranslate ? swiper.translate * -1 : swiper.translate;\n const newTranslate = Math.min(Math.max(translateValue, swiper.maxTranslate()), swiper.minTranslate());\n swiper.setTranslate(newTranslate);\n swiper.updateActiveIndex();\n swiper.updateSlidesClasses();\n }\n\n let translated;\n\n if (swiper.params.freeMode && swiper.params.freeMode.enabled) {\n setTranslate();\n\n if (swiper.params.autoHeight) {\n swiper.updateAutoHeight();\n }\n } else {\n if ((swiper.params.slidesPerView === 'auto' || swiper.params.slidesPerView > 1) && swiper.isEnd && !swiper.params.centeredSlides) {\n translated = swiper.slideTo(swiper.slides.length - 1, 0, false, true);\n } else {\n translated = swiper.slideTo(swiper.activeIndex, 0, false, true);\n }\n\n if (!translated) {\n setTranslate();\n }\n }\n\n if (params.watchOverflow && snapGrid !== swiper.snapGrid) {\n swiper.checkOverflow();\n }\n\n swiper.emit('update');\n }\n\n changeDirection(newDirection, needUpdate = true) {\n const swiper = this;\n const currentDirection = swiper.params.direction;\n\n if (!newDirection) {\n // eslint-disable-next-line\n newDirection = currentDirection === 'horizontal' ? 'vertical' : 'horizontal';\n }\n\n if (newDirection === currentDirection || newDirection !== 'horizontal' && newDirection !== 'vertical') {\n return swiper;\n }\n\n swiper.$el.removeClass(`${swiper.params.containerModifierClass}${currentDirection}`).addClass(`${swiper.params.containerModifierClass}${newDirection}`);\n swiper.emitContainerClasses();\n swiper.params.direction = newDirection;\n swiper.slides.each(slideEl => {\n if (newDirection === 'vertical') {\n slideEl.style.width = '';\n } else {\n slideEl.style.height = '';\n }\n });\n swiper.emit('changeDirection');\n if (needUpdate) swiper.update();\n return swiper;\n }\n\n changeLanguageDirection(direction) {\n const swiper = this;\n if (swiper.rtl && direction === 'rtl' || !swiper.rtl && direction === 'ltr') return;\n swiper.rtl = direction === 'rtl';\n swiper.rtlTranslate = swiper.params.direction === 'horizontal' && swiper.rtl;\n\n if (swiper.rtl) {\n swiper.$el.addClass(`${swiper.params.containerModifierClass}rtl`);\n swiper.el.dir = 'rtl';\n } else {\n swiper.$el.removeClass(`${swiper.params.containerModifierClass}rtl`);\n swiper.el.dir = 'ltr';\n }\n\n swiper.update();\n }\n\n mount(el) {\n const swiper = this;\n if (swiper.mounted) return true; // Find el\n\n const $el = dom(el || swiper.params.el);\n el = $el[0];\n\n if (!el) {\n return false;\n }\n\n el.swiper = swiper;\n\n const getWrapperSelector = () => {\n return `.${(swiper.params.wrapperClass || '').trim().split(' ').join('.')}`;\n };\n\n const getWrapper = () => {\n if (el && el.shadowRoot && el.shadowRoot.querySelector) {\n const res = dom(el.shadowRoot.querySelector(getWrapperSelector())); // Children needs to return slot items\n\n res.children = options => $el.children(options);\n\n return res;\n }\n\n if (!$el.children) {\n return dom($el).children(getWrapperSelector());\n }\n\n return $el.children(getWrapperSelector());\n }; // Find Wrapper\n\n\n let $wrapperEl = getWrapper();\n\n if ($wrapperEl.length === 0 && swiper.params.createElements) {\n const document = ssr_window_esm_getDocument();\n const wrapper = document.createElement('div');\n $wrapperEl = dom(wrapper);\n wrapper.className = swiper.params.wrapperClass;\n $el.append(wrapper);\n $el.children(`.${swiper.params.slideClass}`).each(slideEl => {\n $wrapperEl.append(slideEl);\n });\n }\n\n Object.assign(swiper, {\n $el,\n el,\n $wrapperEl,\n wrapperEl: $wrapperEl[0],\n mounted: true,\n // RTL\n rtl: el.dir.toLowerCase() === 'rtl' || $el.css('direction') === 'rtl',\n rtlTranslate: swiper.params.direction === 'horizontal' && (el.dir.toLowerCase() === 'rtl' || $el.css('direction') === 'rtl'),\n wrongRTL: $wrapperEl.css('display') === '-webkit-box'\n });\n return true;\n }\n\n init(el) {\n const swiper = this;\n if (swiper.initialized) return swiper;\n const mounted = swiper.mount(el);\n if (mounted === false) return swiper;\n swiper.emit('beforeInit'); // Set breakpoint\n\n if (swiper.params.breakpoints) {\n swiper.setBreakpoint();\n } // Add Classes\n\n\n swiper.addClasses(); // Create loop\n\n if (swiper.params.loop) {\n swiper.loopCreate();\n } // Update size\n\n\n swiper.updateSize(); // Update slides\n\n swiper.updateSlides();\n\n if (swiper.params.watchOverflow) {\n swiper.checkOverflow();\n } // Set Grab Cursor\n\n\n if (swiper.params.grabCursor && swiper.enabled) {\n swiper.setGrabCursor();\n }\n\n if (swiper.params.preloadImages) {\n swiper.preloadImages();\n } // Slide To Initial Slide\n\n\n if (swiper.params.loop) {\n swiper.slideTo(swiper.params.initialSlide + swiper.loopedSlides, 0, swiper.params.runCallbacksOnInit, false, true);\n } else {\n swiper.slideTo(swiper.params.initialSlide, 0, swiper.params.runCallbacksOnInit, false, true);\n } // Attach events\n\n\n swiper.attachEvents(); // Init Flag\n\n swiper.initialized = true; // Emit\n\n swiper.emit('init');\n swiper.emit('afterInit');\n return swiper;\n }\n\n destroy(deleteInstance = true, cleanStyles = true) {\n const swiper = this;\n const {\n params,\n $el,\n $wrapperEl,\n slides\n } = swiper;\n\n if (typeof swiper.params === 'undefined' || swiper.destroyed) {\n return null;\n }\n\n swiper.emit('beforeDestroy'); // Init Flag\n\n swiper.initialized = false; // Detach events\n\n swiper.detachEvents(); // Destroy loop\n\n if (params.loop) {\n swiper.loopDestroy();\n } // Cleanup styles\n\n\n if (cleanStyles) {\n swiper.removeClasses();\n $el.removeAttr('style');\n $wrapperEl.removeAttr('style');\n\n if (slides && slides.length) {\n slides.removeClass([params.slideVisibleClass, params.slideActiveClass, params.slideNextClass, params.slidePrevClass].join(' ')).removeAttr('style').removeAttr('data-swiper-slide-index');\n }\n }\n\n swiper.emit('destroy'); // Detach emitter events\n\n Object.keys(swiper.eventsListeners).forEach(eventName => {\n swiper.off(eventName);\n });\n\n if (deleteInstance !== false) {\n swiper.$el[0].swiper = null;\n deleteProps(swiper);\n }\n\n swiper.destroyed = true;\n return null;\n }\n\n static extendDefaults(newDefaults) {\n utils_extend(extendedDefaults, newDefaults);\n }\n\n static get extendedDefaults() {\n return extendedDefaults;\n }\n\n static get defaults() {\n return defaults;\n }\n\n static installModule(mod) {\n if (!Swiper.prototype.__modules__) Swiper.prototype.__modules__ = [];\n const modules = Swiper.prototype.__modules__;\n\n if (typeof mod === 'function' && modules.indexOf(mod) < 0) {\n modules.push(mod);\n }\n }\n\n static use(module) {\n if (Array.isArray(module)) {\n module.forEach(m => Swiper.installModule(m));\n return Swiper;\n }\n\n Swiper.installModule(module);\n return Swiper;\n }\n\n}\n\nObject.keys(prototypes).forEach(prototypeGroup => {\n Object.keys(prototypes[prototypeGroup]).forEach(protoMethod => {\n Swiper.prototype[protoMethod] = prototypes[prototypeGroup][protoMethod];\n });\n});\nSwiper.use([Resize, observer_Observer]);\n/* harmony default export */ const core = (Swiper);\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/virtual/virtual.js\n\n\nfunction Virtual({\n swiper,\n extendParams,\n on,\n emit\n}) {\n extendParams({\n virtual: {\n enabled: false,\n slides: [],\n cache: true,\n renderSlide: null,\n renderExternal: null,\n renderExternalUpdate: true,\n addSlidesBefore: 0,\n addSlidesAfter: 0\n }\n });\n let cssModeTimeout;\n swiper.virtual = {\n cache: {},\n from: undefined,\n to: undefined,\n slides: [],\n offset: 0,\n slidesGrid: []\n };\n\n function renderSlide(slide, index) {\n const params = swiper.params.virtual;\n\n if (params.cache && swiper.virtual.cache[index]) {\n return swiper.virtual.cache[index];\n }\n\n const $slideEl = params.renderSlide ? $(params.renderSlide.call(swiper, slide, index)) : $(`
${slide}
`);\n if (!$slideEl.attr('data-swiper-slide-index')) $slideEl.attr('data-swiper-slide-index', index);\n if (params.cache) swiper.virtual.cache[index] = $slideEl;\n return $slideEl;\n }\n\n function update(force) {\n const {\n slidesPerView,\n slidesPerGroup,\n centeredSlides\n } = swiper.params;\n const {\n addSlidesBefore,\n addSlidesAfter\n } = swiper.params.virtual;\n const {\n from: previousFrom,\n to: previousTo,\n slides,\n slidesGrid: previousSlidesGrid,\n offset: previousOffset\n } = swiper.virtual;\n\n if (!swiper.params.cssMode) {\n swiper.updateActiveIndex();\n }\n\n const activeIndex = swiper.activeIndex || 0;\n let offsetProp;\n if (swiper.rtlTranslate) offsetProp = 'right';else offsetProp = swiper.isHorizontal() ? 'left' : 'top';\n let slidesAfter;\n let slidesBefore;\n\n if (centeredSlides) {\n slidesAfter = Math.floor(slidesPerView / 2) + slidesPerGroup + addSlidesAfter;\n slidesBefore = Math.floor(slidesPerView / 2) + slidesPerGroup + addSlidesBefore;\n } else {\n slidesAfter = slidesPerView + (slidesPerGroup - 1) + addSlidesAfter;\n slidesBefore = slidesPerGroup + addSlidesBefore;\n }\n\n const from = Math.max((activeIndex || 0) - slidesBefore, 0);\n const to = Math.min((activeIndex || 0) + slidesAfter, slides.length - 1);\n const offset = (swiper.slidesGrid[from] || 0) - (swiper.slidesGrid[0] || 0);\n Object.assign(swiper.virtual, {\n from,\n to,\n offset,\n slidesGrid: swiper.slidesGrid\n });\n\n function onRendered() {\n swiper.updateSlides();\n swiper.updateProgress();\n swiper.updateSlidesClasses();\n\n if (swiper.lazy && swiper.params.lazy.enabled) {\n swiper.lazy.load();\n }\n\n emit('virtualUpdate');\n }\n\n if (previousFrom === from && previousTo === to && !force) {\n if (swiper.slidesGrid !== previousSlidesGrid && offset !== previousOffset) {\n swiper.slides.css(offsetProp, `${offset}px`);\n }\n\n swiper.updateProgress();\n emit('virtualUpdate');\n return;\n }\n\n if (swiper.params.virtual.renderExternal) {\n swiper.params.virtual.renderExternal.call(swiper, {\n offset,\n from,\n to,\n slides: function getSlides() {\n const slidesToRender = [];\n\n for (let i = from; i <= to; i += 1) {\n slidesToRender.push(slides[i]);\n }\n\n return slidesToRender;\n }()\n });\n\n if (swiper.params.virtual.renderExternalUpdate) {\n onRendered();\n } else {\n emit('virtualUpdate');\n }\n\n return;\n }\n\n const prependIndexes = [];\n const appendIndexes = [];\n\n if (force) {\n swiper.$wrapperEl.find(`.${swiper.params.slideClass}`).remove();\n } else {\n for (let i = previousFrom; i <= previousTo; i += 1) {\n if (i < from || i > to) {\n swiper.$wrapperEl.find(`.${swiper.params.slideClass}[data-swiper-slide-index=\"${i}\"]`).remove();\n }\n }\n }\n\n for (let i = 0; i < slides.length; i += 1) {\n if (i >= from && i <= to) {\n if (typeof previousTo === 'undefined' || force) {\n appendIndexes.push(i);\n } else {\n if (i > previousTo) appendIndexes.push(i);\n if (i < previousFrom) prependIndexes.push(i);\n }\n }\n }\n\n appendIndexes.forEach(index => {\n swiper.$wrapperEl.append(renderSlide(slides[index], index));\n });\n prependIndexes.sort((a, b) => b - a).forEach(index => {\n swiper.$wrapperEl.prepend(renderSlide(slides[index], index));\n });\n swiper.$wrapperEl.children('.swiper-slide').css(offsetProp, `${offset}px`);\n onRendered();\n }\n\n function appendSlide(slides) {\n if (typeof slides === 'object' && 'length' in slides) {\n for (let i = 0; i < slides.length; i += 1) {\n if (slides[i]) swiper.virtual.slides.push(slides[i]);\n }\n } else {\n swiper.virtual.slides.push(slides);\n }\n\n update(true);\n }\n\n function prependSlide(slides) {\n const activeIndex = swiper.activeIndex;\n let newActiveIndex = activeIndex + 1;\n let numberOfNewSlides = 1;\n\n if (Array.isArray(slides)) {\n for (let i = 0; i < slides.length; i += 1) {\n if (slides[i]) swiper.virtual.slides.unshift(slides[i]);\n }\n\n newActiveIndex = activeIndex + slides.length;\n numberOfNewSlides = slides.length;\n } else {\n swiper.virtual.slides.unshift(slides);\n }\n\n if (swiper.params.virtual.cache) {\n const cache = swiper.virtual.cache;\n const newCache = {};\n Object.keys(cache).forEach(cachedIndex => {\n const $cachedEl = cache[cachedIndex];\n const cachedElIndex = $cachedEl.attr('data-swiper-slide-index');\n\n if (cachedElIndex) {\n $cachedEl.attr('data-swiper-slide-index', parseInt(cachedElIndex, 10) + numberOfNewSlides);\n }\n\n newCache[parseInt(cachedIndex, 10) + numberOfNewSlides] = $cachedEl;\n });\n swiper.virtual.cache = newCache;\n }\n\n update(true);\n swiper.slideTo(newActiveIndex, 0);\n }\n\n function removeSlide(slidesIndexes) {\n if (typeof slidesIndexes === 'undefined' || slidesIndexes === null) return;\n let activeIndex = swiper.activeIndex;\n\n if (Array.isArray(slidesIndexes)) {\n for (let i = slidesIndexes.length - 1; i >= 0; i -= 1) {\n swiper.virtual.slides.splice(slidesIndexes[i], 1);\n\n if (swiper.params.virtual.cache) {\n delete swiper.virtual.cache[slidesIndexes[i]];\n }\n\n if (slidesIndexes[i] < activeIndex) activeIndex -= 1;\n activeIndex = Math.max(activeIndex, 0);\n }\n } else {\n swiper.virtual.slides.splice(slidesIndexes, 1);\n\n if (swiper.params.virtual.cache) {\n delete swiper.virtual.cache[slidesIndexes];\n }\n\n if (slidesIndexes < activeIndex) activeIndex -= 1;\n activeIndex = Math.max(activeIndex, 0);\n }\n\n update(true);\n swiper.slideTo(activeIndex, 0);\n }\n\n function removeAllSlides() {\n swiper.virtual.slides = [];\n\n if (swiper.params.virtual.cache) {\n swiper.virtual.cache = {};\n }\n\n update(true);\n swiper.slideTo(0, 0);\n }\n\n on('beforeInit', () => {\n if (!swiper.params.virtual.enabled) return;\n swiper.virtual.slides = swiper.params.virtual.slides;\n swiper.classNames.push(`${swiper.params.containerModifierClass}virtual`);\n swiper.params.watchSlidesProgress = true;\n swiper.originalParams.watchSlidesProgress = true;\n\n if (!swiper.params.initialSlide) {\n update();\n }\n });\n on('setTranslate', () => {\n if (!swiper.params.virtual.enabled) return;\n\n if (swiper.params.cssMode && !swiper._immediateVirtual) {\n clearTimeout(cssModeTimeout);\n cssModeTimeout = setTimeout(() => {\n update();\n }, 100);\n } else {\n update();\n }\n });\n on('init update resize', () => {\n if (!swiper.params.virtual.enabled) return;\n\n if (swiper.params.cssMode) {\n setCSSProperty(swiper.wrapperEl, '--swiper-virtual-size', `${swiper.virtualSize}px`);\n }\n });\n Object.assign(swiper.virtual, {\n appendSlide,\n prependSlide,\n removeSlide,\n removeAllSlides,\n update\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/keyboard/keyboard.js\n/* eslint-disable consistent-return */\n\n\nfunction Keyboard({\n swiper,\n extendParams,\n on,\n emit\n}) {\n const document = getDocument();\n const window = getWindow();\n swiper.keyboard = {\n enabled: false\n };\n extendParams({\n keyboard: {\n enabled: false,\n onlyInViewport: true,\n pageUpDown: true\n }\n });\n\n function handle(event) {\n if (!swiper.enabled) return;\n const {\n rtlTranslate: rtl\n } = swiper;\n let e = event;\n if (e.originalEvent) e = e.originalEvent; // jquery fix\n\n const kc = e.keyCode || e.charCode;\n const pageUpDown = swiper.params.keyboard.pageUpDown;\n const isPageUp = pageUpDown && kc === 33;\n const isPageDown = pageUpDown && kc === 34;\n const isArrowLeft = kc === 37;\n const isArrowRight = kc === 39;\n const isArrowUp = kc === 38;\n const isArrowDown = kc === 40; // Directions locks\n\n if (!swiper.allowSlideNext && (swiper.isHorizontal() && isArrowRight || swiper.isVertical() && isArrowDown || isPageDown)) {\n return false;\n }\n\n if (!swiper.allowSlidePrev && (swiper.isHorizontal() && isArrowLeft || swiper.isVertical() && isArrowUp || isPageUp)) {\n return false;\n }\n\n if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey) {\n return undefined;\n }\n\n if (document.activeElement && document.activeElement.nodeName && (document.activeElement.nodeName.toLowerCase() === 'input' || document.activeElement.nodeName.toLowerCase() === 'textarea')) {\n return undefined;\n }\n\n if (swiper.params.keyboard.onlyInViewport && (isPageUp || isPageDown || isArrowLeft || isArrowRight || isArrowUp || isArrowDown)) {\n let inView = false; // Check that swiper should be inside of visible area of window\n\n if (swiper.$el.parents(`.${swiper.params.slideClass}`).length > 0 && swiper.$el.parents(`.${swiper.params.slideActiveClass}`).length === 0) {\n return undefined;\n }\n\n const $el = swiper.$el;\n const swiperWidth = $el[0].clientWidth;\n const swiperHeight = $el[0].clientHeight;\n const windowWidth = window.innerWidth;\n const windowHeight = window.innerHeight;\n const swiperOffset = swiper.$el.offset();\n if (rtl) swiperOffset.left -= swiper.$el[0].scrollLeft;\n const swiperCoord = [[swiperOffset.left, swiperOffset.top], [swiperOffset.left + swiperWidth, swiperOffset.top], [swiperOffset.left, swiperOffset.top + swiperHeight], [swiperOffset.left + swiperWidth, swiperOffset.top + swiperHeight]];\n\n for (let i = 0; i < swiperCoord.length; i += 1) {\n const point = swiperCoord[i];\n\n if (point[0] >= 0 && point[0] <= windowWidth && point[1] >= 0 && point[1] <= windowHeight) {\n if (point[0] === 0 && point[1] === 0) continue; // eslint-disable-line\n\n inView = true;\n }\n }\n\n if (!inView) return undefined;\n }\n\n if (swiper.isHorizontal()) {\n if (isPageUp || isPageDown || isArrowLeft || isArrowRight) {\n if (e.preventDefault) e.preventDefault();else e.returnValue = false;\n }\n\n if ((isPageDown || isArrowRight) && !rtl || (isPageUp || isArrowLeft) && rtl) swiper.slideNext();\n if ((isPageUp || isArrowLeft) && !rtl || (isPageDown || isArrowRight) && rtl) swiper.slidePrev();\n } else {\n if (isPageUp || isPageDown || isArrowUp || isArrowDown) {\n if (e.preventDefault) e.preventDefault();else e.returnValue = false;\n }\n\n if (isPageDown || isArrowDown) swiper.slideNext();\n if (isPageUp || isArrowUp) swiper.slidePrev();\n }\n\n emit('keyPress', kc);\n return undefined;\n }\n\n function enable() {\n if (swiper.keyboard.enabled) return;\n $(document).on('keydown', handle);\n swiper.keyboard.enabled = true;\n }\n\n function disable() {\n if (!swiper.keyboard.enabled) return;\n $(document).off('keydown', handle);\n swiper.keyboard.enabled = false;\n }\n\n on('init', () => {\n if (swiper.params.keyboard.enabled) {\n enable();\n }\n });\n on('destroy', () => {\n if (swiper.keyboard.enabled) {\n disable();\n }\n });\n Object.assign(swiper.keyboard, {\n enable,\n disable\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/mousewheel/mousewheel.js\n/* eslint-disable consistent-return */\n\n\n\nfunction Mousewheel({\n swiper,\n extendParams,\n on,\n emit\n}) {\n const window = getWindow();\n extendParams({\n mousewheel: {\n enabled: false,\n releaseOnEdges: false,\n invert: false,\n forceToAxis: false,\n sensitivity: 1,\n eventsTarget: 'container',\n thresholdDelta: null,\n thresholdTime: null\n }\n });\n swiper.mousewheel = {\n enabled: false\n };\n let timeout;\n let lastScrollTime = now();\n let lastEventBeforeSnap;\n const recentWheelEvents = [];\n\n function normalize(e) {\n // Reasonable defaults\n const PIXEL_STEP = 10;\n const LINE_HEIGHT = 40;\n const PAGE_HEIGHT = 800;\n let sX = 0;\n let sY = 0; // spinX, spinY\n\n let pX = 0;\n let pY = 0; // pixelX, pixelY\n // Legacy\n\n if ('detail' in e) {\n sY = e.detail;\n }\n\n if ('wheelDelta' in e) {\n sY = -e.wheelDelta / 120;\n }\n\n if ('wheelDeltaY' in e) {\n sY = -e.wheelDeltaY / 120;\n }\n\n if ('wheelDeltaX' in e) {\n sX = -e.wheelDeltaX / 120;\n } // side scrolling on FF with DOMMouseScroll\n\n\n if ('axis' in e && e.axis === e.HORIZONTAL_AXIS) {\n sX = sY;\n sY = 0;\n }\n\n pX = sX * PIXEL_STEP;\n pY = sY * PIXEL_STEP;\n\n if ('deltaY' in e) {\n pY = e.deltaY;\n }\n\n if ('deltaX' in e) {\n pX = e.deltaX;\n }\n\n if (e.shiftKey && !pX) {\n // if user scrolls with shift he wants horizontal scroll\n pX = pY;\n pY = 0;\n }\n\n if ((pX || pY) && e.deltaMode) {\n if (e.deltaMode === 1) {\n // delta in LINE units\n pX *= LINE_HEIGHT;\n pY *= LINE_HEIGHT;\n } else {\n // delta in PAGE units\n pX *= PAGE_HEIGHT;\n pY *= PAGE_HEIGHT;\n }\n } // Fall-back if spin cannot be determined\n\n\n if (pX && !sX) {\n sX = pX < 1 ? -1 : 1;\n }\n\n if (pY && !sY) {\n sY = pY < 1 ? -1 : 1;\n }\n\n return {\n spinX: sX,\n spinY: sY,\n pixelX: pX,\n pixelY: pY\n };\n }\n\n function handleMouseEnter() {\n if (!swiper.enabled) return;\n swiper.mouseEntered = true;\n }\n\n function handleMouseLeave() {\n if (!swiper.enabled) return;\n swiper.mouseEntered = false;\n }\n\n function animateSlider(newEvent) {\n if (swiper.params.mousewheel.thresholdDelta && newEvent.delta < swiper.params.mousewheel.thresholdDelta) {\n // Prevent if delta of wheel scroll delta is below configured threshold\n return false;\n }\n\n if (swiper.params.mousewheel.thresholdTime && now() - lastScrollTime < swiper.params.mousewheel.thresholdTime) {\n // Prevent if time between scrolls is below configured threshold\n return false;\n } // If the movement is NOT big enough and\n // if the last time the user scrolled was too close to the current one (avoid continuously triggering the slider):\n // Don't go any further (avoid insignificant scroll movement).\n\n\n if (newEvent.delta >= 6 && now() - lastScrollTime < 60) {\n // Return false as a default\n return true;\n } // If user is scrolling towards the end:\n // If the slider hasn't hit the latest slide or\n // if the slider is a loop and\n // if the slider isn't moving right now:\n // Go to next slide and\n // emit a scroll event.\n // Else (the user is scrolling towards the beginning) and\n // if the slider hasn't hit the first slide or\n // if the slider is a loop and\n // if the slider isn't moving right now:\n // Go to prev slide and\n // emit a scroll event.\n\n\n if (newEvent.direction < 0) {\n if ((!swiper.isEnd || swiper.params.loop) && !swiper.animating) {\n swiper.slideNext();\n emit('scroll', newEvent.raw);\n }\n } else if ((!swiper.isBeginning || swiper.params.loop) && !swiper.animating) {\n swiper.slidePrev();\n emit('scroll', newEvent.raw);\n } // If you got here is because an animation has been triggered so store the current time\n\n\n lastScrollTime = new window.Date().getTime(); // Return false as a default\n\n return false;\n }\n\n function releaseScroll(newEvent) {\n const params = swiper.params.mousewheel;\n\n if (newEvent.direction < 0) {\n if (swiper.isEnd && !swiper.params.loop && params.releaseOnEdges) {\n // Return true to animate scroll on edges\n return true;\n }\n } else if (swiper.isBeginning && !swiper.params.loop && params.releaseOnEdges) {\n // Return true to animate scroll on edges\n return true;\n }\n\n return false;\n }\n\n function handle(event) {\n let e = event;\n let disableParentSwiper = true;\n if (!swiper.enabled) return;\n const params = swiper.params.mousewheel;\n\n if (swiper.params.cssMode) {\n e.preventDefault();\n }\n\n let target = swiper.$el;\n\n if (swiper.params.mousewheel.eventsTarget !== 'container') {\n target = $(swiper.params.mousewheel.eventsTarget);\n }\n\n if (!swiper.mouseEntered && !target[0].contains(e.target) && !params.releaseOnEdges) return true;\n if (e.originalEvent) e = e.originalEvent; // jquery fix\n\n let delta = 0;\n const rtlFactor = swiper.rtlTranslate ? -1 : 1;\n const data = normalize(e);\n\n if (params.forceToAxis) {\n if (swiper.isHorizontal()) {\n if (Math.abs(data.pixelX) > Math.abs(data.pixelY)) delta = -data.pixelX * rtlFactor;else return true;\n } else if (Math.abs(data.pixelY) > Math.abs(data.pixelX)) delta = -data.pixelY;else return true;\n } else {\n delta = Math.abs(data.pixelX) > Math.abs(data.pixelY) ? -data.pixelX * rtlFactor : -data.pixelY;\n }\n\n if (delta === 0) return true;\n if (params.invert) delta = -delta; // Get the scroll positions\n\n let positions = swiper.getTranslate() + delta * params.sensitivity;\n if (positions >= swiper.minTranslate()) positions = swiper.minTranslate();\n if (positions <= swiper.maxTranslate()) positions = swiper.maxTranslate(); // When loop is true:\n // the disableParentSwiper will be true.\n // When loop is false:\n // if the scroll positions is not on edge,\n // then the disableParentSwiper will be true.\n // if the scroll on edge positions,\n // then the disableParentSwiper will be false.\n\n disableParentSwiper = swiper.params.loop ? true : !(positions === swiper.minTranslate() || positions === swiper.maxTranslate());\n if (disableParentSwiper && swiper.params.nested) e.stopPropagation();\n\n if (!swiper.params.freeMode || !swiper.params.freeMode.enabled) {\n // Register the new event in a variable which stores the relevant data\n const newEvent = {\n time: now(),\n delta: Math.abs(delta),\n direction: Math.sign(delta),\n raw: event\n }; // Keep the most recent events\n\n if (recentWheelEvents.length >= 2) {\n recentWheelEvents.shift(); // only store the last N events\n }\n\n const prevEvent = recentWheelEvents.length ? recentWheelEvents[recentWheelEvents.length - 1] : undefined;\n recentWheelEvents.push(newEvent); // If there is at least one previous recorded event:\n // If direction has changed or\n // if the scroll is quicker than the previous one:\n // Animate the slider.\n // Else (this is the first time the wheel is moved):\n // Animate the slider.\n\n if (prevEvent) {\n if (newEvent.direction !== prevEvent.direction || newEvent.delta > prevEvent.delta || newEvent.time > prevEvent.time + 150) {\n animateSlider(newEvent);\n }\n } else {\n animateSlider(newEvent);\n } // If it's time to release the scroll:\n // Return now so you don't hit the preventDefault.\n\n\n if (releaseScroll(newEvent)) {\n return true;\n }\n } else {\n // Freemode or scrollContainer:\n // If we recently snapped after a momentum scroll, then ignore wheel events\n // to give time for the deceleration to finish. Stop ignoring after 500 msecs\n // or if it's a new scroll (larger delta or inverse sign as last event before\n // an end-of-momentum snap).\n const newEvent = {\n time: now(),\n delta: Math.abs(delta),\n direction: Math.sign(delta)\n };\n const ignoreWheelEvents = lastEventBeforeSnap && newEvent.time < lastEventBeforeSnap.time + 500 && newEvent.delta <= lastEventBeforeSnap.delta && newEvent.direction === lastEventBeforeSnap.direction;\n\n if (!ignoreWheelEvents) {\n lastEventBeforeSnap = undefined;\n\n if (swiper.params.loop) {\n swiper.loopFix();\n }\n\n let position = swiper.getTranslate() + delta * params.sensitivity;\n const wasBeginning = swiper.isBeginning;\n const wasEnd = swiper.isEnd;\n if (position >= swiper.minTranslate()) position = swiper.minTranslate();\n if (position <= swiper.maxTranslate()) position = swiper.maxTranslate();\n swiper.setTransition(0);\n swiper.setTranslate(position);\n swiper.updateProgress();\n swiper.updateActiveIndex();\n swiper.updateSlidesClasses();\n\n if (!wasBeginning && swiper.isBeginning || !wasEnd && swiper.isEnd) {\n swiper.updateSlidesClasses();\n }\n\n if (swiper.params.freeMode.sticky) {\n // When wheel scrolling starts with sticky (aka snap) enabled, then detect\n // the end of a momentum scroll by storing recent (N=15?) wheel events.\n // 1. do all N events have decreasing or same (absolute value) delta?\n // 2. did all N events arrive in the last M (M=500?) msecs?\n // 3. does the earliest event have an (absolute value) delta that's\n // at least P (P=1?) larger than the most recent event's delta?\n // 4. does the latest event have a delta that's smaller than Q (Q=6?) pixels?\n // If 1-4 are \"yes\" then we're near the end of a momentum scroll deceleration.\n // Snap immediately and ignore remaining wheel events in this scroll.\n // See comment above for \"remaining wheel events in this scroll\" determination.\n // If 1-4 aren't satisfied, then wait to snap until 500ms after the last event.\n clearTimeout(timeout);\n timeout = undefined;\n\n if (recentWheelEvents.length >= 15) {\n recentWheelEvents.shift(); // only store the last N events\n }\n\n const prevEvent = recentWheelEvents.length ? recentWheelEvents[recentWheelEvents.length - 1] : undefined;\n const firstEvent = recentWheelEvents[0];\n recentWheelEvents.push(newEvent);\n\n if (prevEvent && (newEvent.delta > prevEvent.delta || newEvent.direction !== prevEvent.direction)) {\n // Increasing or reverse-sign delta means the user started scrolling again. Clear the wheel event log.\n recentWheelEvents.splice(0);\n } else if (recentWheelEvents.length >= 15 && newEvent.time - firstEvent.time < 500 && firstEvent.delta - newEvent.delta >= 1 && newEvent.delta <= 6) {\n // We're at the end of the deceleration of a momentum scroll, so there's no need\n // to wait for more events. Snap ASAP on the next tick.\n // Also, because there's some remaining momentum we'll bias the snap in the\n // direction of the ongoing scroll because it's better UX for the scroll to snap\n // in the same direction as the scroll instead of reversing to snap. Therefore,\n // if it's already scrolled more than 20% in the current direction, keep going.\n const snapToThreshold = delta > 0 ? 0.8 : 0.2;\n lastEventBeforeSnap = newEvent;\n recentWheelEvents.splice(0);\n timeout = nextTick(() => {\n swiper.slideToClosest(swiper.params.speed, true, undefined, snapToThreshold);\n }, 0); // no delay; move on next tick\n }\n\n if (!timeout) {\n // if we get here, then we haven't detected the end of a momentum scroll, so\n // we'll consider a scroll \"complete\" when there haven't been any wheel events\n // for 500ms.\n timeout = nextTick(() => {\n const snapToThreshold = 0.5;\n lastEventBeforeSnap = newEvent;\n recentWheelEvents.splice(0);\n swiper.slideToClosest(swiper.params.speed, true, undefined, snapToThreshold);\n }, 500);\n }\n } // Emit event\n\n\n if (!ignoreWheelEvents) emit('scroll', e); // Stop autoplay\n\n if (swiper.params.autoplay && swiper.params.autoplayDisableOnInteraction) swiper.autoplay.stop(); // Return page scroll on edge positions\n\n if (position === swiper.minTranslate() || position === swiper.maxTranslate()) return true;\n }\n }\n\n if (e.preventDefault) e.preventDefault();else e.returnValue = false;\n return false;\n }\n\n function events(method) {\n let target = swiper.$el;\n\n if (swiper.params.mousewheel.eventsTarget !== 'container') {\n target = $(swiper.params.mousewheel.eventsTarget);\n }\n\n target[method]('mouseenter', handleMouseEnter);\n target[method]('mouseleave', handleMouseLeave);\n target[method]('wheel', handle);\n }\n\n function enable() {\n if (swiper.params.cssMode) {\n swiper.wrapperEl.removeEventListener('wheel', handle);\n return true;\n }\n\n if (swiper.mousewheel.enabled) return false;\n events('on');\n swiper.mousewheel.enabled = true;\n return true;\n }\n\n function disable() {\n if (swiper.params.cssMode) {\n swiper.wrapperEl.addEventListener(event, handle);\n return true;\n }\n\n if (!swiper.mousewheel.enabled) return false;\n events('off');\n swiper.mousewheel.enabled = false;\n return true;\n }\n\n on('init', () => {\n if (!swiper.params.mousewheel.enabled && swiper.params.cssMode) {\n disable();\n }\n\n if (swiper.params.mousewheel.enabled) enable();\n });\n on('destroy', () => {\n if (swiper.params.cssMode) {\n enable();\n }\n\n if (swiper.mousewheel.enabled) disable();\n });\n Object.assign(swiper.mousewheel, {\n enable,\n disable\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/shared/create-element-if-not-defined.js\n\nfunction create_element_if_not_defined_createElementIfNotDefined(swiper, originalParams, params, checkProps) {\n const document = ssr_window_esm_getDocument();\n\n if (swiper.params.createElements) {\n Object.keys(checkProps).forEach(key => {\n if (!params[key] && params.auto === true) {\n let element = swiper.$el.children(`.${checkProps[key]}`)[0];\n\n if (!element) {\n element = document.createElement('div');\n element.className = checkProps[key];\n swiper.$el.append(element);\n }\n\n params[key] = element;\n originalParams[key] = element;\n }\n });\n }\n\n return params;\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/navigation/navigation.js\n\n\nfunction Navigation({\n swiper,\n extendParams,\n on,\n emit\n}) {\n extendParams({\n navigation: {\n nextEl: null,\n prevEl: null,\n hideOnClick: false,\n disabledClass: 'swiper-button-disabled',\n hiddenClass: 'swiper-button-hidden',\n lockClass: 'swiper-button-lock',\n navigationDisabledClass: 'swiper-navigation-disabled'\n }\n });\n swiper.navigation = {\n nextEl: null,\n $nextEl: null,\n prevEl: null,\n $prevEl: null\n };\n\n function getEl(el) {\n let $el;\n\n if (el) {\n $el = dom(el);\n\n if (swiper.params.uniqueNavElements && typeof el === 'string' && $el.length > 1 && swiper.$el.find(el).length === 1) {\n $el = swiper.$el.find(el);\n }\n }\n\n return $el;\n }\n\n function toggleEl($el, disabled) {\n const params = swiper.params.navigation;\n\n if ($el && $el.length > 0) {\n $el[disabled ? 'addClass' : 'removeClass'](params.disabledClass);\n if ($el[0] && $el[0].tagName === 'BUTTON') $el[0].disabled = disabled;\n\n if (swiper.params.watchOverflow && swiper.enabled) {\n $el[swiper.isLocked ? 'addClass' : 'removeClass'](params.lockClass);\n }\n }\n }\n\n function update() {\n // Update Navigation Buttons\n if (swiper.params.loop) return;\n const {\n $nextEl,\n $prevEl\n } = swiper.navigation;\n toggleEl($prevEl, swiper.isBeginning && !swiper.params.rewind);\n toggleEl($nextEl, swiper.isEnd && !swiper.params.rewind);\n }\n\n function onPrevClick(e) {\n e.preventDefault();\n if (swiper.isBeginning && !swiper.params.loop && !swiper.params.rewind) return;\n swiper.slidePrev();\n emit('navigationPrev');\n }\n\n function onNextClick(e) {\n e.preventDefault();\n if (swiper.isEnd && !swiper.params.loop && !swiper.params.rewind) return;\n swiper.slideNext();\n emit('navigationNext');\n }\n\n function init() {\n const params = swiper.params.navigation;\n swiper.params.navigation = create_element_if_not_defined_createElementIfNotDefined(swiper, swiper.originalParams.navigation, swiper.params.navigation, {\n nextEl: 'swiper-button-next',\n prevEl: 'swiper-button-prev'\n });\n if (!(params.nextEl || params.prevEl)) return;\n const $nextEl = getEl(params.nextEl);\n const $prevEl = getEl(params.prevEl);\n\n if ($nextEl && $nextEl.length > 0) {\n $nextEl.on('click', onNextClick);\n }\n\n if ($prevEl && $prevEl.length > 0) {\n $prevEl.on('click', onPrevClick);\n }\n\n Object.assign(swiper.navigation, {\n $nextEl,\n nextEl: $nextEl && $nextEl[0],\n $prevEl,\n prevEl: $prevEl && $prevEl[0]\n });\n\n if (!swiper.enabled) {\n if ($nextEl) $nextEl.addClass(params.lockClass);\n if ($prevEl) $prevEl.addClass(params.lockClass);\n }\n }\n\n function destroy() {\n const {\n $nextEl,\n $prevEl\n } = swiper.navigation;\n\n if ($nextEl && $nextEl.length) {\n $nextEl.off('click', onNextClick);\n $nextEl.removeClass(swiper.params.navigation.disabledClass);\n }\n\n if ($prevEl && $prevEl.length) {\n $prevEl.off('click', onPrevClick);\n $prevEl.removeClass(swiper.params.navigation.disabledClass);\n }\n }\n\n on('init', () => {\n if (swiper.params.navigation.enabled === false) {\n // eslint-disable-next-line\n disable();\n } else {\n init();\n update();\n }\n });\n on('toEdge fromEdge lock unlock', () => {\n update();\n });\n on('destroy', () => {\n destroy();\n });\n on('enable disable', () => {\n const {\n $nextEl,\n $prevEl\n } = swiper.navigation;\n\n if ($nextEl) {\n $nextEl[swiper.enabled ? 'removeClass' : 'addClass'](swiper.params.navigation.lockClass);\n }\n\n if ($prevEl) {\n $prevEl[swiper.enabled ? 'removeClass' : 'addClass'](swiper.params.navigation.lockClass);\n }\n });\n on('click', (_s, e) => {\n const {\n $nextEl,\n $prevEl\n } = swiper.navigation;\n const targetEl = e.target;\n\n if (swiper.params.navigation.hideOnClick && !dom(targetEl).is($prevEl) && !dom(targetEl).is($nextEl)) {\n if (swiper.pagination && swiper.params.pagination && swiper.params.pagination.clickable && (swiper.pagination.el === targetEl || swiper.pagination.el.contains(targetEl))) return;\n let isHidden;\n\n if ($nextEl) {\n isHidden = $nextEl.hasClass(swiper.params.navigation.hiddenClass);\n } else if ($prevEl) {\n isHidden = $prevEl.hasClass(swiper.params.navigation.hiddenClass);\n }\n\n if (isHidden === true) {\n emit('navigationShow');\n } else {\n emit('navigationHide');\n }\n\n if ($nextEl) {\n $nextEl.toggleClass(swiper.params.navigation.hiddenClass);\n }\n\n if ($prevEl) {\n $prevEl.toggleClass(swiper.params.navigation.hiddenClass);\n }\n }\n });\n\n const enable = () => {\n swiper.$el.removeClass(swiper.params.navigation.navigationDisabledClass);\n init();\n update();\n };\n\n const disable = () => {\n swiper.$el.addClass(swiper.params.navigation.navigationDisabledClass);\n destroy();\n };\n\n Object.assign(swiper.navigation, {\n enable,\n disable,\n update,\n init,\n destroy\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/pagination/pagination.js\n\n\n\nfunction Pagination({\n swiper,\n extendParams,\n on,\n emit\n}) {\n const pfx = 'swiper-pagination';\n extendParams({\n pagination: {\n el: null,\n bulletElement: 'span',\n clickable: false,\n hideOnClick: false,\n renderBullet: null,\n renderProgressbar: null,\n renderFraction: null,\n renderCustom: null,\n progressbarOpposite: false,\n type: 'bullets',\n // 'bullets' or 'progressbar' or 'fraction' or 'custom'\n dynamicBullets: false,\n dynamicMainBullets: 1,\n formatFractionCurrent: number => number,\n formatFractionTotal: number => number,\n bulletClass: `${pfx}-bullet`,\n bulletActiveClass: `${pfx}-bullet-active`,\n modifierClass: `${pfx}-`,\n currentClass: `${pfx}-current`,\n totalClass: `${pfx}-total`,\n hiddenClass: `${pfx}-hidden`,\n progressbarFillClass: `${pfx}-progressbar-fill`,\n progressbarOppositeClass: `${pfx}-progressbar-opposite`,\n clickableClass: `${pfx}-clickable`,\n lockClass: `${pfx}-lock`,\n horizontalClass: `${pfx}-horizontal`,\n verticalClass: `${pfx}-vertical`,\n paginationDisabledClass: `${pfx}-disabled`\n }\n });\n swiper.pagination = {\n el: null,\n $el: null,\n bullets: []\n };\n let bulletSize;\n let dynamicBulletIndex = 0;\n\n function isPaginationDisabled() {\n return !swiper.params.pagination.el || !swiper.pagination.el || !swiper.pagination.$el || swiper.pagination.$el.length === 0;\n }\n\n function setSideBullets($bulletEl, position) {\n const {\n bulletActiveClass\n } = swiper.params.pagination;\n $bulletEl[position]().addClass(`${bulletActiveClass}-${position}`)[position]().addClass(`${bulletActiveClass}-${position}-${position}`);\n }\n\n function update() {\n // Render || Update Pagination bullets/items\n const rtl = swiper.rtl;\n const params = swiper.params.pagination;\n if (isPaginationDisabled()) return;\n const slidesLength = swiper.virtual && swiper.params.virtual.enabled ? swiper.virtual.slides.length : swiper.slides.length;\n const $el = swiper.pagination.$el; // Current/Total\n\n let current;\n const total = swiper.params.loop ? Math.ceil((slidesLength - swiper.loopedSlides * 2) / swiper.params.slidesPerGroup) : swiper.snapGrid.length;\n\n if (swiper.params.loop) {\n current = Math.ceil((swiper.activeIndex - swiper.loopedSlides) / swiper.params.slidesPerGroup);\n\n if (current > slidesLength - 1 - swiper.loopedSlides * 2) {\n current -= slidesLength - swiper.loopedSlides * 2;\n }\n\n if (current > total - 1) current -= total;\n if (current < 0 && swiper.params.paginationType !== 'bullets') current = total + current;\n } else if (typeof swiper.snapIndex !== 'undefined') {\n current = swiper.snapIndex;\n } else {\n current = swiper.activeIndex || 0;\n } // Types\n\n\n if (params.type === 'bullets' && swiper.pagination.bullets && swiper.pagination.bullets.length > 0) {\n const bullets = swiper.pagination.bullets;\n let firstIndex;\n let lastIndex;\n let midIndex;\n\n if (params.dynamicBullets) {\n bulletSize = bullets.eq(0)[swiper.isHorizontal() ? 'outerWidth' : 'outerHeight'](true);\n $el.css(swiper.isHorizontal() ? 'width' : 'height', `${bulletSize * (params.dynamicMainBullets + 4)}px`);\n\n if (params.dynamicMainBullets > 1 && swiper.previousIndex !== undefined) {\n dynamicBulletIndex += current - (swiper.previousIndex - swiper.loopedSlides || 0);\n\n if (dynamicBulletIndex > params.dynamicMainBullets - 1) {\n dynamicBulletIndex = params.dynamicMainBullets - 1;\n } else if (dynamicBulletIndex < 0) {\n dynamicBulletIndex = 0;\n }\n }\n\n firstIndex = Math.max(current - dynamicBulletIndex, 0);\n lastIndex = firstIndex + (Math.min(bullets.length, params.dynamicMainBullets) - 1);\n midIndex = (lastIndex + firstIndex) / 2;\n }\n\n bullets.removeClass(['', '-next', '-next-next', '-prev', '-prev-prev', '-main'].map(suffix => `${params.bulletActiveClass}${suffix}`).join(' '));\n\n if ($el.length > 1) {\n bullets.each(bullet => {\n const $bullet = $(bullet);\n const bulletIndex = $bullet.index();\n\n if (bulletIndex === current) {\n $bullet.addClass(params.bulletActiveClass);\n }\n\n if (params.dynamicBullets) {\n if (bulletIndex >= firstIndex && bulletIndex <= lastIndex) {\n $bullet.addClass(`${params.bulletActiveClass}-main`);\n }\n\n if (bulletIndex === firstIndex) {\n setSideBullets($bullet, 'prev');\n }\n\n if (bulletIndex === lastIndex) {\n setSideBullets($bullet, 'next');\n }\n }\n });\n } else {\n const $bullet = bullets.eq(current);\n const bulletIndex = $bullet.index();\n $bullet.addClass(params.bulletActiveClass);\n\n if (params.dynamicBullets) {\n const $firstDisplayedBullet = bullets.eq(firstIndex);\n const $lastDisplayedBullet = bullets.eq(lastIndex);\n\n for (let i = firstIndex; i <= lastIndex; i += 1) {\n bullets.eq(i).addClass(`${params.bulletActiveClass}-main`);\n }\n\n if (swiper.params.loop) {\n if (bulletIndex >= bullets.length) {\n for (let i = params.dynamicMainBullets; i >= 0; i -= 1) {\n bullets.eq(bullets.length - i).addClass(`${params.bulletActiveClass}-main`);\n }\n\n bullets.eq(bullets.length - params.dynamicMainBullets - 1).addClass(`${params.bulletActiveClass}-prev`);\n } else {\n setSideBullets($firstDisplayedBullet, 'prev');\n setSideBullets($lastDisplayedBullet, 'next');\n }\n } else {\n setSideBullets($firstDisplayedBullet, 'prev');\n setSideBullets($lastDisplayedBullet, 'next');\n }\n }\n }\n\n if (params.dynamicBullets) {\n const dynamicBulletsLength = Math.min(bullets.length, params.dynamicMainBullets + 4);\n const bulletsOffset = (bulletSize * dynamicBulletsLength - bulletSize) / 2 - midIndex * bulletSize;\n const offsetProp = rtl ? 'right' : 'left';\n bullets.css(swiper.isHorizontal() ? offsetProp : 'top', `${bulletsOffset}px`);\n }\n }\n\n if (params.type === 'fraction') {\n $el.find(classesToSelector(params.currentClass)).text(params.formatFractionCurrent(current + 1));\n $el.find(classesToSelector(params.totalClass)).text(params.formatFractionTotal(total));\n }\n\n if (params.type === 'progressbar') {\n let progressbarDirection;\n\n if (params.progressbarOpposite) {\n progressbarDirection = swiper.isHorizontal() ? 'vertical' : 'horizontal';\n } else {\n progressbarDirection = swiper.isHorizontal() ? 'horizontal' : 'vertical';\n }\n\n const scale = (current + 1) / total;\n let scaleX = 1;\n let scaleY = 1;\n\n if (progressbarDirection === 'horizontal') {\n scaleX = scale;\n } else {\n scaleY = scale;\n }\n\n $el.find(classesToSelector(params.progressbarFillClass)).transform(`translate3d(0,0,0) scaleX(${scaleX}) scaleY(${scaleY})`).transition(swiper.params.speed);\n }\n\n if (params.type === 'custom' && params.renderCustom) {\n $el.html(params.renderCustom(swiper, current + 1, total));\n emit('paginationRender', $el[0]);\n } else {\n emit('paginationUpdate', $el[0]);\n }\n\n if (swiper.params.watchOverflow && swiper.enabled) {\n $el[swiper.isLocked ? 'addClass' : 'removeClass'](params.lockClass);\n }\n }\n\n function render() {\n // Render Container\n const params = swiper.params.pagination;\n if (isPaginationDisabled()) return;\n const slidesLength = swiper.virtual && swiper.params.virtual.enabled ? swiper.virtual.slides.length : swiper.slides.length;\n const $el = swiper.pagination.$el;\n let paginationHTML = '';\n\n if (params.type === 'bullets') {\n let numberOfBullets = swiper.params.loop ? Math.ceil((slidesLength - swiper.loopedSlides * 2) / swiper.params.slidesPerGroup) : swiper.snapGrid.length;\n\n if (swiper.params.freeMode && swiper.params.freeMode.enabled && !swiper.params.loop && numberOfBullets > slidesLength) {\n numberOfBullets = slidesLength;\n }\n\n for (let i = 0; i < numberOfBullets; i += 1) {\n if (params.renderBullet) {\n paginationHTML += params.renderBullet.call(swiper, i, params.bulletClass);\n } else {\n paginationHTML += `<${params.bulletElement} class=\"${params.bulletClass}\">`;\n }\n }\n\n $el.html(paginationHTML);\n swiper.pagination.bullets = $el.find(classesToSelector(params.bulletClass));\n }\n\n if (params.type === 'fraction') {\n if (params.renderFraction) {\n paginationHTML = params.renderFraction.call(swiper, params.currentClass, params.totalClass);\n } else {\n paginationHTML = `` + ' / ' + ``;\n }\n\n $el.html(paginationHTML);\n }\n\n if (params.type === 'progressbar') {\n if (params.renderProgressbar) {\n paginationHTML = params.renderProgressbar.call(swiper, params.progressbarFillClass);\n } else {\n paginationHTML = ``;\n }\n\n $el.html(paginationHTML);\n }\n\n if (params.type !== 'custom') {\n emit('paginationRender', swiper.pagination.$el[0]);\n }\n }\n\n function init() {\n swiper.params.pagination = createElementIfNotDefined(swiper, swiper.originalParams.pagination, swiper.params.pagination, {\n el: 'swiper-pagination'\n });\n const params = swiper.params.pagination;\n if (!params.el) return;\n let $el = $(params.el);\n if ($el.length === 0) return;\n\n if (swiper.params.uniqueNavElements && typeof params.el === 'string' && $el.length > 1) {\n $el = swiper.$el.find(params.el); // check if it belongs to another nested Swiper\n\n if ($el.length > 1) {\n $el = $el.filter(el => {\n if ($(el).parents('.swiper')[0] !== swiper.el) return false;\n return true;\n });\n }\n }\n\n if (params.type === 'bullets' && params.clickable) {\n $el.addClass(params.clickableClass);\n }\n\n $el.addClass(params.modifierClass + params.type);\n $el.addClass(swiper.isHorizontal() ? params.horizontalClass : params.verticalClass);\n\n if (params.type === 'bullets' && params.dynamicBullets) {\n $el.addClass(`${params.modifierClass}${params.type}-dynamic`);\n dynamicBulletIndex = 0;\n\n if (params.dynamicMainBullets < 1) {\n params.dynamicMainBullets = 1;\n }\n }\n\n if (params.type === 'progressbar' && params.progressbarOpposite) {\n $el.addClass(params.progressbarOppositeClass);\n }\n\n if (params.clickable) {\n $el.on('click', classesToSelector(params.bulletClass), function onClick(e) {\n e.preventDefault();\n let index = $(this).index() * swiper.params.slidesPerGroup;\n if (swiper.params.loop) index += swiper.loopedSlides;\n swiper.slideTo(index);\n });\n }\n\n Object.assign(swiper.pagination, {\n $el,\n el: $el[0]\n });\n\n if (!swiper.enabled) {\n $el.addClass(params.lockClass);\n }\n }\n\n function destroy() {\n const params = swiper.params.pagination;\n if (isPaginationDisabled()) return;\n const $el = swiper.pagination.$el;\n $el.removeClass(params.hiddenClass);\n $el.removeClass(params.modifierClass + params.type);\n $el.removeClass(swiper.isHorizontal() ? params.horizontalClass : params.verticalClass);\n if (swiper.pagination.bullets && swiper.pagination.bullets.removeClass) swiper.pagination.bullets.removeClass(params.bulletActiveClass);\n\n if (params.clickable) {\n $el.off('click', classesToSelector(params.bulletClass));\n }\n }\n\n on('init', () => {\n if (swiper.params.pagination.enabled === false) {\n // eslint-disable-next-line\n disable();\n } else {\n init();\n render();\n update();\n }\n });\n on('activeIndexChange', () => {\n if (swiper.params.loop) {\n update();\n } else if (typeof swiper.snapIndex === 'undefined') {\n update();\n }\n });\n on('snapIndexChange', () => {\n if (!swiper.params.loop) {\n update();\n }\n });\n on('slidesLengthChange', () => {\n if (swiper.params.loop) {\n render();\n update();\n }\n });\n on('snapGridLengthChange', () => {\n if (!swiper.params.loop) {\n render();\n update();\n }\n });\n on('destroy', () => {\n destroy();\n });\n on('enable disable', () => {\n const {\n $el\n } = swiper.pagination;\n\n if ($el) {\n $el[swiper.enabled ? 'removeClass' : 'addClass'](swiper.params.pagination.lockClass);\n }\n });\n on('lock unlock', () => {\n update();\n });\n on('click', (_s, e) => {\n const targetEl = e.target;\n const {\n $el\n } = swiper.pagination;\n\n if (swiper.params.pagination.el && swiper.params.pagination.hideOnClick && $el && $el.length > 0 && !$(targetEl).hasClass(swiper.params.pagination.bulletClass)) {\n if (swiper.navigation && (swiper.navigation.nextEl && targetEl === swiper.navigation.nextEl || swiper.navigation.prevEl && targetEl === swiper.navigation.prevEl)) return;\n const isHidden = $el.hasClass(swiper.params.pagination.hiddenClass);\n\n if (isHidden === true) {\n emit('paginationShow');\n } else {\n emit('paginationHide');\n }\n\n $el.toggleClass(swiper.params.pagination.hiddenClass);\n }\n });\n\n const enable = () => {\n swiper.$el.removeClass(swiper.params.pagination.paginationDisabledClass);\n\n if (swiper.pagination.$el) {\n swiper.pagination.$el.removeClass(swiper.params.pagination.paginationDisabledClass);\n }\n\n init();\n render();\n update();\n };\n\n const disable = () => {\n swiper.$el.addClass(swiper.params.pagination.paginationDisabledClass);\n\n if (swiper.pagination.$el) {\n swiper.pagination.$el.addClass(swiper.params.pagination.paginationDisabledClass);\n }\n\n destroy();\n };\n\n Object.assign(swiper.pagination, {\n enable,\n disable,\n render,\n update,\n init,\n destroy\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/scrollbar/scrollbar.js\n\n\n\n\nfunction Scrollbar({\n swiper,\n extendParams,\n on,\n emit\n}) {\n const document = getDocument();\n let isTouched = false;\n let timeout = null;\n let dragTimeout = null;\n let dragStartPos;\n let dragSize;\n let trackSize;\n let divider;\n extendParams({\n scrollbar: {\n el: null,\n dragSize: 'auto',\n hide: false,\n draggable: false,\n snapOnRelease: true,\n lockClass: 'swiper-scrollbar-lock',\n dragClass: 'swiper-scrollbar-drag',\n scrollbarDisabledClass: 'swiper-scrollbar-disabled',\n horizontalClass: `swiper-scrollbar-horizontal`,\n verticalClass: `swiper-scrollbar-vertical`\n }\n });\n swiper.scrollbar = {\n el: null,\n dragEl: null,\n $el: null,\n $dragEl: null\n };\n\n function setTranslate() {\n if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;\n const {\n scrollbar,\n rtlTranslate: rtl,\n progress\n } = swiper;\n const {\n $dragEl,\n $el\n } = scrollbar;\n const params = swiper.params.scrollbar;\n let newSize = dragSize;\n let newPos = (trackSize - dragSize) * progress;\n\n if (rtl) {\n newPos = -newPos;\n\n if (newPos > 0) {\n newSize = dragSize - newPos;\n newPos = 0;\n } else if (-newPos + dragSize > trackSize) {\n newSize = trackSize + newPos;\n }\n } else if (newPos < 0) {\n newSize = dragSize + newPos;\n newPos = 0;\n } else if (newPos + dragSize > trackSize) {\n newSize = trackSize - newPos;\n }\n\n if (swiper.isHorizontal()) {\n $dragEl.transform(`translate3d(${newPos}px, 0, 0)`);\n $dragEl[0].style.width = `${newSize}px`;\n } else {\n $dragEl.transform(`translate3d(0px, ${newPos}px, 0)`);\n $dragEl[0].style.height = `${newSize}px`;\n }\n\n if (params.hide) {\n clearTimeout(timeout);\n $el[0].style.opacity = 1;\n timeout = setTimeout(() => {\n $el[0].style.opacity = 0;\n $el.transition(400);\n }, 1000);\n }\n }\n\n function setTransition(duration) {\n if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;\n swiper.scrollbar.$dragEl.transition(duration);\n }\n\n function updateSize() {\n if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;\n const {\n scrollbar\n } = swiper;\n const {\n $dragEl,\n $el\n } = scrollbar;\n $dragEl[0].style.width = '';\n $dragEl[0].style.height = '';\n trackSize = swiper.isHorizontal() ? $el[0].offsetWidth : $el[0].offsetHeight;\n divider = swiper.size / (swiper.virtualSize + swiper.params.slidesOffsetBefore - (swiper.params.centeredSlides ? swiper.snapGrid[0] : 0));\n\n if (swiper.params.scrollbar.dragSize === 'auto') {\n dragSize = trackSize * divider;\n } else {\n dragSize = parseInt(swiper.params.scrollbar.dragSize, 10);\n }\n\n if (swiper.isHorizontal()) {\n $dragEl[0].style.width = `${dragSize}px`;\n } else {\n $dragEl[0].style.height = `${dragSize}px`;\n }\n\n if (divider >= 1) {\n $el[0].style.display = 'none';\n } else {\n $el[0].style.display = '';\n }\n\n if (swiper.params.scrollbar.hide) {\n $el[0].style.opacity = 0;\n }\n\n if (swiper.params.watchOverflow && swiper.enabled) {\n scrollbar.$el[swiper.isLocked ? 'addClass' : 'removeClass'](swiper.params.scrollbar.lockClass);\n }\n }\n\n function getPointerPosition(e) {\n if (swiper.isHorizontal()) {\n return e.type === 'touchstart' || e.type === 'touchmove' ? e.targetTouches[0].clientX : e.clientX;\n }\n\n return e.type === 'touchstart' || e.type === 'touchmove' ? e.targetTouches[0].clientY : e.clientY;\n }\n\n function setDragPosition(e) {\n const {\n scrollbar,\n rtlTranslate: rtl\n } = swiper;\n const {\n $el\n } = scrollbar;\n let positionRatio;\n positionRatio = (getPointerPosition(e) - $el.offset()[swiper.isHorizontal() ? 'left' : 'top'] - (dragStartPos !== null ? dragStartPos : dragSize / 2)) / (trackSize - dragSize);\n positionRatio = Math.max(Math.min(positionRatio, 1), 0);\n\n if (rtl) {\n positionRatio = 1 - positionRatio;\n }\n\n const position = swiper.minTranslate() + (swiper.maxTranslate() - swiper.minTranslate()) * positionRatio;\n swiper.updateProgress(position);\n swiper.setTranslate(position);\n swiper.updateActiveIndex();\n swiper.updateSlidesClasses();\n }\n\n function onDragStart(e) {\n const params = swiper.params.scrollbar;\n const {\n scrollbar,\n $wrapperEl\n } = swiper;\n const {\n $el,\n $dragEl\n } = scrollbar;\n isTouched = true;\n dragStartPos = e.target === $dragEl[0] || e.target === $dragEl ? getPointerPosition(e) - e.target.getBoundingClientRect()[swiper.isHorizontal() ? 'left' : 'top'] : null;\n e.preventDefault();\n e.stopPropagation();\n $wrapperEl.transition(100);\n $dragEl.transition(100);\n setDragPosition(e);\n clearTimeout(dragTimeout);\n $el.transition(0);\n\n if (params.hide) {\n $el.css('opacity', 1);\n }\n\n if (swiper.params.cssMode) {\n swiper.$wrapperEl.css('scroll-snap-type', 'none');\n }\n\n emit('scrollbarDragStart', e);\n }\n\n function onDragMove(e) {\n const {\n scrollbar,\n $wrapperEl\n } = swiper;\n const {\n $el,\n $dragEl\n } = scrollbar;\n if (!isTouched) return;\n if (e.preventDefault) e.preventDefault();else e.returnValue = false;\n setDragPosition(e);\n $wrapperEl.transition(0);\n $el.transition(0);\n $dragEl.transition(0);\n emit('scrollbarDragMove', e);\n }\n\n function onDragEnd(e) {\n const params = swiper.params.scrollbar;\n const {\n scrollbar,\n $wrapperEl\n } = swiper;\n const {\n $el\n } = scrollbar;\n if (!isTouched) return;\n isTouched = false;\n\n if (swiper.params.cssMode) {\n swiper.$wrapperEl.css('scroll-snap-type', '');\n $wrapperEl.transition('');\n }\n\n if (params.hide) {\n clearTimeout(dragTimeout);\n dragTimeout = nextTick(() => {\n $el.css('opacity', 0);\n $el.transition(400);\n }, 1000);\n }\n\n emit('scrollbarDragEnd', e);\n\n if (params.snapOnRelease) {\n swiper.slideToClosest();\n }\n }\n\n function events(method) {\n const {\n scrollbar,\n touchEventsTouch,\n touchEventsDesktop,\n params,\n support\n } = swiper;\n const $el = scrollbar.$el;\n if (!$el) return;\n const target = $el[0];\n const activeListener = support.passiveListener && params.passiveListeners ? {\n passive: false,\n capture: false\n } : false;\n const passiveListener = support.passiveListener && params.passiveListeners ? {\n passive: true,\n capture: false\n } : false;\n if (!target) return;\n const eventMethod = method === 'on' ? 'addEventListener' : 'removeEventListener';\n\n if (!support.touch) {\n target[eventMethod](touchEventsDesktop.start, onDragStart, activeListener);\n document[eventMethod](touchEventsDesktop.move, onDragMove, activeListener);\n document[eventMethod](touchEventsDesktop.end, onDragEnd, passiveListener);\n } else {\n target[eventMethod](touchEventsTouch.start, onDragStart, activeListener);\n target[eventMethod](touchEventsTouch.move, onDragMove, activeListener);\n target[eventMethod](touchEventsTouch.end, onDragEnd, passiveListener);\n }\n }\n\n function enableDraggable() {\n if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;\n events('on');\n }\n\n function disableDraggable() {\n if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;\n events('off');\n }\n\n function init() {\n const {\n scrollbar,\n $el: $swiperEl\n } = swiper;\n swiper.params.scrollbar = createElementIfNotDefined(swiper, swiper.originalParams.scrollbar, swiper.params.scrollbar, {\n el: 'swiper-scrollbar'\n });\n const params = swiper.params.scrollbar;\n if (!params.el) return;\n let $el = $(params.el);\n\n if (swiper.params.uniqueNavElements && typeof params.el === 'string' && $el.length > 1 && $swiperEl.find(params.el).length === 1) {\n $el = $swiperEl.find(params.el);\n }\n\n $el.addClass(swiper.isHorizontal() ? params.horizontalClass : params.verticalClass);\n let $dragEl = $el.find(`.${swiper.params.scrollbar.dragClass}`);\n\n if ($dragEl.length === 0) {\n $dragEl = $(`
`);\n $el.append($dragEl);\n }\n\n Object.assign(scrollbar, {\n $el,\n el: $el[0],\n $dragEl,\n dragEl: $dragEl[0]\n });\n\n if (params.draggable) {\n enableDraggable();\n }\n\n if ($el) {\n $el[swiper.enabled ? 'removeClass' : 'addClass'](swiper.params.scrollbar.lockClass);\n }\n }\n\n function destroy() {\n const params = swiper.params.scrollbar;\n const $el = swiper.scrollbar.$el;\n\n if ($el) {\n $el.removeClass(swiper.isHorizontal() ? params.horizontalClass : params.verticalClass);\n }\n\n disableDraggable();\n }\n\n on('init', () => {\n if (swiper.params.scrollbar.enabled === false) {\n // eslint-disable-next-line\n disable();\n } else {\n init();\n updateSize();\n setTranslate();\n }\n });\n on('update resize observerUpdate lock unlock', () => {\n updateSize();\n });\n on('setTranslate', () => {\n setTranslate();\n });\n on('setTransition', (_s, duration) => {\n setTransition(duration);\n });\n on('enable disable', () => {\n const {\n $el\n } = swiper.scrollbar;\n\n if ($el) {\n $el[swiper.enabled ? 'removeClass' : 'addClass'](swiper.params.scrollbar.lockClass);\n }\n });\n on('destroy', () => {\n destroy();\n });\n\n const enable = () => {\n swiper.$el.removeClass(swiper.params.scrollbar.scrollbarDisabledClass);\n\n if (swiper.scrollbar.$el) {\n swiper.scrollbar.$el.removeClass(swiper.params.scrollbar.scrollbarDisabledClass);\n }\n\n init();\n updateSize();\n setTranslate();\n };\n\n const disable = () => {\n swiper.$el.addClass(swiper.params.scrollbar.scrollbarDisabledClass);\n\n if (swiper.scrollbar.$el) {\n swiper.scrollbar.$el.addClass(swiper.params.scrollbar.scrollbarDisabledClass);\n }\n\n destroy();\n };\n\n Object.assign(swiper.scrollbar, {\n enable,\n disable,\n updateSize,\n setTranslate,\n init,\n destroy\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/parallax/parallax.js\n\nfunction Parallax({\n swiper,\n extendParams,\n on\n}) {\n extendParams({\n parallax: {\n enabled: false\n }\n });\n\n const setTransform = (el, progress) => {\n const {\n rtl\n } = swiper;\n const $el = $(el);\n const rtlFactor = rtl ? -1 : 1;\n const p = $el.attr('data-swiper-parallax') || '0';\n let x = $el.attr('data-swiper-parallax-x');\n let y = $el.attr('data-swiper-parallax-y');\n const scale = $el.attr('data-swiper-parallax-scale');\n const opacity = $el.attr('data-swiper-parallax-opacity');\n\n if (x || y) {\n x = x || '0';\n y = y || '0';\n } else if (swiper.isHorizontal()) {\n x = p;\n y = '0';\n } else {\n y = p;\n x = '0';\n }\n\n if (x.indexOf('%') >= 0) {\n x = `${parseInt(x, 10) * progress * rtlFactor}%`;\n } else {\n x = `${x * progress * rtlFactor}px`;\n }\n\n if (y.indexOf('%') >= 0) {\n y = `${parseInt(y, 10) * progress}%`;\n } else {\n y = `${y * progress}px`;\n }\n\n if (typeof opacity !== 'undefined' && opacity !== null) {\n const currentOpacity = opacity - (opacity - 1) * (1 - Math.abs(progress));\n $el[0].style.opacity = currentOpacity;\n }\n\n if (typeof scale === 'undefined' || scale === null) {\n $el.transform(`translate3d(${x}, ${y}, 0px)`);\n } else {\n const currentScale = scale - (scale - 1) * (1 - Math.abs(progress));\n $el.transform(`translate3d(${x}, ${y}, 0px) scale(${currentScale})`);\n }\n };\n\n const setTranslate = () => {\n const {\n $el,\n slides,\n progress,\n snapGrid\n } = swiper;\n $el.children('[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y], [data-swiper-parallax-opacity], [data-swiper-parallax-scale]').each(el => {\n setTransform(el, progress);\n });\n slides.each((slideEl, slideIndex) => {\n let slideProgress = slideEl.progress;\n\n if (swiper.params.slidesPerGroup > 1 && swiper.params.slidesPerView !== 'auto') {\n slideProgress += Math.ceil(slideIndex / 2) - progress * (snapGrid.length - 1);\n }\n\n slideProgress = Math.min(Math.max(slideProgress, -1), 1);\n $(slideEl).find('[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y], [data-swiper-parallax-opacity], [data-swiper-parallax-scale]').each(el => {\n setTransform(el, slideProgress);\n });\n });\n };\n\n const setTransition = (duration = swiper.params.speed) => {\n const {\n $el\n } = swiper;\n $el.find('[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y], [data-swiper-parallax-opacity], [data-swiper-parallax-scale]').each(parallaxEl => {\n const $parallaxEl = $(parallaxEl);\n let parallaxDuration = parseInt($parallaxEl.attr('data-swiper-parallax-duration'), 10) || duration;\n if (duration === 0) parallaxDuration = 0;\n $parallaxEl.transition(parallaxDuration);\n });\n };\n\n on('beforeInit', () => {\n if (!swiper.params.parallax.enabled) return;\n swiper.params.watchSlidesProgress = true;\n swiper.originalParams.watchSlidesProgress = true;\n });\n on('init', () => {\n if (!swiper.params.parallax.enabled) return;\n setTranslate();\n });\n on('setTranslate', () => {\n if (!swiper.params.parallax.enabled) return;\n setTranslate();\n });\n on('setTransition', (_swiper, duration) => {\n if (!swiper.params.parallax.enabled) return;\n setTransition(duration);\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/zoom/zoom.js\n\n\n\nfunction Zoom({\n swiper,\n extendParams,\n on,\n emit\n}) {\n const window = getWindow();\n extendParams({\n zoom: {\n enabled: false,\n maxRatio: 3,\n minRatio: 1,\n toggle: true,\n containerClass: 'swiper-zoom-container',\n zoomedSlideClass: 'swiper-slide-zoomed'\n }\n });\n swiper.zoom = {\n enabled: false\n };\n let currentScale = 1;\n let isScaling = false;\n let gesturesEnabled;\n let fakeGestureTouched;\n let fakeGestureMoved;\n const gesture = {\n $slideEl: undefined,\n slideWidth: undefined,\n slideHeight: undefined,\n $imageEl: undefined,\n $imageWrapEl: undefined,\n maxRatio: 3\n };\n const image = {\n isTouched: undefined,\n isMoved: undefined,\n currentX: undefined,\n currentY: undefined,\n minX: undefined,\n minY: undefined,\n maxX: undefined,\n maxY: undefined,\n width: undefined,\n height: undefined,\n startX: undefined,\n startY: undefined,\n touchesStart: {},\n touchesCurrent: {}\n };\n const velocity = {\n x: undefined,\n y: undefined,\n prevPositionX: undefined,\n prevPositionY: undefined,\n prevTime: undefined\n };\n let scale = 1;\n Object.defineProperty(swiper.zoom, 'scale', {\n get() {\n return scale;\n },\n\n set(value) {\n if (scale !== value) {\n const imageEl = gesture.$imageEl ? gesture.$imageEl[0] : undefined;\n const slideEl = gesture.$slideEl ? gesture.$slideEl[0] : undefined;\n emit('zoomChange', value, imageEl, slideEl);\n }\n\n scale = value;\n }\n\n });\n\n function getDistanceBetweenTouches(e) {\n if (e.targetTouches.length < 2) return 1;\n const x1 = e.targetTouches[0].pageX;\n const y1 = e.targetTouches[0].pageY;\n const x2 = e.targetTouches[1].pageX;\n const y2 = e.targetTouches[1].pageY;\n const distance = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);\n return distance;\n } // Events\n\n\n function onGestureStart(e) {\n const support = swiper.support;\n const params = swiper.params.zoom;\n fakeGestureTouched = false;\n fakeGestureMoved = false;\n\n if (!support.gestures) {\n if (e.type !== 'touchstart' || e.type === 'touchstart' && e.targetTouches.length < 2) {\n return;\n }\n\n fakeGestureTouched = true;\n gesture.scaleStart = getDistanceBetweenTouches(e);\n }\n\n if (!gesture.$slideEl || !gesture.$slideEl.length) {\n gesture.$slideEl = $(e.target).closest(`.${swiper.params.slideClass}`);\n if (gesture.$slideEl.length === 0) gesture.$slideEl = swiper.slides.eq(swiper.activeIndex);\n gesture.$imageEl = gesture.$slideEl.find(`.${params.containerClass}`).eq(0).find('picture, img, svg, canvas, .swiper-zoom-target').eq(0);\n gesture.$imageWrapEl = gesture.$imageEl.parent(`.${params.containerClass}`);\n gesture.maxRatio = gesture.$imageWrapEl.attr('data-swiper-zoom') || params.maxRatio;\n\n if (gesture.$imageWrapEl.length === 0) {\n gesture.$imageEl = undefined;\n return;\n }\n }\n\n if (gesture.$imageEl) {\n gesture.$imageEl.transition(0);\n }\n\n isScaling = true;\n }\n\n function onGestureChange(e) {\n const support = swiper.support;\n const params = swiper.params.zoom;\n const zoom = swiper.zoom;\n\n if (!support.gestures) {\n if (e.type !== 'touchmove' || e.type === 'touchmove' && e.targetTouches.length < 2) {\n return;\n }\n\n fakeGestureMoved = true;\n gesture.scaleMove = getDistanceBetweenTouches(e);\n }\n\n if (!gesture.$imageEl || gesture.$imageEl.length === 0) {\n if (e.type === 'gesturechange') onGestureStart(e);\n return;\n }\n\n if (support.gestures) {\n zoom.scale = e.scale * currentScale;\n } else {\n zoom.scale = gesture.scaleMove / gesture.scaleStart * currentScale;\n }\n\n if (zoom.scale > gesture.maxRatio) {\n zoom.scale = gesture.maxRatio - 1 + (zoom.scale - gesture.maxRatio + 1) ** 0.5;\n }\n\n if (zoom.scale < params.minRatio) {\n zoom.scale = params.minRatio + 1 - (params.minRatio - zoom.scale + 1) ** 0.5;\n }\n\n gesture.$imageEl.transform(`translate3d(0,0,0) scale(${zoom.scale})`);\n }\n\n function onGestureEnd(e) {\n const device = swiper.device;\n const support = swiper.support;\n const params = swiper.params.zoom;\n const zoom = swiper.zoom;\n\n if (!support.gestures) {\n if (!fakeGestureTouched || !fakeGestureMoved) {\n return;\n }\n\n if (e.type !== 'touchend' || e.type === 'touchend' && e.changedTouches.length < 2 && !device.android) {\n return;\n }\n\n fakeGestureTouched = false;\n fakeGestureMoved = false;\n }\n\n if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;\n zoom.scale = Math.max(Math.min(zoom.scale, gesture.maxRatio), params.minRatio);\n gesture.$imageEl.transition(swiper.params.speed).transform(`translate3d(0,0,0) scale(${zoom.scale})`);\n currentScale = zoom.scale;\n isScaling = false;\n if (zoom.scale === 1) gesture.$slideEl = undefined;\n }\n\n function onTouchStart(e) {\n const device = swiper.device;\n if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;\n if (image.isTouched) return;\n if (device.android && e.cancelable) e.preventDefault();\n image.isTouched = true;\n image.touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;\n image.touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;\n }\n\n function onTouchMove(e) {\n const zoom = swiper.zoom;\n if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;\n swiper.allowClick = false;\n if (!image.isTouched || !gesture.$slideEl) return;\n\n if (!image.isMoved) {\n image.width = gesture.$imageEl[0].offsetWidth;\n image.height = gesture.$imageEl[0].offsetHeight;\n image.startX = getTranslate(gesture.$imageWrapEl[0], 'x') || 0;\n image.startY = getTranslate(gesture.$imageWrapEl[0], 'y') || 0;\n gesture.slideWidth = gesture.$slideEl[0].offsetWidth;\n gesture.slideHeight = gesture.$slideEl[0].offsetHeight;\n gesture.$imageWrapEl.transition(0);\n } // Define if we need image drag\n\n\n const scaledWidth = image.width * zoom.scale;\n const scaledHeight = image.height * zoom.scale;\n if (scaledWidth < gesture.slideWidth && scaledHeight < gesture.slideHeight) return;\n image.minX = Math.min(gesture.slideWidth / 2 - scaledWidth / 2, 0);\n image.maxX = -image.minX;\n image.minY = Math.min(gesture.slideHeight / 2 - scaledHeight / 2, 0);\n image.maxY = -image.minY;\n image.touchesCurrent.x = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;\n image.touchesCurrent.y = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;\n\n if (!image.isMoved && !isScaling) {\n if (swiper.isHorizontal() && (Math.floor(image.minX) === Math.floor(image.startX) && image.touchesCurrent.x < image.touchesStart.x || Math.floor(image.maxX) === Math.floor(image.startX) && image.touchesCurrent.x > image.touchesStart.x)) {\n image.isTouched = false;\n return;\n }\n\n if (!swiper.isHorizontal() && (Math.floor(image.minY) === Math.floor(image.startY) && image.touchesCurrent.y < image.touchesStart.y || Math.floor(image.maxY) === Math.floor(image.startY) && image.touchesCurrent.y > image.touchesStart.y)) {\n image.isTouched = false;\n return;\n }\n }\n\n if (e.cancelable) {\n e.preventDefault();\n }\n\n e.stopPropagation();\n image.isMoved = true;\n image.currentX = image.touchesCurrent.x - image.touchesStart.x + image.startX;\n image.currentY = image.touchesCurrent.y - image.touchesStart.y + image.startY;\n\n if (image.currentX < image.minX) {\n image.currentX = image.minX + 1 - (image.minX - image.currentX + 1) ** 0.8;\n }\n\n if (image.currentX > image.maxX) {\n image.currentX = image.maxX - 1 + (image.currentX - image.maxX + 1) ** 0.8;\n }\n\n if (image.currentY < image.minY) {\n image.currentY = image.minY + 1 - (image.minY - image.currentY + 1) ** 0.8;\n }\n\n if (image.currentY > image.maxY) {\n image.currentY = image.maxY - 1 + (image.currentY - image.maxY + 1) ** 0.8;\n } // Velocity\n\n\n if (!velocity.prevPositionX) velocity.prevPositionX = image.touchesCurrent.x;\n if (!velocity.prevPositionY) velocity.prevPositionY = image.touchesCurrent.y;\n if (!velocity.prevTime) velocity.prevTime = Date.now();\n velocity.x = (image.touchesCurrent.x - velocity.prevPositionX) / (Date.now() - velocity.prevTime) / 2;\n velocity.y = (image.touchesCurrent.y - velocity.prevPositionY) / (Date.now() - velocity.prevTime) / 2;\n if (Math.abs(image.touchesCurrent.x - velocity.prevPositionX) < 2) velocity.x = 0;\n if (Math.abs(image.touchesCurrent.y - velocity.prevPositionY) < 2) velocity.y = 0;\n velocity.prevPositionX = image.touchesCurrent.x;\n velocity.prevPositionY = image.touchesCurrent.y;\n velocity.prevTime = Date.now();\n gesture.$imageWrapEl.transform(`translate3d(${image.currentX}px, ${image.currentY}px,0)`);\n }\n\n function onTouchEnd() {\n const zoom = swiper.zoom;\n if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;\n\n if (!image.isTouched || !image.isMoved) {\n image.isTouched = false;\n image.isMoved = false;\n return;\n }\n\n image.isTouched = false;\n image.isMoved = false;\n let momentumDurationX = 300;\n let momentumDurationY = 300;\n const momentumDistanceX = velocity.x * momentumDurationX;\n const newPositionX = image.currentX + momentumDistanceX;\n const momentumDistanceY = velocity.y * momentumDurationY;\n const newPositionY = image.currentY + momentumDistanceY; // Fix duration\n\n if (velocity.x !== 0) momentumDurationX = Math.abs((newPositionX - image.currentX) / velocity.x);\n if (velocity.y !== 0) momentumDurationY = Math.abs((newPositionY - image.currentY) / velocity.y);\n const momentumDuration = Math.max(momentumDurationX, momentumDurationY);\n image.currentX = newPositionX;\n image.currentY = newPositionY; // Define if we need image drag\n\n const scaledWidth = image.width * zoom.scale;\n const scaledHeight = image.height * zoom.scale;\n image.minX = Math.min(gesture.slideWidth / 2 - scaledWidth / 2, 0);\n image.maxX = -image.minX;\n image.minY = Math.min(gesture.slideHeight / 2 - scaledHeight / 2, 0);\n image.maxY = -image.minY;\n image.currentX = Math.max(Math.min(image.currentX, image.maxX), image.minX);\n image.currentY = Math.max(Math.min(image.currentY, image.maxY), image.minY);\n gesture.$imageWrapEl.transition(momentumDuration).transform(`translate3d(${image.currentX}px, ${image.currentY}px,0)`);\n }\n\n function onTransitionEnd() {\n const zoom = swiper.zoom;\n\n if (gesture.$slideEl && swiper.previousIndex !== swiper.activeIndex) {\n if (gesture.$imageEl) {\n gesture.$imageEl.transform('translate3d(0,0,0) scale(1)');\n }\n\n if (gesture.$imageWrapEl) {\n gesture.$imageWrapEl.transform('translate3d(0,0,0)');\n }\n\n zoom.scale = 1;\n currentScale = 1;\n gesture.$slideEl = undefined;\n gesture.$imageEl = undefined;\n gesture.$imageWrapEl = undefined;\n }\n }\n\n function zoomIn(e) {\n const zoom = swiper.zoom;\n const params = swiper.params.zoom;\n\n if (!gesture.$slideEl) {\n if (e && e.target) {\n gesture.$slideEl = $(e.target).closest(`.${swiper.params.slideClass}`);\n }\n\n if (!gesture.$slideEl) {\n if (swiper.params.virtual && swiper.params.virtual.enabled && swiper.virtual) {\n gesture.$slideEl = swiper.$wrapperEl.children(`.${swiper.params.slideActiveClass}`);\n } else {\n gesture.$slideEl = swiper.slides.eq(swiper.activeIndex);\n }\n }\n\n gesture.$imageEl = gesture.$slideEl.find(`.${params.containerClass}`).eq(0).find('picture, img, svg, canvas, .swiper-zoom-target').eq(0);\n gesture.$imageWrapEl = gesture.$imageEl.parent(`.${params.containerClass}`);\n }\n\n if (!gesture.$imageEl || gesture.$imageEl.length === 0 || !gesture.$imageWrapEl || gesture.$imageWrapEl.length === 0) return;\n\n if (swiper.params.cssMode) {\n swiper.wrapperEl.style.overflow = 'hidden';\n swiper.wrapperEl.style.touchAction = 'none';\n }\n\n gesture.$slideEl.addClass(`${params.zoomedSlideClass}`);\n let touchX;\n let touchY;\n let offsetX;\n let offsetY;\n let diffX;\n let diffY;\n let translateX;\n let translateY;\n let imageWidth;\n let imageHeight;\n let scaledWidth;\n let scaledHeight;\n let translateMinX;\n let translateMinY;\n let translateMaxX;\n let translateMaxY;\n let slideWidth;\n let slideHeight;\n\n if (typeof image.touchesStart.x === 'undefined' && e) {\n touchX = e.type === 'touchend' ? e.changedTouches[0].pageX : e.pageX;\n touchY = e.type === 'touchend' ? e.changedTouches[0].pageY : e.pageY;\n } else {\n touchX = image.touchesStart.x;\n touchY = image.touchesStart.y;\n }\n\n zoom.scale = gesture.$imageWrapEl.attr('data-swiper-zoom') || params.maxRatio;\n currentScale = gesture.$imageWrapEl.attr('data-swiper-zoom') || params.maxRatio;\n\n if (e) {\n slideWidth = gesture.$slideEl[0].offsetWidth;\n slideHeight = gesture.$slideEl[0].offsetHeight;\n offsetX = gesture.$slideEl.offset().left + window.scrollX;\n offsetY = gesture.$slideEl.offset().top + window.scrollY;\n diffX = offsetX + slideWidth / 2 - touchX;\n diffY = offsetY + slideHeight / 2 - touchY;\n imageWidth = gesture.$imageEl[0].offsetWidth;\n imageHeight = gesture.$imageEl[0].offsetHeight;\n scaledWidth = imageWidth * zoom.scale;\n scaledHeight = imageHeight * zoom.scale;\n translateMinX = Math.min(slideWidth / 2 - scaledWidth / 2, 0);\n translateMinY = Math.min(slideHeight / 2 - scaledHeight / 2, 0);\n translateMaxX = -translateMinX;\n translateMaxY = -translateMinY;\n translateX = diffX * zoom.scale;\n translateY = diffY * zoom.scale;\n\n if (translateX < translateMinX) {\n translateX = translateMinX;\n }\n\n if (translateX > translateMaxX) {\n translateX = translateMaxX;\n }\n\n if (translateY < translateMinY) {\n translateY = translateMinY;\n }\n\n if (translateY > translateMaxY) {\n translateY = translateMaxY;\n }\n } else {\n translateX = 0;\n translateY = 0;\n }\n\n gesture.$imageWrapEl.transition(300).transform(`translate3d(${translateX}px, ${translateY}px,0)`);\n gesture.$imageEl.transition(300).transform(`translate3d(0,0,0) scale(${zoom.scale})`);\n }\n\n function zoomOut() {\n const zoom = swiper.zoom;\n const params = swiper.params.zoom;\n\n if (!gesture.$slideEl) {\n if (swiper.params.virtual && swiper.params.virtual.enabled && swiper.virtual) {\n gesture.$slideEl = swiper.$wrapperEl.children(`.${swiper.params.slideActiveClass}`);\n } else {\n gesture.$slideEl = swiper.slides.eq(swiper.activeIndex);\n }\n\n gesture.$imageEl = gesture.$slideEl.find(`.${params.containerClass}`).eq(0).find('picture, img, svg, canvas, .swiper-zoom-target').eq(0);\n gesture.$imageWrapEl = gesture.$imageEl.parent(`.${params.containerClass}`);\n }\n\n if (!gesture.$imageEl || gesture.$imageEl.length === 0 || !gesture.$imageWrapEl || gesture.$imageWrapEl.length === 0) return;\n\n if (swiper.params.cssMode) {\n swiper.wrapperEl.style.overflow = '';\n swiper.wrapperEl.style.touchAction = '';\n }\n\n zoom.scale = 1;\n currentScale = 1;\n gesture.$imageWrapEl.transition(300).transform('translate3d(0,0,0)');\n gesture.$imageEl.transition(300).transform('translate3d(0,0,0) scale(1)');\n gesture.$slideEl.removeClass(`${params.zoomedSlideClass}`);\n gesture.$slideEl = undefined;\n } // Toggle Zoom\n\n\n function zoomToggle(e) {\n const zoom = swiper.zoom;\n\n if (zoom.scale && zoom.scale !== 1) {\n // Zoom Out\n zoomOut();\n } else {\n // Zoom In\n zoomIn(e);\n }\n }\n\n function getListeners() {\n const support = swiper.support;\n const passiveListener = swiper.touchEvents.start === 'touchstart' && support.passiveListener && swiper.params.passiveListeners ? {\n passive: true,\n capture: false\n } : false;\n const activeListenerWithCapture = support.passiveListener ? {\n passive: false,\n capture: true\n } : true;\n return {\n passiveListener,\n activeListenerWithCapture\n };\n }\n\n function getSlideSelector() {\n return `.${swiper.params.slideClass}`;\n }\n\n function toggleGestures(method) {\n const {\n passiveListener\n } = getListeners();\n const slideSelector = getSlideSelector();\n swiper.$wrapperEl[method]('gesturestart', slideSelector, onGestureStart, passiveListener);\n swiper.$wrapperEl[method]('gesturechange', slideSelector, onGestureChange, passiveListener);\n swiper.$wrapperEl[method]('gestureend', slideSelector, onGestureEnd, passiveListener);\n }\n\n function enableGestures() {\n if (gesturesEnabled) return;\n gesturesEnabled = true;\n toggleGestures('on');\n }\n\n function disableGestures() {\n if (!gesturesEnabled) return;\n gesturesEnabled = false;\n toggleGestures('off');\n } // Attach/Detach Events\n\n\n function enable() {\n const zoom = swiper.zoom;\n if (zoom.enabled) return;\n zoom.enabled = true;\n const support = swiper.support;\n const {\n passiveListener,\n activeListenerWithCapture\n } = getListeners();\n const slideSelector = getSlideSelector(); // Scale image\n\n if (support.gestures) {\n swiper.$wrapperEl.on(swiper.touchEvents.start, enableGestures, passiveListener);\n swiper.$wrapperEl.on(swiper.touchEvents.end, disableGestures, passiveListener);\n } else if (swiper.touchEvents.start === 'touchstart') {\n swiper.$wrapperEl.on(swiper.touchEvents.start, slideSelector, onGestureStart, passiveListener);\n swiper.$wrapperEl.on(swiper.touchEvents.move, slideSelector, onGestureChange, activeListenerWithCapture);\n swiper.$wrapperEl.on(swiper.touchEvents.end, slideSelector, onGestureEnd, passiveListener);\n\n if (swiper.touchEvents.cancel) {\n swiper.$wrapperEl.on(swiper.touchEvents.cancel, slideSelector, onGestureEnd, passiveListener);\n }\n } // Move image\n\n\n swiper.$wrapperEl.on(swiper.touchEvents.move, `.${swiper.params.zoom.containerClass}`, onTouchMove, activeListenerWithCapture);\n }\n\n function disable() {\n const zoom = swiper.zoom;\n if (!zoom.enabled) return;\n const support = swiper.support;\n zoom.enabled = false;\n const {\n passiveListener,\n activeListenerWithCapture\n } = getListeners();\n const slideSelector = getSlideSelector(); // Scale image\n\n if (support.gestures) {\n swiper.$wrapperEl.off(swiper.touchEvents.start, enableGestures, passiveListener);\n swiper.$wrapperEl.off(swiper.touchEvents.end, disableGestures, passiveListener);\n } else if (swiper.touchEvents.start === 'touchstart') {\n swiper.$wrapperEl.off(swiper.touchEvents.start, slideSelector, onGestureStart, passiveListener);\n swiper.$wrapperEl.off(swiper.touchEvents.move, slideSelector, onGestureChange, activeListenerWithCapture);\n swiper.$wrapperEl.off(swiper.touchEvents.end, slideSelector, onGestureEnd, passiveListener);\n\n if (swiper.touchEvents.cancel) {\n swiper.$wrapperEl.off(swiper.touchEvents.cancel, slideSelector, onGestureEnd, passiveListener);\n }\n } // Move image\n\n\n swiper.$wrapperEl.off(swiper.touchEvents.move, `.${swiper.params.zoom.containerClass}`, onTouchMove, activeListenerWithCapture);\n }\n\n on('init', () => {\n if (swiper.params.zoom.enabled) {\n enable();\n }\n });\n on('destroy', () => {\n disable();\n });\n on('touchStart', (_s, e) => {\n if (!swiper.zoom.enabled) return;\n onTouchStart(e);\n });\n on('touchEnd', (_s, e) => {\n if (!swiper.zoom.enabled) return;\n onTouchEnd(e);\n });\n on('doubleTap', (_s, e) => {\n if (!swiper.animating && swiper.params.zoom.enabled && swiper.zoom.enabled && swiper.params.zoom.toggle) {\n zoomToggle(e);\n }\n });\n on('transitionEnd', () => {\n if (swiper.zoom.enabled && swiper.params.zoom.enabled) {\n onTransitionEnd();\n }\n });\n on('slideChange', () => {\n if (swiper.zoom.enabled && swiper.params.zoom.enabled && swiper.params.cssMode) {\n onTransitionEnd();\n }\n });\n Object.assign(swiper.zoom, {\n enable,\n disable,\n in: zoomIn,\n out: zoomOut,\n toggle: zoomToggle\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/lazy/lazy.js\n\n\nfunction Lazy({\n swiper,\n extendParams,\n on,\n emit\n}) {\n extendParams({\n lazy: {\n checkInView: false,\n enabled: false,\n loadPrevNext: false,\n loadPrevNextAmount: 1,\n loadOnTransitionStart: false,\n scrollingElement: '',\n elementClass: 'swiper-lazy',\n loadingClass: 'swiper-lazy-loading',\n loadedClass: 'swiper-lazy-loaded',\n preloaderClass: 'swiper-lazy-preloader'\n }\n });\n swiper.lazy = {};\n let scrollHandlerAttached = false;\n let initialImageLoaded = false;\n\n function loadInSlide(index, loadInDuplicate = true) {\n const params = swiper.params.lazy;\n if (typeof index === 'undefined') return;\n if (swiper.slides.length === 0) return;\n const isVirtual = swiper.virtual && swiper.params.virtual.enabled;\n const $slideEl = isVirtual ? swiper.$wrapperEl.children(`.${swiper.params.slideClass}[data-swiper-slide-index=\"${index}\"]`) : swiper.slides.eq(index);\n const $images = $slideEl.find(`.${params.elementClass}:not(.${params.loadedClass}):not(.${params.loadingClass})`);\n\n if ($slideEl.hasClass(params.elementClass) && !$slideEl.hasClass(params.loadedClass) && !$slideEl.hasClass(params.loadingClass)) {\n $images.push($slideEl[0]);\n }\n\n if ($images.length === 0) return;\n $images.each(imageEl => {\n const $imageEl = $(imageEl);\n $imageEl.addClass(params.loadingClass);\n const background = $imageEl.attr('data-background');\n const src = $imageEl.attr('data-src');\n const srcset = $imageEl.attr('data-srcset');\n const sizes = $imageEl.attr('data-sizes');\n const $pictureEl = $imageEl.parent('picture');\n swiper.loadImage($imageEl[0], src || background, srcset, sizes, false, () => {\n if (typeof swiper === 'undefined' || swiper === null || !swiper || swiper && !swiper.params || swiper.destroyed) return;\n\n if (background) {\n $imageEl.css('background-image', `url(\"${background}\")`);\n $imageEl.removeAttr('data-background');\n } else {\n if (srcset) {\n $imageEl.attr('srcset', srcset);\n $imageEl.removeAttr('data-srcset');\n }\n\n if (sizes) {\n $imageEl.attr('sizes', sizes);\n $imageEl.removeAttr('data-sizes');\n }\n\n if ($pictureEl.length) {\n $pictureEl.children('source').each(sourceEl => {\n const $source = $(sourceEl);\n\n if ($source.attr('data-srcset')) {\n $source.attr('srcset', $source.attr('data-srcset'));\n $source.removeAttr('data-srcset');\n }\n });\n }\n\n if (src) {\n $imageEl.attr('src', src);\n $imageEl.removeAttr('data-src');\n }\n }\n\n $imageEl.addClass(params.loadedClass).removeClass(params.loadingClass);\n $slideEl.find(`.${params.preloaderClass}`).remove();\n\n if (swiper.params.loop && loadInDuplicate) {\n const slideOriginalIndex = $slideEl.attr('data-swiper-slide-index');\n\n if ($slideEl.hasClass(swiper.params.slideDuplicateClass)) {\n const originalSlide = swiper.$wrapperEl.children(`[data-swiper-slide-index=\"${slideOriginalIndex}\"]:not(.${swiper.params.slideDuplicateClass})`);\n loadInSlide(originalSlide.index(), false);\n } else {\n const duplicatedSlide = swiper.$wrapperEl.children(`.${swiper.params.slideDuplicateClass}[data-swiper-slide-index=\"${slideOriginalIndex}\"]`);\n loadInSlide(duplicatedSlide.index(), false);\n }\n }\n\n emit('lazyImageReady', $slideEl[0], $imageEl[0]);\n\n if (swiper.params.autoHeight) {\n swiper.updateAutoHeight();\n }\n });\n emit('lazyImageLoad', $slideEl[0], $imageEl[0]);\n });\n }\n\n function load() {\n const {\n $wrapperEl,\n params: swiperParams,\n slides,\n activeIndex\n } = swiper;\n const isVirtual = swiper.virtual && swiperParams.virtual.enabled;\n const params = swiperParams.lazy;\n let slidesPerView = swiperParams.slidesPerView;\n\n if (slidesPerView === 'auto') {\n slidesPerView = 0;\n }\n\n function slideExist(index) {\n if (isVirtual) {\n if ($wrapperEl.children(`.${swiperParams.slideClass}[data-swiper-slide-index=\"${index}\"]`).length) {\n return true;\n }\n } else if (slides[index]) return true;\n\n return false;\n }\n\n function slideIndex(slideEl) {\n if (isVirtual) {\n return $(slideEl).attr('data-swiper-slide-index');\n }\n\n return $(slideEl).index();\n }\n\n if (!initialImageLoaded) initialImageLoaded = true;\n\n if (swiper.params.watchSlidesProgress) {\n $wrapperEl.children(`.${swiperParams.slideVisibleClass}`).each(slideEl => {\n const index = isVirtual ? $(slideEl).attr('data-swiper-slide-index') : $(slideEl).index();\n loadInSlide(index);\n });\n } else if (slidesPerView > 1) {\n for (let i = activeIndex; i < activeIndex + slidesPerView; i += 1) {\n if (slideExist(i)) loadInSlide(i);\n }\n } else {\n loadInSlide(activeIndex);\n }\n\n if (params.loadPrevNext) {\n if (slidesPerView > 1 || params.loadPrevNextAmount && params.loadPrevNextAmount > 1) {\n const amount = params.loadPrevNextAmount;\n const spv = Math.ceil(slidesPerView);\n const maxIndex = Math.min(activeIndex + spv + Math.max(amount, spv), slides.length);\n const minIndex = Math.max(activeIndex - Math.max(spv, amount), 0); // Next Slides\n\n for (let i = activeIndex + spv; i < maxIndex; i += 1) {\n if (slideExist(i)) loadInSlide(i);\n } // Prev Slides\n\n\n for (let i = minIndex; i < activeIndex; i += 1) {\n if (slideExist(i)) loadInSlide(i);\n }\n } else {\n const nextSlide = $wrapperEl.children(`.${swiperParams.slideNextClass}`);\n if (nextSlide.length > 0) loadInSlide(slideIndex(nextSlide));\n const prevSlide = $wrapperEl.children(`.${swiperParams.slidePrevClass}`);\n if (prevSlide.length > 0) loadInSlide(slideIndex(prevSlide));\n }\n }\n }\n\n function checkInViewOnLoad() {\n const window = getWindow();\n if (!swiper || swiper.destroyed) return;\n const $scrollElement = swiper.params.lazy.scrollingElement ? $(swiper.params.lazy.scrollingElement) : $(window);\n const isWindow = $scrollElement[0] === window;\n const scrollElementWidth = isWindow ? window.innerWidth : $scrollElement[0].offsetWidth;\n const scrollElementHeight = isWindow ? window.innerHeight : $scrollElement[0].offsetHeight;\n const swiperOffset = swiper.$el.offset();\n const {\n rtlTranslate: rtl\n } = swiper;\n let inView = false;\n if (rtl) swiperOffset.left -= swiper.$el[0].scrollLeft;\n const swiperCoord = [[swiperOffset.left, swiperOffset.top], [swiperOffset.left + swiper.width, swiperOffset.top], [swiperOffset.left, swiperOffset.top + swiper.height], [swiperOffset.left + swiper.width, swiperOffset.top + swiper.height]];\n\n for (let i = 0; i < swiperCoord.length; i += 1) {\n const point = swiperCoord[i];\n\n if (point[0] >= 0 && point[0] <= scrollElementWidth && point[1] >= 0 && point[1] <= scrollElementHeight) {\n if (point[0] === 0 && point[1] === 0) continue; // eslint-disable-line\n\n inView = true;\n }\n }\n\n const passiveListener = swiper.touchEvents.start === 'touchstart' && swiper.support.passiveListener && swiper.params.passiveListeners ? {\n passive: true,\n capture: false\n } : false;\n\n if (inView) {\n load();\n $scrollElement.off('scroll', checkInViewOnLoad, passiveListener);\n } else if (!scrollHandlerAttached) {\n scrollHandlerAttached = true;\n $scrollElement.on('scroll', checkInViewOnLoad, passiveListener);\n }\n }\n\n on('beforeInit', () => {\n if (swiper.params.lazy.enabled && swiper.params.preloadImages) {\n swiper.params.preloadImages = false;\n }\n });\n on('init', () => {\n if (swiper.params.lazy.enabled) {\n if (swiper.params.lazy.checkInView) {\n checkInViewOnLoad();\n } else {\n load();\n }\n }\n });\n on('scroll', () => {\n if (swiper.params.freeMode && swiper.params.freeMode.enabled && !swiper.params.freeMode.sticky) {\n load();\n }\n });\n on('scrollbarDragMove resize _freeModeNoMomentumRelease', () => {\n if (swiper.params.lazy.enabled) {\n if (swiper.params.lazy.checkInView) {\n checkInViewOnLoad();\n } else {\n load();\n }\n }\n });\n on('transitionStart', () => {\n if (swiper.params.lazy.enabled) {\n if (swiper.params.lazy.loadOnTransitionStart || !swiper.params.lazy.loadOnTransitionStart && !initialImageLoaded) {\n if (swiper.params.lazy.checkInView) {\n checkInViewOnLoad();\n } else {\n load();\n }\n }\n }\n });\n on('transitionEnd', () => {\n if (swiper.params.lazy.enabled && !swiper.params.lazy.loadOnTransitionStart) {\n if (swiper.params.lazy.checkInView) {\n checkInViewOnLoad();\n } else {\n load();\n }\n }\n });\n on('slideChange', () => {\n const {\n lazy,\n cssMode,\n watchSlidesProgress,\n touchReleaseOnEdges,\n resistanceRatio\n } = swiper.params;\n\n if (lazy.enabled && (cssMode || watchSlidesProgress && (touchReleaseOnEdges || resistanceRatio === 0))) {\n load();\n }\n });\n on('destroy', () => {\n if (!swiper.$el) return;\n swiper.$el.find(`.${swiper.params.lazy.loadingClass}`).removeClass(swiper.params.lazy.loadingClass);\n });\n Object.assign(swiper.lazy, {\n load,\n loadInSlide\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/controller/controller.js\n/* eslint no-bitwise: [\"error\", { \"allow\": [\">>\"] }] */\n\nfunction Controller({\n swiper,\n extendParams,\n on\n}) {\n extendParams({\n controller: {\n control: undefined,\n inverse: false,\n by: 'slide' // or 'container'\n\n }\n });\n swiper.controller = {\n control: undefined\n };\n\n function LinearSpline(x, y) {\n const binarySearch = function search() {\n let maxIndex;\n let minIndex;\n let guess;\n return (array, val) => {\n minIndex = -1;\n maxIndex = array.length;\n\n while (maxIndex - minIndex > 1) {\n guess = maxIndex + minIndex >> 1;\n\n if (array[guess] <= val) {\n minIndex = guess;\n } else {\n maxIndex = guess;\n }\n }\n\n return maxIndex;\n };\n }();\n\n this.x = x;\n this.y = y;\n this.lastIndex = x.length - 1; // Given an x value (x2), return the expected y2 value:\n // (x1,y1) is the known point before given value,\n // (x3,y3) is the known point after given value.\n\n let i1;\n let i3;\n\n this.interpolate = function interpolate(x2) {\n if (!x2) return 0; // Get the indexes of x1 and x3 (the array indexes before and after given x2):\n\n i3 = binarySearch(this.x, x2);\n i1 = i3 - 1; // We have our indexes i1 & i3, so we can calculate already:\n // y2 := ((x2−x1) × (y3−y1)) ÷ (x3−x1) + y1\n\n return (x2 - this.x[i1]) * (this.y[i3] - this.y[i1]) / (this.x[i3] - this.x[i1]) + this.y[i1];\n };\n\n return this;\n } // xxx: for now i will just save one spline function to to\n\n\n function getInterpolateFunction(c) {\n if (!swiper.controller.spline) {\n swiper.controller.spline = swiper.params.loop ? new LinearSpline(swiper.slidesGrid, c.slidesGrid) : new LinearSpline(swiper.snapGrid, c.snapGrid);\n }\n }\n\n function setTranslate(_t, byController) {\n const controlled = swiper.controller.control;\n let multiplier;\n let controlledTranslate;\n const Swiper = swiper.constructor;\n\n function setControlledTranslate(c) {\n // this will create an Interpolate function based on the snapGrids\n // x is the Grid of the scrolled scroller and y will be the controlled scroller\n // it makes sense to create this only once and recall it for the interpolation\n // the function does a lot of value caching for performance\n const translate = swiper.rtlTranslate ? -swiper.translate : swiper.translate;\n\n if (swiper.params.controller.by === 'slide') {\n getInterpolateFunction(c); // i am not sure why the values have to be multiplicated this way, tried to invert the snapGrid\n // but it did not work out\n\n controlledTranslate = -swiper.controller.spline.interpolate(-translate);\n }\n\n if (!controlledTranslate || swiper.params.controller.by === 'container') {\n multiplier = (c.maxTranslate() - c.minTranslate()) / (swiper.maxTranslate() - swiper.minTranslate());\n controlledTranslate = (translate - swiper.minTranslate()) * multiplier + c.minTranslate();\n }\n\n if (swiper.params.controller.inverse) {\n controlledTranslate = c.maxTranslate() - controlledTranslate;\n }\n\n c.updateProgress(controlledTranslate);\n c.setTranslate(controlledTranslate, swiper);\n c.updateActiveIndex();\n c.updateSlidesClasses();\n }\n\n if (Array.isArray(controlled)) {\n for (let i = 0; i < controlled.length; i += 1) {\n if (controlled[i] !== byController && controlled[i] instanceof Swiper) {\n setControlledTranslate(controlled[i]);\n }\n }\n } else if (controlled instanceof Swiper && byController !== controlled) {\n setControlledTranslate(controlled);\n }\n }\n\n function setTransition(duration, byController) {\n const Swiper = swiper.constructor;\n const controlled = swiper.controller.control;\n let i;\n\n function setControlledTransition(c) {\n c.setTransition(duration, swiper);\n\n if (duration !== 0) {\n c.transitionStart();\n\n if (c.params.autoHeight) {\n nextTick(() => {\n c.updateAutoHeight();\n });\n }\n\n c.$wrapperEl.transitionEnd(() => {\n if (!controlled) return;\n\n if (c.params.loop && swiper.params.controller.by === 'slide') {\n c.loopFix();\n }\n\n c.transitionEnd();\n });\n }\n }\n\n if (Array.isArray(controlled)) {\n for (i = 0; i < controlled.length; i += 1) {\n if (controlled[i] !== byController && controlled[i] instanceof Swiper) {\n setControlledTransition(controlled[i]);\n }\n }\n } else if (controlled instanceof Swiper && byController !== controlled) {\n setControlledTransition(controlled);\n }\n }\n\n function removeSpline() {\n if (!swiper.controller.control) return;\n\n if (swiper.controller.spline) {\n swiper.controller.spline = undefined;\n delete swiper.controller.spline;\n }\n }\n\n on('beforeInit', () => {\n swiper.controller.control = swiper.params.controller.control;\n });\n on('update', () => {\n removeSpline();\n });\n on('resize', () => {\n removeSpline();\n });\n on('observerUpdate', () => {\n removeSpline();\n });\n on('setTranslate', (_s, translate, byController) => {\n if (!swiper.controller.control) return;\n swiper.controller.setTranslate(translate, byController);\n });\n on('setTransition', (_s, duration, byController) => {\n if (!swiper.controller.control) return;\n swiper.controller.setTransition(duration, byController);\n });\n Object.assign(swiper.controller, {\n setTranslate,\n setTransition\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/a11y/a11y.js\n\n\nfunction A11y({\n swiper,\n extendParams,\n on\n}) {\n extendParams({\n a11y: {\n enabled: true,\n notificationClass: 'swiper-notification',\n prevSlideMessage: 'Previous slide',\n nextSlideMessage: 'Next slide',\n firstSlideMessage: 'This is the first slide',\n lastSlideMessage: 'This is the last slide',\n paginationBulletMessage: 'Go to slide {{index}}',\n slideLabelMessage: '{{index}} / {{slidesLength}}',\n containerMessage: null,\n containerRoleDescriptionMessage: null,\n itemRoleDescriptionMessage: null,\n slideRole: 'group',\n id: null\n }\n });\n swiper.a11y = {\n clicked: false\n };\n let liveRegion = null;\n\n function notify(message) {\n const notification = liveRegion;\n if (notification.length === 0) return;\n notification.html('');\n notification.html(message);\n }\n\n function getRandomNumber(size = 16) {\n const randomChar = () => Math.round(16 * Math.random()).toString(16);\n\n return 'x'.repeat(size).replace(/x/g, randomChar);\n }\n\n function makeElFocusable($el) {\n $el.attr('tabIndex', '0');\n }\n\n function makeElNotFocusable($el) {\n $el.attr('tabIndex', '-1');\n }\n\n function addElRole($el, role) {\n $el.attr('role', role);\n }\n\n function addElRoleDescription($el, description) {\n $el.attr('aria-roledescription', description);\n }\n\n function addElControls($el, controls) {\n $el.attr('aria-controls', controls);\n }\n\n function addElLabel($el, label) {\n $el.attr('aria-label', label);\n }\n\n function addElId($el, id) {\n $el.attr('id', id);\n }\n\n function addElLive($el, live) {\n $el.attr('aria-live', live);\n }\n\n function disableEl($el) {\n $el.attr('aria-disabled', true);\n }\n\n function enableEl($el) {\n $el.attr('aria-disabled', false);\n }\n\n function onEnterOrSpaceKey(e) {\n if (e.keyCode !== 13 && e.keyCode !== 32) return;\n const params = swiper.params.a11y;\n const $targetEl = $(e.target);\n\n if (swiper.navigation && swiper.navigation.$nextEl && $targetEl.is(swiper.navigation.$nextEl)) {\n if (!(swiper.isEnd && !swiper.params.loop)) {\n swiper.slideNext();\n }\n\n if (swiper.isEnd) {\n notify(params.lastSlideMessage);\n } else {\n notify(params.nextSlideMessage);\n }\n }\n\n if (swiper.navigation && swiper.navigation.$prevEl && $targetEl.is(swiper.navigation.$prevEl)) {\n if (!(swiper.isBeginning && !swiper.params.loop)) {\n swiper.slidePrev();\n }\n\n if (swiper.isBeginning) {\n notify(params.firstSlideMessage);\n } else {\n notify(params.prevSlideMessage);\n }\n }\n\n if (swiper.pagination && $targetEl.is(classesToSelector(swiper.params.pagination.bulletClass))) {\n $targetEl[0].click();\n }\n }\n\n function updateNavigation() {\n if (swiper.params.loop || swiper.params.rewind || !swiper.navigation) return;\n const {\n $nextEl,\n $prevEl\n } = swiper.navigation;\n\n if ($prevEl && $prevEl.length > 0) {\n if (swiper.isBeginning) {\n disableEl($prevEl);\n makeElNotFocusable($prevEl);\n } else {\n enableEl($prevEl);\n makeElFocusable($prevEl);\n }\n }\n\n if ($nextEl && $nextEl.length > 0) {\n if (swiper.isEnd) {\n disableEl($nextEl);\n makeElNotFocusable($nextEl);\n } else {\n enableEl($nextEl);\n makeElFocusable($nextEl);\n }\n }\n }\n\n function hasPagination() {\n return swiper.pagination && swiper.pagination.bullets && swiper.pagination.bullets.length;\n }\n\n function hasClickablePagination() {\n return hasPagination() && swiper.params.pagination.clickable;\n }\n\n function updatePagination() {\n const params = swiper.params.a11y;\n if (!hasPagination()) return;\n swiper.pagination.bullets.each(bulletEl => {\n const $bulletEl = $(bulletEl);\n\n if (swiper.params.pagination.clickable) {\n makeElFocusable($bulletEl);\n\n if (!swiper.params.pagination.renderBullet) {\n addElRole($bulletEl, 'button');\n addElLabel($bulletEl, params.paginationBulletMessage.replace(/\\{\\{index\\}\\}/, $bulletEl.index() + 1));\n }\n }\n\n if ($bulletEl.is(`.${swiper.params.pagination.bulletActiveClass}`)) {\n $bulletEl.attr('aria-current', 'true');\n } else {\n $bulletEl.removeAttr('aria-current');\n }\n });\n }\n\n const initNavEl = ($el, wrapperId, message) => {\n makeElFocusable($el);\n\n if ($el[0].tagName !== 'BUTTON') {\n addElRole($el, 'button');\n $el.on('keydown', onEnterOrSpaceKey);\n }\n\n addElLabel($el, message);\n addElControls($el, wrapperId);\n };\n\n const handlePointerDown = () => {\n swiper.a11y.clicked = true;\n };\n\n const handlePointerUp = () => {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (!swiper.destroyed) {\n swiper.a11y.clicked = false;\n }\n });\n });\n };\n\n const handleFocus = e => {\n if (swiper.a11y.clicked) return;\n const slideEl = e.target.closest(`.${swiper.params.slideClass}`);\n if (!slideEl || !swiper.slides.includes(slideEl)) return;\n const isActive = swiper.slides.indexOf(slideEl) === swiper.activeIndex;\n const isVisible = swiper.params.watchSlidesProgress && swiper.visibleSlides && swiper.visibleSlides.includes(slideEl);\n if (isActive || isVisible) return;\n if (e.sourceCapabilities && e.sourceCapabilities.firesTouchEvents) return;\n\n if (swiper.isHorizontal()) {\n swiper.el.scrollLeft = 0;\n } else {\n swiper.el.scrollTop = 0;\n }\n\n swiper.slideTo(swiper.slides.indexOf(slideEl), 0);\n };\n\n const initSlides = () => {\n const params = swiper.params.a11y;\n\n if (params.itemRoleDescriptionMessage) {\n addElRoleDescription($(swiper.slides), params.itemRoleDescriptionMessage);\n }\n\n if (params.slideRole) {\n addElRole($(swiper.slides), params.slideRole);\n }\n\n const slidesLength = swiper.params.loop ? swiper.slides.filter(el => !el.classList.contains(swiper.params.slideDuplicateClass)).length : swiper.slides.length;\n\n if (params.slideLabelMessage) {\n swiper.slides.each((slideEl, index) => {\n const $slideEl = $(slideEl);\n const slideIndex = swiper.params.loop ? parseInt($slideEl.attr('data-swiper-slide-index'), 10) : index;\n const ariaLabelMessage = params.slideLabelMessage.replace(/\\{\\{index\\}\\}/, slideIndex + 1).replace(/\\{\\{slidesLength\\}\\}/, slidesLength);\n addElLabel($slideEl, ariaLabelMessage);\n });\n }\n };\n\n const init = () => {\n const params = swiper.params.a11y;\n swiper.$el.append(liveRegion); // Container\n\n const $containerEl = swiper.$el;\n\n if (params.containerRoleDescriptionMessage) {\n addElRoleDescription($containerEl, params.containerRoleDescriptionMessage);\n }\n\n if (params.containerMessage) {\n addElLabel($containerEl, params.containerMessage);\n } // Wrapper\n\n\n const $wrapperEl = swiper.$wrapperEl;\n const wrapperId = params.id || $wrapperEl.attr('id') || `swiper-wrapper-${getRandomNumber(16)}`;\n const live = swiper.params.autoplay && swiper.params.autoplay.enabled ? 'off' : 'polite';\n addElId($wrapperEl, wrapperId);\n addElLive($wrapperEl, live); // Slide\n\n initSlides(); // Navigation\n\n let $nextEl;\n let $prevEl;\n\n if (swiper.navigation && swiper.navigation.$nextEl) {\n $nextEl = swiper.navigation.$nextEl;\n }\n\n if (swiper.navigation && swiper.navigation.$prevEl) {\n $prevEl = swiper.navigation.$prevEl;\n }\n\n if ($nextEl && $nextEl.length) {\n initNavEl($nextEl, wrapperId, params.nextSlideMessage);\n }\n\n if ($prevEl && $prevEl.length) {\n initNavEl($prevEl, wrapperId, params.prevSlideMessage);\n } // Pagination\n\n\n if (hasClickablePagination()) {\n swiper.pagination.$el.on('keydown', classesToSelector(swiper.params.pagination.bulletClass), onEnterOrSpaceKey);\n } // Tab focus\n\n\n swiper.$el.on('focus', handleFocus, true);\n swiper.$el.on('pointerdown', handlePointerDown, true);\n swiper.$el.on('pointerup', handlePointerUp, true);\n };\n\n function destroy() {\n if (liveRegion && liveRegion.length > 0) liveRegion.remove();\n let $nextEl;\n let $prevEl;\n\n if (swiper.navigation && swiper.navigation.$nextEl) {\n $nextEl = swiper.navigation.$nextEl;\n }\n\n if (swiper.navigation && swiper.navigation.$prevEl) {\n $prevEl = swiper.navigation.$prevEl;\n }\n\n if ($nextEl) {\n $nextEl.off('keydown', onEnterOrSpaceKey);\n }\n\n if ($prevEl) {\n $prevEl.off('keydown', onEnterOrSpaceKey);\n } // Pagination\n\n\n if (hasClickablePagination()) {\n swiper.pagination.$el.off('keydown', classesToSelector(swiper.params.pagination.bulletClass), onEnterOrSpaceKey);\n } // Tab focus\n\n\n swiper.$el.off('focus', handleFocus, true);\n swiper.$el.off('pointerdown', handlePointerDown, true);\n swiper.$el.off('pointerup', handlePointerUp, true);\n }\n\n on('beforeInit', () => {\n liveRegion = $(``);\n });\n on('afterInit', () => {\n if (!swiper.params.a11y.enabled) return;\n init();\n });\n on('slidesLengthChange snapGridLengthChange slidesGridLengthChange', () => {\n if (!swiper.params.a11y.enabled) return;\n initSlides();\n });\n on('fromEdge toEdge afterInit lock unlock', () => {\n if (!swiper.params.a11y.enabled) return;\n updateNavigation();\n });\n on('paginationUpdate', () => {\n if (!swiper.params.a11y.enabled) return;\n updatePagination();\n });\n on('destroy', () => {\n if (!swiper.params.a11y.enabled) return;\n destroy();\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/history/history.js\n\nfunction History({\n swiper,\n extendParams,\n on\n}) {\n extendParams({\n history: {\n enabled: false,\n root: '',\n replaceState: false,\n key: 'slides',\n keepQuery: false\n }\n });\n let initialized = false;\n let paths = {};\n\n const slugify = text => {\n return text.toString().replace(/\\s+/g, '-').replace(/[^\\w-]+/g, '').replace(/--+/g, '-').replace(/^-+/, '').replace(/-+$/, '');\n };\n\n const getPathValues = urlOverride => {\n const window = getWindow();\n let location;\n\n if (urlOverride) {\n location = new URL(urlOverride);\n } else {\n location = window.location;\n }\n\n const pathArray = location.pathname.slice(1).split('/').filter(part => part !== '');\n const total = pathArray.length;\n const key = pathArray[total - 2];\n const value = pathArray[total - 1];\n return {\n key,\n value\n };\n };\n\n const setHistory = (key, index) => {\n const window = getWindow();\n if (!initialized || !swiper.params.history.enabled) return;\n let location;\n\n if (swiper.params.url) {\n location = new URL(swiper.params.url);\n } else {\n location = window.location;\n }\n\n const slide = swiper.slides.eq(index);\n let value = slugify(slide.attr('data-history'));\n\n if (swiper.params.history.root.length > 0) {\n let root = swiper.params.history.root;\n if (root[root.length - 1] === '/') root = root.slice(0, root.length - 1);\n value = `${root}/${key}/${value}`;\n } else if (!location.pathname.includes(key)) {\n value = `${key}/${value}`;\n }\n\n if (swiper.params.history.keepQuery) {\n value += location.search;\n }\n\n const currentState = window.history.state;\n\n if (currentState && currentState.value === value) {\n return;\n }\n\n if (swiper.params.history.replaceState) {\n window.history.replaceState({\n value\n }, null, value);\n } else {\n window.history.pushState({\n value\n }, null, value);\n }\n };\n\n const scrollToSlide = (speed, value, runCallbacks) => {\n if (value) {\n for (let i = 0, length = swiper.slides.length; i < length; i += 1) {\n const slide = swiper.slides.eq(i);\n const slideHistory = slugify(slide.attr('data-history'));\n\n if (slideHistory === value && !slide.hasClass(swiper.params.slideDuplicateClass)) {\n const index = slide.index();\n swiper.slideTo(index, speed, runCallbacks);\n }\n }\n } else {\n swiper.slideTo(0, speed, runCallbacks);\n }\n };\n\n const setHistoryPopState = () => {\n paths = getPathValues(swiper.params.url);\n scrollToSlide(swiper.params.speed, paths.value, false);\n };\n\n const init = () => {\n const window = getWindow();\n if (!swiper.params.history) return;\n\n if (!window.history || !window.history.pushState) {\n swiper.params.history.enabled = false;\n swiper.params.hashNavigation.enabled = true;\n return;\n }\n\n initialized = true;\n paths = getPathValues(swiper.params.url);\n if (!paths.key && !paths.value) return;\n scrollToSlide(0, paths.value, swiper.params.runCallbacksOnInit);\n\n if (!swiper.params.history.replaceState) {\n window.addEventListener('popstate', setHistoryPopState);\n }\n };\n\n const destroy = () => {\n const window = getWindow();\n\n if (!swiper.params.history.replaceState) {\n window.removeEventListener('popstate', setHistoryPopState);\n }\n };\n\n on('init', () => {\n if (swiper.params.history.enabled) {\n init();\n }\n });\n on('destroy', () => {\n if (swiper.params.history.enabled) {\n destroy();\n }\n });\n on('transitionEnd _freeModeNoMomentumRelease', () => {\n if (initialized) {\n setHistory(swiper.params.history.key, swiper.activeIndex);\n }\n });\n on('slideChange', () => {\n if (initialized && swiper.params.cssMode) {\n setHistory(swiper.params.history.key, swiper.activeIndex);\n }\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/hash-navigation/hash-navigation.js\n\n\nfunction HashNavigation({\n swiper,\n extendParams,\n emit,\n on\n}) {\n let initialized = false;\n const document = getDocument();\n const window = getWindow();\n extendParams({\n hashNavigation: {\n enabled: false,\n replaceState: false,\n watchState: false\n }\n });\n\n const onHashChange = () => {\n emit('hashChange');\n const newHash = document.location.hash.replace('#', '');\n const activeSlideHash = swiper.slides.eq(swiper.activeIndex).attr('data-hash');\n\n if (newHash !== activeSlideHash) {\n const newIndex = swiper.$wrapperEl.children(`.${swiper.params.slideClass}[data-hash=\"${newHash}\"]`).index();\n if (typeof newIndex === 'undefined') return;\n swiper.slideTo(newIndex);\n }\n };\n\n const setHash = () => {\n if (!initialized || !swiper.params.hashNavigation.enabled) return;\n\n if (swiper.params.hashNavigation.replaceState && window.history && window.history.replaceState) {\n window.history.replaceState(null, null, `#${swiper.slides.eq(swiper.activeIndex).attr('data-hash')}` || '');\n emit('hashSet');\n } else {\n const slide = swiper.slides.eq(swiper.activeIndex);\n const hash = slide.attr('data-hash') || slide.attr('data-history');\n document.location.hash = hash || '';\n emit('hashSet');\n }\n };\n\n const init = () => {\n if (!swiper.params.hashNavigation.enabled || swiper.params.history && swiper.params.history.enabled) return;\n initialized = true;\n const hash = document.location.hash.replace('#', '');\n\n if (hash) {\n const speed = 0;\n\n for (let i = 0, length = swiper.slides.length; i < length; i += 1) {\n const slide = swiper.slides.eq(i);\n const slideHash = slide.attr('data-hash') || slide.attr('data-history');\n\n if (slideHash === hash && !slide.hasClass(swiper.params.slideDuplicateClass)) {\n const index = slide.index();\n swiper.slideTo(index, speed, swiper.params.runCallbacksOnInit, true);\n }\n }\n }\n\n if (swiper.params.hashNavigation.watchState) {\n $(window).on('hashchange', onHashChange);\n }\n };\n\n const destroy = () => {\n if (swiper.params.hashNavigation.watchState) {\n $(window).off('hashchange', onHashChange);\n }\n };\n\n on('init', () => {\n if (swiper.params.hashNavigation.enabled) {\n init();\n }\n });\n on('destroy', () => {\n if (swiper.params.hashNavigation.enabled) {\n destroy();\n }\n });\n on('transitionEnd _freeModeNoMomentumRelease', () => {\n if (initialized) {\n setHash();\n }\n });\n on('slideChange', () => {\n if (initialized && swiper.params.cssMode) {\n setHash();\n }\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/autoplay/autoplay.js\n/* eslint no-underscore-dangle: \"off\" */\n\n/* eslint no-use-before-define: \"off\" */\n\n\nfunction Autoplay({\n swiper,\n extendParams,\n on,\n emit\n}) {\n let timeout;\n swiper.autoplay = {\n running: false,\n paused: false\n };\n extendParams({\n autoplay: {\n enabled: false,\n delay: 3000,\n waitForTransition: true,\n disableOnInteraction: true,\n stopOnLastSlide: false,\n reverseDirection: false,\n pauseOnMouseEnter: false\n }\n });\n\n function run() {\n if (!swiper.size) {\n swiper.autoplay.running = false;\n swiper.autoplay.paused = false;\n return;\n }\n\n const $activeSlideEl = swiper.slides.eq(swiper.activeIndex);\n let delay = swiper.params.autoplay.delay;\n\n if ($activeSlideEl.attr('data-swiper-autoplay')) {\n delay = $activeSlideEl.attr('data-swiper-autoplay') || swiper.params.autoplay.delay;\n }\n\n clearTimeout(timeout);\n timeout = nextTick(() => {\n let autoplayResult;\n\n if (swiper.params.autoplay.reverseDirection) {\n if (swiper.params.loop) {\n swiper.loopFix();\n autoplayResult = swiper.slidePrev(swiper.params.speed, true, true);\n emit('autoplay');\n } else if (!swiper.isBeginning) {\n autoplayResult = swiper.slidePrev(swiper.params.speed, true, true);\n emit('autoplay');\n } else if (!swiper.params.autoplay.stopOnLastSlide) {\n autoplayResult = swiper.slideTo(swiper.slides.length - 1, swiper.params.speed, true, true);\n emit('autoplay');\n } else {\n stop();\n }\n } else if (swiper.params.loop) {\n swiper.loopFix();\n autoplayResult = swiper.slideNext(swiper.params.speed, true, true);\n emit('autoplay');\n } else if (!swiper.isEnd) {\n autoplayResult = swiper.slideNext(swiper.params.speed, true, true);\n emit('autoplay');\n } else if (!swiper.params.autoplay.stopOnLastSlide) {\n autoplayResult = swiper.slideTo(0, swiper.params.speed, true, true);\n emit('autoplay');\n } else {\n stop();\n }\n\n if (swiper.params.cssMode && swiper.autoplay.running) run();else if (autoplayResult === false) {\n run();\n }\n }, delay);\n }\n\n function start() {\n if (typeof timeout !== 'undefined') return false;\n if (swiper.autoplay.running) return false;\n swiper.autoplay.running = true;\n emit('autoplayStart');\n run();\n return true;\n }\n\n function stop() {\n if (!swiper.autoplay.running) return false;\n if (typeof timeout === 'undefined') return false;\n\n if (timeout) {\n clearTimeout(timeout);\n timeout = undefined;\n }\n\n swiper.autoplay.running = false;\n emit('autoplayStop');\n return true;\n }\n\n function pause(speed) {\n if (!swiper.autoplay.running) return;\n if (swiper.autoplay.paused) return;\n if (timeout) clearTimeout(timeout);\n swiper.autoplay.paused = true;\n\n if (speed === 0 || !swiper.params.autoplay.waitForTransition) {\n swiper.autoplay.paused = false;\n run();\n } else {\n ['transitionend', 'webkitTransitionEnd'].forEach(event => {\n swiper.$wrapperEl[0].addEventListener(event, onTransitionEnd);\n });\n }\n }\n\n function onVisibilityChange() {\n const document = getDocument();\n\n if (document.visibilityState === 'hidden' && swiper.autoplay.running) {\n pause();\n }\n\n if (document.visibilityState === 'visible' && swiper.autoplay.paused) {\n run();\n swiper.autoplay.paused = false;\n }\n }\n\n function onTransitionEnd(e) {\n if (!swiper || swiper.destroyed || !swiper.$wrapperEl) return;\n if (e.target !== swiper.$wrapperEl[0]) return;\n ['transitionend', 'webkitTransitionEnd'].forEach(event => {\n swiper.$wrapperEl[0].removeEventListener(event, onTransitionEnd);\n });\n swiper.autoplay.paused = false;\n\n if (!swiper.autoplay.running) {\n stop();\n } else {\n run();\n }\n }\n\n function onMouseEnter() {\n if (swiper.params.autoplay.disableOnInteraction) {\n stop();\n } else {\n emit('autoplayPause');\n pause();\n }\n\n ['transitionend', 'webkitTransitionEnd'].forEach(event => {\n swiper.$wrapperEl[0].removeEventListener(event, onTransitionEnd);\n });\n }\n\n function onMouseLeave() {\n if (swiper.params.autoplay.disableOnInteraction) {\n return;\n }\n\n swiper.autoplay.paused = false;\n emit('autoplayResume');\n run();\n }\n\n function attachMouseEvents() {\n if (swiper.params.autoplay.pauseOnMouseEnter) {\n swiper.$el.on('mouseenter', onMouseEnter);\n swiper.$el.on('mouseleave', onMouseLeave);\n }\n }\n\n function detachMouseEvents() {\n swiper.$el.off('mouseenter', onMouseEnter);\n swiper.$el.off('mouseleave', onMouseLeave);\n }\n\n on('init', () => {\n if (swiper.params.autoplay.enabled) {\n start();\n const document = getDocument();\n document.addEventListener('visibilitychange', onVisibilityChange);\n attachMouseEvents();\n }\n });\n on('beforeTransitionStart', (_s, speed, internal) => {\n if (swiper.autoplay.running) {\n if (internal || !swiper.params.autoplay.disableOnInteraction) {\n swiper.autoplay.pause(speed);\n } else {\n stop();\n }\n }\n });\n on('sliderFirstMove', () => {\n if (swiper.autoplay.running) {\n if (swiper.params.autoplay.disableOnInteraction) {\n stop();\n } else {\n pause();\n }\n }\n });\n on('touchEnd', () => {\n if (swiper.params.cssMode && swiper.autoplay.paused && !swiper.params.autoplay.disableOnInteraction) {\n run();\n }\n });\n on('destroy', () => {\n detachMouseEvents();\n\n if (swiper.autoplay.running) {\n stop();\n }\n\n const document = getDocument();\n document.removeEventListener('visibilitychange', onVisibilityChange);\n });\n Object.assign(swiper.autoplay, {\n pause,\n run,\n start,\n stop\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/thumbs/thumbs.js\n\n\nfunction Thumb({\n swiper,\n extendParams,\n on\n}) {\n extendParams({\n thumbs: {\n swiper: null,\n multipleActiveThumbs: true,\n autoScrollOffset: 0,\n slideThumbActiveClass: 'swiper-slide-thumb-active',\n thumbsContainerClass: 'swiper-thumbs'\n }\n });\n let initialized = false;\n let swiperCreated = false;\n swiper.thumbs = {\n swiper: null\n };\n\n function onThumbClick() {\n const thumbsSwiper = swiper.thumbs.swiper;\n if (!thumbsSwiper || thumbsSwiper.destroyed) return;\n const clickedIndex = thumbsSwiper.clickedIndex;\n const clickedSlide = thumbsSwiper.clickedSlide;\n if (clickedSlide && $(clickedSlide).hasClass(swiper.params.thumbs.slideThumbActiveClass)) return;\n if (typeof clickedIndex === 'undefined' || clickedIndex === null) return;\n let slideToIndex;\n\n if (thumbsSwiper.params.loop) {\n slideToIndex = parseInt($(thumbsSwiper.clickedSlide).attr('data-swiper-slide-index'), 10);\n } else {\n slideToIndex = clickedIndex;\n }\n\n if (swiper.params.loop) {\n let currentIndex = swiper.activeIndex;\n\n if (swiper.slides.eq(currentIndex).hasClass(swiper.params.slideDuplicateClass)) {\n swiper.loopFix(); // eslint-disable-next-line\n\n swiper._clientLeft = swiper.$wrapperEl[0].clientLeft;\n currentIndex = swiper.activeIndex;\n }\n\n const prevIndex = swiper.slides.eq(currentIndex).prevAll(`[data-swiper-slide-index=\"${slideToIndex}\"]`).eq(0).index();\n const nextIndex = swiper.slides.eq(currentIndex).nextAll(`[data-swiper-slide-index=\"${slideToIndex}\"]`).eq(0).index();\n if (typeof prevIndex === 'undefined') slideToIndex = nextIndex;else if (typeof nextIndex === 'undefined') slideToIndex = prevIndex;else if (nextIndex - currentIndex < currentIndex - prevIndex) slideToIndex = nextIndex;else slideToIndex = prevIndex;\n }\n\n swiper.slideTo(slideToIndex);\n }\n\n function init() {\n const {\n thumbs: thumbsParams\n } = swiper.params;\n if (initialized) return false;\n initialized = true;\n const SwiperClass = swiper.constructor;\n\n if (thumbsParams.swiper instanceof SwiperClass) {\n swiper.thumbs.swiper = thumbsParams.swiper;\n Object.assign(swiper.thumbs.swiper.originalParams, {\n watchSlidesProgress: true,\n slideToClickedSlide: false\n });\n Object.assign(swiper.thumbs.swiper.params, {\n watchSlidesProgress: true,\n slideToClickedSlide: false\n });\n } else if (isObject(thumbsParams.swiper)) {\n const thumbsSwiperParams = Object.assign({}, thumbsParams.swiper);\n Object.assign(thumbsSwiperParams, {\n watchSlidesProgress: true,\n slideToClickedSlide: false\n });\n swiper.thumbs.swiper = new SwiperClass(thumbsSwiperParams);\n swiperCreated = true;\n }\n\n swiper.thumbs.swiper.$el.addClass(swiper.params.thumbs.thumbsContainerClass);\n swiper.thumbs.swiper.on('tap', onThumbClick);\n return true;\n }\n\n function update(initial) {\n const thumbsSwiper = swiper.thumbs.swiper;\n if (!thumbsSwiper || thumbsSwiper.destroyed) return;\n const slidesPerView = thumbsSwiper.params.slidesPerView === 'auto' ? thumbsSwiper.slidesPerViewDynamic() : thumbsSwiper.params.slidesPerView; // Activate thumbs\n\n let thumbsToActivate = 1;\n const thumbActiveClass = swiper.params.thumbs.slideThumbActiveClass;\n\n if (swiper.params.slidesPerView > 1 && !swiper.params.centeredSlides) {\n thumbsToActivate = swiper.params.slidesPerView;\n }\n\n if (!swiper.params.thumbs.multipleActiveThumbs) {\n thumbsToActivate = 1;\n }\n\n thumbsToActivate = Math.floor(thumbsToActivate);\n thumbsSwiper.slides.removeClass(thumbActiveClass);\n\n if (thumbsSwiper.params.loop || thumbsSwiper.params.virtual && thumbsSwiper.params.virtual.enabled) {\n for (let i = 0; i < thumbsToActivate; i += 1) {\n thumbsSwiper.$wrapperEl.children(`[data-swiper-slide-index=\"${swiper.realIndex + i}\"]`).addClass(thumbActiveClass);\n }\n } else {\n for (let i = 0; i < thumbsToActivate; i += 1) {\n thumbsSwiper.slides.eq(swiper.realIndex + i).addClass(thumbActiveClass);\n }\n }\n\n const autoScrollOffset = swiper.params.thumbs.autoScrollOffset;\n const useOffset = autoScrollOffset && !thumbsSwiper.params.loop;\n\n if (swiper.realIndex !== thumbsSwiper.realIndex || useOffset) {\n let currentThumbsIndex = thumbsSwiper.activeIndex;\n let newThumbsIndex;\n let direction;\n\n if (thumbsSwiper.params.loop) {\n if (thumbsSwiper.slides.eq(currentThumbsIndex).hasClass(thumbsSwiper.params.slideDuplicateClass)) {\n thumbsSwiper.loopFix(); // eslint-disable-next-line\n\n thumbsSwiper._clientLeft = thumbsSwiper.$wrapperEl[0].clientLeft;\n currentThumbsIndex = thumbsSwiper.activeIndex;\n } // Find actual thumbs index to slide to\n\n\n const prevThumbsIndex = thumbsSwiper.slides.eq(currentThumbsIndex).prevAll(`[data-swiper-slide-index=\"${swiper.realIndex}\"]`).eq(0).index();\n const nextThumbsIndex = thumbsSwiper.slides.eq(currentThumbsIndex).nextAll(`[data-swiper-slide-index=\"${swiper.realIndex}\"]`).eq(0).index();\n\n if (typeof prevThumbsIndex === 'undefined') {\n newThumbsIndex = nextThumbsIndex;\n } else if (typeof nextThumbsIndex === 'undefined') {\n newThumbsIndex = prevThumbsIndex;\n } else if (nextThumbsIndex - currentThumbsIndex === currentThumbsIndex - prevThumbsIndex) {\n newThumbsIndex = thumbsSwiper.params.slidesPerGroup > 1 ? nextThumbsIndex : currentThumbsIndex;\n } else if (nextThumbsIndex - currentThumbsIndex < currentThumbsIndex - prevThumbsIndex) {\n newThumbsIndex = nextThumbsIndex;\n } else {\n newThumbsIndex = prevThumbsIndex;\n }\n\n direction = swiper.activeIndex > swiper.previousIndex ? 'next' : 'prev';\n } else {\n newThumbsIndex = swiper.realIndex;\n direction = newThumbsIndex > swiper.previousIndex ? 'next' : 'prev';\n }\n\n if (useOffset) {\n newThumbsIndex += direction === 'next' ? autoScrollOffset : -1 * autoScrollOffset;\n }\n\n if (thumbsSwiper.visibleSlidesIndexes && thumbsSwiper.visibleSlidesIndexes.indexOf(newThumbsIndex) < 0) {\n if (thumbsSwiper.params.centeredSlides) {\n if (newThumbsIndex > currentThumbsIndex) {\n newThumbsIndex = newThumbsIndex - Math.floor(slidesPerView / 2) + 1;\n } else {\n newThumbsIndex = newThumbsIndex + Math.floor(slidesPerView / 2) - 1;\n }\n } else if (newThumbsIndex > currentThumbsIndex && thumbsSwiper.params.slidesPerGroup === 1) {// newThumbsIndex = newThumbsIndex - slidesPerView + 1;\n }\n\n thumbsSwiper.slideTo(newThumbsIndex, initial ? 0 : undefined);\n }\n }\n }\n\n on('beforeInit', () => {\n const {\n thumbs\n } = swiper.params;\n if (!thumbs || !thumbs.swiper) return;\n init();\n update(true);\n });\n on('slideChange update resize observerUpdate', () => {\n update();\n });\n on('setTransition', (_s, duration) => {\n const thumbsSwiper = swiper.thumbs.swiper;\n if (!thumbsSwiper || thumbsSwiper.destroyed) return;\n thumbsSwiper.setTransition(duration);\n });\n on('beforeDestroy', () => {\n const thumbsSwiper = swiper.thumbs.swiper;\n if (!thumbsSwiper || thumbsSwiper.destroyed) return;\n\n if (swiperCreated) {\n thumbsSwiper.destroy();\n }\n });\n Object.assign(swiper.thumbs, {\n init,\n update\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/free-mode/free-mode.js\n\nfunction freeMode({\n swiper,\n extendParams,\n emit,\n once\n}) {\n extendParams({\n freeMode: {\n enabled: false,\n momentum: true,\n momentumRatio: 1,\n momentumBounce: true,\n momentumBounceRatio: 1,\n momentumVelocityRatio: 1,\n sticky: false,\n minimumVelocity: 0.02\n }\n });\n\n function onTouchStart() {\n const translate = swiper.getTranslate();\n swiper.setTranslate(translate);\n swiper.setTransition(0);\n swiper.touchEventsData.velocities.length = 0;\n swiper.freeMode.onTouchEnd({\n currentPos: swiper.rtl ? swiper.translate : -swiper.translate\n });\n }\n\n function onTouchMove() {\n const {\n touchEventsData: data,\n touches\n } = swiper; // Velocity\n\n if (data.velocities.length === 0) {\n data.velocities.push({\n position: touches[swiper.isHorizontal() ? 'startX' : 'startY'],\n time: data.touchStartTime\n });\n }\n\n data.velocities.push({\n position: touches[swiper.isHorizontal() ? 'currentX' : 'currentY'],\n time: now()\n });\n }\n\n function onTouchEnd({\n currentPos\n }) {\n const {\n params,\n $wrapperEl,\n rtlTranslate: rtl,\n snapGrid,\n touchEventsData: data\n } = swiper; // Time diff\n\n const touchEndTime = now();\n const timeDiff = touchEndTime - data.touchStartTime;\n\n if (currentPos < -swiper.minTranslate()) {\n swiper.slideTo(swiper.activeIndex);\n return;\n }\n\n if (currentPos > -swiper.maxTranslate()) {\n if (swiper.slides.length < snapGrid.length) {\n swiper.slideTo(snapGrid.length - 1);\n } else {\n swiper.slideTo(swiper.slides.length - 1);\n }\n\n return;\n }\n\n if (params.freeMode.momentum) {\n if (data.velocities.length > 1) {\n const lastMoveEvent = data.velocities.pop();\n const velocityEvent = data.velocities.pop();\n const distance = lastMoveEvent.position - velocityEvent.position;\n const time = lastMoveEvent.time - velocityEvent.time;\n swiper.velocity = distance / time;\n swiper.velocity /= 2;\n\n if (Math.abs(swiper.velocity) < params.freeMode.minimumVelocity) {\n swiper.velocity = 0;\n } // this implies that the user stopped moving a finger then released.\n // There would be no events with distance zero, so the last event is stale.\n\n\n if (time > 150 || now() - lastMoveEvent.time > 300) {\n swiper.velocity = 0;\n }\n } else {\n swiper.velocity = 0;\n }\n\n swiper.velocity *= params.freeMode.momentumVelocityRatio;\n data.velocities.length = 0;\n let momentumDuration = 1000 * params.freeMode.momentumRatio;\n const momentumDistance = swiper.velocity * momentumDuration;\n let newPosition = swiper.translate + momentumDistance;\n if (rtl) newPosition = -newPosition;\n let doBounce = false;\n let afterBouncePosition;\n const bounceAmount = Math.abs(swiper.velocity) * 20 * params.freeMode.momentumBounceRatio;\n let needsLoopFix;\n\n if (newPosition < swiper.maxTranslate()) {\n if (params.freeMode.momentumBounce) {\n if (newPosition + swiper.maxTranslate() < -bounceAmount) {\n newPosition = swiper.maxTranslate() - bounceAmount;\n }\n\n afterBouncePosition = swiper.maxTranslate();\n doBounce = true;\n data.allowMomentumBounce = true;\n } else {\n newPosition = swiper.maxTranslate();\n }\n\n if (params.loop && params.centeredSlides) needsLoopFix = true;\n } else if (newPosition > swiper.minTranslate()) {\n if (params.freeMode.momentumBounce) {\n if (newPosition - swiper.minTranslate() > bounceAmount) {\n newPosition = swiper.minTranslate() + bounceAmount;\n }\n\n afterBouncePosition = swiper.minTranslate();\n doBounce = true;\n data.allowMomentumBounce = true;\n } else {\n newPosition = swiper.minTranslate();\n }\n\n if (params.loop && params.centeredSlides) needsLoopFix = true;\n } else if (params.freeMode.sticky) {\n let nextSlide;\n\n for (let j = 0; j < snapGrid.length; j += 1) {\n if (snapGrid[j] > -newPosition) {\n nextSlide = j;\n break;\n }\n }\n\n if (Math.abs(snapGrid[nextSlide] - newPosition) < Math.abs(snapGrid[nextSlide - 1] - newPosition) || swiper.swipeDirection === 'next') {\n newPosition = snapGrid[nextSlide];\n } else {\n newPosition = snapGrid[nextSlide - 1];\n }\n\n newPosition = -newPosition;\n }\n\n if (needsLoopFix) {\n once('transitionEnd', () => {\n swiper.loopFix();\n });\n } // Fix duration\n\n\n if (swiper.velocity !== 0) {\n if (rtl) {\n momentumDuration = Math.abs((-newPosition - swiper.translate) / swiper.velocity);\n } else {\n momentumDuration = Math.abs((newPosition - swiper.translate) / swiper.velocity);\n }\n\n if (params.freeMode.sticky) {\n // If freeMode.sticky is active and the user ends a swipe with a slow-velocity\n // event, then durations can be 20+ seconds to slide one (or zero!) slides.\n // It's easy to see this when simulating touch with mouse events. To fix this,\n // limit single-slide swipes to the default slide duration. This also has the\n // nice side effect of matching slide speed if the user stopped moving before\n // lifting finger or mouse vs. moving slowly before lifting the finger/mouse.\n // For faster swipes, also apply limits (albeit higher ones).\n const moveDistance = Math.abs((rtl ? -newPosition : newPosition) - swiper.translate);\n const currentSlideSize = swiper.slidesSizesGrid[swiper.activeIndex];\n\n if (moveDistance < currentSlideSize) {\n momentumDuration = params.speed;\n } else if (moveDistance < 2 * currentSlideSize) {\n momentumDuration = params.speed * 1.5;\n } else {\n momentumDuration = params.speed * 2.5;\n }\n }\n } else if (params.freeMode.sticky) {\n swiper.slideToClosest();\n return;\n }\n\n if (params.freeMode.momentumBounce && doBounce) {\n swiper.updateProgress(afterBouncePosition);\n swiper.setTransition(momentumDuration);\n swiper.setTranslate(newPosition);\n swiper.transitionStart(true, swiper.swipeDirection);\n swiper.animating = true;\n $wrapperEl.transitionEnd(() => {\n if (!swiper || swiper.destroyed || !data.allowMomentumBounce) return;\n emit('momentumBounce');\n swiper.setTransition(params.speed);\n setTimeout(() => {\n swiper.setTranslate(afterBouncePosition);\n $wrapperEl.transitionEnd(() => {\n if (!swiper || swiper.destroyed) return;\n swiper.transitionEnd();\n });\n }, 0);\n });\n } else if (swiper.velocity) {\n emit('_freeModeNoMomentumRelease');\n swiper.updateProgress(newPosition);\n swiper.setTransition(momentumDuration);\n swiper.setTranslate(newPosition);\n swiper.transitionStart(true, swiper.swipeDirection);\n\n if (!swiper.animating) {\n swiper.animating = true;\n $wrapperEl.transitionEnd(() => {\n if (!swiper || swiper.destroyed) return;\n swiper.transitionEnd();\n });\n }\n } else {\n swiper.updateProgress(newPosition);\n }\n\n swiper.updateActiveIndex();\n swiper.updateSlidesClasses();\n } else if (params.freeMode.sticky) {\n swiper.slideToClosest();\n return;\n } else if (params.freeMode) {\n emit('_freeModeNoMomentumRelease');\n }\n\n if (!params.freeMode.momentum || timeDiff >= params.longSwipesMs) {\n swiper.updateProgress();\n swiper.updateActiveIndex();\n swiper.updateSlidesClasses();\n }\n }\n\n Object.assign(swiper, {\n freeMode: {\n onTouchStart,\n onTouchMove,\n onTouchEnd\n }\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/effect-cube/effect-cube.js\n\n\nfunction EffectCube({\n swiper,\n extendParams,\n on\n}) {\n extendParams({\n cubeEffect: {\n slideShadows: true,\n shadow: true,\n shadowOffset: 20,\n shadowScale: 0.94\n }\n });\n\n const createSlideShadows = ($slideEl, progress, isHorizontal) => {\n let shadowBefore = isHorizontal ? $slideEl.find('.swiper-slide-shadow-left') : $slideEl.find('.swiper-slide-shadow-top');\n let shadowAfter = isHorizontal ? $slideEl.find('.swiper-slide-shadow-right') : $slideEl.find('.swiper-slide-shadow-bottom');\n\n if (shadowBefore.length === 0) {\n shadowBefore = $(`
`);\n $slideEl.append(shadowBefore);\n }\n\n if (shadowAfter.length === 0) {\n shadowAfter = $(`
`);\n $slideEl.append(shadowAfter);\n }\n\n if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0);\n if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0);\n };\n\n const recreateShadows = () => {\n // create new ones\n const isHorizontal = swiper.isHorizontal();\n swiper.slides.each(slideEl => {\n const progress = Math.max(Math.min(slideEl.progress, 1), -1);\n createSlideShadows($(slideEl), progress, isHorizontal);\n });\n };\n\n const setTranslate = () => {\n const {\n $el,\n $wrapperEl,\n slides,\n width: swiperWidth,\n height: swiperHeight,\n rtlTranslate: rtl,\n size: swiperSize,\n browser\n } = swiper;\n const params = swiper.params.cubeEffect;\n const isHorizontal = swiper.isHorizontal();\n const isVirtual = swiper.virtual && swiper.params.virtual.enabled;\n let wrapperRotate = 0;\n let $cubeShadowEl;\n\n if (params.shadow) {\n if (isHorizontal) {\n $cubeShadowEl = $wrapperEl.find('.swiper-cube-shadow');\n\n if ($cubeShadowEl.length === 0) {\n $cubeShadowEl = $('
');\n $wrapperEl.append($cubeShadowEl);\n }\n\n $cubeShadowEl.css({\n height: `${swiperWidth}px`\n });\n } else {\n $cubeShadowEl = $el.find('.swiper-cube-shadow');\n\n if ($cubeShadowEl.length === 0) {\n $cubeShadowEl = $('
');\n $el.append($cubeShadowEl);\n }\n }\n }\n\n for (let i = 0; i < slides.length; i += 1) {\n const $slideEl = slides.eq(i);\n let slideIndex = i;\n\n if (isVirtual) {\n slideIndex = parseInt($slideEl.attr('data-swiper-slide-index'), 10);\n }\n\n let slideAngle = slideIndex * 90;\n let round = Math.floor(slideAngle / 360);\n\n if (rtl) {\n slideAngle = -slideAngle;\n round = Math.floor(-slideAngle / 360);\n }\n\n const progress = Math.max(Math.min($slideEl[0].progress, 1), -1);\n let tx = 0;\n let ty = 0;\n let tz = 0;\n\n if (slideIndex % 4 === 0) {\n tx = -round * 4 * swiperSize;\n tz = 0;\n } else if ((slideIndex - 1) % 4 === 0) {\n tx = 0;\n tz = -round * 4 * swiperSize;\n } else if ((slideIndex - 2) % 4 === 0) {\n tx = swiperSize + round * 4 * swiperSize;\n tz = swiperSize;\n } else if ((slideIndex - 3) % 4 === 0) {\n tx = -swiperSize;\n tz = 3 * swiperSize + swiperSize * 4 * round;\n }\n\n if (rtl) {\n tx = -tx;\n }\n\n if (!isHorizontal) {\n ty = tx;\n tx = 0;\n }\n\n const transform = `rotateX(${isHorizontal ? 0 : -slideAngle}deg) rotateY(${isHorizontal ? slideAngle : 0}deg) translate3d(${tx}px, ${ty}px, ${tz}px)`;\n\n if (progress <= 1 && progress > -1) {\n wrapperRotate = slideIndex * 90 + progress * 90;\n if (rtl) wrapperRotate = -slideIndex * 90 - progress * 90;\n }\n\n $slideEl.transform(transform);\n\n if (params.slideShadows) {\n createSlideShadows($slideEl, progress, isHorizontal);\n }\n }\n\n $wrapperEl.css({\n '-webkit-transform-origin': `50% 50% -${swiperSize / 2}px`,\n 'transform-origin': `50% 50% -${swiperSize / 2}px`\n });\n\n if (params.shadow) {\n if (isHorizontal) {\n $cubeShadowEl.transform(`translate3d(0px, ${swiperWidth / 2 + params.shadowOffset}px, ${-swiperWidth / 2}px) rotateX(90deg) rotateZ(0deg) scale(${params.shadowScale})`);\n } else {\n const shadowAngle = Math.abs(wrapperRotate) - Math.floor(Math.abs(wrapperRotate) / 90) * 90;\n const multiplier = 1.5 - (Math.sin(shadowAngle * 2 * Math.PI / 360) / 2 + Math.cos(shadowAngle * 2 * Math.PI / 360) / 2);\n const scale1 = params.shadowScale;\n const scale2 = params.shadowScale / multiplier;\n const offset = params.shadowOffset;\n $cubeShadowEl.transform(`scale3d(${scale1}, 1, ${scale2}) translate3d(0px, ${swiperHeight / 2 + offset}px, ${-swiperHeight / 2 / scale2}px) rotateX(-90deg)`);\n }\n }\n\n const zFactor = browser.isSafari || browser.isWebView ? -swiperSize / 2 : 0;\n $wrapperEl.transform(`translate3d(0px,0,${zFactor}px) rotateX(${swiper.isHorizontal() ? 0 : wrapperRotate}deg) rotateY(${swiper.isHorizontal() ? -wrapperRotate : 0}deg)`);\n $wrapperEl[0].style.setProperty('--swiper-cube-translate-z', `${zFactor}px`);\n };\n\n const setTransition = duration => {\n const {\n $el,\n slides\n } = swiper;\n slides.transition(duration).find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left').transition(duration);\n\n if (swiper.params.cubeEffect.shadow && !swiper.isHorizontal()) {\n $el.find('.swiper-cube-shadow').transition(duration);\n }\n };\n\n effectInit({\n effect: 'cube',\n swiper,\n on,\n setTranslate,\n setTransition,\n recreateShadows,\n getEffectParams: () => swiper.params.cubeEffect,\n perspective: () => true,\n overwriteParams: () => ({\n slidesPerView: 1,\n slidesPerGroup: 1,\n watchSlidesProgress: true,\n resistanceRatio: 0,\n spaceBetween: 0,\n centeredSlides: false,\n virtualTranslate: true\n })\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/shared/create-shadow.js\n\nfunction create_shadow_createShadow(params, $slideEl, side) {\n const shadowClass = `swiper-slide-shadow${side ? `-${side}` : ''}`;\n const $shadowContainer = params.transformEl ? $slideEl.find(params.transformEl) : $slideEl;\n let $shadowEl = $shadowContainer.children(`.${shadowClass}`);\n\n if (!$shadowEl.length) {\n $shadowEl = $(`
`);\n $shadowContainer.append($shadowEl);\n }\n\n return $shadowEl;\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/effect-flip/effect-flip.js\n\n\n\n\n\nfunction EffectFlip({\n swiper,\n extendParams,\n on\n}) {\n extendParams({\n flipEffect: {\n slideShadows: true,\n limitRotation: true,\n transformEl: null\n }\n });\n\n const createSlideShadows = ($slideEl, progress, params) => {\n let shadowBefore = swiper.isHorizontal() ? $slideEl.find('.swiper-slide-shadow-left') : $slideEl.find('.swiper-slide-shadow-top');\n let shadowAfter = swiper.isHorizontal() ? $slideEl.find('.swiper-slide-shadow-right') : $slideEl.find('.swiper-slide-shadow-bottom');\n\n if (shadowBefore.length === 0) {\n shadowBefore = createShadow(params, $slideEl, swiper.isHorizontal() ? 'left' : 'top');\n }\n\n if (shadowAfter.length === 0) {\n shadowAfter = createShadow(params, $slideEl, swiper.isHorizontal() ? 'right' : 'bottom');\n }\n\n if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0);\n if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0);\n };\n\n const recreateShadows = () => {\n // Set shadows\n const params = swiper.params.flipEffect;\n swiper.slides.each(slideEl => {\n const $slideEl = $(slideEl);\n let progress = $slideEl[0].progress;\n\n if (swiper.params.flipEffect.limitRotation) {\n progress = Math.max(Math.min(slideEl.progress, 1), -1);\n }\n\n createSlideShadows($slideEl, progress, params);\n });\n };\n\n const setTranslate = () => {\n const {\n slides,\n rtlTranslate: rtl\n } = swiper;\n const params = swiper.params.flipEffect;\n\n for (let i = 0; i < slides.length; i += 1) {\n const $slideEl = slides.eq(i);\n let progress = $slideEl[0].progress;\n\n if (swiper.params.flipEffect.limitRotation) {\n progress = Math.max(Math.min($slideEl[0].progress, 1), -1);\n }\n\n const offset = $slideEl[0].swiperSlideOffset;\n const rotate = -180 * progress;\n let rotateY = rotate;\n let rotateX = 0;\n let tx = swiper.params.cssMode ? -offset - swiper.translate : -offset;\n let ty = 0;\n\n if (!swiper.isHorizontal()) {\n ty = tx;\n tx = 0;\n rotateX = -rotateY;\n rotateY = 0;\n } else if (rtl) {\n rotateY = -rotateY;\n }\n\n $slideEl[0].style.zIndex = -Math.abs(Math.round(progress)) + slides.length;\n\n if (params.slideShadows) {\n createSlideShadows($slideEl, progress, params);\n }\n\n const transform = `translate3d(${tx}px, ${ty}px, 0px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;\n const $targetEl = effectTarget(params, $slideEl);\n $targetEl.transform(transform);\n }\n };\n\n const setTransition = duration => {\n const {\n transformEl\n } = swiper.params.flipEffect;\n const $transitionElements = transformEl ? swiper.slides.find(transformEl) : swiper.slides;\n $transitionElements.transition(duration).find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left').transition(duration);\n effectVirtualTransitionEnd({\n swiper,\n duration,\n transformEl\n });\n };\n\n effectInit({\n effect: 'flip',\n swiper,\n on,\n setTranslate,\n setTransition,\n recreateShadows,\n getEffectParams: () => swiper.params.flipEffect,\n perspective: () => true,\n overwriteParams: () => ({\n slidesPerView: 1,\n slidesPerGroup: 1,\n watchSlidesProgress: true,\n spaceBetween: 0,\n virtualTranslate: !swiper.params.cssMode\n })\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/effect-coverflow/effect-coverflow.js\n\n\n\nfunction EffectCoverflow({\n swiper,\n extendParams,\n on\n}) {\n extendParams({\n coverflowEffect: {\n rotate: 50,\n stretch: 0,\n depth: 100,\n scale: 1,\n modifier: 1,\n slideShadows: true,\n transformEl: null\n }\n });\n\n const setTranslate = () => {\n const {\n width: swiperWidth,\n height: swiperHeight,\n slides,\n slidesSizesGrid\n } = swiper;\n const params = swiper.params.coverflowEffect;\n const isHorizontal = swiper.isHorizontal();\n const transform = swiper.translate;\n const center = isHorizontal ? -transform + swiperWidth / 2 : -transform + swiperHeight / 2;\n const rotate = isHorizontal ? params.rotate : -params.rotate;\n const translate = params.depth; // Each slide offset from center\n\n for (let i = 0, length = slides.length; i < length; i += 1) {\n const $slideEl = slides.eq(i);\n const slideSize = slidesSizesGrid[i];\n const slideOffset = $slideEl[0].swiperSlideOffset;\n const centerOffset = (center - slideOffset - slideSize / 2) / slideSize;\n const offsetMultiplier = typeof params.modifier === 'function' ? params.modifier(centerOffset) : centerOffset * params.modifier;\n let rotateY = isHorizontal ? rotate * offsetMultiplier : 0;\n let rotateX = isHorizontal ? 0 : rotate * offsetMultiplier; // var rotateZ = 0\n\n let translateZ = -translate * Math.abs(offsetMultiplier);\n let stretch = params.stretch; // Allow percentage to make a relative stretch for responsive sliders\n\n if (typeof stretch === 'string' && stretch.indexOf('%') !== -1) {\n stretch = parseFloat(params.stretch) / 100 * slideSize;\n }\n\n let translateY = isHorizontal ? 0 : stretch * offsetMultiplier;\n let translateX = isHorizontal ? stretch * offsetMultiplier : 0;\n let scale = 1 - (1 - params.scale) * Math.abs(offsetMultiplier); // Fix for ultra small values\n\n if (Math.abs(translateX) < 0.001) translateX = 0;\n if (Math.abs(translateY) < 0.001) translateY = 0;\n if (Math.abs(translateZ) < 0.001) translateZ = 0;\n if (Math.abs(rotateY) < 0.001) rotateY = 0;\n if (Math.abs(rotateX) < 0.001) rotateX = 0;\n if (Math.abs(scale) < 0.001) scale = 0;\n const slideTransform = `translate3d(${translateX}px,${translateY}px,${translateZ}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale(${scale})`;\n const $targetEl = effectTarget(params, $slideEl);\n $targetEl.transform(slideTransform);\n $slideEl[0].style.zIndex = -Math.abs(Math.round(offsetMultiplier)) + 1;\n\n if (params.slideShadows) {\n // Set shadows\n let $shadowBeforeEl = isHorizontal ? $slideEl.find('.swiper-slide-shadow-left') : $slideEl.find('.swiper-slide-shadow-top');\n let $shadowAfterEl = isHorizontal ? $slideEl.find('.swiper-slide-shadow-right') : $slideEl.find('.swiper-slide-shadow-bottom');\n\n if ($shadowBeforeEl.length === 0) {\n $shadowBeforeEl = createShadow(params, $slideEl, isHorizontal ? 'left' : 'top');\n }\n\n if ($shadowAfterEl.length === 0) {\n $shadowAfterEl = createShadow(params, $slideEl, isHorizontal ? 'right' : 'bottom');\n }\n\n if ($shadowBeforeEl.length) $shadowBeforeEl[0].style.opacity = offsetMultiplier > 0 ? offsetMultiplier : 0;\n if ($shadowAfterEl.length) $shadowAfterEl[0].style.opacity = -offsetMultiplier > 0 ? -offsetMultiplier : 0;\n }\n }\n };\n\n const setTransition = duration => {\n const {\n transformEl\n } = swiper.params.coverflowEffect;\n const $transitionElements = transformEl ? swiper.slides.find(transformEl) : swiper.slides;\n $transitionElements.transition(duration).find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left').transition(duration);\n };\n\n effectInit({\n effect: 'coverflow',\n swiper,\n on,\n setTranslate,\n setTransition,\n perspective: () => true,\n overwriteParams: () => ({\n watchSlidesProgress: true\n })\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/effect-creative/effect-creative.js\n\n\n\n\nfunction EffectCreative({\n swiper,\n extendParams,\n on\n}) {\n extendParams({\n creativeEffect: {\n transformEl: null,\n limitProgress: 1,\n shadowPerProgress: false,\n progressMultiplier: 1,\n perspective: true,\n prev: {\n translate: [0, 0, 0],\n rotate: [0, 0, 0],\n opacity: 1,\n scale: 1\n },\n next: {\n translate: [0, 0, 0],\n rotate: [0, 0, 0],\n opacity: 1,\n scale: 1\n }\n }\n });\n\n const getTranslateValue = value => {\n if (typeof value === 'string') return value;\n return `${value}px`;\n };\n\n const setTranslate = () => {\n const {\n slides,\n $wrapperEl,\n slidesSizesGrid\n } = swiper;\n const params = swiper.params.creativeEffect;\n const {\n progressMultiplier: multiplier\n } = params;\n const isCenteredSlides = swiper.params.centeredSlides;\n\n if (isCenteredSlides) {\n const margin = slidesSizesGrid[0] / 2 - swiper.params.slidesOffsetBefore || 0;\n $wrapperEl.transform(`translateX(calc(50% - ${margin}px))`);\n }\n\n for (let i = 0; i < slides.length; i += 1) {\n const $slideEl = slides.eq(i);\n const slideProgress = $slideEl[0].progress;\n const progress = Math.min(Math.max($slideEl[0].progress, -params.limitProgress), params.limitProgress);\n let originalProgress = progress;\n\n if (!isCenteredSlides) {\n originalProgress = Math.min(Math.max($slideEl[0].originalProgress, -params.limitProgress), params.limitProgress);\n }\n\n const offset = $slideEl[0].swiperSlideOffset;\n const t = [swiper.params.cssMode ? -offset - swiper.translate : -offset, 0, 0];\n const r = [0, 0, 0];\n let custom = false;\n\n if (!swiper.isHorizontal()) {\n t[1] = t[0];\n t[0] = 0;\n }\n\n let data = {\n translate: [0, 0, 0],\n rotate: [0, 0, 0],\n scale: 1,\n opacity: 1\n };\n\n if (progress < 0) {\n data = params.next;\n custom = true;\n } else if (progress > 0) {\n data = params.prev;\n custom = true;\n } // set translate\n\n\n t.forEach((value, index) => {\n t[index] = `calc(${value}px + (${getTranslateValue(data.translate[index])} * ${Math.abs(progress * multiplier)}))`;\n }); // set rotates\n\n r.forEach((value, index) => {\n r[index] = data.rotate[index] * Math.abs(progress * multiplier);\n });\n $slideEl[0].style.zIndex = -Math.abs(Math.round(slideProgress)) + slides.length;\n const translateString = t.join(', ');\n const rotateString = `rotateX(${r[0]}deg) rotateY(${r[1]}deg) rotateZ(${r[2]}deg)`;\n const scaleString = originalProgress < 0 ? `scale(${1 + (1 - data.scale) * originalProgress * multiplier})` : `scale(${1 - (1 - data.scale) * originalProgress * multiplier})`;\n const opacityString = originalProgress < 0 ? 1 + (1 - data.opacity) * originalProgress * multiplier : 1 - (1 - data.opacity) * originalProgress * multiplier;\n const transform = `translate3d(${translateString}) ${rotateString} ${scaleString}`; // Set shadows\n\n if (custom && data.shadow || !custom) {\n let $shadowEl = $slideEl.children('.swiper-slide-shadow');\n\n if ($shadowEl.length === 0 && data.shadow) {\n $shadowEl = createShadow(params, $slideEl);\n }\n\n if ($shadowEl.length) {\n const shadowOpacity = params.shadowPerProgress ? progress * (1 / params.limitProgress) : progress;\n $shadowEl[0].style.opacity = Math.min(Math.max(Math.abs(shadowOpacity), 0), 1);\n }\n }\n\n const $targetEl = effectTarget(params, $slideEl);\n $targetEl.transform(transform).css({\n opacity: opacityString\n });\n\n if (data.origin) {\n $targetEl.css('transform-origin', data.origin);\n }\n }\n };\n\n const setTransition = duration => {\n const {\n transformEl\n } = swiper.params.creativeEffect;\n const $transitionElements = transformEl ? swiper.slides.find(transformEl) : swiper.slides;\n $transitionElements.transition(duration).find('.swiper-slide-shadow').transition(duration);\n effectVirtualTransitionEnd({\n swiper,\n duration,\n transformEl,\n allSlides: true\n });\n };\n\n effectInit({\n effect: 'creative',\n swiper,\n on,\n setTranslate,\n setTransition,\n perspective: () => swiper.params.creativeEffect.perspective,\n overwriteParams: () => ({\n watchSlidesProgress: true,\n virtualTranslate: !swiper.params.cssMode\n })\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/modules/effect-cards/effect-cards.js\n\n\n\n\nfunction EffectCards({\n swiper,\n extendParams,\n on\n}) {\n extendParams({\n cardsEffect: {\n slideShadows: true,\n transformEl: null,\n rotate: true,\n perSlideRotate: 2,\n perSlideOffset: 8\n }\n });\n\n const setTranslate = () => {\n const {\n slides,\n activeIndex\n } = swiper;\n const params = swiper.params.cardsEffect;\n const {\n startTranslate,\n isTouched\n } = swiper.touchEventsData;\n const currentTranslate = swiper.translate;\n\n for (let i = 0; i < slides.length; i += 1) {\n const $slideEl = slides.eq(i);\n const slideProgress = $slideEl[0].progress;\n const progress = Math.min(Math.max(slideProgress, -4), 4);\n let offset = $slideEl[0].swiperSlideOffset;\n\n if (swiper.params.centeredSlides && !swiper.params.cssMode) {\n swiper.$wrapperEl.transform(`translateX(${swiper.minTranslate()}px)`);\n }\n\n if (swiper.params.centeredSlides && swiper.params.cssMode) {\n offset -= slides[0].swiperSlideOffset;\n }\n\n let tX = swiper.params.cssMode ? -offset - swiper.translate : -offset;\n let tY = 0;\n const tZ = -100 * Math.abs(progress);\n let scale = 1;\n let rotate = -params.perSlideRotate * progress;\n let tXAdd = params.perSlideOffset - Math.abs(progress) * 0.75;\n const slideIndex = swiper.virtual && swiper.params.virtual.enabled ? swiper.virtual.from + i : i;\n const isSwipeToNext = (slideIndex === activeIndex || slideIndex === activeIndex - 1) && progress > 0 && progress < 1 && (isTouched || swiper.params.cssMode) && currentTranslate < startTranslate;\n const isSwipeToPrev = (slideIndex === activeIndex || slideIndex === activeIndex + 1) && progress < 0 && progress > -1 && (isTouched || swiper.params.cssMode) && currentTranslate > startTranslate;\n\n if (isSwipeToNext || isSwipeToPrev) {\n const subProgress = (1 - Math.abs((Math.abs(progress) - 0.5) / 0.5)) ** 0.5;\n rotate += -28 * progress * subProgress;\n scale += -0.5 * subProgress;\n tXAdd += 96 * subProgress;\n tY = `${-25 * subProgress * Math.abs(progress)}%`;\n }\n\n if (progress < 0) {\n // next\n tX = `calc(${tX}px + (${tXAdd * Math.abs(progress)}%))`;\n } else if (progress > 0) {\n // prev\n tX = `calc(${tX}px + (-${tXAdd * Math.abs(progress)}%))`;\n } else {\n tX = `${tX}px`;\n }\n\n if (!swiper.isHorizontal()) {\n const prevY = tY;\n tY = tX;\n tX = prevY;\n }\n\n const scaleString = progress < 0 ? `${1 + (1 - scale) * progress}` : `${1 - (1 - scale) * progress}`;\n const transform = `\n translate3d(${tX}, ${tY}, ${tZ}px)\n rotateZ(${params.rotate ? rotate : 0}deg)\n scale(${scaleString})\n `;\n\n if (params.slideShadows) {\n // Set shadows\n let $shadowEl = $slideEl.find('.swiper-slide-shadow');\n\n if ($shadowEl.length === 0) {\n $shadowEl = createShadow(params, $slideEl);\n }\n\n if ($shadowEl.length) $shadowEl[0].style.opacity = Math.min(Math.max((Math.abs(progress) - 0.5) / 0.5, 0), 1);\n }\n\n $slideEl[0].style.zIndex = -Math.abs(Math.round(slideProgress)) + slides.length;\n const $targetEl = effectTarget(params, $slideEl);\n $targetEl.transform(transform);\n }\n };\n\n const setTransition = duration => {\n const {\n transformEl\n } = swiper.params.cardsEffect;\n const $transitionElements = transformEl ? swiper.slides.find(transformEl) : swiper.slides;\n $transitionElements.transition(duration).find('.swiper-slide-shadow').transition(duration);\n effectVirtualTransitionEnd({\n swiper,\n duration,\n transformEl\n });\n };\n\n effectInit({\n effect: 'cards',\n swiper,\n on,\n setTranslate,\n setTransition,\n perspective: () => true,\n overwriteParams: () => ({\n watchSlidesProgress: true,\n virtualTranslate: !swiper.params.cssMode\n })\n });\n}\n;// CONCATENATED MODULE: ./node_modules/swiper/swiper.esm.js\n/**\n * Swiper 8.4.7\n * Most modern mobile touch slider and framework with hardware accelerated transitions\n * https://swiperjs.com\n *\n * Copyright 2014-2023 Vladimir Kharlampidi\n *\n * Released under the MIT License\n *\n * Released on: January 30, 2023\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n;// CONCATENATED MODULE: ./src/components/slider/slider.js\n//Vendor scripts\n\ncore.use([Navigation]);\nconst slider_vw = window.outerWidth;\nlet slidesMarkup = '';\nlet sliderInit;\nconst swiperContainer = document.querySelector('.sectionSlider_slider');\nconst slideClick = () => {\n const swiperslides = swiperContainer.querySelectorAll('.swiper-slide');\n swiperslides.forEach(slide => {\n const slideLink = slide.querySelector('.sectionSlider_slider-link');\n slide.addEventListener('click', () => {\n slideLink.click();\n });\n });\n};\nconst swiperInit = () => {\n sliderInit = new core(swiperContainer, {\n slidesPerView: 1.2,\n spaceBetween: 32,\n // simulateTouch: false,\n breakpoints: {\n 640: {\n slidesPerView: 3\n },\n 992: {\n slidesPerView: 5\n }\n },\n navigation: {\n prevEl: '.sectionSlider_slider-navigation--prev',\n nextEl: '.sectionSlider_slider-navigation--next',\n disabledClass: 'disabled-arrow'\n },\n on: {\n init: slideClick()\n }\n });\n};\nif (swiperContainer) {\n swiperInit();\n}\n;// CONCATENATED MODULE: ./src/main.js\n//Main styles\n\n//Vendor scripts\n\n//Common scripts\n\n//Components scripts\n\n\n\n\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiODQ4LmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDcjRJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ3ZpREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQzVxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDaG1GQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7O0FDL1FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ25IQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ3pGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUN0UUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUNuSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ3o5Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUNuTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ3ZDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUN2REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ3hCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0NBO0FBQ0E7QUFDQTs7QUNGQTtBQUNBO0FBQ0E7O0FDRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbklBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDem5CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeFNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbElBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcmFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5TUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hiQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbm1CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOVZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6SkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ25DQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9nc2FwL2dzYXAtY29yZS5qcz9hNWNmIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvZ3NhcC9DU1NQbHVnaW4uanM/OWNlNiIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL2dzYXAvaW5kZXguanM/Y2ZmYSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL2dzYXAvT2JzZXJ2ZXIuanM/NjZjMyIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL2dzYXAvU2Nyb2xsVHJpZ2dlci5qcz8xZGFjIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvZ3NhcC9TY3JvbGxUb1BsdWdpbi5qcz85NDIwIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9zcmMvY29tcG9uZW50cy9uYXZiYXIvbmF2YmFyLmpzPzkwZjgiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL3NyYy9jb21wb25lbnRzL2NoYXB0ZXJNb2RhbC9jaGFwdGVyTW9kYWwuanM/YmU1NCIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vc3JjL2NvbXBvbmVudHMvY2hhcHRlci9jaGFwdGVyLmpzPzNmMjUiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL3NyYy9hc3NldHMvanMvY29tbW9uLmpzP2Q4NTgiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL3NyYy9jb21wb25lbnRzL3Zpc3VhbC92aXN1YWwuanM/Zjc2ZCIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vc3JjL2NvbXBvbmVudHMvYWx0ZXJuYXRlL2FsdGVybmF0ZS5qcz80ZGU4Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9zcmMvY29tcG9uZW50cy9tYXAvbWFwLmpzPzk2ZmQiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zc3Itd2luZG93L3Nzci13aW5kb3cuZXNtLmpzP2Q2YzgiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9kb203L2RvbTcuZXNtLmpzPzJlMTUiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvc2hhcmVkL2RvbS5qcz9kMDE4Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL3NoYXJlZC91dGlscy5qcz8wY2JlIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL3NoYXJlZC9nZXQtc3VwcG9ydC5qcz84NjE3Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL3NoYXJlZC9nZXQtZGV2aWNlLmpzP2QxMTciLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvc2hhcmVkL2dldC1icm93c2VyLmpzP2Y5ZDYiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvY29yZS9tb2R1bGVzL3Jlc2l6ZS9yZXNpemUuanM/ZTdmOSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL21vZHVsZXMvb2JzZXJ2ZXIvb2JzZXJ2ZXIuanM/MzM2ZCIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL2V2ZW50cy1lbWl0dGVyLmpzPzYyM2UiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvY29yZS91cGRhdGUvdXBkYXRlU2l6ZS5qcz8wYTExIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvdXBkYXRlL3VwZGF0ZVNsaWRlcy5qcz9hOGE1Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvdXBkYXRlL3VwZGF0ZUF1dG9IZWlnaHQuanM/ZDcxOCIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL3VwZGF0ZS91cGRhdGVTbGlkZXNPZmZzZXQuanM/MTExMCIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL3VwZGF0ZS91cGRhdGVTbGlkZXNQcm9ncmVzcy5qcz9hNWY5Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvdXBkYXRlL3VwZGF0ZVByb2dyZXNzLmpzP2QwMTkiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvY29yZS91cGRhdGUvdXBkYXRlU2xpZGVzQ2xhc3Nlcy5qcz9lYzczIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvdXBkYXRlL3VwZGF0ZUFjdGl2ZUluZGV4LmpzPzFiYWUiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvY29yZS91cGRhdGUvdXBkYXRlQ2xpY2tlZFNsaWRlLmpzPzgyY2QiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvY29yZS91cGRhdGUvaW5kZXguanM/M2JjYiIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL3RyYW5zbGF0ZS9nZXRUcmFuc2xhdGUuanM/OWFjMCIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL3RyYW5zbGF0ZS9zZXRUcmFuc2xhdGUuanM/Y2YxOCIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL3RyYW5zbGF0ZS9taW5UcmFuc2xhdGUuanM/Njg1YSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL3RyYW5zbGF0ZS9tYXhUcmFuc2xhdGUuanM/MGM4YSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL3RyYW5zbGF0ZS90cmFuc2xhdGVUby5qcz83NzNkIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvdHJhbnNsYXRlL2luZGV4LmpzPzc5NmMiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvY29yZS90cmFuc2l0aW9uL3NldFRyYW5zaXRpb24uanM/ODBiOCIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL3RyYW5zaXRpb24vdHJhbnNpdGlvbkVtaXQuanM/MWI5OCIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL3RyYW5zaXRpb24vdHJhbnNpdGlvblN0YXJ0LmpzPzFmYWQiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvY29yZS90cmFuc2l0aW9uL3RyYW5zaXRpb25FbmQuanM/OWIzZiIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL3RyYW5zaXRpb24vaW5kZXguanM/MTQ2NSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL3NsaWRlL3NsaWRlVG8uanM/MDFhNCIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL3NsaWRlL3NsaWRlVG9Mb29wLmpzPzlmNmMiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvY29yZS9zbGlkZS9zbGlkZU5leHQuanM/ZWM0MSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL3NsaWRlL3NsaWRlUHJldi5qcz8zNGZlIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvc2xpZGUvc2xpZGVSZXNldC5qcz9mOThkIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvc2xpZGUvc2xpZGVUb0Nsb3Nlc3QuanM/ZjM5NiIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL3NsaWRlL3NsaWRlVG9DbGlja2VkU2xpZGUuanM/ZTNjZSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL3NsaWRlL2luZGV4LmpzPzcxYzAiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvY29yZS9sb29wL2xvb3BDcmVhdGUuanM/NzUxYyIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL2xvb3AvbG9vcEZpeC5qcz83YTI4Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvbG9vcC9sb29wRGVzdHJveS5qcz83OGIyIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvbG9vcC9pbmRleC5qcz8yMmJkIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvZ3JhYi1jdXJzb3Ivc2V0R3JhYkN1cnNvci5qcz82ZjU0Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvZ3JhYi1jdXJzb3IvdW5zZXRHcmFiQ3Vyc29yLmpzPzAyODMiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvY29yZS9ncmFiLWN1cnNvci9pbmRleC5qcz9iY2U3Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvZXZlbnRzL29uVG91Y2hTdGFydC5qcz8yOGYyIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvZXZlbnRzL29uVG91Y2hNb3ZlLmpzPzczNTAiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvY29yZS9ldmVudHMvb25Ub3VjaEVuZC5qcz9jYTkxIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvZXZlbnRzL29uUmVzaXplLmpzPzIzMTYiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvY29yZS9ldmVudHMvb25DbGljay5qcz9jZGY5Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvZXZlbnRzL29uU2Nyb2xsLmpzPzJkMmIiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvY29yZS9ldmVudHMvaW5kZXguanM/NTFkMSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL2JyZWFrcG9pbnRzL3NldEJyZWFrcG9pbnQuanM/NTU2MiIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL2JyZWFrcG9pbnRzL2dldEJyZWFrcG9pbnQuanM/OTY0NCIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL2JyZWFrcG9pbnRzL2luZGV4LmpzP2I4M2MiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvY29yZS9jbGFzc2VzL2FkZENsYXNzZXMuanM/ODA5YyIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL2NsYXNzZXMvcmVtb3ZlQ2xhc3Nlcy5qcz83M2JjIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvY2xhc3Nlcy9pbmRleC5qcz9jN2Q0Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvaW1hZ2VzL2xvYWRJbWFnZS5qcz9iNzY1Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvaW1hZ2VzL3ByZWxvYWRJbWFnZXMuanM/YzE0YiIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL2ltYWdlcy9pbmRleC5qcz84ZTQxIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL2NvcmUvY2hlY2stb3ZlcmZsb3cvaW5kZXguanM/MTViZSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL2RlZmF1bHRzLmpzPzExN2QiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvY29yZS9tb2R1bGVFeHRlbmRQYXJhbXMuanM/M2FjZiIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9jb3JlL2NvcmUuanM/ZTIxZiIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9tb2R1bGVzL3ZpcnR1YWwvdmlydHVhbC5qcz8xNDE1Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL21vZHVsZXMva2V5Ym9hcmQva2V5Ym9hcmQuanM/YTk3YSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9tb2R1bGVzL21vdXNld2hlZWwvbW91c2V3aGVlbC5qcz9lY2MzIiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL3NoYXJlZC9jcmVhdGUtZWxlbWVudC1pZi1ub3QtZGVmaW5lZC5qcz9kMDQ3Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL21vZHVsZXMvbmF2aWdhdGlvbi9uYXZpZ2F0aW9uLmpzPzlkZmEiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvbW9kdWxlcy9wYWdpbmF0aW9uL3BhZ2luYXRpb24uanM/OGY3MiIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9tb2R1bGVzL3Njcm9sbGJhci9zY3JvbGxiYXIuanM/NWFjNSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9tb2R1bGVzL3BhcmFsbGF4L3BhcmFsbGF4LmpzPzg3MjAiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvbW9kdWxlcy96b29tL3pvb20uanM/MGM0NyIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9tb2R1bGVzL2xhenkvbGF6eS5qcz83MGY3Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL21vZHVsZXMvY29udHJvbGxlci9jb250cm9sbGVyLmpzPzIzNGEiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvbW9kdWxlcy9hMTF5L2ExMXkuanM/NjYyNSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9tb2R1bGVzL2hpc3RvcnkvaGlzdG9yeS5qcz9jNTE0Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL21vZHVsZXMvaGFzaC1uYXZpZ2F0aW9uL2hhc2gtbmF2aWdhdGlvbi5qcz82MTA2Iiwid2VicGFjazovL3BpcmVsbGlfYmVjY2FyaWEvLi9ub2RlX21vZHVsZXMvc3dpcGVyL21vZHVsZXMvYXV0b3BsYXkvYXV0b3BsYXkuanM/Njc0MCIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9tb2R1bGVzL3RodW1icy90aHVtYnMuanM/ZjdkMiIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9tb2R1bGVzL2ZyZWUtbW9kZS9mcmVlLW1vZGUuanM/MDM0NSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9tb2R1bGVzL2VmZmVjdC1jdWJlL2VmZmVjdC1jdWJlLmpzPzIzNDciLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvc2hhcmVkL2NyZWF0ZS1zaGFkb3cuanM/NDQ1YSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9tb2R1bGVzL2VmZmVjdC1mbGlwL2VmZmVjdC1mbGlwLmpzP2JjZWEiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9zd2lwZXIvbW9kdWxlcy9lZmZlY3QtY292ZXJmbG93L2VmZmVjdC1jb3ZlcmZsb3cuanM/ZTYxNSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9tb2R1bGVzL2VmZmVjdC1jcmVhdGl2ZS9lZmZlY3QtY3JlYXRpdmUuanM/Mjg0MSIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9tb2R1bGVzL2VmZmVjdC1jYXJkcy9lZmZlY3QtY2FyZHMuanM/ODA1YyIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3N3aXBlci9zd2lwZXIuZXNtLmpzP2EwZDAiLCJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL3NyYy9jb21wb25lbnRzL3NsaWRlci9zbGlkZXIuanM/YWQ1YiIsIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vc3JjL21haW4uanM/ZDI1NiJdLCJzb3VyY2VzQ29udGVudCI6WyJmdW5jdGlvbiBfYXNzZXJ0VGhpc0luaXRpYWxpemVkKHNlbGYpIHsgaWYgKHNlbGYgPT09IHZvaWQgMCkgeyB0aHJvdyBuZXcgUmVmZXJlbmNlRXJyb3IoXCJ0aGlzIGhhc24ndCBiZWVuIGluaXRpYWxpc2VkIC0gc3VwZXIoKSBoYXNuJ3QgYmVlbiBjYWxsZWRcIik7IH0gcmV0dXJuIHNlbGY7IH1cblxuZnVuY3Rpb24gX2luaGVyaXRzTG9vc2Uoc3ViQ2xhc3MsIHN1cGVyQ2xhc3MpIHsgc3ViQ2xhc3MucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShzdXBlckNsYXNzLnByb3RvdHlwZSk7IHN1YkNsYXNzLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IHN1YkNsYXNzOyBzdWJDbGFzcy5fX3Byb3RvX18gPSBzdXBlckNsYXNzOyB9XG5cbi8qIVxuICogR1NBUCAzLjEyLjVcbiAqIGh0dHBzOi8vZ3NhcC5jb21cbiAqXG4gKiBAbGljZW5zZSBDb3B5cmlnaHQgMjAwOC0yMDI0LCBHcmVlblNvY2suIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhdCBodHRwczovL2dzYXAuY29tL3N0YW5kYXJkLWxpY2Vuc2Ugb3IgZm9yXG4gKiBDbHViIEdTQVAgbWVtYmVycywgdGhlIGFncmVlbWVudCBpc3N1ZWQgd2l0aCB0aGF0IG1lbWJlcnNoaXAuXG4gKiBAYXV0aG9yOiBKYWNrIERveWxlLCBqYWNrQGdyZWVuc29jay5jb21cbiovXG5cbi8qIGVzbGludC1kaXNhYmxlICovXG52YXIgX2NvbmZpZyA9IHtcbiAgYXV0b1NsZWVwOiAxMjAsXG4gIGZvcmNlM0Q6IFwiYXV0b1wiLFxuICBudWxsVGFyZ2V0V2FybjogMSxcbiAgdW5pdHM6IHtcbiAgICBsaW5lSGVpZ2h0OiBcIlwiXG4gIH1cbn0sXG4gICAgX2RlZmF1bHRzID0ge1xuICBkdXJhdGlvbjogLjUsXG4gIG92ZXJ3cml0ZTogZmFsc2UsXG4gIGRlbGF5OiAwXG59LFxuICAgIF9zdXBwcmVzc092ZXJ3cml0ZXMsXG4gICAgX3JldmVydGluZyxcbiAgICBfY29udGV4dCxcbiAgICBfYmlnTnVtID0gMWU4LFxuICAgIF90aW55TnVtID0gMSAvIF9iaWdOdW0sXG4gICAgXzJQSSA9IE1hdGguUEkgKiAyLFxuICAgIF9IQUxGX1BJID0gXzJQSSAvIDQsXG4gICAgX2dzSUQgPSAwLFxuICAgIF9zcXJ0ID0gTWF0aC5zcXJ0LFxuICAgIF9jb3MgPSBNYXRoLmNvcyxcbiAgICBfc2luID0gTWF0aC5zaW4sXG4gICAgX2lzU3RyaW5nID0gZnVuY3Rpb24gX2lzU3RyaW5nKHZhbHVlKSB7XG4gIHJldHVybiB0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCI7XG59LFxuICAgIF9pc0Z1bmN0aW9uID0gZnVuY3Rpb24gX2lzRnVuY3Rpb24odmFsdWUpIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gXCJmdW5jdGlvblwiO1xufSxcbiAgICBfaXNOdW1iZXIgPSBmdW5jdGlvbiBfaXNOdW1iZXIodmFsdWUpIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gXCJudW1iZXJcIjtcbn0sXG4gICAgX2lzVW5kZWZpbmVkID0gZnVuY3Rpb24gX2lzVW5kZWZpbmVkKHZhbHVlKSB7XG4gIHJldHVybiB0eXBlb2YgdmFsdWUgPT09IFwidW5kZWZpbmVkXCI7XG59LFxuICAgIF9pc09iamVjdCA9IGZ1bmN0aW9uIF9pc09iamVjdCh2YWx1ZSkge1xuICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSBcIm9iamVjdFwiO1xufSxcbiAgICBfaXNOb3RGYWxzZSA9IGZ1bmN0aW9uIF9pc05vdEZhbHNlKHZhbHVlKSB7XG4gIHJldHVybiB2YWx1ZSAhPT0gZmFsc2U7XG59LFxuICAgIF93aW5kb3dFeGlzdHMgPSBmdW5jdGlvbiBfd2luZG93RXhpc3RzKCkge1xuICByZXR1cm4gdHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIjtcbn0sXG4gICAgX2lzRnVuY09yU3RyaW5nID0gZnVuY3Rpb24gX2lzRnVuY09yU3RyaW5nKHZhbHVlKSB7XG4gIHJldHVybiBfaXNGdW5jdGlvbih2YWx1ZSkgfHwgX2lzU3RyaW5nKHZhbHVlKTtcbn0sXG4gICAgX2lzVHlwZWRBcnJheSA9IHR5cGVvZiBBcnJheUJ1ZmZlciA9PT0gXCJmdW5jdGlvblwiICYmIEFycmF5QnVmZmVyLmlzVmlldyB8fCBmdW5jdGlvbiAoKSB7fSxcbiAgICAvLyBub3RlOiBJRTEwIGhhcyBBcnJheUJ1ZmZlciwgYnV0IE5PVCBBcnJheUJ1ZmZlci5pc1ZpZXcoKS5cbl9pc0FycmF5ID0gQXJyYXkuaXNBcnJheSxcbiAgICBfc3RyaWN0TnVtRXhwID0gLyg/Oi0/XFwuP1xcZHxcXC4pKy9naSxcbiAgICAvL29ubHkgbnVtYmVycyAoaW5jbHVkaW5nIG5lZ2F0aXZlcyBhbmQgZGVjaW1hbHMpIGJ1dCBOT1QgcmVsYXRpdmUgdmFsdWVzLlxuX251bUV4cCA9IC9bLSs9Ll0qXFxkK1suZVxcLStdKlxcZCpbZVxcLStdKlxcZCovZyxcbiAgICAvL2ZpbmRzIGFueSBudW1iZXJzLCBpbmNsdWRpbmcgb25lcyB0aGF0IHN0YXJ0IHdpdGggKz0gb3IgLT0sIG5lZ2F0aXZlIG51bWJlcnMsIGFuZCBvbmVzIGluIHNjaWVudGlmaWMgbm90YXRpb24gbGlrZSAxZS04LlxuX251bVdpdGhVbml0RXhwID0gL1stKz0uXSpcXGQrWy5lLV0qXFxkKlthLXolXSovZyxcbiAgICBfY29tcGxleFN0cmluZ051bUV4cCA9IC9bLSs9Ll0qXFxkK1xcLj9cXGQqKD86ZS18ZVxcKyk/XFxkKi9naSxcbiAgICAvL2R1cGxpY2F0ZSBzbyB0aGF0IHdoaWxlIHdlJ3JlIGxvb3BpbmcgdGhyb3VnaCBtYXRjaGVzIGZyb20gZXhlYygpLCBpdCBkb2Vzbid0IGNvbnRhbWluYXRlIHRoZSBsYXN0SW5kZXggb2YgX251bUV4cCB3aGljaCB3ZSB1c2UgdG8gc2VhcmNoIGZvciBjb2xvcnMgdG9vLlxuX3JlbEV4cCA9IC9bKy1dPS0/Wy5cXGRdKy8sXG4gICAgX2RlbGltaXRlZFZhbHVlRXhwID0gL1teLCdcIlxcW1xcXVxcc10rL2dpLFxuICAgIC8vIHByZXZpb3VzbHkgL1sjXFwtKy5dKlxcYlthLXpcXGRcXC09KyUuXSsvZ2kgYnV0IGRpZG4ndCBjYXRjaCBzcGVjaWFsIGNoYXJhY3RlcnMuXG5fdW5pdEV4cCA9IC9eWytcXC09ZVxcc1xcZF0qXFxkK1suXFxkXSooW2Etel0qfCUpXFxzKiQvaSxcbiAgICBfZ2xvYmFsVGltZWxpbmUsXG4gICAgX3dpbixcbiAgICBfY29yZUluaXR0ZWQsXG4gICAgX2RvYyxcbiAgICBfZ2xvYmFscyA9IHt9LFxuICAgIF9pbnN0YWxsU2NvcGUgPSB7fSxcbiAgICBfY29yZVJlYWR5LFxuICAgIF9pbnN0YWxsID0gZnVuY3Rpb24gX2luc3RhbGwoc2NvcGUpIHtcbiAgcmV0dXJuIChfaW5zdGFsbFNjb3BlID0gX21lcmdlKHNjb3BlLCBfZ2xvYmFscykpICYmIGdzYXA7XG59LFxuICAgIF9taXNzaW5nUGx1Z2luID0gZnVuY3Rpb24gX21pc3NpbmdQbHVnaW4ocHJvcGVydHksIHZhbHVlKSB7XG4gIHJldHVybiBjb25zb2xlLndhcm4oXCJJbnZhbGlkIHByb3BlcnR5XCIsIHByb3BlcnR5LCBcInNldCB0b1wiLCB2YWx1ZSwgXCJNaXNzaW5nIHBsdWdpbj8gZ3NhcC5yZWdpc3RlclBsdWdpbigpXCIpO1xufSxcbiAgICBfd2FybiA9IGZ1bmN0aW9uIF93YXJuKG1lc3NhZ2UsIHN1cHByZXNzKSB7XG4gIHJldHVybiAhc3VwcHJlc3MgJiYgY29uc29sZS53YXJuKG1lc3NhZ2UpO1xufSxcbiAgICBfYWRkR2xvYmFsID0gZnVuY3Rpb24gX2FkZEdsb2JhbChuYW1lLCBvYmopIHtcbiAgcmV0dXJuIG5hbWUgJiYgKF9nbG9iYWxzW25hbWVdID0gb2JqKSAmJiBfaW5zdGFsbFNjb3BlICYmIChfaW5zdGFsbFNjb3BlW25hbWVdID0gb2JqKSB8fCBfZ2xvYmFscztcbn0sXG4gICAgX2VtcHR5RnVuYyA9IGZ1bmN0aW9uIF9lbXB0eUZ1bmMoKSB7XG4gIHJldHVybiAwO1xufSxcbiAgICBfc3RhcnRBdFJldmVydENvbmZpZyA9IHtcbiAgc3VwcHJlc3NFdmVudHM6IHRydWUsXG4gIGlzU3RhcnQ6IHRydWUsXG4gIGtpbGw6IGZhbHNlXG59LFxuICAgIF9yZXZlcnRDb25maWdOb0tpbGwgPSB7XG4gIHN1cHByZXNzRXZlbnRzOiB0cnVlLFxuICBraWxsOiBmYWxzZVxufSxcbiAgICBfcmV2ZXJ0Q29uZmlnID0ge1xuICBzdXBwcmVzc0V2ZW50czogdHJ1ZVxufSxcbiAgICBfcmVzZXJ2ZWRQcm9wcyA9IHt9LFxuICAgIF9sYXp5VHdlZW5zID0gW10sXG4gICAgX2xhenlMb29rdXAgPSB7fSxcbiAgICBfbGFzdFJlbmRlcmVkRnJhbWUsXG4gICAgX3BsdWdpbnMgPSB7fSxcbiAgICBfZWZmZWN0cyA9IHt9LFxuICAgIF9uZXh0R0NGcmFtZSA9IDMwLFxuICAgIF9oYXJuZXNzUGx1Z2lucyA9IFtdLFxuICAgIF9jYWxsYmFja05hbWVzID0gXCJcIixcbiAgICBfaGFybmVzcyA9IGZ1bmN0aW9uIF9oYXJuZXNzKHRhcmdldHMpIHtcbiAgdmFyIHRhcmdldCA9IHRhcmdldHNbMF0sXG4gICAgICBoYXJuZXNzUGx1Z2luLFxuICAgICAgaTtcbiAgX2lzT2JqZWN0KHRhcmdldCkgfHwgX2lzRnVuY3Rpb24odGFyZ2V0KSB8fCAodGFyZ2V0cyA9IFt0YXJnZXRzXSk7XG5cbiAgaWYgKCEoaGFybmVzc1BsdWdpbiA9ICh0YXJnZXQuX2dzYXAgfHwge30pLmhhcm5lc3MpKSB7XG4gICAgLy8gZmluZCB0aGUgZmlyc3QgdGFyZ2V0IHdpdGggYSBoYXJuZXNzLiBXZSBhc3N1bWUgdGFyZ2V0cyBwYXNzZWQgaW50byBhbiBhbmltYXRpb24gd2lsbCBiZSBvZiBzaW1pbGFyIHR5cGUsIG1lYW5pbmcgdGhlIHNhbWUga2luZCBvZiBoYXJuZXNzIGNhbiBiZSB1c2VkIGZvciB0aGVtIGFsbCAocGVyZm9ybWFuY2Ugb3B0aW1pemF0aW9uKVxuICAgIGkgPSBfaGFybmVzc1BsdWdpbnMubGVuZ3RoO1xuXG4gICAgd2hpbGUgKGktLSAmJiAhX2hhcm5lc3NQbHVnaW5zW2ldLnRhcmdldFRlc3QodGFyZ2V0KSkge31cblxuICAgIGhhcm5lc3NQbHVnaW4gPSBfaGFybmVzc1BsdWdpbnNbaV07XG4gIH1cblxuICBpID0gdGFyZ2V0cy5sZW5ndGg7XG5cbiAgd2hpbGUgKGktLSkge1xuICAgIHRhcmdldHNbaV0gJiYgKHRhcmdldHNbaV0uX2dzYXAgfHwgKHRhcmdldHNbaV0uX2dzYXAgPSBuZXcgR1NDYWNoZSh0YXJnZXRzW2ldLCBoYXJuZXNzUGx1Z2luKSkpIHx8IHRhcmdldHMuc3BsaWNlKGksIDEpO1xuICB9XG5cbiAgcmV0dXJuIHRhcmdldHM7XG59LFxuICAgIF9nZXRDYWNoZSA9IGZ1bmN0aW9uIF9nZXRDYWNoZSh0YXJnZXQpIHtcbiAgcmV0dXJuIHRhcmdldC5fZ3NhcCB8fCBfaGFybmVzcyh0b0FycmF5KHRhcmdldCkpWzBdLl9nc2FwO1xufSxcbiAgICBfZ2V0UHJvcGVydHkgPSBmdW5jdGlvbiBfZ2V0UHJvcGVydHkodGFyZ2V0LCBwcm9wZXJ0eSwgdikge1xuICByZXR1cm4gKHYgPSB0YXJnZXRbcHJvcGVydHldKSAmJiBfaXNGdW5jdGlvbih2KSA/IHRhcmdldFtwcm9wZXJ0eV0oKSA6IF9pc1VuZGVmaW5lZCh2KSAmJiB0YXJnZXQuZ2V0QXR0cmlidXRlICYmIHRhcmdldC5nZXRBdHRyaWJ1dGUocHJvcGVydHkpIHx8IHY7XG59LFxuICAgIF9mb3JFYWNoTmFtZSA9IGZ1bmN0aW9uIF9mb3JFYWNoTmFtZShuYW1lcywgZnVuYykge1xuICByZXR1cm4gKG5hbWVzID0gbmFtZXMuc3BsaXQoXCIsXCIpKS5mb3JFYWNoKGZ1bmMpIHx8IG5hbWVzO1xufSxcbiAgICAvL3NwbGl0IGEgY29tbWEtZGVsaW1pdGVkIGxpc3Qgb2YgbmFtZXMgaW50byBhbiBhcnJheSwgdGhlbiBydW4gYSBmb3JFYWNoKCkgZnVuY3Rpb24gYW5kIHJldHVybiB0aGUgc3BsaXQgYXJyYXkgKHRoaXMgaXMganVzdCBhIHdheSB0byBjb25zb2xpZGF0ZS9zaG9ydGVuIHNvbWUgY29kZSkuXG5fcm91bmQgPSBmdW5jdGlvbiBfcm91bmQodmFsdWUpIHtcbiAgcmV0dXJuIE1hdGgucm91bmQodmFsdWUgKiAxMDAwMDApIC8gMTAwMDAwIHx8IDA7XG59LFxuICAgIF9yb3VuZFByZWNpc2UgPSBmdW5jdGlvbiBfcm91bmRQcmVjaXNlKHZhbHVlKSB7XG4gIHJldHVybiBNYXRoLnJvdW5kKHZhbHVlICogMTAwMDAwMDApIC8gMTAwMDAwMDAgfHwgMDtcbn0sXG4gICAgLy8gaW5jcmVhc2VkIHByZWNpc2lvbiBtb3N0bHkgZm9yIHRpbWluZyB2YWx1ZXMuXG5fcGFyc2VSZWxhdGl2ZSA9IGZ1bmN0aW9uIF9wYXJzZVJlbGF0aXZlKHN0YXJ0LCB2YWx1ZSkge1xuICB2YXIgb3BlcmF0b3IgPSB2YWx1ZS5jaGFyQXQoMCksXG4gICAgICBlbmQgPSBwYXJzZUZsb2F0KHZhbHVlLnN1YnN0cigyKSk7XG4gIHN0YXJ0ID0gcGFyc2VGbG9hdChzdGFydCk7XG4gIHJldHVybiBvcGVyYXRvciA9PT0gXCIrXCIgPyBzdGFydCArIGVuZCA6IG9wZXJhdG9yID09PSBcIi1cIiA/IHN0YXJ0IC0gZW5kIDogb3BlcmF0b3IgPT09IFwiKlwiID8gc3RhcnQgKiBlbmQgOiBzdGFydCAvIGVuZDtcbn0sXG4gICAgX2FycmF5Q29udGFpbnNBbnkgPSBmdW5jdGlvbiBfYXJyYXlDb250YWluc0FueSh0b1NlYXJjaCwgdG9GaW5kKSB7XG4gIC8vc2VhcmNoZXMgb25lIGFycmF5IHRvIGZpbmQgbWF0Y2hlcyBmb3IgYW55IG9mIHRoZSBpdGVtcyBpbiB0aGUgdG9GaW5kIGFycmF5LiBBcyBzb29uIGFzIG9uZSBpcyBmb3VuZCwgaXQgcmV0dXJucyB0cnVlLiBJdCBkb2VzIE5PVCByZXR1cm4gYWxsIHRoZSBtYXRjaGVzOyBpdCdzIHNpbXBseSBhIGJvb2xlYW4gc2VhcmNoLlxuICB2YXIgbCA9IHRvRmluZC5sZW5ndGgsXG4gICAgICBpID0gMDtcblxuICBmb3IgKDsgdG9TZWFyY2guaW5kZXhPZih0b0ZpbmRbaV0pIDwgMCAmJiArK2kgPCBsOykge31cblxuICByZXR1cm4gaSA8IGw7XG59LFxuICAgIF9sYXp5UmVuZGVyID0gZnVuY3Rpb24gX2xhenlSZW5kZXIoKSB7XG4gIHZhciBsID0gX2xhenlUd2VlbnMubGVuZ3RoLFxuICAgICAgYSA9IF9sYXp5VHdlZW5zLnNsaWNlKDApLFxuICAgICAgaSxcbiAgICAgIHR3ZWVuO1xuXG4gIF9sYXp5TG9va3VwID0ge307XG4gIF9sYXp5VHdlZW5zLmxlbmd0aCA9IDA7XG5cbiAgZm9yIChpID0gMDsgaSA8IGw7IGkrKykge1xuICAgIHR3ZWVuID0gYVtpXTtcbiAgICB0d2VlbiAmJiB0d2Vlbi5fbGF6eSAmJiAodHdlZW4ucmVuZGVyKHR3ZWVuLl9sYXp5WzBdLCB0d2Vlbi5fbGF6eVsxXSwgdHJ1ZSkuX2xhenkgPSAwKTtcbiAgfVxufSxcbiAgICBfbGF6eVNhZmVSZW5kZXIgPSBmdW5jdGlvbiBfbGF6eVNhZmVSZW5kZXIoYW5pbWF0aW9uLCB0aW1lLCBzdXBwcmVzc0V2ZW50cywgZm9yY2UpIHtcbiAgX2xhenlUd2VlbnMubGVuZ3RoICYmICFfcmV2ZXJ0aW5nICYmIF9sYXp5UmVuZGVyKCk7XG4gIGFuaW1hdGlvbi5yZW5kZXIodGltZSwgc3VwcHJlc3NFdmVudHMsIGZvcmNlIHx8IF9yZXZlcnRpbmcgJiYgdGltZSA8IDAgJiYgKGFuaW1hdGlvbi5faW5pdHRlZCB8fCBhbmltYXRpb24uX3N0YXJ0QXQpKTtcbiAgX2xhenlUd2VlbnMubGVuZ3RoICYmICFfcmV2ZXJ0aW5nICYmIF9sYXp5UmVuZGVyKCk7IC8vaW4gY2FzZSByZW5kZXJpbmcgY2F1c2VkIGFueSB0d2VlbnMgdG8gbGF6eS1pbml0LCB3ZSBzaG91bGQgcmVuZGVyIHRoZW0gYmVjYXVzZSB0eXBpY2FsbHkgd2hlbiBzb21lb25lIGNhbGxzIHNlZWsoKSBvciB0aW1lKCkgb3IgcHJvZ3Jlc3MoKSwgdGhleSBleHBlY3QgYW4gaW1tZWRpYXRlIHJlbmRlci5cbn0sXG4gICAgX251bWVyaWNJZlBvc3NpYmxlID0gZnVuY3Rpb24gX251bWVyaWNJZlBvc3NpYmxlKHZhbHVlKSB7XG4gIHZhciBuID0gcGFyc2VGbG9hdCh2YWx1ZSk7XG4gIHJldHVybiAobiB8fCBuID09PSAwKSAmJiAodmFsdWUgKyBcIlwiKS5tYXRjaChfZGVsaW1pdGVkVmFsdWVFeHApLmxlbmd0aCA8IDIgPyBuIDogX2lzU3RyaW5nKHZhbHVlKSA/IHZhbHVlLnRyaW0oKSA6IHZhbHVlO1xufSxcbiAgICBfcGFzc1Rocm91Z2ggPSBmdW5jdGlvbiBfcGFzc1Rocm91Z2gocCkge1xuICByZXR1cm4gcDtcbn0sXG4gICAgX3NldERlZmF1bHRzID0gZnVuY3Rpb24gX3NldERlZmF1bHRzKG9iaiwgZGVmYXVsdHMpIHtcbiAgZm9yICh2YXIgcCBpbiBkZWZhdWx0cykge1xuICAgIHAgaW4gb2JqIHx8IChvYmpbcF0gPSBkZWZhdWx0c1twXSk7XG4gIH1cblxuICByZXR1cm4gb2JqO1xufSxcbiAgICBfc2V0S2V5ZnJhbWVEZWZhdWx0cyA9IGZ1bmN0aW9uIF9zZXRLZXlmcmFtZURlZmF1bHRzKGV4Y2x1ZGVEdXJhdGlvbikge1xuICByZXR1cm4gZnVuY3Rpb24gKG9iaiwgZGVmYXVsdHMpIHtcbiAgICBmb3IgKHZhciBwIGluIGRlZmF1bHRzKSB7XG4gICAgICBwIGluIG9iaiB8fCBwID09PSBcImR1cmF0aW9uXCIgJiYgZXhjbHVkZUR1cmF0aW9uIHx8IHAgPT09IFwiZWFzZVwiIHx8IChvYmpbcF0gPSBkZWZhdWx0c1twXSk7XG4gICAgfVxuICB9O1xufSxcbiAgICBfbWVyZ2UgPSBmdW5jdGlvbiBfbWVyZ2UoYmFzZSwgdG9NZXJnZSkge1xuICBmb3IgKHZhciBwIGluIHRvTWVyZ2UpIHtcbiAgICBiYXNlW3BdID0gdG9NZXJnZVtwXTtcbiAgfVxuXG4gIHJldHVybiBiYXNlO1xufSxcbiAgICBfbWVyZ2VEZWVwID0gZnVuY3Rpb24gX21lcmdlRGVlcChiYXNlLCB0b01lcmdlKSB7XG4gIGZvciAodmFyIHAgaW4gdG9NZXJnZSkge1xuICAgIHAgIT09IFwiX19wcm90b19fXCIgJiYgcCAhPT0gXCJjb25zdHJ1Y3RvclwiICYmIHAgIT09IFwicHJvdG90eXBlXCIgJiYgKGJhc2VbcF0gPSBfaXNPYmplY3QodG9NZXJnZVtwXSkgPyBfbWVyZ2VEZWVwKGJhc2VbcF0gfHwgKGJhc2VbcF0gPSB7fSksIHRvTWVyZ2VbcF0pIDogdG9NZXJnZVtwXSk7XG4gIH1cblxuICByZXR1cm4gYmFzZTtcbn0sXG4gICAgX2NvcHlFeGNsdWRpbmcgPSBmdW5jdGlvbiBfY29weUV4Y2x1ZGluZyhvYmosIGV4Y2x1ZGluZykge1xuICB2YXIgY29weSA9IHt9LFxuICAgICAgcDtcblxuICBmb3IgKHAgaW4gb2JqKSB7XG4gICAgcCBpbiBleGNsdWRpbmcgfHwgKGNvcHlbcF0gPSBvYmpbcF0pO1xuICB9XG5cbiAgcmV0dXJuIGNvcHk7XG59LFxuICAgIF9pbmhlcml0RGVmYXVsdHMgPSBmdW5jdGlvbiBfaW5oZXJpdERlZmF1bHRzKHZhcnMpIHtcbiAgdmFyIHBhcmVudCA9IHZhcnMucGFyZW50IHx8IF9nbG9iYWxUaW1lbGluZSxcbiAgICAgIGZ1bmMgPSB2YXJzLmtleWZyYW1lcyA/IF9zZXRLZXlmcmFtZURlZmF1bHRzKF9pc0FycmF5KHZhcnMua2V5ZnJhbWVzKSkgOiBfc2V0RGVmYXVsdHM7XG5cbiAgaWYgKF9pc05vdEZhbHNlKHZhcnMuaW5oZXJpdCkpIHtcbiAgICB3aGlsZSAocGFyZW50KSB7XG4gICAgICBmdW5jKHZhcnMsIHBhcmVudC52YXJzLmRlZmF1bHRzKTtcbiAgICAgIHBhcmVudCA9IHBhcmVudC5wYXJlbnQgfHwgcGFyZW50Ll9kcDtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gdmFycztcbn0sXG4gICAgX2FycmF5c01hdGNoID0gZnVuY3Rpb24gX2FycmF5c01hdGNoKGExLCBhMikge1xuICB2YXIgaSA9IGExLmxlbmd0aCxcbiAgICAgIG1hdGNoID0gaSA9PT0gYTIubGVuZ3RoO1xuXG4gIHdoaWxlIChtYXRjaCAmJiBpLS0gJiYgYTFbaV0gPT09IGEyW2ldKSB7fVxuXG4gIHJldHVybiBpIDwgMDtcbn0sXG4gICAgX2FkZExpbmtlZExpc3RJdGVtID0gZnVuY3Rpb24gX2FkZExpbmtlZExpc3RJdGVtKHBhcmVudCwgY2hpbGQsIGZpcnN0UHJvcCwgbGFzdFByb3AsIHNvcnRCeSkge1xuICBpZiAoZmlyc3RQcm9wID09PSB2b2lkIDApIHtcbiAgICBmaXJzdFByb3AgPSBcIl9maXJzdFwiO1xuICB9XG5cbiAgaWYgKGxhc3RQcm9wID09PSB2b2lkIDApIHtcbiAgICBsYXN0UHJvcCA9IFwiX2xhc3RcIjtcbiAgfVxuXG4gIHZhciBwcmV2ID0gcGFyZW50W2xhc3RQcm9wXSxcbiAgICAgIHQ7XG5cbiAgaWYgKHNvcnRCeSkge1xuICAgIHQgPSBjaGlsZFtzb3J0QnldO1xuXG4gICAgd2hpbGUgKHByZXYgJiYgcHJldltzb3J0QnldID4gdCkge1xuICAgICAgcHJldiA9IHByZXYuX3ByZXY7XG4gICAgfVxuICB9XG5cbiAgaWYgKHByZXYpIHtcbiAgICBjaGlsZC5fbmV4dCA9IHByZXYuX25leHQ7XG4gICAgcHJldi5fbmV4dCA9IGNoaWxkO1xuICB9IGVsc2Uge1xuICAgIGNoaWxkLl9uZXh0ID0gcGFyZW50W2ZpcnN0UHJvcF07XG4gICAgcGFyZW50W2ZpcnN0UHJvcF0gPSBjaGlsZDtcbiAgfVxuXG4gIGlmIChjaGlsZC5fbmV4dCkge1xuICAgIGNoaWxkLl9uZXh0Ll9wcmV2ID0gY2hpbGQ7XG4gIH0gZWxzZSB7XG4gICAgcGFyZW50W2xhc3RQcm9wXSA9IGNoaWxkO1xuICB9XG5cbiAgY2hpbGQuX3ByZXYgPSBwcmV2O1xuICBjaGlsZC5wYXJlbnQgPSBjaGlsZC5fZHAgPSBwYXJlbnQ7XG4gIHJldHVybiBjaGlsZDtcbn0sXG4gICAgX3JlbW92ZUxpbmtlZExpc3RJdGVtID0gZnVuY3Rpb24gX3JlbW92ZUxpbmtlZExpc3RJdGVtKHBhcmVudCwgY2hpbGQsIGZpcnN0UHJvcCwgbGFzdFByb3ApIHtcbiAgaWYgKGZpcnN0UHJvcCA9PT0gdm9pZCAwKSB7XG4gICAgZmlyc3RQcm9wID0gXCJfZmlyc3RcIjtcbiAgfVxuXG4gIGlmIChsYXN0UHJvcCA9PT0gdm9pZCAwKSB7XG4gICAgbGFzdFByb3AgPSBcIl9sYXN0XCI7XG4gIH1cblxuICB2YXIgcHJldiA9IGNoaWxkLl9wcmV2LFxuICAgICAgbmV4dCA9IGNoaWxkLl9uZXh0O1xuXG4gIGlmIChwcmV2KSB7XG4gICAgcHJldi5fbmV4dCA9IG5leHQ7XG4gIH0gZWxzZSBpZiAocGFyZW50W2ZpcnN0UHJvcF0gPT09IGNoaWxkKSB7XG4gICAgcGFyZW50W2ZpcnN0UHJvcF0gPSBuZXh0O1xuICB9XG5cbiAgaWYgKG5leHQpIHtcbiAgICBuZXh0Ll9wcmV2ID0gcHJldjtcbiAgfSBlbHNlIGlmIChwYXJlbnRbbGFzdFByb3BdID09PSBjaGlsZCkge1xuICAgIHBhcmVudFtsYXN0UHJvcF0gPSBwcmV2O1xuICB9XG5cbiAgY2hpbGQuX25leHQgPSBjaGlsZC5fcHJldiA9IGNoaWxkLnBhcmVudCA9IG51bGw7IC8vIGRvbid0IGRlbGV0ZSB0aGUgX2RwIGp1c3Qgc28gd2UgY2FuIHJldmVydCBpZiBuZWNlc3NhcnkuIEJ1dCBwYXJlbnQgc2hvdWxkIGJlIG51bGwgdG8gaW5kaWNhdGUgdGhlIGl0ZW0gaXNuJ3QgaW4gYSBsaW5rZWQgbGlzdC5cbn0sXG4gICAgX3JlbW92ZUZyb21QYXJlbnQgPSBmdW5jdGlvbiBfcmVtb3ZlRnJvbVBhcmVudChjaGlsZCwgb25seUlmUGFyZW50SGFzQXV0b1JlbW92ZSkge1xuICBjaGlsZC5wYXJlbnQgJiYgKCFvbmx5SWZQYXJlbnRIYXNBdXRvUmVtb3ZlIHx8IGNoaWxkLnBhcmVudC5hdXRvUmVtb3ZlQ2hpbGRyZW4pICYmIGNoaWxkLnBhcmVudC5yZW1vdmUgJiYgY2hpbGQucGFyZW50LnJlbW92ZShjaGlsZCk7XG4gIGNoaWxkLl9hY3QgPSAwO1xufSxcbiAgICBfdW5jYWNoZSA9IGZ1bmN0aW9uIF91bmNhY2hlKGFuaW1hdGlvbiwgY2hpbGQpIHtcbiAgaWYgKGFuaW1hdGlvbiAmJiAoIWNoaWxkIHx8IGNoaWxkLl9lbmQgPiBhbmltYXRpb24uX2R1ciB8fCBjaGlsZC5fc3RhcnQgPCAwKSkge1xuICAgIC8vIHBlcmZvcm1hbmNlIG9wdGltaXphdGlvbjogaWYgYSBjaGlsZCBhbmltYXRpb24gaXMgcGFzc2VkIGluIHdlIHNob3VsZCBvbmx5IHVuY2FjaGUgaWYgdGhhdCBjaGlsZCBFWFRFTkRTIHRoZSBhbmltYXRpb24gKGl0cyBlbmQgdGltZSBpcyBiZXlvbmQgdGhlIGVuZClcbiAgICB2YXIgYSA9IGFuaW1hdGlvbjtcblxuICAgIHdoaWxlIChhKSB7XG4gICAgICBhLl9kaXJ0eSA9IDE7XG4gICAgICBhID0gYS5wYXJlbnQ7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGFuaW1hdGlvbjtcbn0sXG4gICAgX3JlY2FjaGVBbmNlc3RvcnMgPSBmdW5jdGlvbiBfcmVjYWNoZUFuY2VzdG9ycyhhbmltYXRpb24pIHtcbiAgdmFyIHBhcmVudCA9IGFuaW1hdGlvbi5wYXJlbnQ7XG5cbiAgd2hpbGUgKHBhcmVudCAmJiBwYXJlbnQucGFyZW50KSB7XG4gICAgLy9zb21ldGltZXMgd2UgbXVzdCBmb3JjZSBhIHJlLXNvcnQgb2YgYWxsIGNoaWxkcmVuIGFuZCB1cGRhdGUgdGhlIGR1cmF0aW9uL3RvdGFsRHVyYXRpb24gb2YgYWxsIGFuY2VzdG9yIHRpbWVsaW5lcyBpbW1lZGlhdGVseSBpbiBjYXNlLCBmb3IgZXhhbXBsZSwgaW4gdGhlIG1pZGRsZSBvZiBhIHJlbmRlciBsb29wLCBvbmUgdHdlZW4gYWx0ZXJzIGFub3RoZXIgdHdlZW4ncyB0aW1lU2NhbGUgd2hpY2ggc2hvdmVzIGl0cyBzdGFydFRpbWUgYmVmb3JlIDAsIGZvcmNpbmcgdGhlIHBhcmVudCB0aW1lbGluZSB0byBzaGlmdCBhcm91bmQgYW5kIHNoaWZ0Q2hpbGRyZW4oKSB3aGljaCBjb3VsZCBhZmZlY3QgdGhhdCBuZXh0IHR3ZWVuJ3MgcmVuZGVyIChzdGFydFRpbWUpLiBEb2Vzbid0IG1hdHRlciBmb3IgdGhlIHJvb3QgdGltZWxpbmUgdGhvdWdoLlxuICAgIHBhcmVudC5fZGlydHkgPSAxO1xuICAgIHBhcmVudC50b3RhbER1cmF0aW9uKCk7XG4gICAgcGFyZW50ID0gcGFyZW50LnBhcmVudDtcbiAgfVxuXG4gIHJldHVybiBhbmltYXRpb247XG59LFxuICAgIF9yZXdpbmRTdGFydEF0ID0gZnVuY3Rpb24gX3Jld2luZFN0YXJ0QXQodHdlZW4sIHRvdGFsVGltZSwgc3VwcHJlc3NFdmVudHMsIGZvcmNlKSB7XG4gIHJldHVybiB0d2Vlbi5fc3RhcnRBdCAmJiAoX3JldmVydGluZyA/IHR3ZWVuLl9zdGFydEF0LnJldmVydChfcmV2ZXJ0Q29uZmlnTm9LaWxsKSA6IHR3ZWVuLnZhcnMuaW1tZWRpYXRlUmVuZGVyICYmICF0d2Vlbi52YXJzLmF1dG9SZXZlcnQgfHwgdHdlZW4uX3N0YXJ0QXQucmVuZGVyKHRvdGFsVGltZSwgdHJ1ZSwgZm9yY2UpKTtcbn0sXG4gICAgX2hhc05vUGF1c2VkQW5jZXN0b3JzID0gZnVuY3Rpb24gX2hhc05vUGF1c2VkQW5jZXN0b3JzKGFuaW1hdGlvbikge1xuICByZXR1cm4gIWFuaW1hdGlvbiB8fCBhbmltYXRpb24uX3RzICYmIF9oYXNOb1BhdXNlZEFuY2VzdG9ycyhhbmltYXRpb24ucGFyZW50KTtcbn0sXG4gICAgX2VsYXBzZWRDeWNsZUR1cmF0aW9uID0gZnVuY3Rpb24gX2VsYXBzZWRDeWNsZUR1cmF0aW9uKGFuaW1hdGlvbikge1xuICByZXR1cm4gYW5pbWF0aW9uLl9yZXBlYXQgPyBfYW5pbWF0aW9uQ3ljbGUoYW5pbWF0aW9uLl90VGltZSwgYW5pbWF0aW9uID0gYW5pbWF0aW9uLmR1cmF0aW9uKCkgKyBhbmltYXRpb24uX3JEZWxheSkgKiBhbmltYXRpb24gOiAwO1xufSxcbiAgICAvLyBmZWVkIGluIHRoZSB0b3RhbFRpbWUgYW5kIGN5Y2xlRHVyYXRpb24gYW5kIGl0J2xsIHJldHVybiB0aGUgY3ljbGUgKGl0ZXJhdGlvbiBtaW51cyAxKSBhbmQgaWYgdGhlIHBsYXloZWFkIGlzIGV4YWN0bHkgYXQgdGhlIHZlcnkgRU5ELCBpdCB3aWxsIE5PVCBidW1wIHVwIHRvIHRoZSBuZXh0IGN5Y2xlLlxuX2FuaW1hdGlvbkN5Y2xlID0gZnVuY3Rpb24gX2FuaW1hdGlvbkN5Y2xlKHRUaW1lLCBjeWNsZUR1cmF0aW9uKSB7XG4gIHZhciB3aG9sZSA9IE1hdGguZmxvb3IodFRpbWUgLz0gY3ljbGVEdXJhdGlvbik7XG4gIHJldHVybiB0VGltZSAmJiB3aG9sZSA9PT0gdFRpbWUgPyB3aG9sZSAtIDEgOiB3aG9sZTtcbn0sXG4gICAgX3BhcmVudFRvQ2hpbGRUb3RhbFRpbWUgPSBmdW5jdGlvbiBfcGFyZW50VG9DaGlsZFRvdGFsVGltZShwYXJlbnRUaW1lLCBjaGlsZCkge1xuICByZXR1cm4gKHBhcmVudFRpbWUgLSBjaGlsZC5fc3RhcnQpICogY2hpbGQuX3RzICsgKGNoaWxkLl90cyA+PSAwID8gMCA6IGNoaWxkLl9kaXJ0eSA/IGNoaWxkLnRvdGFsRHVyYXRpb24oKSA6IGNoaWxkLl90RHVyKTtcbn0sXG4gICAgX3NldEVuZCA9IGZ1bmN0aW9uIF9zZXRFbmQoYW5pbWF0aW9uKSB7XG4gIHJldHVybiBhbmltYXRpb24uX2VuZCA9IF9yb3VuZFByZWNpc2UoYW5pbWF0aW9uLl9zdGFydCArIChhbmltYXRpb24uX3REdXIgLyBNYXRoLmFicyhhbmltYXRpb24uX3RzIHx8IGFuaW1hdGlvbi5fcnRzIHx8IF90aW55TnVtKSB8fCAwKSk7XG59LFxuICAgIF9hbGlnblBsYXloZWFkID0gZnVuY3Rpb24gX2FsaWduUGxheWhlYWQoYW5pbWF0aW9uLCB0b3RhbFRpbWUpIHtcbiAgLy8gYWRqdXN0cyB0aGUgYW5pbWF0aW9uJ3MgX3N0YXJ0IGFuZCBfZW5kIGFjY29yZGluZyB0byB0aGUgcHJvdmlkZWQgdG90YWxUaW1lIChvbmx5IGlmIHRoZSBwYXJlbnQncyBzbW9vdGhDaGlsZFRpbWluZyBpcyB0cnVlIGFuZCB0aGUgYW5pbWF0aW9uIGlzbid0IHBhdXNlZCkuIEl0IGRvZXNuJ3QgZG8gYW55IHJlbmRlcmluZyBvciBmb3JjaW5nIHRoaW5ncyBiYWNrIGludG8gcGFyZW50IHRpbWVsaW5lcywgZXRjLiAtIHRoYXQncyB3aGF0IHRvdGFsVGltZSgpIGlzIGZvci5cbiAgdmFyIHBhcmVudCA9IGFuaW1hdGlvbi5fZHA7XG5cbiAgaWYgKHBhcmVudCAmJiBwYXJlbnQuc21vb3RoQ2hpbGRUaW1pbmcgJiYgYW5pbWF0aW9uLl90cykge1xuICAgIGFuaW1hdGlvbi5fc3RhcnQgPSBfcm91bmRQcmVjaXNlKHBhcmVudC5fdGltZSAtIChhbmltYXRpb24uX3RzID4gMCA/IHRvdGFsVGltZSAvIGFuaW1hdGlvbi5fdHMgOiAoKGFuaW1hdGlvbi5fZGlydHkgPyBhbmltYXRpb24udG90YWxEdXJhdGlvbigpIDogYW5pbWF0aW9uLl90RHVyKSAtIHRvdGFsVGltZSkgLyAtYW5pbWF0aW9uLl90cykpO1xuXG4gICAgX3NldEVuZChhbmltYXRpb24pO1xuXG4gICAgcGFyZW50Ll9kaXJ0eSB8fCBfdW5jYWNoZShwYXJlbnQsIGFuaW1hdGlvbik7IC8vZm9yIHBlcmZvcm1hbmNlIGltcHJvdmVtZW50LiBJZiB0aGUgcGFyZW50J3MgY2FjaGUgaXMgYWxyZWFkeSBkaXJ0eSwgaXQgYWxyZWFkeSB0b29rIGNhcmUgb2YgbWFya2luZyB0aGUgYW5jZXN0b3JzIGFzIGRpcnR5IHRvbywgc28gc2tpcCB0aGUgZnVuY3Rpb24gY2FsbCBoZXJlLlxuICB9XG5cbiAgcmV0dXJuIGFuaW1hdGlvbjtcbn0sXG5cbi8qXG5fdG90YWxUaW1lVG9UaW1lID0gKGNsYW1wZWRUb3RhbFRpbWUsIGR1cmF0aW9uLCByZXBlYXQsIHJlcGVhdERlbGF5LCB5b3lvKSA9PiB7XG5cdGxldCBjeWNsZUR1cmF0aW9uID0gZHVyYXRpb24gKyByZXBlYXREZWxheSxcblx0XHR0aW1lID0gX3JvdW5kKGNsYW1wZWRUb3RhbFRpbWUgJSBjeWNsZUR1cmF0aW9uKTtcblx0aWYgKHRpbWUgPiBkdXJhdGlvbikge1xuXHRcdHRpbWUgPSBkdXJhdGlvbjtcblx0fVxuXHRyZXR1cm4gKHlveW8gJiYgKH5+KGNsYW1wZWRUb3RhbFRpbWUgLyBjeWNsZUR1cmF0aW9uKSAmIDEpKSA/IGR1cmF0aW9uIC0gdGltZSA6IHRpbWU7XG59LFxuKi9cbl9wb3N0QWRkQ2hlY2tzID0gZnVuY3Rpb24gX3Bvc3RBZGRDaGVja3ModGltZWxpbmUsIGNoaWxkKSB7XG4gIHZhciB0O1xuXG4gIGlmIChjaGlsZC5fdGltZSB8fCAhY2hpbGQuX2R1ciAmJiBjaGlsZC5faW5pdHRlZCB8fCBjaGlsZC5fc3RhcnQgPCB0aW1lbGluZS5fdGltZSAmJiAoY2hpbGQuX2R1ciB8fCAhY2hpbGQuYWRkKSkge1xuICAgIC8vIGluIGNhc2UsIGZvciBleGFtcGxlLCB0aGUgX3N0YXJ0IGlzIG1vdmVkIG9uIGEgdHdlZW4gdGhhdCBoYXMgYWxyZWFkeSByZW5kZXJlZCwgb3IgaWYgaXQncyBiZWluZyBpbnNlcnRlZCBpbnRvIGEgdGltZWxpbmUgQkVGT1JFIHdoZXJlIHRoZSBwbGF5aGVhZCBpcyBjdXJyZW50bHkuIEltYWdpbmUgaXQncyBhdCBpdHMgZW5kIHN0YXRlLCB0aGVuIHRoZSBzdGFydFRpbWUgaXMgbW92ZWQgV0FZIGxhdGVyIChhZnRlciB0aGUgZW5kIG9mIHRoaXMgdGltZWxpbmUpLCBpdCBzaG91bGQgcmVuZGVyIGF0IGl0cyBiZWdpbm5pbmcuIFNwZWNpYWwgY2FzZTogaWYgaXQncyBhIHRpbWVsaW5lIChoYXMgLmFkZCgpIG1ldGhvZCkgYW5kIG5vIGR1cmF0aW9uLCB3ZSBjYW4gc2tpcCByZW5kZXJpbmcgYmVjYXVzZSB0aGUgdXNlciBtYXkgYmUgcG9wdWxhdGluZyBpdCBBRlRFUiBhZGRpbmcgaXQgdG8gYSBwYXJlbnQgdGltZWxpbmUgKHVuY29udmVudGlvbmFsLCBidXQgcG9zc2libGUsIGFuZCB3ZSB3b3VsZG4ndCB3YW50IGl0IHRvIGdldCByZW1vdmVkIGlmIHRoZSBwYXJlbnQncyBhdXRvUmVtb3ZlQ2hpbGRyZW4gaXMgdHJ1ZSkuXG4gICAgdCA9IF9wYXJlbnRUb0NoaWxkVG90YWxUaW1lKHRpbWVsaW5lLnJhd1RpbWUoKSwgY2hpbGQpO1xuXG4gICAgaWYgKCFjaGlsZC5fZHVyIHx8IF9jbGFtcCgwLCBjaGlsZC50b3RhbER1cmF0aW9uKCksIHQpIC0gY2hpbGQuX3RUaW1lID4gX3RpbnlOdW0pIHtcbiAgICAgIGNoaWxkLnJlbmRlcih0LCB0cnVlKTtcbiAgICB9XG4gIH0gLy9pZiB0aGUgdGltZWxpbmUgaGFzIGFscmVhZHkgZW5kZWQgYnV0IHRoZSBpbnNlcnRlZCB0d2Vlbi90aW1lbGluZSBleHRlbmRzIHRoZSBkdXJhdGlvbiwgd2Ugc2hvdWxkIGVuYWJsZSB0aGlzIHRpbWVsaW5lIGFnYWluIHNvIHRoYXQgaXQgcmVuZGVycyBwcm9wZXJseS4gV2Ugc2hvdWxkIGFsc28gYWxpZ24gdGhlIHBsYXloZWFkIHdpdGggdGhlIHBhcmVudCB0aW1lbGluZSdzIHdoZW4gYXBwcm9wcmlhdGUuXG5cblxuICBpZiAoX3VuY2FjaGUodGltZWxpbmUsIGNoaWxkKS5fZHAgJiYgdGltZWxpbmUuX2luaXR0ZWQgJiYgdGltZWxpbmUuX3RpbWUgPj0gdGltZWxpbmUuX2R1ciAmJiB0aW1lbGluZS5fdHMpIHtcbiAgICAvL2luIGNhc2UgYW55IG9mIHRoZSBhbmNlc3RvcnMgaGFkIGNvbXBsZXRlZCBidXQgc2hvdWxkIG5vdyBiZSBlbmFibGVkLi4uXG4gICAgaWYgKHRpbWVsaW5lLl9kdXIgPCB0aW1lbGluZS5kdXJhdGlvbigpKSB7XG4gICAgICB0ID0gdGltZWxpbmU7XG5cbiAgICAgIHdoaWxlICh0Ll9kcCkge1xuICAgICAgICB0LnJhd1RpbWUoKSA+PSAwICYmIHQudG90YWxUaW1lKHQuX3RUaW1lKTsgLy9tb3ZlcyB0aGUgdGltZWxpbmUgKHNoaWZ0cyBpdHMgc3RhcnRUaW1lKSBpZiBuZWNlc3NhcnksIGFuZCBhbHNvIGVuYWJsZXMgaXQuIElmIGl0J3MgY3VycmVudGx5IHplcm8sIHRob3VnaCwgaXQgbWF5IG5vdCBiZSBzY2hlZHVsZWQgdG8gcmVuZGVyIHVudGlsIGxhdGVyIHNvIHRoZXJlJ3Mgbm8gbmVlZCB0byBmb3JjZSBpdCB0byBhbGlnbiB3aXRoIHRoZSBjdXJyZW50IHBsYXloZWFkIHBvc2l0aW9uLiBPbmx5IG1vdmUgdG8gY2F0Y2ggdXAgd2l0aCB0aGUgcGxheWhlYWQuXG5cbiAgICAgICAgdCA9IHQuX2RwO1xuICAgICAgfVxuICAgIH1cblxuICAgIHRpbWVsaW5lLl96VGltZSA9IC1fdGlueU51bTsgLy8gaGVscHMgZW5zdXJlIHRoYXQgdGhlIG5leHQgcmVuZGVyKCkgd2lsbCBiZSBmb3JjZWQgKGNyb3NzaW5nU3RhcnQgPSB0cnVlIGluIHJlbmRlcigpKSwgZXZlbiBpZiB0aGUgZHVyYXRpb24gaGFzbid0IGNoYW5nZWQgKHdlJ3JlIGFkZGluZyBhIGNoaWxkIHdoaWNoIHdvdWxkIG5lZWQgdG8gZ2V0IHJlbmRlcmVkKS4gRGVmaW5pdGVseSBhbiBlZGdlIGNhc2UuIE5vdGU6IHdlIE1VU1QgZG8gdGhpcyBBRlRFUiB0aGUgbG9vcCBhYm92ZSB3aGVyZSB0aGUgdG90YWxUaW1lKCkgbWlnaHQgdHJpZ2dlciBhIHJlbmRlcigpIGJlY2F1c2UgdGhpcyBfYWRkVG9UaW1lbGluZSgpIG1ldGhvZCBnZXRzIGNhbGxlZCBmcm9tIHRoZSBBbmltYXRpb24gY29uc3RydWN0b3IsIEJFRk9SRSB0d2VlbnMgZXZlbiByZWNvcmQgdGhlaXIgdGFyZ2V0cywgZXRjLiBzbyB3ZSB3b3VsZG4ndCB3YW50IHRoaW5ncyB0byBnZXQgdHJpZ2dlcmVkIGluIHRoZSB3cm9uZyBvcmRlci5cbiAgfVxufSxcbiAgICBfYWRkVG9UaW1lbGluZSA9IGZ1bmN0aW9uIF9hZGRUb1RpbWVsaW5lKHRpbWVsaW5lLCBjaGlsZCwgcG9zaXRpb24sIHNraXBDaGVja3MpIHtcbiAgY2hpbGQucGFyZW50ICYmIF9yZW1vdmVGcm9tUGFyZW50KGNoaWxkKTtcbiAgY2hpbGQuX3N0YXJ0ID0gX3JvdW5kUHJlY2lzZSgoX2lzTnVtYmVyKHBvc2l0aW9uKSA/IHBvc2l0aW9uIDogcG9zaXRpb24gfHwgdGltZWxpbmUgIT09IF9nbG9iYWxUaW1lbGluZSA/IF9wYXJzZVBvc2l0aW9uKHRpbWVsaW5lLCBwb3NpdGlvbiwgY2hpbGQpIDogdGltZWxpbmUuX3RpbWUpICsgY2hpbGQuX2RlbGF5KTtcbiAgY2hpbGQuX2VuZCA9IF9yb3VuZFByZWNpc2UoY2hpbGQuX3N0YXJ0ICsgKGNoaWxkLnRvdGFsRHVyYXRpb24oKSAvIE1hdGguYWJzKGNoaWxkLnRpbWVTY2FsZSgpKSB8fCAwKSk7XG5cbiAgX2FkZExpbmtlZExpc3RJdGVtKHRpbWVsaW5lLCBjaGlsZCwgXCJfZmlyc3RcIiwgXCJfbGFzdFwiLCB0aW1lbGluZS5fc29ydCA/IFwiX3N0YXJ0XCIgOiAwKTtcblxuICBfaXNGcm9tT3JGcm9tU3RhcnQoY2hpbGQpIHx8ICh0aW1lbGluZS5fcmVjZW50ID0gY2hpbGQpO1xuICBza2lwQ2hlY2tzIHx8IF9wb3N0QWRkQ2hlY2tzKHRpbWVsaW5lLCBjaGlsZCk7XG4gIHRpbWVsaW5lLl90cyA8IDAgJiYgX2FsaWduUGxheWhlYWQodGltZWxpbmUsIHRpbWVsaW5lLl90VGltZSk7IC8vIGlmIHRoZSB0aW1lbGluZSBpcyByZXZlcnNlZCBhbmQgdGhlIG5ldyBjaGlsZCBtYWtlcyBpdCBsb25nZXIsIHdlIG1heSBuZWVkIHRvIGFkanVzdCB0aGUgcGFyZW50J3MgX3N0YXJ0IChwdXNoIGl0IGJhY2spXG5cbiAgcmV0dXJuIHRpbWVsaW5lO1xufSxcbiAgICBfc2Nyb2xsVHJpZ2dlciA9IGZ1bmN0aW9uIF9zY3JvbGxUcmlnZ2VyKGFuaW1hdGlvbiwgdHJpZ2dlcikge1xuICByZXR1cm4gKF9nbG9iYWxzLlNjcm9sbFRyaWdnZXIgfHwgX21pc3NpbmdQbHVnaW4oXCJzY3JvbGxUcmlnZ2VyXCIsIHRyaWdnZXIpKSAmJiBfZ2xvYmFscy5TY3JvbGxUcmlnZ2VyLmNyZWF0ZSh0cmlnZ2VyLCBhbmltYXRpb24pO1xufSxcbiAgICBfYXR0ZW1wdEluaXRUd2VlbiA9IGZ1bmN0aW9uIF9hdHRlbXB0SW5pdFR3ZWVuKHR3ZWVuLCB0aW1lLCBmb3JjZSwgc3VwcHJlc3NFdmVudHMsIHRUaW1lKSB7XG4gIF9pbml0VHdlZW4odHdlZW4sIHRpbWUsIHRUaW1lKTtcblxuICBpZiAoIXR3ZWVuLl9pbml0dGVkKSB7XG4gICAgcmV0dXJuIDE7XG4gIH1cblxuICBpZiAoIWZvcmNlICYmIHR3ZWVuLl9wdCAmJiAhX3JldmVydGluZyAmJiAodHdlZW4uX2R1ciAmJiB0d2Vlbi52YXJzLmxhenkgIT09IGZhbHNlIHx8ICF0d2Vlbi5fZHVyICYmIHR3ZWVuLnZhcnMubGF6eSkgJiYgX2xhc3RSZW5kZXJlZEZyYW1lICE9PSBfdGlja2VyLmZyYW1lKSB7XG4gICAgX2xhenlUd2VlbnMucHVzaCh0d2Vlbik7XG5cbiAgICB0d2Vlbi5fbGF6eSA9IFt0VGltZSwgc3VwcHJlc3NFdmVudHNdO1xuICAgIHJldHVybiAxO1xuICB9XG59LFxuICAgIF9wYXJlbnRQbGF5aGVhZElzQmVmb3JlU3RhcnQgPSBmdW5jdGlvbiBfcGFyZW50UGxheWhlYWRJc0JlZm9yZVN0YXJ0KF9yZWYpIHtcbiAgdmFyIHBhcmVudCA9IF9yZWYucGFyZW50O1xuICByZXR1cm4gcGFyZW50ICYmIHBhcmVudC5fdHMgJiYgcGFyZW50Ll9pbml0dGVkICYmICFwYXJlbnQuX2xvY2sgJiYgKHBhcmVudC5yYXdUaW1lKCkgPCAwIHx8IF9wYXJlbnRQbGF5aGVhZElzQmVmb3JlU3RhcnQocGFyZW50KSk7XG59LFxuICAgIC8vIGNoZWNrIHBhcmVudCdzIF9sb2NrIGJlY2F1c2Ugd2hlbiBhIHRpbWVsaW5lIHJlcGVhdHMveW95b3MgYW5kIGRvZXMgaXRzIGFydGlmaWNpYWwgd3JhcHBpbmcsIHdlIHNob3VsZG4ndCBmb3JjZSB0aGUgcmF0aW8gYmFjayB0byAwXG5faXNGcm9tT3JGcm9tU3RhcnQgPSBmdW5jdGlvbiBfaXNGcm9tT3JGcm9tU3RhcnQoX3JlZjIpIHtcbiAgdmFyIGRhdGEgPSBfcmVmMi5kYXRhO1xuICByZXR1cm4gZGF0YSA9PT0gXCJpc0Zyb21TdGFydFwiIHx8IGRhdGEgPT09IFwiaXNTdGFydFwiO1xufSxcbiAgICBfcmVuZGVyWmVyb0R1cmF0aW9uVHdlZW4gPSBmdW5jdGlvbiBfcmVuZGVyWmVyb0R1cmF0aW9uVHdlZW4odHdlZW4sIHRvdGFsVGltZSwgc3VwcHJlc3NFdmVudHMsIGZvcmNlKSB7XG4gIHZhciBwcmV2UmF0aW8gPSB0d2Vlbi5yYXRpbyxcbiAgICAgIHJhdGlvID0gdG90YWxUaW1lIDwgMCB8fCAhdG90YWxUaW1lICYmICghdHdlZW4uX3N0YXJ0ICYmIF9wYXJlbnRQbGF5aGVhZElzQmVmb3JlU3RhcnQodHdlZW4pICYmICEoIXR3ZWVuLl9pbml0dGVkICYmIF9pc0Zyb21PckZyb21TdGFydCh0d2VlbikpIHx8ICh0d2Vlbi5fdHMgPCAwIHx8IHR3ZWVuLl9kcC5fdHMgPCAwKSAmJiAhX2lzRnJvbU9yRnJvbVN0YXJ0KHR3ZWVuKSkgPyAwIDogMSxcbiAgICAgIC8vIGlmIHRoZSB0d2VlbiBvciBpdHMgcGFyZW50IGlzIHJldmVyc2VkIGFuZCB0aGUgdG90YWxUaW1lIGlzIDAsIHdlIHNob3VsZCBnbyB0byBhIHJhdGlvIG9mIDAuIEVkZ2UgY2FzZTogaWYgYSBmcm9tKCkgb3IgZnJvbVRvKCkgc3RhZ2dlciB0d2VlbiBpcyBwbGFjZWQgbGF0ZXIgaW4gYSB0aW1lbGluZSwgdGhlIFwic3RhcnRBdFwiIHplcm8tZHVyYXRpb24gdHdlZW4gY291bGQgaW5pdGlhbGx5IHJlbmRlciBhdCBhIHRpbWUgd2hlbiB0aGUgcGFyZW50IHRpbWVsaW5lJ3MgcGxheWhlYWQgaXMgdGVjaG5pY2FsbHkgQkVGT1JFIHdoZXJlIHRoaXMgdHdlZW4gaXMsIHNvIG1ha2Ugc3VyZSB0aGF0IGFueSBcImZyb21cIiBhbmQgXCJmcm9tVG9cIiBzdGFydEF0IHR3ZWVucyBhcmUgcmVuZGVyZWQgdGhlIGZpcnN0IHRpbWUgYXQgYSByYXRpbyBvZiAxLlxuICByZXBlYXREZWxheSA9IHR3ZWVuLl9yRGVsYXksXG4gICAgICB0VGltZSA9IDAsXG4gICAgICBwdCxcbiAgICAgIGl0ZXJhdGlvbixcbiAgICAgIHByZXZJdGVyYXRpb247XG5cbiAgaWYgKHJlcGVhdERlbGF5ICYmIHR3ZWVuLl9yZXBlYXQpIHtcbiAgICAvLyBpbiBjYXNlIHRoZXJlJ3MgYSB6ZXJvLWR1cmF0aW9uIHR3ZWVuIHRoYXQgaGFzIGEgcmVwZWF0IHdpdGggYSByZXBlYXREZWxheVxuICAgIHRUaW1lID0gX2NsYW1wKDAsIHR3ZWVuLl90RHVyLCB0b3RhbFRpbWUpO1xuICAgIGl0ZXJhdGlvbiA9IF9hbmltYXRpb25DeWNsZSh0VGltZSwgcmVwZWF0RGVsYXkpO1xuICAgIHR3ZWVuLl95b3lvICYmIGl0ZXJhdGlvbiAmIDEgJiYgKHJhdGlvID0gMSAtIHJhdGlvKTtcblxuICAgIGlmIChpdGVyYXRpb24gIT09IF9hbmltYXRpb25DeWNsZSh0d2Vlbi5fdFRpbWUsIHJlcGVhdERlbGF5KSkge1xuICAgICAgLy8gaWYgaXRlcmF0aW9uIGNoYW5nZWRcbiAgICAgIHByZXZSYXRpbyA9IDEgLSByYXRpbztcbiAgICAgIHR3ZWVuLnZhcnMucmVwZWF0UmVmcmVzaCAmJiB0d2Vlbi5faW5pdHRlZCAmJiB0d2Vlbi5pbnZhbGlkYXRlKCk7XG4gICAgfVxuICB9XG5cbiAgaWYgKHJhdGlvICE9PSBwcmV2UmF0aW8gfHwgX3JldmVydGluZyB8fCBmb3JjZSB8fCB0d2Vlbi5felRpbWUgPT09IF90aW55TnVtIHx8ICF0b3RhbFRpbWUgJiYgdHdlZW4uX3pUaW1lKSB7XG4gICAgaWYgKCF0d2Vlbi5faW5pdHRlZCAmJiBfYXR0ZW1wdEluaXRUd2Vlbih0d2VlbiwgdG90YWxUaW1lLCBmb3JjZSwgc3VwcHJlc3NFdmVudHMsIHRUaW1lKSkge1xuICAgICAgLy8gaWYgd2UgcmVuZGVyIHRoZSB2ZXJ5IGJlZ2lubmluZyAodGltZSA9PSAwKSBvZiBhIGZyb21UbygpLCB3ZSBtdXN0IGZvcmNlIHRoZSByZW5kZXIgKG5vcm1hbCB0d2VlbnMgd291bGRuJ3QgbmVlZCB0byByZW5kZXIgYXQgYSB0aW1lIG9mIDAgd2hlbiB0aGUgcHJldlRpbWUgd2FzIGFsc28gMCkuIFRoaXMgaXMgYWxzbyBtYW5kYXRvcnkgdG8gbWFrZSBzdXJlIG92ZXJ3cml0aW5nIGtpY2tzIGluIGltbWVkaWF0ZWx5LlxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHByZXZJdGVyYXRpb24gPSB0d2Vlbi5felRpbWU7XG4gICAgdHdlZW4uX3pUaW1lID0gdG90YWxUaW1lIHx8IChzdXBwcmVzc0V2ZW50cyA/IF90aW55TnVtIDogMCk7IC8vIHdoZW4gdGhlIHBsYXloZWFkIGFycml2ZXMgYXQgRVhBQ1RMWSB0aW1lIDAgKHJpZ2h0IG9uIHRvcCkgb2YgYSB6ZXJvLWR1cmF0aW9uIHR3ZWVuLCB3ZSBuZWVkIHRvIGRpc2Nlcm4gaWYgZXZlbnRzIGFyZSBzdXBwcmVzc2VkIHNvIHRoYXQgd2hlbiB0aGUgcGxheWhlYWQgbW92ZXMgYWdhaW4gKG5leHQgdGltZSksIGl0J2xsIHRyaWdnZXIgdGhlIGNhbGxiYWNrLiBJZiBldmVudHMgYXJlIE5PVCBzdXBwcmVzc2VkLCBvYnZpb3VzbHkgdGhlIGNhbGxiYWNrIHdvdWxkIGJlIHRyaWdnZXJlZCBpbiB0aGlzIHJlbmRlci4gQmFzaWNhbGx5LCB0aGUgY2FsbGJhY2sgc2hvdWxkIGZpcmUgZWl0aGVyIHdoZW4gdGhlIHBsYXloZWFkIEFSUklWRVMgb3IgTEVBVkVTIHRoaXMgZXhhY3Qgc3BvdCwgbm90IGJvdGguIEltYWdpbmUgZG9pbmcgYSB0aW1lbGluZS5zZWVrKDApIGFuZCB0aGVyZSdzIGEgY2FsbGJhY2sgdGhhdCBzaXRzIGF0IDAuIFNpbmNlIGV2ZW50cyBhcmUgc3VwcHJlc3NlZCBvbiB0aGF0IHNlZWsoKSBieSBkZWZhdWx0LCBub3RoaW5nIHdpbGwgZmlyZSwgYnV0IHdoZW4gdGhlIHBsYXloZWFkIG1vdmVzIG9mZiBvZiB0aGF0IHBvc2l0aW9uLCB0aGUgY2FsbGJhY2sgc2hvdWxkIGZpcmUuIFRoaXMgYmVoYXZpb3IgaXMgd2hhdCBwZW9wbGUgaW50dWl0aXZlbHkgZXhwZWN0LlxuXG4gICAgc3VwcHJlc3NFdmVudHMgfHwgKHN1cHByZXNzRXZlbnRzID0gdG90YWxUaW1lICYmICFwcmV2SXRlcmF0aW9uKTsgLy8gaWYgaXQgd2FzIHJlbmRlcmVkIHByZXZpb3VzbHkgYXQgZXhhY3RseSAwIChfelRpbWUpIGFuZCBub3cgdGhlIHBsYXloZWFkIGlzIG1vdmluZyBhd2F5LCBET04nVCBmaXJlIGNhbGxiYWNrcyBvdGhlcndpc2UgdGhleSdsbCBzZWVtIGxpa2UgZHVwbGljYXRlcy5cblxuICAgIHR3ZWVuLnJhdGlvID0gcmF0aW87XG4gICAgdHdlZW4uX2Zyb20gJiYgKHJhdGlvID0gMSAtIHJhdGlvKTtcbiAgICB0d2Vlbi5fdGltZSA9IDA7XG4gICAgdHdlZW4uX3RUaW1lID0gdFRpbWU7XG4gICAgcHQgPSB0d2Vlbi5fcHQ7XG5cbiAgICB3aGlsZSAocHQpIHtcbiAgICAgIHB0LnIocmF0aW8sIHB0LmQpO1xuICAgICAgcHQgPSBwdC5fbmV4dDtcbiAgICB9XG5cbiAgICB0b3RhbFRpbWUgPCAwICYmIF9yZXdpbmRTdGFydEF0KHR3ZWVuLCB0b3RhbFRpbWUsIHN1cHByZXNzRXZlbnRzLCB0cnVlKTtcbiAgICB0d2Vlbi5fb25VcGRhdGUgJiYgIXN1cHByZXNzRXZlbnRzICYmIF9jYWxsYmFjayh0d2VlbiwgXCJvblVwZGF0ZVwiKTtcbiAgICB0VGltZSAmJiB0d2Vlbi5fcmVwZWF0ICYmICFzdXBwcmVzc0V2ZW50cyAmJiB0d2Vlbi5wYXJlbnQgJiYgX2NhbGxiYWNrKHR3ZWVuLCBcIm9uUmVwZWF0XCIpO1xuXG4gICAgaWYgKCh0b3RhbFRpbWUgPj0gdHdlZW4uX3REdXIgfHwgdG90YWxUaW1lIDwgMCkgJiYgdHdlZW4ucmF0aW8gPT09IHJhdGlvKSB7XG4gICAgICByYXRpbyAmJiBfcmVtb3ZlRnJvbVBhcmVudCh0d2VlbiwgMSk7XG5cbiAgICAgIGlmICghc3VwcHJlc3NFdmVudHMgJiYgIV9yZXZlcnRpbmcpIHtcbiAgICAgICAgX2NhbGxiYWNrKHR3ZWVuLCByYXRpbyA/IFwib25Db21wbGV0ZVwiIDogXCJvblJldmVyc2VDb21wbGV0ZVwiLCB0cnVlKTtcblxuICAgICAgICB0d2Vlbi5fcHJvbSAmJiB0d2Vlbi5fcHJvbSgpO1xuICAgICAgfVxuICAgIH1cbiAgfSBlbHNlIGlmICghdHdlZW4uX3pUaW1lKSB7XG4gICAgdHdlZW4uX3pUaW1lID0gdG90YWxUaW1lO1xuICB9XG59LFxuICAgIF9maW5kTmV4dFBhdXNlVHdlZW4gPSBmdW5jdGlvbiBfZmluZE5leHRQYXVzZVR3ZWVuKGFuaW1hdGlvbiwgcHJldlRpbWUsIHRpbWUpIHtcbiAgdmFyIGNoaWxkO1xuXG4gIGlmICh0aW1lID4gcHJldlRpbWUpIHtcbiAgICBjaGlsZCA9IGFuaW1hdGlvbi5fZmlyc3Q7XG5cbiAgICB3aGlsZSAoY2hpbGQgJiYgY2hpbGQuX3N0YXJ0IDw9IHRpbWUpIHtcbiAgICAgIGlmIChjaGlsZC5kYXRhID09PSBcImlzUGF1c2VcIiAmJiBjaGlsZC5fc3RhcnQgPiBwcmV2VGltZSkge1xuICAgICAgICByZXR1cm4gY2hpbGQ7XG4gICAgICB9XG5cbiAgICAgIGNoaWxkID0gY2hpbGQuX25leHQ7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGNoaWxkID0gYW5pbWF0aW9uLl9sYXN0O1xuXG4gICAgd2hpbGUgKGNoaWxkICYmIGNoaWxkLl9zdGFydCA+PSB0aW1lKSB7XG4gICAgICBpZiAoY2hpbGQuZGF0YSA9PT0gXCJpc1BhdXNlXCIgJiYgY2hpbGQuX3N0YXJ0IDwgcHJldlRpbWUpIHtcbiAgICAgICAgcmV0dXJuIGNoaWxkO1xuICAgICAgfVxuXG4gICAgICBjaGlsZCA9IGNoaWxkLl9wcmV2O1xuICAgIH1cbiAgfVxufSxcbiAgICBfc2V0RHVyYXRpb24gPSBmdW5jdGlvbiBfc2V0RHVyYXRpb24oYW5pbWF0aW9uLCBkdXJhdGlvbiwgc2tpcFVuY2FjaGUsIGxlYXZlUGxheWhlYWQpIHtcbiAgdmFyIHJlcGVhdCA9IGFuaW1hdGlvbi5fcmVwZWF0LFxuICAgICAgZHVyID0gX3JvdW5kUHJlY2lzZShkdXJhdGlvbikgfHwgMCxcbiAgICAgIHRvdGFsUHJvZ3Jlc3MgPSBhbmltYXRpb24uX3RUaW1lIC8gYW5pbWF0aW9uLl90RHVyO1xuICB0b3RhbFByb2dyZXNzICYmICFsZWF2ZVBsYXloZWFkICYmIChhbmltYXRpb24uX3RpbWUgKj0gZHVyIC8gYW5pbWF0aW9uLl9kdXIpO1xuICBhbmltYXRpb24uX2R1ciA9IGR1cjtcbiAgYW5pbWF0aW9uLl90RHVyID0gIXJlcGVhdCA/IGR1ciA6IHJlcGVhdCA8IDAgPyAxZTEwIDogX3JvdW5kUHJlY2lzZShkdXIgKiAocmVwZWF0ICsgMSkgKyBhbmltYXRpb24uX3JEZWxheSAqIHJlcGVhdCk7XG4gIHRvdGFsUHJvZ3Jlc3MgPiAwICYmICFsZWF2ZVBsYXloZWFkICYmIF9hbGlnblBsYXloZWFkKGFuaW1hdGlvbiwgYW5pbWF0aW9uLl90VGltZSA9IGFuaW1hdGlvbi5fdER1ciAqIHRvdGFsUHJvZ3Jlc3MpO1xuICBhbmltYXRpb24ucGFyZW50ICYmIF9zZXRFbmQoYW5pbWF0aW9uKTtcbiAgc2tpcFVuY2FjaGUgfHwgX3VuY2FjaGUoYW5pbWF0aW9uLnBhcmVudCwgYW5pbWF0aW9uKTtcbiAgcmV0dXJuIGFuaW1hdGlvbjtcbn0sXG4gICAgX29uVXBkYXRlVG90YWxEdXJhdGlvbiA9IGZ1bmN0aW9uIF9vblVwZGF0ZVRvdGFsRHVyYXRpb24oYW5pbWF0aW9uKSB7XG4gIHJldHVybiBhbmltYXRpb24gaW5zdGFuY2VvZiBUaW1lbGluZSA/IF91bmNhY2hlKGFuaW1hdGlvbikgOiBfc2V0RHVyYXRpb24oYW5pbWF0aW9uLCBhbmltYXRpb24uX2R1cik7XG59LFxuICAgIF96ZXJvUG9zaXRpb24gPSB7XG4gIF9zdGFydDogMCxcbiAgZW5kVGltZTogX2VtcHR5RnVuYyxcbiAgdG90YWxEdXJhdGlvbjogX2VtcHR5RnVuY1xufSxcbiAgICBfcGFyc2VQb3NpdGlvbiA9IGZ1bmN0aW9uIF9wYXJzZVBvc2l0aW9uKGFuaW1hdGlvbiwgcG9zaXRpb24sIHBlcmNlbnRBbmltYXRpb24pIHtcbiAgdmFyIGxhYmVscyA9IGFuaW1hdGlvbi5sYWJlbHMsXG4gICAgICByZWNlbnQgPSBhbmltYXRpb24uX3JlY2VudCB8fCBfemVyb1Bvc2l0aW9uLFxuICAgICAgY2xpcHBlZER1cmF0aW9uID0gYW5pbWF0aW9uLmR1cmF0aW9uKCkgPj0gX2JpZ051bSA/IHJlY2VudC5lbmRUaW1lKGZhbHNlKSA6IGFuaW1hdGlvbi5fZHVyLFxuICAgICAgLy9pbiBjYXNlIHRoZXJlJ3MgYSBjaGlsZCB0aGF0IGluZmluaXRlbHkgcmVwZWF0cywgdXNlcnMgYWxtb3N0IG5ldmVyIGludGVuZCBmb3IgdGhlIGluc2VydGlvbiBwb2ludCBvZiBhIG5ldyBjaGlsZCB0byBiZSBiYXNlZCBvbiBhIFNVUEVSIGxvbmcgdmFsdWUgbGlrZSB0aGF0IHNvIHdlIGNsaXAgaXQgYW5kIGFzc3VtZSB0aGUgbW9zdCByZWNlbnRseS1hZGRlZCBjaGlsZCdzIGVuZFRpbWUgc2hvdWxkIGJlIHVzZWQgaW5zdGVhZC5cbiAgaSxcbiAgICAgIG9mZnNldCxcbiAgICAgIGlzUGVyY2VudDtcblxuICBpZiAoX2lzU3RyaW5nKHBvc2l0aW9uKSAmJiAoaXNOYU4ocG9zaXRpb24pIHx8IHBvc2l0aW9uIGluIGxhYmVscykpIHtcbiAgICAvL2lmIHRoZSBzdHJpbmcgaXMgYSBudW1iZXIgbGlrZSBcIjFcIiwgY2hlY2sgdG8gc2VlIGlmIHRoZXJlJ3MgYSBsYWJlbCB3aXRoIHRoYXQgbmFtZSwgb3RoZXJ3aXNlIGludGVycHJldCBpdCBhcyBhIG51bWJlciAoYWJzb2x1dGUgdmFsdWUpLlxuICAgIG9mZnNldCA9IHBvc2l0aW9uLmNoYXJBdCgwKTtcbiAgICBpc1BlcmNlbnQgPSBwb3NpdGlvbi5zdWJzdHIoLTEpID09PSBcIiVcIjtcbiAgICBpID0gcG9zaXRpb24uaW5kZXhPZihcIj1cIik7XG5cbiAgICBpZiAob2Zmc2V0ID09PSBcIjxcIiB8fCBvZmZzZXQgPT09IFwiPlwiKSB7XG4gICAgICBpID49IDAgJiYgKHBvc2l0aW9uID0gcG9zaXRpb24ucmVwbGFjZSgvPS8sIFwiXCIpKTtcbiAgICAgIHJldHVybiAob2Zmc2V0ID09PSBcIjxcIiA/IHJlY2VudC5fc3RhcnQgOiByZWNlbnQuZW5kVGltZShyZWNlbnQuX3JlcGVhdCA+PSAwKSkgKyAocGFyc2VGbG9hdChwb3NpdGlvbi5zdWJzdHIoMSkpIHx8IDApICogKGlzUGVyY2VudCA/IChpIDwgMCA/IHJlY2VudCA6IHBlcmNlbnRBbmltYXRpb24pLnRvdGFsRHVyYXRpb24oKSAvIDEwMCA6IDEpO1xuICAgIH1cblxuICAgIGlmIChpIDwgMCkge1xuICAgICAgcG9zaXRpb24gaW4gbGFiZWxzIHx8IChsYWJlbHNbcG9zaXRpb25dID0gY2xpcHBlZER1cmF0aW9uKTtcbiAgICAgIHJldHVybiBsYWJlbHNbcG9zaXRpb25dO1xuICAgIH1cblxuICAgIG9mZnNldCA9IHBhcnNlRmxvYXQocG9zaXRpb24uY2hhckF0KGkgLSAxKSArIHBvc2l0aW9uLnN1YnN0cihpICsgMSkpO1xuXG4gICAgaWYgKGlzUGVyY2VudCAmJiBwZXJjZW50QW5pbWF0aW9uKSB7XG4gICAgICBvZmZzZXQgPSBvZmZzZXQgLyAxMDAgKiAoX2lzQXJyYXkocGVyY2VudEFuaW1hdGlvbikgPyBwZXJjZW50QW5pbWF0aW9uWzBdIDogcGVyY2VudEFuaW1hdGlvbikudG90YWxEdXJhdGlvbigpO1xuICAgIH1cblxuICAgIHJldHVybiBpID4gMSA/IF9wYXJzZVBvc2l0aW9uKGFuaW1hdGlvbiwgcG9zaXRpb24uc3Vic3RyKDAsIGkgLSAxKSwgcGVyY2VudEFuaW1hdGlvbikgKyBvZmZzZXQgOiBjbGlwcGVkRHVyYXRpb24gKyBvZmZzZXQ7XG4gIH1cblxuICByZXR1cm4gcG9zaXRpb24gPT0gbnVsbCA/IGNsaXBwZWREdXJhdGlvbiA6ICtwb3NpdGlvbjtcbn0sXG4gICAgX2NyZWF0ZVR3ZWVuVHlwZSA9IGZ1bmN0aW9uIF9jcmVhdGVUd2VlblR5cGUodHlwZSwgcGFyYW1zLCB0aW1lbGluZSkge1xuICB2YXIgaXNMZWdhY3kgPSBfaXNOdW1iZXIocGFyYW1zWzFdKSxcbiAgICAgIHZhcnNJbmRleCA9IChpc0xlZ2FjeSA/IDIgOiAxKSArICh0eXBlIDwgMiA/IDAgOiAxKSxcbiAgICAgIHZhcnMgPSBwYXJhbXNbdmFyc0luZGV4XSxcbiAgICAgIGlyVmFycyxcbiAgICAgIHBhcmVudDtcblxuICBpc0xlZ2FjeSAmJiAodmFycy5kdXJhdGlvbiA9IHBhcmFtc1sxXSk7XG4gIHZhcnMucGFyZW50ID0gdGltZWxpbmU7XG5cbiAgaWYgKHR5cGUpIHtcbiAgICBpclZhcnMgPSB2YXJzO1xuICAgIHBhcmVudCA9IHRpbWVsaW5lO1xuXG4gICAgd2hpbGUgKHBhcmVudCAmJiAhKFwiaW1tZWRpYXRlUmVuZGVyXCIgaW4gaXJWYXJzKSkge1xuICAgICAgLy8gaW5oZXJpdGFuY2UgaGFzbid0IGhhcHBlbmVkIHlldCwgYnV0IHNvbWVvbmUgbWF5IGhhdmUgc2V0IGEgZGVmYXVsdCBpbiBhbiBhbmNlc3RvciB0aW1lbGluZS4gV2UgY291bGQgZG8gdmFycy5pbW1lZGlhdGVSZW5kZXIgPSBfaXNOb3RGYWxzZShfaW5oZXJpdERlZmF1bHRzKHZhcnMpLmltbWVkaWF0ZVJlbmRlcikgYnV0IHRoYXQnZCBleGFjdCBhIHNsaWdodCBwZXJmb3JtYW5jZSBwZW5hbHR5IGJlY2F1c2UgX2luaGVyaXREZWZhdWx0cygpIGFsc28gcnVucyBpbiB0aGUgVHdlZW4gY29uc3RydWN0b3IuIFdlJ3JlIHBheWluZyBhIHNtYWxsIGtiIHByaWNlIGhlcmUgdG8gZ2FpbiBzcGVlZC5cbiAgICAgIGlyVmFycyA9IHBhcmVudC52YXJzLmRlZmF1bHRzIHx8IHt9O1xuICAgICAgcGFyZW50ID0gX2lzTm90RmFsc2UocGFyZW50LnZhcnMuaW5oZXJpdCkgJiYgcGFyZW50LnBhcmVudDtcbiAgICB9XG5cbiAgICB2YXJzLmltbWVkaWF0ZVJlbmRlciA9IF9pc05vdEZhbHNlKGlyVmFycy5pbW1lZGlhdGVSZW5kZXIpO1xuICAgIHR5cGUgPCAyID8gdmFycy5ydW5CYWNrd2FyZHMgPSAxIDogdmFycy5zdGFydEF0ID0gcGFyYW1zW3ZhcnNJbmRleCAtIDFdOyAvLyBcImZyb21cIiB2YXJzXG4gIH1cblxuICByZXR1cm4gbmV3IFR3ZWVuKHBhcmFtc1swXSwgdmFycywgcGFyYW1zW3ZhcnNJbmRleCArIDFdKTtcbn0sXG4gICAgX2NvbmRpdGlvbmFsUmV0dXJuID0gZnVuY3Rpb24gX2NvbmRpdGlvbmFsUmV0dXJuKHZhbHVlLCBmdW5jKSB7XG4gIHJldHVybiB2YWx1ZSB8fCB2YWx1ZSA9PT0gMCA/IGZ1bmModmFsdWUpIDogZnVuYztcbn0sXG4gICAgX2NsYW1wID0gZnVuY3Rpb24gX2NsYW1wKG1pbiwgbWF4LCB2YWx1ZSkge1xuICByZXR1cm4gdmFsdWUgPCBtaW4gPyBtaW4gOiB2YWx1ZSA+IG1heCA/IG1heCA6IHZhbHVlO1xufSxcbiAgICBnZXRVbml0ID0gZnVuY3Rpb24gZ2V0VW5pdCh2YWx1ZSwgdikge1xuICByZXR1cm4gIV9pc1N0cmluZyh2YWx1ZSkgfHwgISh2ID0gX3VuaXRFeHAuZXhlYyh2YWx1ZSkpID8gXCJcIiA6IHZbMV07XG59LFxuICAgIC8vIG5vdGU6IHByb3RlY3QgYWdhaW5zdCBwYWRkZWQgbnVtYmVycyBhcyBzdHJpbmdzLCBsaWtlIFwiMTAwLjEwMFwiLiBUaGF0IHNob3VsZG4ndCByZXR1cm4gXCIwMFwiIGFzIHRoZSB1bml0LiBJZiBpdCdzIG51bWVyaWMsIHJldHVybiBubyB1bml0LlxuY2xhbXAgPSBmdW5jdGlvbiBjbGFtcChtaW4sIG1heCwgdmFsdWUpIHtcbiAgcmV0dXJuIF9jb25kaXRpb25hbFJldHVybih2YWx1ZSwgZnVuY3Rpb24gKHYpIHtcbiAgICByZXR1cm4gX2NsYW1wKG1pbiwgbWF4LCB2KTtcbiAgfSk7XG59LFxuICAgIF9zbGljZSA9IFtdLnNsaWNlLFxuICAgIF9pc0FycmF5TGlrZSA9IGZ1bmN0aW9uIF9pc0FycmF5TGlrZSh2YWx1ZSwgbm9uRW1wdHkpIHtcbiAgcmV0dXJuIHZhbHVlICYmIF9pc09iamVjdCh2YWx1ZSkgJiYgXCJsZW5ndGhcIiBpbiB2YWx1ZSAmJiAoIW5vbkVtcHR5ICYmICF2YWx1ZS5sZW5ndGggfHwgdmFsdWUubGVuZ3RoIC0gMSBpbiB2YWx1ZSAmJiBfaXNPYmplY3QodmFsdWVbMF0pKSAmJiAhdmFsdWUubm9kZVR5cGUgJiYgdmFsdWUgIT09IF93aW47XG59LFxuICAgIF9mbGF0dGVuID0gZnVuY3Rpb24gX2ZsYXR0ZW4oYXIsIGxlYXZlU3RyaW5ncywgYWNjdW11bGF0b3IpIHtcbiAgaWYgKGFjY3VtdWxhdG9yID09PSB2b2lkIDApIHtcbiAgICBhY2N1bXVsYXRvciA9IFtdO1xuICB9XG5cbiAgcmV0dXJuIGFyLmZvckVhY2goZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgdmFyIF9hY2N1bXVsYXRvcjtcblxuICAgIHJldHVybiBfaXNTdHJpbmcodmFsdWUpICYmICFsZWF2ZVN0cmluZ3MgfHwgX2lzQXJyYXlMaWtlKHZhbHVlLCAxKSA/IChfYWNjdW11bGF0b3IgPSBhY2N1bXVsYXRvcikucHVzaC5hcHBseShfYWNjdW11bGF0b3IsIHRvQXJyYXkodmFsdWUpKSA6IGFjY3VtdWxhdG9yLnB1c2godmFsdWUpO1xuICB9KSB8fCBhY2N1bXVsYXRvcjtcbn0sXG4gICAgLy90YWtlcyBhbnkgdmFsdWUgYW5kIHJldHVybnMgYW4gYXJyYXkuIElmIGl0J3MgYSBzdHJpbmcgKGFuZCBsZWF2ZVN0cmluZ3MgaXNuJ3QgdHJ1ZSksIGl0J2xsIHVzZSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCkgYW5kIGNvbnZlcnQgdGhhdCB0byBhbiBhcnJheS4gSXQnbGwgYWxzbyBhY2NlcHQgaXRlcmFibGVzIGxpa2UgalF1ZXJ5IG9iamVjdHMuXG50b0FycmF5ID0gZnVuY3Rpb24gdG9BcnJheSh2YWx1ZSwgc2NvcGUsIGxlYXZlU3RyaW5ncykge1xuICByZXR1cm4gX2NvbnRleHQgJiYgIXNjb3BlICYmIF9jb250ZXh0LnNlbGVjdG9yID8gX2NvbnRleHQuc2VsZWN0b3IodmFsdWUpIDogX2lzU3RyaW5nKHZhbHVlKSAmJiAhbGVhdmVTdHJpbmdzICYmIChfY29yZUluaXR0ZWQgfHwgIV93YWtlKCkpID8gX3NsaWNlLmNhbGwoKHNjb3BlIHx8IF9kb2MpLnF1ZXJ5U2VsZWN0b3JBbGwodmFsdWUpLCAwKSA6IF9pc0FycmF5KHZhbHVlKSA/IF9mbGF0dGVuKHZhbHVlLCBsZWF2ZVN0cmluZ3MpIDogX2lzQXJyYXlMaWtlKHZhbHVlKSA/IF9zbGljZS5jYWxsKHZhbHVlLCAwKSA6IHZhbHVlID8gW3ZhbHVlXSA6IFtdO1xufSxcbiAgICBzZWxlY3RvciA9IGZ1bmN0aW9uIHNlbGVjdG9yKHZhbHVlKSB7XG4gIHZhbHVlID0gdG9BcnJheSh2YWx1ZSlbMF0gfHwgX3dhcm4oXCJJbnZhbGlkIHNjb3BlXCIpIHx8IHt9O1xuICByZXR1cm4gZnVuY3Rpb24gKHYpIHtcbiAgICB2YXIgZWwgPSB2YWx1ZS5jdXJyZW50IHx8IHZhbHVlLm5hdGl2ZUVsZW1lbnQgfHwgdmFsdWU7XG4gICAgcmV0dXJuIHRvQXJyYXkodiwgZWwucXVlcnlTZWxlY3RvckFsbCA/IGVsIDogZWwgPT09IHZhbHVlID8gX3dhcm4oXCJJbnZhbGlkIHNjb3BlXCIpIHx8IF9kb2MuY3JlYXRlRWxlbWVudChcImRpdlwiKSA6IHZhbHVlKTtcbiAgfTtcbn0sXG4gICAgc2h1ZmZsZSA9IGZ1bmN0aW9uIHNodWZmbGUoYSkge1xuICByZXR1cm4gYS5zb3J0KGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gLjUgLSBNYXRoLnJhbmRvbSgpO1xuICB9KTtcbn0sXG4gICAgLy8gYWx0ZXJuYXRpdmUgdGhhdCdzIGEgYml0IGZhc3RlciBhbmQgbW9yZSByZWxpYWJseSBkaXZlcnNlIGJ1dCBiaWdnZXI6ICAgZm9yIChsZXQgaiwgdiwgaSA9IGEubGVuZ3RoOyBpOyBqID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogaSksIHYgPSBhWy0taV0sIGFbaV0gPSBhW2pdLCBhW2pdID0gdik7IHJldHVybiBhO1xuLy9mb3IgZGlzdHJpYnV0aW5nIHZhbHVlcyBhY3Jvc3MgYW4gYXJyYXkuIENhbiBhY2NlcHQgYSBudW1iZXIsIGEgZnVuY3Rpb24gb3IgKG1vc3QgY29tbW9ubHkpIGEgZnVuY3Rpb24gd2hpY2ggY2FuIGNvbnRhaW4gdGhlIGZvbGxvd2luZyBwcm9wZXJ0aWVzOiB7YmFzZSwgYW1vdW50LCBmcm9tLCBlYXNlLCBncmlkLCBheGlzLCBsZW5ndGgsIGVhY2h9LiBSZXR1cm5zIGEgZnVuY3Rpb24gdGhhdCBleHBlY3RzIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVyczogaW5kZXgsIHRhcmdldCwgYXJyYXkuIFJlY29nbml6ZXMgdGhlIGZvbGxvd2luZ1xuZGlzdHJpYnV0ZSA9IGZ1bmN0aW9uIGRpc3RyaWJ1dGUodikge1xuICBpZiAoX2lzRnVuY3Rpb24odikpIHtcbiAgICByZXR1cm4gdjtcbiAgfVxuXG4gIHZhciB2YXJzID0gX2lzT2JqZWN0KHYpID8gdiA6IHtcbiAgICBlYWNoOiB2XG4gIH0sXG4gICAgICAvL246MSBpcyBqdXN0IHRvIGluZGljYXRlIHYgd2FzIGEgbnVtYmVyOyB3ZSBsZXZlcmFnZSB0aGF0IGxhdGVyIHRvIHNldCB2IGFjY29yZGluZyB0byB0aGUgbGVuZ3RoIHdlIGdldC4gSWYgYSBudW1iZXIgaXMgcGFzc2VkIGluLCB3ZSB0cmVhdCBpdCBsaWtlIHRoZSBvbGQgc3RhZ2dlciB2YWx1ZSB3aGVyZSAwLjEsIGZvciBleGFtcGxlLCB3b3VsZCBtZWFuIHRoYXQgdGhpbmdzIHdvdWxkIGJlIGRpc3RyaWJ1dGVkIHdpdGggMC4xIGJldHdlZW4gZWFjaCBlbGVtZW50IGluIHRoZSBhcnJheSByYXRoZXIgdGhhbiBhIHRvdGFsIFwiYW1vdW50XCIgdGhhdCdzIGNodW5rZWQgb3V0IGFtb25nIHRoZW0gYWxsLlxuICBlYXNlID0gX3BhcnNlRWFzZSh2YXJzLmVhc2UpLFxuICAgICAgZnJvbSA9IHZhcnMuZnJvbSB8fCAwLFxuICAgICAgYmFzZSA9IHBhcnNlRmxvYXQodmFycy5iYXNlKSB8fCAwLFxuICAgICAgY2FjaGUgPSB7fSxcbiAgICAgIGlzRGVjaW1hbCA9IGZyb20gPiAwICYmIGZyb20gPCAxLFxuICAgICAgcmF0aW9zID0gaXNOYU4oZnJvbSkgfHwgaXNEZWNpbWFsLFxuICAgICAgYXhpcyA9IHZhcnMuYXhpcyxcbiAgICAgIHJhdGlvWCA9IGZyb20sXG4gICAgICByYXRpb1kgPSBmcm9tO1xuXG4gIGlmIChfaXNTdHJpbmcoZnJvbSkpIHtcbiAgICByYXRpb1ggPSByYXRpb1kgPSB7XG4gICAgICBjZW50ZXI6IC41LFxuICAgICAgZWRnZXM6IC41LFxuICAgICAgZW5kOiAxXG4gICAgfVtmcm9tXSB8fCAwO1xuICB9IGVsc2UgaWYgKCFpc0RlY2ltYWwgJiYgcmF0aW9zKSB7XG4gICAgcmF0aW9YID0gZnJvbVswXTtcbiAgICByYXRpb1kgPSBmcm9tWzFdO1xuICB9XG5cbiAgcmV0dXJuIGZ1bmN0aW9uIChpLCB0YXJnZXQsIGEpIHtcbiAgICB2YXIgbCA9IChhIHx8IHZhcnMpLmxlbmd0aCxcbiAgICAgICAgZGlzdGFuY2VzID0gY2FjaGVbbF0sXG4gICAgICAgIG9yaWdpblgsXG4gICAgICAgIG9yaWdpblksXG4gICAgICAgIHgsXG4gICAgICAgIHksXG4gICAgICAgIGQsXG4gICAgICAgIGosXG4gICAgICAgIG1heCxcbiAgICAgICAgbWluLFxuICAgICAgICB3cmFwQXQ7XG5cbiAgICBpZiAoIWRpc3RhbmNlcykge1xuICAgICAgd3JhcEF0ID0gdmFycy5ncmlkID09PSBcImF1dG9cIiA/IDAgOiAodmFycy5ncmlkIHx8IFsxLCBfYmlnTnVtXSlbMV07XG5cbiAgICAgIGlmICghd3JhcEF0KSB7XG4gICAgICAgIG1heCA9IC1fYmlnTnVtO1xuXG4gICAgICAgIHdoaWxlIChtYXggPCAobWF4ID0gYVt3cmFwQXQrK10uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkubGVmdCkgJiYgd3JhcEF0IDwgbCkge31cblxuICAgICAgICB3cmFwQXQgPCBsICYmIHdyYXBBdC0tO1xuICAgICAgfVxuXG4gICAgICBkaXN0YW5jZXMgPSBjYWNoZVtsXSA9IFtdO1xuICAgICAgb3JpZ2luWCA9IHJhdGlvcyA/IE1hdGgubWluKHdyYXBBdCwgbCkgKiByYXRpb1ggLSAuNSA6IGZyb20gJSB3cmFwQXQ7XG4gICAgICBvcmlnaW5ZID0gd3JhcEF0ID09PSBfYmlnTnVtID8gMCA6IHJhdGlvcyA/IGwgKiByYXRpb1kgLyB3cmFwQXQgLSAuNSA6IGZyb20gLyB3cmFwQXQgfCAwO1xuICAgICAgbWF4ID0gMDtcbiAgICAgIG1pbiA9IF9iaWdOdW07XG5cbiAgICAgIGZvciAoaiA9IDA7IGogPCBsOyBqKyspIHtcbiAgICAgICAgeCA9IGogJSB3cmFwQXQgLSBvcmlnaW5YO1xuICAgICAgICB5ID0gb3JpZ2luWSAtIChqIC8gd3JhcEF0IHwgMCk7XG4gICAgICAgIGRpc3RhbmNlc1tqXSA9IGQgPSAhYXhpcyA/IF9zcXJ0KHggKiB4ICsgeSAqIHkpIDogTWF0aC5hYnMoYXhpcyA9PT0gXCJ5XCIgPyB5IDogeCk7XG4gICAgICAgIGQgPiBtYXggJiYgKG1heCA9IGQpO1xuICAgICAgICBkIDwgbWluICYmIChtaW4gPSBkKTtcbiAgICAgIH1cblxuICAgICAgZnJvbSA9PT0gXCJyYW5kb21cIiAmJiBzaHVmZmxlKGRpc3RhbmNlcyk7XG4gICAgICBkaXN0YW5jZXMubWF4ID0gbWF4IC0gbWluO1xuICAgICAgZGlzdGFuY2VzLm1pbiA9IG1pbjtcbiAgICAgIGRpc3RhbmNlcy52ID0gbCA9IChwYXJzZUZsb2F0KHZhcnMuYW1vdW50KSB8fCBwYXJzZUZsb2F0KHZhcnMuZWFjaCkgKiAod3JhcEF0ID4gbCA/IGwgLSAxIDogIWF4aXMgPyBNYXRoLm1heCh3cmFwQXQsIGwgLyB3cmFwQXQpIDogYXhpcyA9PT0gXCJ5XCIgPyBsIC8gd3JhcEF0IDogd3JhcEF0KSB8fCAwKSAqIChmcm9tID09PSBcImVkZ2VzXCIgPyAtMSA6IDEpO1xuICAgICAgZGlzdGFuY2VzLmIgPSBsIDwgMCA/IGJhc2UgLSBsIDogYmFzZTtcbiAgICAgIGRpc3RhbmNlcy51ID0gZ2V0VW5pdCh2YXJzLmFtb3VudCB8fCB2YXJzLmVhY2gpIHx8IDA7IC8vdW5pdFxuXG4gICAgICBlYXNlID0gZWFzZSAmJiBsIDwgMCA/IF9pbnZlcnRFYXNlKGVhc2UpIDogZWFzZTtcbiAgICB9XG5cbiAgICBsID0gKGRpc3RhbmNlc1tpXSAtIGRpc3RhbmNlcy5taW4pIC8gZGlzdGFuY2VzLm1heCB8fCAwO1xuICAgIHJldHVybiBfcm91bmRQcmVjaXNlKGRpc3RhbmNlcy5iICsgKGVhc2UgPyBlYXNlKGwpIDogbCkgKiBkaXN0YW5jZXMudikgKyBkaXN0YW5jZXMudTsgLy9yb3VuZCBpbiBvcmRlciB0byB3b3JrIGFyb3VuZCBmbG9hdGluZyBwb2ludCBlcnJvcnNcbiAgfTtcbn0sXG4gICAgX3JvdW5kTW9kaWZpZXIgPSBmdW5jdGlvbiBfcm91bmRNb2RpZmllcih2KSB7XG4gIC8vcGFzcyBpbiAwLjEgZ2V0IGEgZnVuY3Rpb24gdGhhdCdsbCByb3VuZCB0byB0aGUgbmVhcmVzdCB0ZW50aCwgb3IgNSB0byByb3VuZCB0byB0aGUgY2xvc2VzdCA1LCBvciAwLjAwMSB0byB0aGUgY2xvc2VzdCAxMDAwdGgsIGV0Yy5cbiAgdmFyIHAgPSBNYXRoLnBvdygxMCwgKCh2ICsgXCJcIikuc3BsaXQoXCIuXCIpWzFdIHx8IFwiXCIpLmxlbmd0aCk7IC8vdG8gYXZvaWQgZmxvYXRpbmcgcG9pbnQgbWF0aCBlcnJvcnMgKGxpa2UgMjQgKiAwLjEgPT0gMi40MDAwMDAwMDAwMDAwMDA0KSwgd2UgY2hvcCBvZmYgYXQgYSBzcGVjaWZpYyBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgKG11Y2ggZmFzdGVyIHRoYW4gdG9GaXhlZCgpKVxuXG4gIHJldHVybiBmdW5jdGlvbiAocmF3KSB7XG4gICAgdmFyIG4gPSBfcm91bmRQcmVjaXNlKE1hdGgucm91bmQocGFyc2VGbG9hdChyYXcpIC8gdikgKiB2ICogcCk7XG5cbiAgICByZXR1cm4gKG4gLSBuICUgMSkgLyBwICsgKF9pc051bWJlcihyYXcpID8gMCA6IGdldFVuaXQocmF3KSk7IC8vIG4gLSBuICUgMSByZXBsYWNlcyBNYXRoLmZsb29yKCkgaW4gb3JkZXIgdG8gaGFuZGxlIG5lZ2F0aXZlIHZhbHVlcyBwcm9wZXJseS4gRm9yIGV4YW1wbGUsIE1hdGguZmxvb3IoLTE1MC4wMDAwMDAwMDAwMDAwMykgaXMgMTUxIVxuICB9O1xufSxcbiAgICBzbmFwID0gZnVuY3Rpb24gc25hcChzbmFwVG8sIHZhbHVlKSB7XG4gIHZhciBpc0FycmF5ID0gX2lzQXJyYXkoc25hcFRvKSxcbiAgICAgIHJhZGl1cyxcbiAgICAgIGlzMkQ7XG5cbiAgaWYgKCFpc0FycmF5ICYmIF9pc09iamVjdChzbmFwVG8pKSB7XG4gICAgcmFkaXVzID0gaXNBcnJheSA9IHNuYXBUby5yYWRpdXMgfHwgX2JpZ051bTtcblxuICAgIGlmIChzbmFwVG8udmFsdWVzKSB7XG4gICAgICBzbmFwVG8gPSB0b0FycmF5KHNuYXBUby52YWx1ZXMpO1xuXG4gICAgICBpZiAoaXMyRCA9ICFfaXNOdW1iZXIoc25hcFRvWzBdKSkge1xuICAgICAgICByYWRpdXMgKj0gcmFkaXVzOyAvL3BlcmZvcm1hbmNlIG9wdGltaXphdGlvbiBzbyB3ZSBkb24ndCBoYXZlIHRvIE1hdGguc3FydCgpIGluIHRoZSBsb29wLlxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBzbmFwVG8gPSBfcm91bmRNb2RpZmllcihzbmFwVG8uaW5jcmVtZW50KTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gX2NvbmRpdGlvbmFsUmV0dXJuKHZhbHVlLCAhaXNBcnJheSA/IF9yb3VuZE1vZGlmaWVyKHNuYXBUbykgOiBfaXNGdW5jdGlvbihzbmFwVG8pID8gZnVuY3Rpb24gKHJhdykge1xuICAgIGlzMkQgPSBzbmFwVG8ocmF3KTtcbiAgICByZXR1cm4gTWF0aC5hYnMoaXMyRCAtIHJhdykgPD0gcmFkaXVzID8gaXMyRCA6IHJhdztcbiAgfSA6IGZ1bmN0aW9uIChyYXcpIHtcbiAgICB2YXIgeCA9IHBhcnNlRmxvYXQoaXMyRCA/IHJhdy54IDogcmF3KSxcbiAgICAgICAgeSA9IHBhcnNlRmxvYXQoaXMyRCA/IHJhdy55IDogMCksXG4gICAgICAgIG1pbiA9IF9iaWdOdW0sXG4gICAgICAgIGNsb3Nlc3QgPSAwLFxuICAgICAgICBpID0gc25hcFRvLmxlbmd0aCxcbiAgICAgICAgZHgsXG4gICAgICAgIGR5O1xuXG4gICAgd2hpbGUgKGktLSkge1xuICAgICAgaWYgKGlzMkQpIHtcbiAgICAgICAgZHggPSBzbmFwVG9baV0ueCAtIHg7XG4gICAgICAgIGR5ID0gc25hcFRvW2ldLnkgLSB5O1xuICAgICAgICBkeCA9IGR4ICogZHggKyBkeSAqIGR5O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZHggPSBNYXRoLmFicyhzbmFwVG9baV0gLSB4KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGR4IDwgbWluKSB7XG4gICAgICAgIG1pbiA9IGR4O1xuICAgICAgICBjbG9zZXN0ID0gaTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjbG9zZXN0ID0gIXJhZGl1cyB8fCBtaW4gPD0gcmFkaXVzID8gc25hcFRvW2Nsb3Nlc3RdIDogcmF3O1xuICAgIHJldHVybiBpczJEIHx8IGNsb3Nlc3QgPT09IHJhdyB8fCBfaXNOdW1iZXIocmF3KSA/IGNsb3Nlc3QgOiBjbG9zZXN0ICsgZ2V0VW5pdChyYXcpO1xuICB9KTtcbn0sXG4gICAgcmFuZG9tID0gZnVuY3Rpb24gcmFuZG9tKG1pbiwgbWF4LCByb3VuZGluZ0luY3JlbWVudCwgcmV0dXJuRnVuY3Rpb24pIHtcbiAgcmV0dXJuIF9jb25kaXRpb25hbFJldHVybihfaXNBcnJheShtaW4pID8gIW1heCA6IHJvdW5kaW5nSW5jcmVtZW50ID09PSB0cnVlID8gISEocm91bmRpbmdJbmNyZW1lbnQgPSAwKSA6ICFyZXR1cm5GdW5jdGlvbiwgZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBfaXNBcnJheShtaW4pID8gbWluW35+KE1hdGgucmFuZG9tKCkgKiBtaW4ubGVuZ3RoKV0gOiAocm91bmRpbmdJbmNyZW1lbnQgPSByb3VuZGluZ0luY3JlbWVudCB8fCAxZS01KSAmJiAocmV0dXJuRnVuY3Rpb24gPSByb3VuZGluZ0luY3JlbWVudCA8IDEgPyBNYXRoLnBvdygxMCwgKHJvdW5kaW5nSW5jcmVtZW50ICsgXCJcIikubGVuZ3RoIC0gMikgOiAxKSAmJiBNYXRoLmZsb29yKE1hdGgucm91bmQoKG1pbiAtIHJvdW5kaW5nSW5jcmVtZW50IC8gMiArIE1hdGgucmFuZG9tKCkgKiAobWF4IC0gbWluICsgcm91bmRpbmdJbmNyZW1lbnQgKiAuOTkpKSAvIHJvdW5kaW5nSW5jcmVtZW50KSAqIHJvdW5kaW5nSW5jcmVtZW50ICogcmV0dXJuRnVuY3Rpb24pIC8gcmV0dXJuRnVuY3Rpb247XG4gIH0pO1xufSxcbiAgICBwaXBlID0gZnVuY3Rpb24gcGlwZSgpIHtcbiAgZm9yICh2YXIgX2xlbiA9IGFyZ3VtZW50cy5sZW5ndGgsIGZ1bmN0aW9ucyA9IG5ldyBBcnJheShfbGVuKSwgX2tleSA9IDA7IF9rZXkgPCBfbGVuOyBfa2V5KyspIHtcbiAgICBmdW5jdGlvbnNbX2tleV0gPSBhcmd1bWVudHNbX2tleV07XG4gIH1cblxuICByZXR1cm4gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9ucy5yZWR1Y2UoZnVuY3Rpb24gKHYsIGYpIHtcbiAgICAgIHJldHVybiBmKHYpO1xuICAgIH0sIHZhbHVlKTtcbiAgfTtcbn0sXG4gICAgdW5pdGl6ZSA9IGZ1bmN0aW9uIHVuaXRpemUoZnVuYywgdW5pdCkge1xuICByZXR1cm4gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgcmV0dXJuIGZ1bmMocGFyc2VGbG9hdCh2YWx1ZSkpICsgKHVuaXQgfHwgZ2V0VW5pdCh2YWx1ZSkpO1xuICB9O1xufSxcbiAgICBub3JtYWxpemUgPSBmdW5jdGlvbiBub3JtYWxpemUobWluLCBtYXgsIHZhbHVlKSB7XG4gIHJldHVybiBtYXBSYW5nZShtaW4sIG1heCwgMCwgMSwgdmFsdWUpO1xufSxcbiAgICBfd3JhcEFycmF5ID0gZnVuY3Rpb24gX3dyYXBBcnJheShhLCB3cmFwcGVyLCB2YWx1ZSkge1xuICByZXR1cm4gX2NvbmRpdGlvbmFsUmV0dXJuKHZhbHVlLCBmdW5jdGlvbiAoaW5kZXgpIHtcbiAgICByZXR1cm4gYVt+fndyYXBwZXIoaW5kZXgpXTtcbiAgfSk7XG59LFxuICAgIHdyYXAgPSBmdW5jdGlvbiB3cmFwKG1pbiwgbWF4LCB2YWx1ZSkge1xuICAvLyBOT1RFOiB3cmFwKCkgQ0FOTk9UIGJlIGFuIGFycm93IGZ1bmN0aW9uISBBIHZlcnkgb2RkIGNvbXBpbGluZyBidWcgY2F1c2VzIHByb2JsZW1zICh1bnJlbGF0ZWQgdG8gR1NBUCkuXG4gIHZhciByYW5nZSA9IG1heCAtIG1pbjtcbiAgcmV0dXJuIF9pc0FycmF5KG1pbikgPyBfd3JhcEFycmF5KG1pbiwgd3JhcCgwLCBtaW4ubGVuZ3RoKSwgbWF4KSA6IF9jb25kaXRpb25hbFJldHVybih2YWx1ZSwgZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgcmV0dXJuIChyYW5nZSArICh2YWx1ZSAtIG1pbikgJSByYW5nZSkgJSByYW5nZSArIG1pbjtcbiAgfSk7XG59LFxuICAgIHdyYXBZb3lvID0gZnVuY3Rpb24gd3JhcFlveW8obWluLCBtYXgsIHZhbHVlKSB7XG4gIHZhciByYW5nZSA9IG1heCAtIG1pbixcbiAgICAgIHRvdGFsID0gcmFuZ2UgKiAyO1xuICByZXR1cm4gX2lzQXJyYXkobWluKSA/IF93cmFwQXJyYXkobWluLCB3cmFwWW95bygwLCBtaW4ubGVuZ3RoIC0gMSksIG1heCkgOiBfY29uZGl0aW9uYWxSZXR1cm4odmFsdWUsIGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHZhbHVlID0gKHRvdGFsICsgKHZhbHVlIC0gbWluKSAlIHRvdGFsKSAlIHRvdGFsIHx8IDA7XG4gICAgcmV0dXJuIG1pbiArICh2YWx1ZSA+IHJhbmdlID8gdG90YWwgLSB2YWx1ZSA6IHZhbHVlKTtcbiAgfSk7XG59LFxuICAgIF9yZXBsYWNlUmFuZG9tID0gZnVuY3Rpb24gX3JlcGxhY2VSYW5kb20odmFsdWUpIHtcbiAgLy9yZXBsYWNlcyBhbGwgb2NjdXJyZW5jZXMgb2YgcmFuZG9tKC4uLikgaW4gYSBzdHJpbmcgd2l0aCB0aGUgY2FsY3VsYXRlZCByYW5kb20gdmFsdWUuIGNhbiBiZSBhIHJhbmdlIGxpa2UgcmFuZG9tKC0xMDAsIDEwMCwgNSkgb3IgYW4gYXJyYXkgbGlrZSByYW5kb20oWzAsIDEwMCwgNTAwXSlcbiAgdmFyIHByZXYgPSAwLFxuICAgICAgcyA9IFwiXCIsXG4gICAgICBpLFxuICAgICAgbnVtcyxcbiAgICAgIGVuZCxcbiAgICAgIGlzQXJyYXk7XG5cbiAgd2hpbGUgKH4oaSA9IHZhbHVlLmluZGV4T2YoXCJyYW5kb20oXCIsIHByZXYpKSkge1xuICAgIGVuZCA9IHZhbHVlLmluZGV4T2YoXCIpXCIsIGkpO1xuICAgIGlzQXJyYXkgPSB2YWx1ZS5jaGFyQXQoaSArIDcpID09PSBcIltcIjtcbiAgICBudW1zID0gdmFsdWUuc3Vic3RyKGkgKyA3LCBlbmQgLSBpIC0gNykubWF0Y2goaXNBcnJheSA/IF9kZWxpbWl0ZWRWYWx1ZUV4cCA6IF9zdHJpY3ROdW1FeHApO1xuICAgIHMgKz0gdmFsdWUuc3Vic3RyKHByZXYsIGkgLSBwcmV2KSArIHJhbmRvbShpc0FycmF5ID8gbnVtcyA6ICtudW1zWzBdLCBpc0FycmF5ID8gMCA6ICtudW1zWzFdLCArbnVtc1syXSB8fCAxZS01KTtcbiAgICBwcmV2ID0gZW5kICsgMTtcbiAgfVxuXG4gIHJldHVybiBzICsgdmFsdWUuc3Vic3RyKHByZXYsIHZhbHVlLmxlbmd0aCAtIHByZXYpO1xufSxcbiAgICBtYXBSYW5nZSA9IGZ1bmN0aW9uIG1hcFJhbmdlKGluTWluLCBpbk1heCwgb3V0TWluLCBvdXRNYXgsIHZhbHVlKSB7XG4gIHZhciBpblJhbmdlID0gaW5NYXggLSBpbk1pbixcbiAgICAgIG91dFJhbmdlID0gb3V0TWF4IC0gb3V0TWluO1xuICByZXR1cm4gX2NvbmRpdGlvbmFsUmV0dXJuKHZhbHVlLCBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gb3V0TWluICsgKCh2YWx1ZSAtIGluTWluKSAvIGluUmFuZ2UgKiBvdXRSYW5nZSB8fCAwKTtcbiAgfSk7XG59LFxuICAgIGludGVycG9sYXRlID0gZnVuY3Rpb24gaW50ZXJwb2xhdGUoc3RhcnQsIGVuZCwgcHJvZ3Jlc3MsIG11dGF0ZSkge1xuICB2YXIgZnVuYyA9IGlzTmFOKHN0YXJ0ICsgZW5kKSA/IDAgOiBmdW5jdGlvbiAocCkge1xuICAgIHJldHVybiAoMSAtIHApICogc3RhcnQgKyBwICogZW5kO1xuICB9O1xuXG4gIGlmICghZnVuYykge1xuICAgIHZhciBpc1N0cmluZyA9IF9pc1N0cmluZyhzdGFydCksXG4gICAgICAgIG1hc3RlciA9IHt9LFxuICAgICAgICBwLFxuICAgICAgICBpLFxuICAgICAgICBpbnRlcnBvbGF0b3JzLFxuICAgICAgICBsLFxuICAgICAgICBpbDtcblxuICAgIHByb2dyZXNzID09PSB0cnVlICYmIChtdXRhdGUgPSAxKSAmJiAocHJvZ3Jlc3MgPSBudWxsKTtcblxuICAgIGlmIChpc1N0cmluZykge1xuICAgICAgc3RhcnQgPSB7XG4gICAgICAgIHA6IHN0YXJ0XG4gICAgICB9O1xuICAgICAgZW5kID0ge1xuICAgICAgICBwOiBlbmRcbiAgICAgIH07XG4gICAgfSBlbHNlIGlmIChfaXNBcnJheShzdGFydCkgJiYgIV9pc0FycmF5KGVuZCkpIHtcbiAgICAgIGludGVycG9sYXRvcnMgPSBbXTtcbiAgICAgIGwgPSBzdGFydC5sZW5ndGg7XG4gICAgICBpbCA9IGwgLSAyO1xuXG4gICAgICBmb3IgKGkgPSAxOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgIGludGVycG9sYXRvcnMucHVzaChpbnRlcnBvbGF0ZShzdGFydFtpIC0gMV0sIHN0YXJ0W2ldKSk7IC8vYnVpbGQgdGhlIGludGVycG9sYXRvcnMgdXAgZnJvbnQgYXMgYSBwZXJmb3JtYW5jZSBvcHRpbWl6YXRpb24gc28gdGhhdCB3aGVuIHRoZSBmdW5jdGlvbiBpcyBjYWxsZWQgbWFueSB0aW1lcywgaXQgY2FuIGp1c3QgcmV1c2UgdGhlbS5cbiAgICAgIH1cblxuICAgICAgbC0tO1xuXG4gICAgICBmdW5jID0gZnVuY3Rpb24gZnVuYyhwKSB7XG4gICAgICAgIHAgKj0gbDtcbiAgICAgICAgdmFyIGkgPSBNYXRoLm1pbihpbCwgfn5wKTtcbiAgICAgICAgcmV0dXJuIGludGVycG9sYXRvcnNbaV0ocCAtIGkpO1xuICAgICAgfTtcblxuICAgICAgcHJvZ3Jlc3MgPSBlbmQ7XG4gICAgfSBlbHNlIGlmICghbXV0YXRlKSB7XG4gICAgICBzdGFydCA9IF9tZXJnZShfaXNBcnJheShzdGFydCkgPyBbXSA6IHt9LCBzdGFydCk7XG4gICAgfVxuXG4gICAgaWYgKCFpbnRlcnBvbGF0b3JzKSB7XG4gICAgICBmb3IgKHAgaW4gZW5kKSB7XG4gICAgICAgIF9hZGRQcm9wVHdlZW4uY2FsbChtYXN0ZXIsIHN0YXJ0LCBwLCBcImdldFwiLCBlbmRbcF0pO1xuICAgICAgfVxuXG4gICAgICBmdW5jID0gZnVuY3Rpb24gZnVuYyhwKSB7XG4gICAgICAgIHJldHVybiBfcmVuZGVyUHJvcFR3ZWVucyhwLCBtYXN0ZXIpIHx8IChpc1N0cmluZyA/IHN0YXJ0LnAgOiBzdGFydCk7XG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBfY29uZGl0aW9uYWxSZXR1cm4ocHJvZ3Jlc3MsIGZ1bmMpO1xufSxcbiAgICBfZ2V0TGFiZWxJbkRpcmVjdGlvbiA9IGZ1bmN0aW9uIF9nZXRMYWJlbEluRGlyZWN0aW9uKHRpbWVsaW5lLCBmcm9tVGltZSwgYmFja3dhcmQpIHtcbiAgLy91c2VkIGZvciBuZXh0TGFiZWwoKSBhbmQgcHJldmlvdXNMYWJlbCgpXG4gIHZhciBsYWJlbHMgPSB0aW1lbGluZS5sYWJlbHMsXG4gICAgICBtaW4gPSBfYmlnTnVtLFxuICAgICAgcCxcbiAgICAgIGRpc3RhbmNlLFxuICAgICAgbGFiZWw7XG5cbiAgZm9yIChwIGluIGxhYmVscykge1xuICAgIGRpc3RhbmNlID0gbGFiZWxzW3BdIC0gZnJvbVRpbWU7XG5cbiAgICBpZiAoZGlzdGFuY2UgPCAwID09PSAhIWJhY2t3YXJkICYmIGRpc3RhbmNlICYmIG1pbiA+IChkaXN0YW5jZSA9IE1hdGguYWJzKGRpc3RhbmNlKSkpIHtcbiAgICAgIGxhYmVsID0gcDtcbiAgICAgIG1pbiA9IGRpc3RhbmNlO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBsYWJlbDtcbn0sXG4gICAgX2NhbGxiYWNrID0gZnVuY3Rpb24gX2NhbGxiYWNrKGFuaW1hdGlvbiwgdHlwZSwgZXhlY3V0ZUxhenlGaXJzdCkge1xuICB2YXIgdiA9IGFuaW1hdGlvbi52YXJzLFxuICAgICAgY2FsbGJhY2sgPSB2W3R5cGVdLFxuICAgICAgcHJldkNvbnRleHQgPSBfY29udGV4dCxcbiAgICAgIGNvbnRleHQgPSBhbmltYXRpb24uX2N0eCxcbiAgICAgIHBhcmFtcyxcbiAgICAgIHNjb3BlLFxuICAgICAgcmVzdWx0O1xuXG4gIGlmICghY2FsbGJhY2spIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBwYXJhbXMgPSB2W3R5cGUgKyBcIlBhcmFtc1wiXTtcbiAgc2NvcGUgPSB2LmNhbGxiYWNrU2NvcGUgfHwgYW5pbWF0aW9uO1xuICBleGVjdXRlTGF6eUZpcnN0ICYmIF9sYXp5VHdlZW5zLmxlbmd0aCAmJiBfbGF6eVJlbmRlcigpOyAvL2luIGNhc2UgcmVuZGVyaW5nIGNhdXNlZCBhbnkgdHdlZW5zIHRvIGxhenktaW5pdCwgd2Ugc2hvdWxkIHJlbmRlciB0aGVtIGJlY2F1c2UgdHlwaWNhbGx5IHdoZW4gYSB0aW1lbGluZSBmaW5pc2hlcywgdXNlcnMgZXhwZWN0IHRoaW5ncyB0byBoYXZlIHJlbmRlcmVkIGZ1bGx5LiBJbWFnaW5lIGFuIG9uVXBkYXRlIG9uIGEgdGltZWxpbmUgdGhhdCByZXBvcnRzL2NoZWNrcyB0d2VlbmVkIHZhbHVlcy5cblxuICBjb250ZXh0ICYmIChfY29udGV4dCA9IGNvbnRleHQpO1xuICByZXN1bHQgPSBwYXJhbXMgPyBjYWxsYmFjay5hcHBseShzY29wZSwgcGFyYW1zKSA6IGNhbGxiYWNrLmNhbGwoc2NvcGUpO1xuICBfY29udGV4dCA9IHByZXZDb250ZXh0O1xuICByZXR1cm4gcmVzdWx0O1xufSxcbiAgICBfaW50ZXJydXB0ID0gZnVuY3Rpb24gX2ludGVycnVwdChhbmltYXRpb24pIHtcbiAgX3JlbW92ZUZyb21QYXJlbnQoYW5pbWF0aW9uKTtcblxuICBhbmltYXRpb24uc2Nyb2xsVHJpZ2dlciAmJiBhbmltYXRpb24uc2Nyb2xsVHJpZ2dlci5raWxsKCEhX3JldmVydGluZyk7XG4gIGFuaW1hdGlvbi5wcm9ncmVzcygpIDwgMSAmJiBfY2FsbGJhY2soYW5pbWF0aW9uLCBcIm9uSW50ZXJydXB0XCIpO1xuICByZXR1cm4gYW5pbWF0aW9uO1xufSxcbiAgICBfcXVpY2tUd2VlbixcbiAgICBfcmVnaXN0ZXJQbHVnaW5RdWV1ZSA9IFtdLFxuICAgIF9jcmVhdGVQbHVnaW4gPSBmdW5jdGlvbiBfY3JlYXRlUGx1Z2luKGNvbmZpZykge1xuICBpZiAoIWNvbmZpZykgcmV0dXJuO1xuICBjb25maWcgPSAhY29uZmlnLm5hbWUgJiYgY29uZmlnW1wiZGVmYXVsdFwiXSB8fCBjb25maWc7IC8vIFVNRCBwYWNrYWdpbmcgd3JhcHMgdGhpbmdzIG9kZGx5LCBzbyBmb3IgZXhhbXBsZSBNb3Rpb25QYXRoSGVscGVyIGJlY29tZXMge01vdGlvblBhdGhIZWxwZXI6TW90aW9uUGF0aEhlbHBlciwgZGVmYXVsdDpNb3Rpb25QYXRoSGVscGVyfS5cblxuICBpZiAoX3dpbmRvd0V4aXN0cygpIHx8IGNvbmZpZy5oZWFkbGVzcykge1xuICAgIC8vIGVkZ2UgY2FzZTogc29tZSBidWlsZCB0b29scyBtYXkgcGFzcyBpbiBhIG51bGwvdW5kZWZpbmVkIHZhbHVlXG4gICAgdmFyIG5hbWUgPSBjb25maWcubmFtZSxcbiAgICAgICAgaXNGdW5jID0gX2lzRnVuY3Rpb24oY29uZmlnKSxcbiAgICAgICAgUGx1Z2luID0gbmFtZSAmJiAhaXNGdW5jICYmIGNvbmZpZy5pbml0ID8gZnVuY3Rpb24gKCkge1xuICAgICAgdGhpcy5fcHJvcHMgPSBbXTtcbiAgICB9IDogY29uZmlnLFxuICAgICAgICAvL2luIGNhc2Ugc29tZW9uZSBwYXNzZXMgaW4gYW4gb2JqZWN0IHRoYXQncyBub3QgYSBwbHVnaW4sIGxpa2UgQ3VzdG9tRWFzZVxuICAgIGluc3RhbmNlRGVmYXVsdHMgPSB7XG4gICAgICBpbml0OiBfZW1wdHlGdW5jLFxuICAgICAgcmVuZGVyOiBfcmVuZGVyUHJvcFR3ZWVucyxcbiAgICAgIGFkZDogX2FkZFByb3BUd2VlbixcbiAgICAgIGtpbGw6IF9raWxsUHJvcFR3ZWVuc09mLFxuICAgICAgbW9kaWZpZXI6IF9hZGRQbHVnaW5Nb2RpZmllcixcbiAgICAgIHJhd1ZhcnM6IDBcbiAgICB9LFxuICAgICAgICBzdGF0aWNzID0ge1xuICAgICAgdGFyZ2V0VGVzdDogMCxcbiAgICAgIGdldDogMCxcbiAgICAgIGdldFNldHRlcjogX2dldFNldHRlcixcbiAgICAgIGFsaWFzZXM6IHt9LFxuICAgICAgcmVnaXN0ZXI6IDBcbiAgICB9O1xuXG4gICAgX3dha2UoKTtcblxuICAgIGlmIChjb25maWcgIT09IFBsdWdpbikge1xuICAgICAgaWYgKF9wbHVnaW5zW25hbWVdKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgX3NldERlZmF1bHRzKFBsdWdpbiwgX3NldERlZmF1bHRzKF9jb3B5RXhjbHVkaW5nKGNvbmZpZywgaW5zdGFuY2VEZWZhdWx0cyksIHN0YXRpY3MpKTsgLy9zdGF0aWMgbWV0aG9kc1xuXG5cbiAgICAgIF9tZXJnZShQbHVnaW4ucHJvdG90eXBlLCBfbWVyZ2UoaW5zdGFuY2VEZWZhdWx0cywgX2NvcHlFeGNsdWRpbmcoY29uZmlnLCBzdGF0aWNzKSkpOyAvL2luc3RhbmNlIG1ldGhvZHNcblxuXG4gICAgICBfcGx1Z2luc1tQbHVnaW4ucHJvcCA9IG5hbWVdID0gUGx1Z2luO1xuXG4gICAgICBpZiAoY29uZmlnLnRhcmdldFRlc3QpIHtcbiAgICAgICAgX2hhcm5lc3NQbHVnaW5zLnB1c2goUGx1Z2luKTtcblxuICAgICAgICBfcmVzZXJ2ZWRQcm9wc1tuYW1lXSA9IDE7XG4gICAgICB9XG5cbiAgICAgIG5hbWUgPSAobmFtZSA9PT0gXCJjc3NcIiA/IFwiQ1NTXCIgOiBuYW1lLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgbmFtZS5zdWJzdHIoMSkpICsgXCJQbHVnaW5cIjsgLy9mb3IgdGhlIGdsb2JhbCBuYW1lLiBcIm1vdGlvblBhdGhcIiBzaG91bGQgYmVjb21lIE1vdGlvblBhdGhQbHVnaW5cbiAgICB9XG5cbiAgICBfYWRkR2xvYmFsKG5hbWUsIFBsdWdpbik7XG5cbiAgICBjb25maWcucmVnaXN0ZXIgJiYgY29uZmlnLnJlZ2lzdGVyKGdzYXAsIFBsdWdpbiwgUHJvcFR3ZWVuKTtcbiAgfSBlbHNlIHtcbiAgICBfcmVnaXN0ZXJQbHVnaW5RdWV1ZS5wdXNoKGNvbmZpZyk7XG4gIH1cbn0sXG5cbi8qXG4gKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogQ09MT1JTXG4gKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICovXG5fMjU1ID0gMjU1LFxuICAgIF9jb2xvckxvb2t1cCA9IHtcbiAgYXF1YTogWzAsIF8yNTUsIF8yNTVdLFxuICBsaW1lOiBbMCwgXzI1NSwgMF0sXG4gIHNpbHZlcjogWzE5MiwgMTkyLCAxOTJdLFxuICBibGFjazogWzAsIDAsIDBdLFxuICBtYXJvb246IFsxMjgsIDAsIDBdLFxuICB0ZWFsOiBbMCwgMTI4LCAxMjhdLFxuICBibHVlOiBbMCwgMCwgXzI1NV0sXG4gIG5hdnk6IFswLCAwLCAxMjhdLFxuICB3aGl0ZTogW18yNTUsIF8yNTUsIF8yNTVdLFxuICBvbGl2ZTogWzEyOCwgMTI4LCAwXSxcbiAgeWVsbG93OiBbXzI1NSwgXzI1NSwgMF0sXG4gIG9yYW5nZTogW18yNTUsIDE2NSwgMF0sXG4gIGdyYXk6IFsxMjgsIDEyOCwgMTI4XSxcbiAgcHVycGxlOiBbMTI4LCAwLCAxMjhdLFxuICBncmVlbjogWzAsIDEyOCwgMF0sXG4gIHJlZDogW18yNTUsIDAsIDBdLFxuICBwaW5rOiBbXzI1NSwgMTkyLCAyMDNdLFxuICBjeWFuOiBbMCwgXzI1NSwgXzI1NV0sXG4gIHRyYW5zcGFyZW50OiBbXzI1NSwgXzI1NSwgXzI1NSwgMF1cbn0sXG4gICAgLy8gcG9zc2libGUgZnV0dXJlIGlkZWEgdG8gcmVwbGFjZSB0aGUgaGFyZC1jb2RlZCBjb2xvciBuYW1lIHZhbHVlcyAtIHB1dCB0aGlzIGluIHRoZSB0aWNrZXIud2FrZSgpIHdoZXJlIHdlIHNldCB0aGUgX2RvYzpcbi8vIGxldCBjdHggPSBfZG9jLmNyZWF0ZUVsZW1lbnQoXCJjYW52YXNcIikuZ2V0Q29udGV4dChcIjJkXCIpO1xuLy8gX2ZvckVhY2hOYW1lKFwiYXF1YSxsaW1lLHNpbHZlcixibGFjayxtYXJvb24sdGVhbCxibHVlLG5hdnksd2hpdGUsb2xpdmUseWVsbG93LG9yYW5nZSxncmF5LHB1cnBsZSxncmVlbixyZWQscGluayxjeWFuXCIsIGNvbG9yID0+IHtjdHguZmlsbFN0eWxlID0gY29sb3I7IF9jb2xvckxvb2t1cFtjb2xvcl0gPSBzcGxpdENvbG9yKGN0eC5maWxsU3R5bGUpfSk7XG5faHVlID0gZnVuY3Rpb24gX2h1ZShoLCBtMSwgbTIpIHtcbiAgaCArPSBoIDwgMCA/IDEgOiBoID4gMSA/IC0xIDogMDtcbiAgcmV0dXJuIChoICogNiA8IDEgPyBtMSArIChtMiAtIG0xKSAqIGggKiA2IDogaCA8IC41ID8gbTIgOiBoICogMyA8IDIgPyBtMSArIChtMiAtIG0xKSAqICgyIC8gMyAtIGgpICogNiA6IG0xKSAqIF8yNTUgKyAuNSB8IDA7XG59LFxuICAgIHNwbGl0Q29sb3IgPSBmdW5jdGlvbiBzcGxpdENvbG9yKHYsIHRvSFNMLCBmb3JjZUFscGhhKSB7XG4gIHZhciBhID0gIXYgPyBfY29sb3JMb29rdXAuYmxhY2sgOiBfaXNOdW1iZXIodikgPyBbdiA+PiAxNiwgdiA+PiA4ICYgXzI1NSwgdiAmIF8yNTVdIDogMCxcbiAgICAgIHIsXG4gICAgICBnLFxuICAgICAgYixcbiAgICAgIGgsXG4gICAgICBzLFxuICAgICAgbCxcbiAgICAgIG1heCxcbiAgICAgIG1pbixcbiAgICAgIGQsXG4gICAgICB3YXNIU0w7XG5cbiAgaWYgKCFhKSB7XG4gICAgaWYgKHYuc3Vic3RyKC0xKSA9PT0gXCIsXCIpIHtcbiAgICAgIC8vc29tZXRpbWVzIGEgdHJhaWxpbmcgY29tbWEgaXMgaW5jbHVkZWQgYW5kIHdlIHNob3VsZCBjaG9wIGl0IG9mZiAodHlwaWNhbGx5IGZyb20gYSBjb21tYS1kZWxpbWl0ZWQgbGlzdCBvZiB2YWx1ZXMgbGlrZSBhIHRleHRTaGFkb3c6XCIycHggMnB4IDJweCBibHVlLCA1cHggNXB4IDVweCByZ2IoMjU1LDAsMClcIiAtIGluIHRoaXMgZXhhbXBsZSBcImJsdWUsXCIgaGFzIGEgdHJhaWxpbmcgY29tbWEuIFdlIGNvdWxkIHN0cmlwIGl0IG91dCBpbnNpZGUgcGFyc2VDb21wbGV4KCkgYnV0IHdlJ2QgbmVlZCB0byBkbyBpdCB0byB0aGUgYmVnaW5uaW5nIGFuZCBlbmRpbmcgdmFsdWVzIHBsdXMgaXQgd291bGRuJ3QgcHJvdmlkZSBwcm90ZWN0aW9uIGZyb20gb3RoZXIgcG90ZW50aWFsIHNjZW5hcmlvcyBsaWtlIGlmIHRoZSB1c2VyIHBhc3NlcyBpbiBhIHNpbWlsYXIgdmFsdWUuXG4gICAgICB2ID0gdi5zdWJzdHIoMCwgdi5sZW5ndGggLSAxKTtcbiAgICB9XG5cbiAgICBpZiAoX2NvbG9yTG9va3VwW3ZdKSB7XG4gICAgICBhID0gX2NvbG9yTG9va3VwW3ZdO1xuICAgIH0gZWxzZSBpZiAodi5jaGFyQXQoMCkgPT09IFwiI1wiKSB7XG4gICAgICBpZiAodi5sZW5ndGggPCA2KSB7XG4gICAgICAgIC8vZm9yIHNob3J0aGFuZCBsaWtlICM5RjAgb3IgIzlGMEYgKGNvdWxkIGhhdmUgYWxwaGEpXG4gICAgICAgIHIgPSB2LmNoYXJBdCgxKTtcbiAgICAgICAgZyA9IHYuY2hhckF0KDIpO1xuICAgICAgICBiID0gdi5jaGFyQXQoMyk7XG4gICAgICAgIHYgPSBcIiNcIiArIHIgKyByICsgZyArIGcgKyBiICsgYiArICh2Lmxlbmd0aCA9PT0gNSA/IHYuY2hhckF0KDQpICsgdi5jaGFyQXQoNCkgOiBcIlwiKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHYubGVuZ3RoID09PSA5KSB7XG4gICAgICAgIC8vIGhleCB3aXRoIGFscGhhLCBsaWtlICNmZDVlNTNmZlxuICAgICAgICBhID0gcGFyc2VJbnQodi5zdWJzdHIoMSwgNiksIDE2KTtcbiAgICAgICAgcmV0dXJuIFthID4+IDE2LCBhID4+IDggJiBfMjU1LCBhICYgXzI1NSwgcGFyc2VJbnQodi5zdWJzdHIoNyksIDE2KSAvIDI1NV07XG4gICAgICB9XG5cbiAgICAgIHYgPSBwYXJzZUludCh2LnN1YnN0cigxKSwgMTYpO1xuICAgICAgYSA9IFt2ID4+IDE2LCB2ID4+IDggJiBfMjU1LCB2ICYgXzI1NV07XG4gICAgfSBlbHNlIGlmICh2LnN1YnN0cigwLCAzKSA9PT0gXCJoc2xcIikge1xuICAgICAgYSA9IHdhc0hTTCA9IHYubWF0Y2goX3N0cmljdE51bUV4cCk7XG5cbiAgICAgIGlmICghdG9IU0wpIHtcbiAgICAgICAgaCA9ICthWzBdICUgMzYwIC8gMzYwO1xuICAgICAgICBzID0gK2FbMV0gLyAxMDA7XG4gICAgICAgIGwgPSArYVsyXSAvIDEwMDtcbiAgICAgICAgZyA9IGwgPD0gLjUgPyBsICogKHMgKyAxKSA6IGwgKyBzIC0gbCAqIHM7XG4gICAgICAgIHIgPSBsICogMiAtIGc7XG4gICAgICAgIGEubGVuZ3RoID4gMyAmJiAoYVszXSAqPSAxKTsgLy9jYXN0IGFzIG51bWJlclxuXG4gICAgICAgIGFbMF0gPSBfaHVlKGggKyAxIC8gMywgciwgZyk7XG4gICAgICAgIGFbMV0gPSBfaHVlKGgsIHIsIGcpO1xuICAgICAgICBhWzJdID0gX2h1ZShoIC0gMSAvIDMsIHIsIGcpO1xuICAgICAgfSBlbHNlIGlmICh+di5pbmRleE9mKFwiPVwiKSkge1xuICAgICAgICAvL2lmIHJlbGF0aXZlIHZhbHVlcyBhcmUgZm91bmQsIGp1c3QgcmV0dXJuIHRoZSByYXcgc3RyaW5ncyB3aXRoIHRoZSByZWxhdGl2ZSBwcmVmaXhlcyBpbiBwbGFjZS5cbiAgICAgICAgYSA9IHYubWF0Y2goX251bUV4cCk7XG4gICAgICAgIGZvcmNlQWxwaGEgJiYgYS5sZW5ndGggPCA0ICYmIChhWzNdID0gMSk7XG4gICAgICAgIHJldHVybiBhO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBhID0gdi5tYXRjaChfc3RyaWN0TnVtRXhwKSB8fCBfY29sb3JMb29rdXAudHJhbnNwYXJlbnQ7XG4gICAgfVxuXG4gICAgYSA9IGEubWFwKE51bWJlcik7XG4gIH1cblxuICBpZiAodG9IU0wgJiYgIXdhc0hTTCkge1xuICAgIHIgPSBhWzBdIC8gXzI1NTtcbiAgICBnID0gYVsxXSAvIF8yNTU7XG4gICAgYiA9IGFbMl0gLyBfMjU1O1xuICAgIG1heCA9IE1hdGgubWF4KHIsIGcsIGIpO1xuICAgIG1pbiA9IE1hdGgubWluKHIsIGcsIGIpO1xuICAgIGwgPSAobWF4ICsgbWluKSAvIDI7XG5cbiAgICBpZiAobWF4ID09PSBtaW4pIHtcbiAgICAgIGggPSBzID0gMDtcbiAgICB9IGVsc2Uge1xuICAgICAgZCA9IG1heCAtIG1pbjtcbiAgICAgIHMgPSBsID4gMC41ID8gZCAvICgyIC0gbWF4IC0gbWluKSA6IGQgLyAobWF4ICsgbWluKTtcbiAgICAgIGggPSBtYXggPT09IHIgPyAoZyAtIGIpIC8gZCArIChnIDwgYiA/IDYgOiAwKSA6IG1heCA9PT0gZyA/IChiIC0gcikgLyBkICsgMiA6IChyIC0gZykgLyBkICsgNDtcbiAgICAgIGggKj0gNjA7XG4gICAgfVxuXG4gICAgYVswXSA9IH5+KGggKyAuNSk7XG4gICAgYVsxXSA9IH5+KHMgKiAxMDAgKyAuNSk7XG4gICAgYVsyXSA9IH5+KGwgKiAxMDAgKyAuNSk7XG4gIH1cblxuICBmb3JjZUFscGhhICYmIGEubGVuZ3RoIDwgNCAmJiAoYVszXSA9IDEpO1xuICByZXR1cm4gYTtcbn0sXG4gICAgX2NvbG9yT3JkZXJEYXRhID0gZnVuY3Rpb24gX2NvbG9yT3JkZXJEYXRhKHYpIHtcbiAgLy8gc3RyaXBzIG91dCB0aGUgY29sb3JzIGZyb20gdGhlIHN0cmluZywgZmluZHMgYWxsIHRoZSBudW1lcmljIHNsb3RzICh3aXRoIHVuaXRzKSBhbmQgcmV0dXJucyBhbiBhcnJheSBvZiB0aG9zZS4gVGhlIEFycmF5IGFsc28gaGFzIGEgXCJjXCIgcHJvcGVydHkgd2hpY2ggaXMgYW4gQXJyYXkgb2YgdGhlIGluZGV4IHZhbHVlcyB3aGVyZSB0aGUgY29sb3JzIGJlbG9uZy4gVGhpcyBpcyB0byBoZWxwIHdvcmsgYXJvdW5kIGlzc3VlcyB3aGVyZSB0aGVyZSdzIGEgbWlzLW1hdGNoZWQgb3JkZXIgb2YgY29sb3IvbnVtZXJpYyBkYXRhIGxpa2UgZHJvcC1zaGFkb3coI2YwMCAwcHggMXB4IDJweCkgYW5kIGRyb3Atc2hhZG93KDB4IDFweCAycHggI2YwMCkuIFRoaXMgaXMgYmFzaWNhbGx5IGEgaGVscGVyIGZ1bmN0aW9uIHVzZWQgaW4gX2Zvcm1hdENvbG9ycygpXG4gIHZhciB2YWx1ZXMgPSBbXSxcbiAgICAgIGMgPSBbXSxcbiAgICAgIGkgPSAtMTtcbiAgdi5zcGxpdChfY29sb3JFeHApLmZvckVhY2goZnVuY3Rpb24gKHYpIHtcbiAgICB2YXIgYSA9IHYubWF0Y2goX251bVdpdGhVbml0RXhwKSB8fCBbXTtcbiAgICB2YWx1ZXMucHVzaC5hcHBseSh2YWx1ZXMsIGEpO1xuICAgIGMucHVzaChpICs9IGEubGVuZ3RoICsgMSk7XG4gIH0pO1xuICB2YWx1ZXMuYyA9IGM7XG4gIHJldHVybiB2YWx1ZXM7XG59LFxuICAgIF9mb3JtYXRDb2xvcnMgPSBmdW5jdGlvbiBfZm9ybWF0Q29sb3JzKHMsIHRvSFNMLCBvcmRlck1hdGNoRGF0YSkge1xuICB2YXIgcmVzdWx0ID0gXCJcIixcbiAgICAgIGNvbG9ycyA9IChzICsgcmVzdWx0KS5tYXRjaChfY29sb3JFeHApLFxuICAgICAgdHlwZSA9IHRvSFNMID8gXCJoc2xhKFwiIDogXCJyZ2JhKFwiLFxuICAgICAgaSA9IDAsXG4gICAgICBjLFxuICAgICAgc2hlbGwsXG4gICAgICBkLFxuICAgICAgbDtcblxuICBpZiAoIWNvbG9ycykge1xuICAgIHJldHVybiBzO1xuICB9XG5cbiAgY29sb3JzID0gY29sb3JzLm1hcChmdW5jdGlvbiAoY29sb3IpIHtcbiAgICByZXR1cm4gKGNvbG9yID0gc3BsaXRDb2xvcihjb2xvciwgdG9IU0wsIDEpKSAmJiB0eXBlICsgKHRvSFNMID8gY29sb3JbMF0gKyBcIixcIiArIGNvbG9yWzFdICsgXCIlLFwiICsgY29sb3JbMl0gKyBcIiUsXCIgKyBjb2xvclszXSA6IGNvbG9yLmpvaW4oXCIsXCIpKSArIFwiKVwiO1xuICB9KTtcblxuICBpZiAob3JkZXJNYXRjaERhdGEpIHtcbiAgICBkID0gX2NvbG9yT3JkZXJEYXRhKHMpO1xuICAgIGMgPSBvcmRlck1hdGNoRGF0YS5jO1xuXG4gICAgaWYgKGMuam9pbihyZXN1bHQpICE9PSBkLmMuam9pbihyZXN1bHQpKSB7XG4gICAgICBzaGVsbCA9IHMucmVwbGFjZShfY29sb3JFeHAsIFwiMVwiKS5zcGxpdChfbnVtV2l0aFVuaXRFeHApO1xuICAgICAgbCA9IHNoZWxsLmxlbmd0aCAtIDE7XG5cbiAgICAgIGZvciAoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgIHJlc3VsdCArPSBzaGVsbFtpXSArICh+Yy5pbmRleE9mKGkpID8gY29sb3JzLnNoaWZ0KCkgfHwgdHlwZSArIFwiMCwwLDAsMClcIiA6IChkLmxlbmd0aCA/IGQgOiBjb2xvcnMubGVuZ3RoID8gY29sb3JzIDogb3JkZXJNYXRjaERhdGEpLnNoaWZ0KCkpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGlmICghc2hlbGwpIHtcbiAgICBzaGVsbCA9IHMuc3BsaXQoX2NvbG9yRXhwKTtcbiAgICBsID0gc2hlbGwubGVuZ3RoIC0gMTtcblxuICAgIGZvciAoOyBpIDwgbDsgaSsrKSB7XG4gICAgICByZXN1bHQgKz0gc2hlbGxbaV0gKyBjb2xvcnNbaV07XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHJlc3VsdCArIHNoZWxsW2xdO1xufSxcbiAgICBfY29sb3JFeHAgPSBmdW5jdGlvbiAoKSB7XG4gIHZhciBzID0gXCIoPzpcXFxcYig/Oig/OnJnYnxyZ2JhfGhzbHxoc2xhKVxcXFwoLis/XFxcXCkpfFxcXFxCIyg/OlswLTlhLWZdezMsNH0pezEsMn1cXFxcYlwiLFxuICAgICAgLy93ZSdsbCBkeW5hbWljYWxseSBidWlsZCB0aGlzIFJlZ3VsYXIgRXhwcmVzc2lvbiB0byBjb25zZXJ2ZSBmaWxlIHNpemUuIEFmdGVyIGJ1aWxkaW5nIGl0LCBpdCB3aWxsIGJlIGFibGUgdG8gZmluZCByZ2IoKSwgcmdiYSgpLCAjIChoZXhhZGVjaW1hbCksIGFuZCBuYW1lZCBjb2xvciB2YWx1ZXMgbGlrZSByZWQsIGJsdWUsIHB1cnBsZSwgZXRjLixcbiAgcDtcblxuICBmb3IgKHAgaW4gX2NvbG9yTG9va3VwKSB7XG4gICAgcyArPSBcInxcIiArIHAgKyBcIlxcXFxiXCI7XG4gIH1cblxuICByZXR1cm4gbmV3IFJlZ0V4cChzICsgXCIpXCIsIFwiZ2lcIik7XG59KCksXG4gICAgX2hzbEV4cCA9IC9oc2xbYV0/XFwoLyxcbiAgICBfY29sb3JTdHJpbmdGaWx0ZXIgPSBmdW5jdGlvbiBfY29sb3JTdHJpbmdGaWx0ZXIoYSkge1xuICB2YXIgY29tYmluZWQgPSBhLmpvaW4oXCIgXCIpLFxuICAgICAgdG9IU0w7XG4gIF9jb2xvckV4cC5sYXN0SW5kZXggPSAwO1xuXG4gIGlmIChfY29sb3JFeHAudGVzdChjb21iaW5lZCkpIHtcbiAgICB0b0hTTCA9IF9oc2xFeHAudGVzdChjb21iaW5lZCk7XG4gICAgYVsxXSA9IF9mb3JtYXRDb2xvcnMoYVsxXSwgdG9IU0wpO1xuICAgIGFbMF0gPSBfZm9ybWF0Q29sb3JzKGFbMF0sIHRvSFNMLCBfY29sb3JPcmRlckRhdGEoYVsxXSkpOyAvLyBtYWtlIHN1cmUgdGhlIG9yZGVyIG9mIG51bWJlcnMvY29sb3JzIG1hdGNoIHdpdGggdGhlIEVORCB2YWx1ZS5cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG59LFxuXG4vKlxuICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqIFRJQ0tFUlxuICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqL1xuX3RpY2tlckFjdGl2ZSxcbiAgICBfdGlja2VyID0gZnVuY3Rpb24gKCkge1xuICB2YXIgX2dldFRpbWUgPSBEYXRlLm5vdyxcbiAgICAgIF9sYWdUaHJlc2hvbGQgPSA1MDAsXG4gICAgICBfYWRqdXN0ZWRMYWcgPSAzMyxcbiAgICAgIF9zdGFydFRpbWUgPSBfZ2V0VGltZSgpLFxuICAgICAgX2xhc3RVcGRhdGUgPSBfc3RhcnRUaW1lLFxuICAgICAgX2dhcCA9IDEwMDAgLyAyNDAsXG4gICAgICBfbmV4dFRpbWUgPSBfZ2FwLFxuICAgICAgX2xpc3RlbmVycyA9IFtdLFxuICAgICAgX2lkLFxuICAgICAgX3JlcSxcbiAgICAgIF9yYWYsXG4gICAgICBfc2VsZixcbiAgICAgIF9kZWx0YSxcbiAgICAgIF9pLFxuICAgICAgX3RpY2sgPSBmdW5jdGlvbiBfdGljayh2KSB7XG4gICAgdmFyIGVsYXBzZWQgPSBfZ2V0VGltZSgpIC0gX2xhc3RVcGRhdGUsXG4gICAgICAgIG1hbnVhbCA9IHYgPT09IHRydWUsXG4gICAgICAgIG92ZXJsYXAsXG4gICAgICAgIGRpc3BhdGNoLFxuICAgICAgICB0aW1lLFxuICAgICAgICBmcmFtZTtcblxuICAgIChlbGFwc2VkID4gX2xhZ1RocmVzaG9sZCB8fCBlbGFwc2VkIDwgMCkgJiYgKF9zdGFydFRpbWUgKz0gZWxhcHNlZCAtIF9hZGp1c3RlZExhZyk7XG4gICAgX2xhc3RVcGRhdGUgKz0gZWxhcHNlZDtcbiAgICB0aW1lID0gX2xhc3RVcGRhdGUgLSBfc3RhcnRUaW1lO1xuICAgIG92ZXJsYXAgPSB0aW1lIC0gX25leHRUaW1lO1xuXG4gICAgaWYgKG92ZXJsYXAgPiAwIHx8IG1hbnVhbCkge1xuICAgICAgZnJhbWUgPSArK19zZWxmLmZyYW1lO1xuICAgICAgX2RlbHRhID0gdGltZSAtIF9zZWxmLnRpbWUgKiAxMDAwO1xuICAgICAgX3NlbGYudGltZSA9IHRpbWUgPSB0aW1lIC8gMTAwMDtcbiAgICAgIF9uZXh0VGltZSArPSBvdmVybGFwICsgKG92ZXJsYXAgPj0gX2dhcCA/IDQgOiBfZ2FwIC0gb3ZlcmxhcCk7XG4gICAgICBkaXNwYXRjaCA9IDE7XG4gICAgfVxuXG4gICAgbWFudWFsIHx8IChfaWQgPSBfcmVxKF90aWNrKSk7IC8vbWFrZSBzdXJlIHRoZSByZXF1ZXN0IGlzIG1hZGUgYmVmb3JlIHdlIGRpc3BhdGNoIHRoZSBcInRpY2tcIiBldmVudCBzbyB0aGF0IHRpbWluZyBpcyBtYWludGFpbmVkLiBPdGhlcndpc2UsIGlmIHByb2Nlc3NpbmcgdGhlIFwidGlja1wiIHJlcXVpcmVzIGEgYnVuY2ggb2YgdGltZSAobGlrZSAxNW1zKSBhbmQgd2UncmUgdXNpbmcgYSBzZXRUaW1lb3V0KCkgdGhhdCdzIGJhc2VkIG9uIDE2LjdtcywgaXQnZCB0ZWNobmljYWxseSB0YWtlIDMxLjdtcyBiZXR3ZWVuIGZyYW1lcyBvdGhlcndpc2UuXG5cbiAgICBpZiAoZGlzcGF0Y2gpIHtcbiAgICAgIGZvciAoX2kgPSAwOyBfaSA8IF9saXN0ZW5lcnMubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgIC8vIHVzZSBfaSBhbmQgY2hlY2sgX2xpc3RlbmVycy5sZW5ndGggaW5zdGVhZCBvZiBhIHZhcmlhYmxlIGJlY2F1c2UgYSBsaXN0ZW5lciBjb3VsZCBnZXQgcmVtb3ZlZCBkdXJpbmcgdGhlIGxvb3AsIGFuZCBpZiB0aGF0IGhhcHBlbnMgdG8gYW4gZWxlbWVudCBsZXNzIHRoYW4gdGhlIGN1cnJlbnQgaW5kZXgsIGl0J2QgdGhyb3cgdGhpbmdzIG9mZiBpbiB0aGUgbG9vcC5cbiAgICAgICAgX2xpc3RlbmVyc1tfaV0odGltZSwgX2RlbHRhLCBmcmFtZSwgdik7XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIF9zZWxmID0ge1xuICAgIHRpbWU6IDAsXG4gICAgZnJhbWU6IDAsXG4gICAgdGljazogZnVuY3Rpb24gdGljaygpIHtcbiAgICAgIF90aWNrKHRydWUpO1xuICAgIH0sXG4gICAgZGVsdGFSYXRpbzogZnVuY3Rpb24gZGVsdGFSYXRpbyhmcHMpIHtcbiAgICAgIHJldHVybiBfZGVsdGEgLyAoMTAwMCAvIChmcHMgfHwgNjApKTtcbiAgICB9LFxuICAgIHdha2U6IGZ1bmN0aW9uIHdha2UoKSB7XG4gICAgICBpZiAoX2NvcmVSZWFkeSkge1xuICAgICAgICBpZiAoIV9jb3JlSW5pdHRlZCAmJiBfd2luZG93RXhpc3RzKCkpIHtcbiAgICAgICAgICBfd2luID0gX2NvcmVJbml0dGVkID0gd2luZG93O1xuICAgICAgICAgIF9kb2MgPSBfd2luLmRvY3VtZW50IHx8IHt9O1xuICAgICAgICAgIF9nbG9iYWxzLmdzYXAgPSBnc2FwO1xuICAgICAgICAgIChfd2luLmdzYXBWZXJzaW9ucyB8fCAoX3dpbi5nc2FwVmVyc2lvbnMgPSBbXSkpLnB1c2goZ3NhcC52ZXJzaW9uKTtcblxuICAgICAgICAgIF9pbnN0YWxsKF9pbnN0YWxsU2NvcGUgfHwgX3dpbi5HcmVlblNvY2tHbG9iYWxzIHx8ICFfd2luLmdzYXAgJiYgX3dpbiB8fCB7fSk7XG5cbiAgICAgICAgICBfcmVnaXN0ZXJQbHVnaW5RdWV1ZS5mb3JFYWNoKF9jcmVhdGVQbHVnaW4pO1xuICAgICAgICB9XG5cbiAgICAgICAgX3JhZiA9IHR5cGVvZiByZXF1ZXN0QW5pbWF0aW9uRnJhbWUgIT09IFwidW5kZWZpbmVkXCIgJiYgcmVxdWVzdEFuaW1hdGlvbkZyYW1lO1xuICAgICAgICBfaWQgJiYgX3NlbGYuc2xlZXAoKTtcblxuICAgICAgICBfcmVxID0gX3JhZiB8fCBmdW5jdGlvbiAoZikge1xuICAgICAgICAgIHJldHVybiBzZXRUaW1lb3V0KGYsIF9uZXh0VGltZSAtIF9zZWxmLnRpbWUgKiAxMDAwICsgMSB8IDApO1xuICAgICAgICB9O1xuXG4gICAgICAgIF90aWNrZXJBY3RpdmUgPSAxO1xuXG4gICAgICAgIF90aWNrKDIpO1xuICAgICAgfVxuICAgIH0sXG4gICAgc2xlZXA6IGZ1bmN0aW9uIHNsZWVwKCkge1xuICAgICAgKF9yYWYgPyBjYW5jZWxBbmltYXRpb25GcmFtZSA6IGNsZWFyVGltZW91dCkoX2lkKTtcbiAgICAgIF90aWNrZXJBY3RpdmUgPSAwO1xuICAgICAgX3JlcSA9IF9lbXB0eUZ1bmM7XG4gICAgfSxcbiAgICBsYWdTbW9vdGhpbmc6IGZ1bmN0aW9uIGxhZ1Ntb290aGluZyh0aHJlc2hvbGQsIGFkanVzdGVkTGFnKSB7XG4gICAgICBfbGFnVGhyZXNob2xkID0gdGhyZXNob2xkIHx8IEluZmluaXR5OyAvLyB6ZXJvIHNob3VsZCBiZSBpbnRlcnByZXRlZCBhcyBiYXNpY2FsbHkgdW5saW1pdGVkXG5cbiAgICAgIF9hZGp1c3RlZExhZyA9IE1hdGgubWluKGFkanVzdGVkTGFnIHx8IDMzLCBfbGFnVGhyZXNob2xkKTtcbiAgICB9LFxuICAgIGZwczogZnVuY3Rpb24gZnBzKF9mcHMpIHtcbiAgICAgIF9nYXAgPSAxMDAwIC8gKF9mcHMgfHwgMjQwKTtcbiAgICAgIF9uZXh0VGltZSA9IF9zZWxmLnRpbWUgKiAxMDAwICsgX2dhcDtcbiAgICB9LFxuICAgIGFkZDogZnVuY3Rpb24gYWRkKGNhbGxiYWNrLCBvbmNlLCBwcmlvcml0aXplKSB7XG4gICAgICB2YXIgZnVuYyA9IG9uY2UgPyBmdW5jdGlvbiAodCwgZCwgZiwgdikge1xuICAgICAgICBjYWxsYmFjayh0LCBkLCBmLCB2KTtcblxuICAgICAgICBfc2VsZi5yZW1vdmUoZnVuYyk7XG4gICAgICB9IDogY2FsbGJhY2s7XG5cbiAgICAgIF9zZWxmLnJlbW92ZShjYWxsYmFjayk7XG5cbiAgICAgIF9saXN0ZW5lcnNbcHJpb3JpdGl6ZSA/IFwidW5zaGlmdFwiIDogXCJwdXNoXCJdKGZ1bmMpO1xuXG4gICAgICBfd2FrZSgpO1xuXG4gICAgICByZXR1cm4gZnVuYztcbiAgICB9LFxuICAgIHJlbW92ZTogZnVuY3Rpb24gcmVtb3ZlKGNhbGxiYWNrLCBpKSB7XG4gICAgICB+KGkgPSBfbGlzdGVuZXJzLmluZGV4T2YoY2FsbGJhY2spKSAmJiBfbGlzdGVuZXJzLnNwbGljZShpLCAxKSAmJiBfaSA+PSBpICYmIF9pLS07XG4gICAgfSxcbiAgICBfbGlzdGVuZXJzOiBfbGlzdGVuZXJzXG4gIH07XG4gIHJldHVybiBfc2VsZjtcbn0oKSxcbiAgICBfd2FrZSA9IGZ1bmN0aW9uIF93YWtlKCkge1xuICByZXR1cm4gIV90aWNrZXJBY3RpdmUgJiYgX3RpY2tlci53YWtlKCk7XG59LFxuICAgIC8vYWxzbyBlbnN1cmVzIHRoZSBjb3JlIGNsYXNzZXMgYXJlIGluaXRpYWxpemVkLlxuXG4vKlxuKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4qIEVBU0lOR1xuKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4qL1xuX2Vhc2VNYXAgPSB7fSxcbiAgICBfY3VzdG9tRWFzZUV4cCA9IC9eW1xcZC5cXC1NXVtcXGQuXFwtLFxcc10vLFxuICAgIF9xdW90ZXNFeHAgPSAvW1wiJ10vZyxcbiAgICBfcGFyc2VPYmplY3RJblN0cmluZyA9IGZ1bmN0aW9uIF9wYXJzZU9iamVjdEluU3RyaW5nKHZhbHVlKSB7XG4gIC8vdGFrZXMgYSBzdHJpbmcgbGlrZSBcInt3aWdnbGVzOjEwLCB0eXBlOmFudGljaXBhdGV9KVwiIGFuZCB0dXJucyBpdCBpbnRvIGEgcmVhbCBvYmplY3QuIE5vdGljZSBpdCBlbmRzIGluIFwiKVwiIGFuZCBpbmNsdWRlcyB0aGUge30gd3JhcHBlcnMuIFRoaXMgaXMgYmVjYXVzZSB3ZSBvbmx5IHVzZSB0aGlzIGZ1bmN0aW9uIGZvciBwYXJzaW5nIGVhc2UgY29uZmlncyBhbmQgcHJpb3JpdGl6ZWQgb3B0aW1pemF0aW9uIHJhdGhlciB0aGFuIHJldXNhYmlsaXR5LlxuICB2YXIgb2JqID0ge30sXG4gICAgICBzcGxpdCA9IHZhbHVlLnN1YnN0cigxLCB2YWx1ZS5sZW5ndGggLSAzKS5zcGxpdChcIjpcIiksXG4gICAgICBrZXkgPSBzcGxpdFswXSxcbiAgICAgIGkgPSAxLFxuICAgICAgbCA9IHNwbGl0Lmxlbmd0aCxcbiAgICAgIGluZGV4LFxuICAgICAgdmFsLFxuICAgICAgcGFyc2VkVmFsO1xuXG4gIGZvciAoOyBpIDwgbDsgaSsrKSB7XG4gICAgdmFsID0gc3BsaXRbaV07XG4gICAgaW5kZXggPSBpICE9PSBsIC0gMSA/IHZhbC5sYXN0SW5kZXhPZihcIixcIikgOiB2YWwubGVuZ3RoO1xuICAgIHBhcnNlZFZhbCA9IHZhbC5zdWJzdHIoMCwgaW5kZXgpO1xuICAgIG9ialtrZXldID0gaXNOYU4ocGFyc2VkVmFsKSA/IHBhcnNlZFZhbC5yZXBsYWNlKF9xdW90ZXNFeHAsIFwiXCIpLnRyaW0oKSA6ICtwYXJzZWRWYWw7XG4gICAga2V5ID0gdmFsLnN1YnN0cihpbmRleCArIDEpLnRyaW0oKTtcbiAgfVxuXG4gIHJldHVybiBvYmo7XG59LFxuICAgIF92YWx1ZUluUGFyZW50aGVzZXMgPSBmdW5jdGlvbiBfdmFsdWVJblBhcmVudGhlc2VzKHZhbHVlKSB7XG4gIHZhciBvcGVuID0gdmFsdWUuaW5kZXhPZihcIihcIikgKyAxLFxuICAgICAgY2xvc2UgPSB2YWx1ZS5pbmRleE9mKFwiKVwiKSxcbiAgICAgIG5lc3RlZCA9IHZhbHVlLmluZGV4T2YoXCIoXCIsIG9wZW4pO1xuICByZXR1cm4gdmFsdWUuc3Vic3RyaW5nKG9wZW4sIH5uZXN0ZWQgJiYgbmVzdGVkIDwgY2xvc2UgPyB2YWx1ZS5pbmRleE9mKFwiKVwiLCBjbG9zZSArIDEpIDogY2xvc2UpO1xufSxcbiAgICBfY29uZmlnRWFzZUZyb21TdHJpbmcgPSBmdW5jdGlvbiBfY29uZmlnRWFzZUZyb21TdHJpbmcobmFtZSkge1xuICAvL25hbWUgY2FuIGJlIGEgc3RyaW5nIGxpa2UgXCJlbGFzdGljLm91dCgxLDAuNSlcIiwgYW5kIHBhc3MgaW4gX2Vhc2VNYXAgYXMgb2JqIGFuZCBpdCdsbCBwYXJzZSBpdCBvdXQgYW5kIGNhbGwgdGhlIGFjdHVhbCBmdW5jdGlvbiBsaWtlIF9lYXNlTWFwLkVsYXN0aWMuZWFzZU91dC5jb25maWcoMSwwLjUpLiBJdCB3aWxsIGFsc28gcGFyc2UgY3VzdG9tIGVhc2Ugc3RyaW5ncyBhcyBsb25nIGFzIEN1c3RvbUVhc2UgaXMgbG9hZGVkIGFuZCByZWdpc3RlcmVkIChpbnRlcm5hbGx5IGFzIF9lYXNlTWFwLl9DRSkuXG4gIHZhciBzcGxpdCA9IChuYW1lICsgXCJcIikuc3BsaXQoXCIoXCIpLFxuICAgICAgZWFzZSA9IF9lYXNlTWFwW3NwbGl0WzBdXTtcbiAgcmV0dXJuIGVhc2UgJiYgc3BsaXQubGVuZ3RoID4gMSAmJiBlYXNlLmNvbmZpZyA/IGVhc2UuY29uZmlnLmFwcGx5KG51bGwsIH5uYW1lLmluZGV4T2YoXCJ7XCIpID8gW19wYXJzZU9iamVjdEluU3RyaW5nKHNwbGl0WzFdKV0gOiBfdmFsdWVJblBhcmVudGhlc2VzKG5hbWUpLnNwbGl0KFwiLFwiKS5tYXAoX251bWVyaWNJZlBvc3NpYmxlKSkgOiBfZWFzZU1hcC5fQ0UgJiYgX2N1c3RvbUVhc2VFeHAudGVzdChuYW1lKSA/IF9lYXNlTWFwLl9DRShcIlwiLCBuYW1lKSA6IGVhc2U7XG59LFxuICAgIF9pbnZlcnRFYXNlID0gZnVuY3Rpb24gX2ludmVydEVhc2UoZWFzZSkge1xuICByZXR1cm4gZnVuY3Rpb24gKHApIHtcbiAgICByZXR1cm4gMSAtIGVhc2UoMSAtIHApO1xuICB9O1xufSxcbiAgICAvLyBhbGxvdyB5b3lvRWFzZSB0byBiZSBzZXQgaW4gY2hpbGRyZW4gYW5kIGhhdmUgdGhvc2UgYWZmZWN0ZWQgd2hlbiB0aGUgcGFyZW50L2FuY2VzdG9yIHRpbWVsaW5lIHlveW9zLlxuX3Byb3BhZ2F0ZVlveW9FYXNlID0gZnVuY3Rpb24gX3Byb3BhZ2F0ZVlveW9FYXNlKHRpbWVsaW5lLCBpc1lveW8pIHtcbiAgdmFyIGNoaWxkID0gdGltZWxpbmUuX2ZpcnN0LFxuICAgICAgZWFzZTtcblxuICB3aGlsZSAoY2hpbGQpIHtcbiAgICBpZiAoY2hpbGQgaW5zdGFuY2VvZiBUaW1lbGluZSkge1xuICAgICAgX3Byb3BhZ2F0ZVlveW9FYXNlKGNoaWxkLCBpc1lveW8pO1xuICAgIH0gZWxzZSBpZiAoY2hpbGQudmFycy55b3lvRWFzZSAmJiAoIWNoaWxkLl95b3lvIHx8ICFjaGlsZC5fcmVwZWF0KSAmJiBjaGlsZC5feW95byAhPT0gaXNZb3lvKSB7XG4gICAgICBpZiAoY2hpbGQudGltZWxpbmUpIHtcbiAgICAgICAgX3Byb3BhZ2F0ZVlveW9FYXNlKGNoaWxkLnRpbWVsaW5lLCBpc1lveW8pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZWFzZSA9IGNoaWxkLl9lYXNlO1xuICAgICAgICBjaGlsZC5fZWFzZSA9IGNoaWxkLl95RWFzZTtcbiAgICAgICAgY2hpbGQuX3lFYXNlID0gZWFzZTtcbiAgICAgICAgY2hpbGQuX3lveW8gPSBpc1lveW87XG4gICAgICB9XG4gICAgfVxuXG4gICAgY2hpbGQgPSBjaGlsZC5fbmV4dDtcbiAgfVxufSxcbiAgICBfcGFyc2VFYXNlID0gZnVuY3Rpb24gX3BhcnNlRWFzZShlYXNlLCBkZWZhdWx0RWFzZSkge1xuICByZXR1cm4gIWVhc2UgPyBkZWZhdWx0RWFzZSA6IChfaXNGdW5jdGlvbihlYXNlKSA/IGVhc2UgOiBfZWFzZU1hcFtlYXNlXSB8fCBfY29uZmlnRWFzZUZyb21TdHJpbmcoZWFzZSkpIHx8IGRlZmF1bHRFYXNlO1xufSxcbiAgICBfaW5zZXJ0RWFzZSA9IGZ1bmN0aW9uIF9pbnNlcnRFYXNlKG5hbWVzLCBlYXNlSW4sIGVhc2VPdXQsIGVhc2VJbk91dCkge1xuICBpZiAoZWFzZU91dCA9PT0gdm9pZCAwKSB7XG4gICAgZWFzZU91dCA9IGZ1bmN0aW9uIGVhc2VPdXQocCkge1xuICAgICAgcmV0dXJuIDEgLSBlYXNlSW4oMSAtIHApO1xuICAgIH07XG4gIH1cblxuICBpZiAoZWFzZUluT3V0ID09PSB2b2lkIDApIHtcbiAgICBlYXNlSW5PdXQgPSBmdW5jdGlvbiBlYXNlSW5PdXQocCkge1xuICAgICAgcmV0dXJuIHAgPCAuNSA/IGVhc2VJbihwICogMikgLyAyIDogMSAtIGVhc2VJbigoMSAtIHApICogMikgLyAyO1xuICAgIH07XG4gIH1cblxuICB2YXIgZWFzZSA9IHtcbiAgICBlYXNlSW46IGVhc2VJbixcbiAgICBlYXNlT3V0OiBlYXNlT3V0LFxuICAgIGVhc2VJbk91dDogZWFzZUluT3V0XG4gIH0sXG4gICAgICBsb3dlcmNhc2VOYW1lO1xuXG4gIF9mb3JFYWNoTmFtZShuYW1lcywgZnVuY3Rpb24gKG5hbWUpIHtcbiAgICBfZWFzZU1hcFtuYW1lXSA9IF9nbG9iYWxzW25hbWVdID0gZWFzZTtcbiAgICBfZWFzZU1hcFtsb3dlcmNhc2VOYW1lID0gbmFtZS50b0xvd2VyQ2FzZSgpXSA9IGVhc2VPdXQ7XG5cbiAgICBmb3IgKHZhciBwIGluIGVhc2UpIHtcbiAgICAgIF9lYXNlTWFwW2xvd2VyY2FzZU5hbWUgKyAocCA9PT0gXCJlYXNlSW5cIiA/IFwiLmluXCIgOiBwID09PSBcImVhc2VPdXRcIiA/IFwiLm91dFwiIDogXCIuaW5PdXRcIildID0gX2Vhc2VNYXBbbmFtZSArIFwiLlwiICsgcF0gPSBlYXNlW3BdO1xuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIGVhc2U7XG59LFxuICAgIF9lYXNlSW5PdXRGcm9tT3V0ID0gZnVuY3Rpb24gX2Vhc2VJbk91dEZyb21PdXQoZWFzZU91dCkge1xuICByZXR1cm4gZnVuY3Rpb24gKHApIHtcbiAgICByZXR1cm4gcCA8IC41ID8gKDEgLSBlYXNlT3V0KDEgLSBwICogMikpIC8gMiA6IC41ICsgZWFzZU91dCgocCAtIC41KSAqIDIpIC8gMjtcbiAgfTtcbn0sXG4gICAgX2NvbmZpZ0VsYXN0aWMgPSBmdW5jdGlvbiBfY29uZmlnRWxhc3RpYyh0eXBlLCBhbXBsaXR1ZGUsIHBlcmlvZCkge1xuICB2YXIgcDEgPSBhbXBsaXR1ZGUgPj0gMSA/IGFtcGxpdHVkZSA6IDEsXG4gICAgICAvL25vdGU6IGlmIGFtcGxpdHVkZSBpcyA8IDEsIHdlIHNpbXBseSBhZGp1c3QgdGhlIHBlcmlvZCBmb3IgYSBtb3JlIG5hdHVyYWwgZmVlbC4gT3RoZXJ3aXNlIHRoZSBtYXRoIGRvZXNuJ3Qgd29yayByaWdodCBhbmQgdGhlIGN1cnZlIHN0YXJ0cyBhdCAxLlxuICBwMiA9IChwZXJpb2QgfHwgKHR5cGUgPyAuMyA6IC40NSkpIC8gKGFtcGxpdHVkZSA8IDEgPyBhbXBsaXR1ZGUgOiAxKSxcbiAgICAgIHAzID0gcDIgLyBfMlBJICogKE1hdGguYXNpbigxIC8gcDEpIHx8IDApLFxuICAgICAgZWFzZU91dCA9IGZ1bmN0aW9uIGVhc2VPdXQocCkge1xuICAgIHJldHVybiBwID09PSAxID8gMSA6IHAxICogTWF0aC5wb3coMiwgLTEwICogcCkgKiBfc2luKChwIC0gcDMpICogcDIpICsgMTtcbiAgfSxcbiAgICAgIGVhc2UgPSB0eXBlID09PSBcIm91dFwiID8gZWFzZU91dCA6IHR5cGUgPT09IFwiaW5cIiA/IGZ1bmN0aW9uIChwKSB7XG4gICAgcmV0dXJuIDEgLSBlYXNlT3V0KDEgLSBwKTtcbiAgfSA6IF9lYXNlSW5PdXRGcm9tT3V0KGVhc2VPdXQpO1xuXG4gIHAyID0gXzJQSSAvIHAyOyAvL3ByZWNhbGN1bGF0ZSB0byBvcHRpbWl6ZVxuXG4gIGVhc2UuY29uZmlnID0gZnVuY3Rpb24gKGFtcGxpdHVkZSwgcGVyaW9kKSB7XG4gICAgcmV0dXJuIF9jb25maWdFbGFzdGljKHR5cGUsIGFtcGxpdHVkZSwgcGVyaW9kKTtcbiAgfTtcblxuICByZXR1cm4gZWFzZTtcbn0sXG4gICAgX2NvbmZpZ0JhY2sgPSBmdW5jdGlvbiBfY29uZmlnQmFjayh0eXBlLCBvdmVyc2hvb3QpIHtcbiAgaWYgKG92ZXJzaG9vdCA9PT0gdm9pZCAwKSB7XG4gICAgb3ZlcnNob290ID0gMS43MDE1ODtcbiAgfVxuXG4gIHZhciBlYXNlT3V0ID0gZnVuY3Rpb24gZWFzZU91dChwKSB7XG4gICAgcmV0dXJuIHAgPyAtLXAgKiBwICogKChvdmVyc2hvb3QgKyAxKSAqIHAgKyBvdmVyc2hvb3QpICsgMSA6IDA7XG4gIH0sXG4gICAgICBlYXNlID0gdHlwZSA9PT0gXCJvdXRcIiA/IGVhc2VPdXQgOiB0eXBlID09PSBcImluXCIgPyBmdW5jdGlvbiAocCkge1xuICAgIHJldHVybiAxIC0gZWFzZU91dCgxIC0gcCk7XG4gIH0gOiBfZWFzZUluT3V0RnJvbU91dChlYXNlT3V0KTtcblxuICBlYXNlLmNvbmZpZyA9IGZ1bmN0aW9uIChvdmVyc2hvb3QpIHtcbiAgICByZXR1cm4gX2NvbmZpZ0JhY2sodHlwZSwgb3ZlcnNob290KTtcbiAgfTtcblxuICByZXR1cm4gZWFzZTtcbn07IC8vIGEgY2hlYXBlciAoa2IgYW5kIGNwdSkgYnV0IG1vcmUgbWlsZCB3YXkgdG8gZ2V0IGEgcGFyYW1ldGVyaXplZCB3ZWlnaHRlZCBlYXNlIGJ5IGZlZWRpbmcgaW4gYSB2YWx1ZSBiZXR3ZWVuIC0xIChlYXNlSW4pIGFuZCAxIChlYXNlT3V0KSB3aGVyZSAwIGlzIGxpbmVhci5cbi8vIF93ZWlnaHRlZEVhc2UgPSByYXRpbyA9PiB7XG4vLyBcdGxldCB5ID0gMC41ICsgcmF0aW8gLyAyO1xuLy8gXHRyZXR1cm4gcCA9PiAoMiAqICgxIC0gcCkgKiBwICogeSArIHAgKiBwKTtcbi8vIH0sXG4vLyBhIHN0cm9uZ2VyIChidXQgbW9yZSBleHBlbnNpdmUga2IvY3B1KSBwYXJhbWV0ZXJpemVkIHdlaWdodGVkIGVhc2UgdGhhdCBsZXRzIHlvdSBmZWVkIGluIGEgdmFsdWUgYmV0d2VlbiAtMSAoZWFzZUluKSBhbmQgMSAoZWFzZU91dCkgd2hlcmUgMCBpcyBsaW5lYXIuXG4vLyBfd2VpZ2h0ZWRFYXNlU3Ryb25nID0gcmF0aW8gPT4ge1xuLy8gXHRyYXRpbyA9IC41ICsgcmF0aW8gLyAyO1xuLy8gXHRsZXQgbyA9IDEgLyAzICogKHJhdGlvIDwgLjUgPyByYXRpbyA6IDEgLSByYXRpbyksXG4vLyBcdFx0YiA9IHJhdGlvIC0gbyxcbi8vIFx0XHRjID0gcmF0aW8gKyBvO1xuLy8gXHRyZXR1cm4gcCA9PiBwID09PSAxID8gcCA6IDMgKiBiICogKDEgLSBwKSAqICgxIC0gcCkgKiBwICsgMyAqIGMgKiAoMSAtIHApICogcCAqIHAgKyBwICogcCAqIHA7XG4vLyB9O1xuXG5cbl9mb3JFYWNoTmFtZShcIkxpbmVhcixRdWFkLEN1YmljLFF1YXJ0LFF1aW50LFN0cm9uZ1wiLCBmdW5jdGlvbiAobmFtZSwgaSkge1xuICB2YXIgcG93ZXIgPSBpIDwgNSA/IGkgKyAxIDogaTtcblxuICBfaW5zZXJ0RWFzZShuYW1lICsgXCIsUG93ZXJcIiArIChwb3dlciAtIDEpLCBpID8gZnVuY3Rpb24gKHApIHtcbiAgICByZXR1cm4gTWF0aC5wb3cocCwgcG93ZXIpO1xuICB9IDogZnVuY3Rpb24gKHApIHtcbiAgICByZXR1cm4gcDtcbiAgfSwgZnVuY3Rpb24gKHApIHtcbiAgICByZXR1cm4gMSAtIE1hdGgucG93KDEgLSBwLCBwb3dlcik7XG4gIH0sIGZ1bmN0aW9uIChwKSB7XG4gICAgcmV0dXJuIHAgPCAuNSA/IE1hdGgucG93KHAgKiAyLCBwb3dlcikgLyAyIDogMSAtIE1hdGgucG93KCgxIC0gcCkgKiAyLCBwb3dlcikgLyAyO1xuICB9KTtcbn0pO1xuXG5fZWFzZU1hcC5MaW5lYXIuZWFzZU5vbmUgPSBfZWFzZU1hcC5ub25lID0gX2Vhc2VNYXAuTGluZWFyLmVhc2VJbjtcblxuX2luc2VydEVhc2UoXCJFbGFzdGljXCIsIF9jb25maWdFbGFzdGljKFwiaW5cIiksIF9jb25maWdFbGFzdGljKFwib3V0XCIpLCBfY29uZmlnRWxhc3RpYygpKTtcblxuKGZ1bmN0aW9uIChuLCBjKSB7XG4gIHZhciBuMSA9IDEgLyBjLFxuICAgICAgbjIgPSAyICogbjEsXG4gICAgICBuMyA9IDIuNSAqIG4xLFxuICAgICAgZWFzZU91dCA9IGZ1bmN0aW9uIGVhc2VPdXQocCkge1xuICAgIHJldHVybiBwIDwgbjEgPyBuICogcCAqIHAgOiBwIDwgbjIgPyBuICogTWF0aC5wb3cocCAtIDEuNSAvIGMsIDIpICsgLjc1IDogcCA8IG4zID8gbiAqIChwIC09IDIuMjUgLyBjKSAqIHAgKyAuOTM3NSA6IG4gKiBNYXRoLnBvdyhwIC0gMi42MjUgLyBjLCAyKSArIC45ODQzNzU7XG4gIH07XG5cbiAgX2luc2VydEVhc2UoXCJCb3VuY2VcIiwgZnVuY3Rpb24gKHApIHtcbiAgICByZXR1cm4gMSAtIGVhc2VPdXQoMSAtIHApO1xuICB9LCBlYXNlT3V0KTtcbn0pKDcuNTYyNSwgMi43NSk7XG5cbl9pbnNlcnRFYXNlKFwiRXhwb1wiLCBmdW5jdGlvbiAocCkge1xuICByZXR1cm4gcCA/IE1hdGgucG93KDIsIDEwICogKHAgLSAxKSkgOiAwO1xufSk7XG5cbl9pbnNlcnRFYXNlKFwiQ2lyY1wiLCBmdW5jdGlvbiAocCkge1xuICByZXR1cm4gLShfc3FydCgxIC0gcCAqIHApIC0gMSk7XG59KTtcblxuX2luc2VydEVhc2UoXCJTaW5lXCIsIGZ1bmN0aW9uIChwKSB7XG4gIHJldHVybiBwID09PSAxID8gMSA6IC1fY29zKHAgKiBfSEFMRl9QSSkgKyAxO1xufSk7XG5cbl9pbnNlcnRFYXNlKFwiQmFja1wiLCBfY29uZmlnQmFjayhcImluXCIpLCBfY29uZmlnQmFjayhcIm91dFwiKSwgX2NvbmZpZ0JhY2soKSk7XG5cbl9lYXNlTWFwLlN0ZXBwZWRFYXNlID0gX2Vhc2VNYXAuc3RlcHMgPSBfZ2xvYmFscy5TdGVwcGVkRWFzZSA9IHtcbiAgY29uZmlnOiBmdW5jdGlvbiBjb25maWcoc3RlcHMsIGltbWVkaWF0ZVN0YXJ0KSB7XG4gICAgaWYgKHN0ZXBzID09PSB2b2lkIDApIHtcbiAgICAgIHN0ZXBzID0gMTtcbiAgICB9XG5cbiAgICB2YXIgcDEgPSAxIC8gc3RlcHMsXG4gICAgICAgIHAyID0gc3RlcHMgKyAoaW1tZWRpYXRlU3RhcnQgPyAwIDogMSksXG4gICAgICAgIHAzID0gaW1tZWRpYXRlU3RhcnQgPyAxIDogMCxcbiAgICAgICAgbWF4ID0gMSAtIF90aW55TnVtO1xuICAgIHJldHVybiBmdW5jdGlvbiAocCkge1xuICAgICAgcmV0dXJuICgocDIgKiBfY2xhbXAoMCwgbWF4LCBwKSB8IDApICsgcDMpICogcDE7XG4gICAgfTtcbiAgfVxufTtcbl9kZWZhdWx0cy5lYXNlID0gX2Vhc2VNYXBbXCJxdWFkLm91dFwiXTtcblxuX2ZvckVhY2hOYW1lKFwib25Db21wbGV0ZSxvblVwZGF0ZSxvblN0YXJ0LG9uUmVwZWF0LG9uUmV2ZXJzZUNvbXBsZXRlLG9uSW50ZXJydXB0XCIsIGZ1bmN0aW9uIChuYW1lKSB7XG4gIHJldHVybiBfY2FsbGJhY2tOYW1lcyArPSBuYW1lICsgXCIsXCIgKyBuYW1lICsgXCJQYXJhbXMsXCI7XG59KTtcbi8qXG4gKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogQ0FDSEVcbiAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKi9cblxuXG5leHBvcnQgdmFyIEdTQ2FjaGUgPSBmdW5jdGlvbiBHU0NhY2hlKHRhcmdldCwgaGFybmVzcykge1xuICB0aGlzLmlkID0gX2dzSUQrKztcbiAgdGFyZ2V0Ll9nc2FwID0gdGhpcztcbiAgdGhpcy50YXJnZXQgPSB0YXJnZXQ7XG4gIHRoaXMuaGFybmVzcyA9IGhhcm5lc3M7XG4gIHRoaXMuZ2V0ID0gaGFybmVzcyA/IGhhcm5lc3MuZ2V0IDogX2dldFByb3BlcnR5O1xuICB0aGlzLnNldCA9IGhhcm5lc3MgPyBoYXJuZXNzLmdldFNldHRlciA6IF9nZXRTZXR0ZXI7XG59O1xuLypcbiAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiBBTklNQVRJT05cbiAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKi9cblxuZXhwb3J0IHZhciBBbmltYXRpb24gPSAvKiNfX1BVUkVfXyovZnVuY3Rpb24gKCkge1xuICBmdW5jdGlvbiBBbmltYXRpb24odmFycykge1xuICAgIHRoaXMudmFycyA9IHZhcnM7XG4gICAgdGhpcy5fZGVsYXkgPSArdmFycy5kZWxheSB8fCAwO1xuXG4gICAgaWYgKHRoaXMuX3JlcGVhdCA9IHZhcnMucmVwZWF0ID09PSBJbmZpbml0eSA/IC0yIDogdmFycy5yZXBlYXQgfHwgMCkge1xuICAgICAgLy8gVE9ETzogcmVwZWF0OiBJbmZpbml0eSBvbiBhIHRpbWVsaW5lJ3MgY2hpbGRyZW4gbXVzdCBmbGFnIHRoYXQgdGltZWxpbmUgaW50ZXJuYWxseSBhbmQgYWZmZWN0IGl0cyB0b3RhbER1cmF0aW9uLCBvdGhlcndpc2UgaXQnbGwgc3RvcCBpbiB0aGUgbmVnYXRpdmUgZGlyZWN0aW9uIHdoZW4gcmVhY2hpbmcgdGhlIHN0YXJ0LlxuICAgICAgdGhpcy5fckRlbGF5ID0gdmFycy5yZXBlYXREZWxheSB8fCAwO1xuICAgICAgdGhpcy5feW95byA9ICEhdmFycy55b3lvIHx8ICEhdmFycy55b3lvRWFzZTtcbiAgICB9XG5cbiAgICB0aGlzLl90cyA9IDE7XG5cbiAgICBfc2V0RHVyYXRpb24odGhpcywgK3ZhcnMuZHVyYXRpb24sIDEsIDEpO1xuXG4gICAgdGhpcy5kYXRhID0gdmFycy5kYXRhO1xuXG4gICAgaWYgKF9jb250ZXh0KSB7XG4gICAgICB0aGlzLl9jdHggPSBfY29udGV4dDtcblxuICAgICAgX2NvbnRleHQuZGF0YS5wdXNoKHRoaXMpO1xuICAgIH1cblxuICAgIF90aWNrZXJBY3RpdmUgfHwgX3RpY2tlci53YWtlKCk7XG4gIH1cblxuICB2YXIgX3Byb3RvID0gQW5pbWF0aW9uLnByb3RvdHlwZTtcblxuICBfcHJvdG8uZGVsYXkgPSBmdW5jdGlvbiBkZWxheSh2YWx1ZSkge1xuICAgIGlmICh2YWx1ZSB8fCB2YWx1ZSA9PT0gMCkge1xuICAgICAgdGhpcy5wYXJlbnQgJiYgdGhpcy5wYXJlbnQuc21vb3RoQ2hpbGRUaW1pbmcgJiYgdGhpcy5zdGFydFRpbWUodGhpcy5fc3RhcnQgKyB2YWx1ZSAtIHRoaXMuX2RlbGF5KTtcbiAgICAgIHRoaXMuX2RlbGF5ID0gdmFsdWU7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5fZGVsYXk7XG4gIH07XG5cbiAgX3Byb3RvLmR1cmF0aW9uID0gZnVuY3Rpb24gZHVyYXRpb24odmFsdWUpIHtcbiAgICByZXR1cm4gYXJndW1lbnRzLmxlbmd0aCA/IHRoaXMudG90YWxEdXJhdGlvbih0aGlzLl9yZXBlYXQgPiAwID8gdmFsdWUgKyAodmFsdWUgKyB0aGlzLl9yRGVsYXkpICogdGhpcy5fcmVwZWF0IDogdmFsdWUpIDogdGhpcy50b3RhbER1cmF0aW9uKCkgJiYgdGhpcy5fZHVyO1xuICB9O1xuXG4gIF9wcm90by50b3RhbER1cmF0aW9uID0gZnVuY3Rpb24gdG90YWxEdXJhdGlvbih2YWx1ZSkge1xuICAgIGlmICghYXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgcmV0dXJuIHRoaXMuX3REdXI7XG4gICAgfVxuXG4gICAgdGhpcy5fZGlydHkgPSAwO1xuICAgIHJldHVybiBfc2V0RHVyYXRpb24odGhpcywgdGhpcy5fcmVwZWF0IDwgMCA/IHZhbHVlIDogKHZhbHVlIC0gdGhpcy5fcmVwZWF0ICogdGhpcy5fckRlbGF5KSAvICh0aGlzLl9yZXBlYXQgKyAxKSk7XG4gIH07XG5cbiAgX3Byb3RvLnRvdGFsVGltZSA9IGZ1bmN0aW9uIHRvdGFsVGltZShfdG90YWxUaW1lLCBzdXBwcmVzc0V2ZW50cykge1xuICAgIF93YWtlKCk7XG5cbiAgICBpZiAoIWFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgIHJldHVybiB0aGlzLl90VGltZTtcbiAgICB9XG5cbiAgICB2YXIgcGFyZW50ID0gdGhpcy5fZHA7XG5cbiAgICBpZiAocGFyZW50ICYmIHBhcmVudC5zbW9vdGhDaGlsZFRpbWluZyAmJiB0aGlzLl90cykge1xuICAgICAgX2FsaWduUGxheWhlYWQodGhpcywgX3RvdGFsVGltZSk7XG5cbiAgICAgICFwYXJlbnQuX2RwIHx8IHBhcmVudC5wYXJlbnQgfHwgX3Bvc3RBZGRDaGVja3MocGFyZW50LCB0aGlzKTsgLy8gZWRnZSBjYXNlOiBpZiB0aGlzIGlzIGEgY2hpbGQgb2YgYSB0aW1lbGluZSB0aGF0IGFscmVhZHkgY29tcGxldGVkLCBmb3IgZXhhbXBsZSwgd2UgbXVzdCByZS1hY3RpdmF0ZSB0aGUgcGFyZW50LlxuICAgICAgLy9pbiBjYXNlIGFueSBvZiB0aGUgYW5jZXN0b3IgdGltZWxpbmVzIGhhZCBjb21wbGV0ZWQgYnV0IHNob3VsZCBub3cgYmUgZW5hYmxlZCwgd2Ugc2hvdWxkIHJlc2V0IHRoZWlyIHRvdGFsVGltZSgpIHdoaWNoIHdpbGwgYWxzbyBlbnN1cmUgdGhhdCB0aGV5J3JlIGxpbmVkIHVwIHByb3Blcmx5IGFuZCBlbmFibGVkLiBTa2lwIGZvciBhbmltYXRpb25zIHRoYXQgYXJlIG9uIHRoZSByb290ICh3YXN0ZWZ1bCkuIEV4YW1wbGU6IGEgVGltZWxpbmVMaXRlLmV4cG9ydFJvb3QoKSBpcyBwZXJmb3JtZWQgd2hlbiB0aGVyZSdzIGEgcGF1c2VkIHR3ZWVuIG9uIHRoZSByb290LCB0aGUgZXhwb3J0IHdpbGwgbm90IGNvbXBsZXRlIHVudGlsIHRoYXQgdHdlZW4gaXMgdW5wYXVzZWQsIGJ1dCBpbWFnaW5lIGEgY2hpbGQgZ2V0cyByZXN0YXJ0ZWQgbGF0ZXIsIGFmdGVyIGFsbCBbdW5wYXVzZWRdIHR3ZWVucyBoYXZlIGNvbXBsZXRlZC4gVGhlIHN0YXJ0IG9mIHRoYXQgY2hpbGQgd291bGQgZ2V0IHB1c2hlZCBvdXQsIGJ1dCBvbmUgb2YgdGhlIGFuY2VzdG9ycyBtYXkgaGF2ZSBjb21wbGV0ZWQuXG5cbiAgICAgIHdoaWxlIChwYXJlbnQgJiYgcGFyZW50LnBhcmVudCkge1xuICAgICAgICBpZiAocGFyZW50LnBhcmVudC5fdGltZSAhPT0gcGFyZW50Ll9zdGFydCArIChwYXJlbnQuX3RzID49IDAgPyBwYXJlbnQuX3RUaW1lIC8gcGFyZW50Ll90cyA6IChwYXJlbnQudG90YWxEdXJhdGlvbigpIC0gcGFyZW50Ll90VGltZSkgLyAtcGFyZW50Ll90cykpIHtcbiAgICAgICAgICBwYXJlbnQudG90YWxUaW1lKHBhcmVudC5fdFRpbWUsIHRydWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgcGFyZW50ID0gcGFyZW50LnBhcmVudDtcbiAgICAgIH1cblxuICAgICAgaWYgKCF0aGlzLnBhcmVudCAmJiB0aGlzLl9kcC5hdXRvUmVtb3ZlQ2hpbGRyZW4gJiYgKHRoaXMuX3RzID4gMCAmJiBfdG90YWxUaW1lIDwgdGhpcy5fdER1ciB8fCB0aGlzLl90cyA8IDAgJiYgX3RvdGFsVGltZSA+IDAgfHwgIXRoaXMuX3REdXIgJiYgIV90b3RhbFRpbWUpKSB7XG4gICAgICAgIC8vaWYgdGhlIGFuaW1hdGlvbiBkb2Vzbid0IGhhdmUgYSBwYXJlbnQsIHB1dCBpdCBiYWNrIGludG8gaXRzIGxhc3QgcGFyZW50IChyZWNvcmRlZCBhcyBfZHAgZm9yIGV4YWN0bHkgY2FzZXMgbGlrZSB0aGlzKS4gTGltaXQgdG8gcGFyZW50cyB3aXRoIGF1dG9SZW1vdmVDaGlsZHJlbiAobGlrZSBnbG9iYWxUaW1lbGluZSkgc28gdGhhdCBpZiB0aGUgdXNlciBtYW51YWxseSByZW1vdmVzIGFuIGFuaW1hdGlvbiBmcm9tIGEgdGltZWxpbmUgYW5kIHRoZW4gYWx0ZXJzIGl0cyBwbGF5aGVhZCwgaXQgZG9lc24ndCBnZXQgYWRkZWQgYmFjayBpbi5cbiAgICAgICAgX2FkZFRvVGltZWxpbmUodGhpcy5fZHAsIHRoaXMsIHRoaXMuX3N0YXJ0IC0gdGhpcy5fZGVsYXkpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICh0aGlzLl90VGltZSAhPT0gX3RvdGFsVGltZSB8fCAhdGhpcy5fZHVyICYmICFzdXBwcmVzc0V2ZW50cyB8fCB0aGlzLl9pbml0dGVkICYmIE1hdGguYWJzKHRoaXMuX3pUaW1lKSA9PT0gX3RpbnlOdW0gfHwgIV90b3RhbFRpbWUgJiYgIXRoaXMuX2luaXR0ZWQgJiYgKHRoaXMuYWRkIHx8IHRoaXMuX3B0TG9va3VwKSkge1xuICAgICAgLy8gY2hlY2sgZm9yIF9wdExvb2t1cCBvbiBhIFR3ZWVuIGluc3RhbmNlIHRvIGVuc3VyZSBpdCBoYXMgYWN0dWFsbHkgZmluaXNoZWQgYmVpbmcgaW5zdGFudGlhdGVkLCBvdGhlcndpc2UgaWYgdGhpcy5yZXZlcnNlKCkgZ2V0cyBjYWxsZWQgaW4gdGhlIEFuaW1hdGlvbiBjb25zdHJ1Y3RvciwgaXQgY291bGQgdHJpZ2dlciBhIHJlbmRlcigpIGhlcmUgZXZlbiB0aG91Z2ggdGhlIF90YXJnZXRzIHdlcmVuJ3QgcG9wdWxhdGVkLCB0aHVzIHdoZW4gX2luaXQoKSBpcyBjYWxsZWQgdGhlcmUgd29uJ3QgYmUgYW55IFByb3BUd2VlbnMgKGl0J2xsIGFjdCBsaWtlIHRoZSB0d2VlbiBpcyBub24tZnVuY3Rpb25hbClcbiAgICAgIHRoaXMuX3RzIHx8ICh0aGlzLl9wVGltZSA9IF90b3RhbFRpbWUpOyAvLyBvdGhlcndpc2UsIGlmIGFuIGFuaW1hdGlvbiBpcyBwYXVzZWQsIHRoZW4gdGhlIHBsYXloZWFkIGlzIG1vdmVkIGJhY2sgdG8gemVybywgdGhlbiByZXN1bWVkLCBpdCdkIHJldmVydCBiYWNrIHRvIHRoZSBvcmlnaW5hbCB0aW1lIGF0IHRoZSBwYXVzZVxuICAgICAgLy9pZiAoIXRoaXMuX2xvY2spIHsgLy8gYXZvaWQgZW5kbGVzcyByZWN1cnNpb24gKG5vdCBzdXJlIHdlIG5lZWQgdGhpcyB5ZXQgb3IgaWYgaXQncyB3b3J0aCB0aGUgcGVyZm9ybWFuY2UgaGl0KVxuICAgICAgLy8gICB0aGlzLl9sb2NrID0gMTtcblxuICAgICAgX2xhenlTYWZlUmVuZGVyKHRoaXMsIF90b3RhbFRpbWUsIHN1cHByZXNzRXZlbnRzKTsgLy8gICB0aGlzLl9sb2NrID0gMDtcbiAgICAgIC8vfVxuXG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH07XG5cbiAgX3Byb3RvLnRpbWUgPSBmdW5jdGlvbiB0aW1lKHZhbHVlLCBzdXBwcmVzc0V2ZW50cykge1xuICAgIHJldHVybiBhcmd1bWVudHMubGVuZ3RoID8gdGhpcy50b3RhbFRpbWUoTWF0aC5taW4odGhpcy50b3RhbER1cmF0aW9uKCksIHZhbHVlICsgX2VsYXBzZWRDeWNsZUR1cmF0aW9uKHRoaXMpKSAlICh0aGlzLl9kdXIgKyB0aGlzLl9yRGVsYXkpIHx8ICh2YWx1ZSA/IHRoaXMuX2R1ciA6IDApLCBzdXBwcmVzc0V2ZW50cykgOiB0aGlzLl90aW1lOyAvLyBub3RlOiBpZiB0aGUgbW9kdWx1cyByZXN1bHRzIGluIDAsIHRoZSBwbGF5aGVhZCBjb3VsZCBiZSBleGFjdGx5IGF0IHRoZSBlbmQgb3IgdGhlIGJlZ2lubmluZywgYW5kIHdlIGFsd2F5cyBkZWZlciB0byB0aGUgRU5EIHdpdGggYSBub24temVybyB2YWx1ZSwgb3RoZXJ3aXNlIGlmIHlvdSBzZXQgdGhlIHRpbWUoKSB0byB0aGUgdmVyeSBlbmQgKGR1cmF0aW9uKCkpLCBpdCB3b3VsZCByZW5kZXIgYXQgdGhlIFNUQVJUIVxuICB9O1xuXG4gIF9wcm90by50b3RhbFByb2dyZXNzID0gZnVuY3Rpb24gdG90YWxQcm9ncmVzcyh2YWx1ZSwgc3VwcHJlc3NFdmVudHMpIHtcbiAgICByZXR1cm4gYXJndW1lbnRzLmxlbmd0aCA/IHRoaXMudG90YWxUaW1lKHRoaXMudG90YWxEdXJhdGlvbigpICogdmFsdWUsIHN1cHByZXNzRXZlbnRzKSA6IHRoaXMudG90YWxEdXJhdGlvbigpID8gTWF0aC5taW4oMSwgdGhpcy5fdFRpbWUgLyB0aGlzLl90RHVyKSA6IHRoaXMucmF3VGltZSgpID4gMCA/IDEgOiAwO1xuICB9O1xuXG4gIF9wcm90by5wcm9ncmVzcyA9IGZ1bmN0aW9uIHByb2dyZXNzKHZhbHVlLCBzdXBwcmVzc0V2ZW50cykge1xuICAgIHJldHVybiBhcmd1bWVudHMubGVuZ3RoID8gdGhpcy50b3RhbFRpbWUodGhpcy5kdXJhdGlvbigpICogKHRoaXMuX3lveW8gJiYgISh0aGlzLml0ZXJhdGlvbigpICYgMSkgPyAxIC0gdmFsdWUgOiB2YWx1ZSkgKyBfZWxhcHNlZEN5Y2xlRHVyYXRpb24odGhpcyksIHN1cHByZXNzRXZlbnRzKSA6IHRoaXMuZHVyYXRpb24oKSA/IE1hdGgubWluKDEsIHRoaXMuX3RpbWUgLyB0aGlzLl9kdXIpIDogdGhpcy5yYXdUaW1lKCkgPiAwID8gMSA6IDA7XG4gIH07XG5cbiAgX3Byb3RvLml0ZXJhdGlvbiA9IGZ1bmN0aW9uIGl0ZXJhdGlvbih2YWx1ZSwgc3VwcHJlc3NFdmVudHMpIHtcbiAgICB2YXIgY3ljbGVEdXJhdGlvbiA9IHRoaXMuZHVyYXRpb24oKSArIHRoaXMuX3JEZWxheTtcblxuICAgIHJldHVybiBhcmd1bWVudHMubGVuZ3RoID8gdGhpcy50b3RhbFRpbWUodGhpcy5fdGltZSArICh2YWx1ZSAtIDEpICogY3ljbGVEdXJhdGlvbiwgc3VwcHJlc3NFdmVudHMpIDogdGhpcy5fcmVwZWF0ID8gX2FuaW1hdGlvbkN5Y2xlKHRoaXMuX3RUaW1lLCBjeWNsZUR1cmF0aW9uKSArIDEgOiAxO1xuICB9IC8vIHBvdGVudGlhbCBmdXR1cmUgYWRkaXRpb246XG4gIC8vIGlzUGxheWluZ0JhY2t3YXJkcygpIHtcbiAgLy8gXHRsZXQgYW5pbWF0aW9uID0gdGhpcyxcbiAgLy8gXHRcdG9yaWVudGF0aW9uID0gMTsgLy8gMSA9IGZvcndhcmQsIC0xID0gYmFja3dhcmRcbiAgLy8gXHR3aGlsZSAoYW5pbWF0aW9uKSB7XG4gIC8vIFx0XHRvcmllbnRhdGlvbiAqPSBhbmltYXRpb24ucmV2ZXJzZWQoKSB8fCAoYW5pbWF0aW9uLnJlcGVhdCgpICYmICEoYW5pbWF0aW9uLml0ZXJhdGlvbigpICYgMSkpID8gLTEgOiAxO1xuICAvLyBcdFx0YW5pbWF0aW9uID0gYW5pbWF0aW9uLnBhcmVudDtcbiAgLy8gXHR9XG4gIC8vIFx0cmV0dXJuIG9yaWVudGF0aW9uIDwgMDtcbiAgLy8gfVxuICA7XG5cbiAgX3Byb3RvLnRpbWVTY2FsZSA9IGZ1bmN0aW9uIHRpbWVTY2FsZSh2YWx1ZSwgc3VwcHJlc3NFdmVudHMpIHtcbiAgICBpZiAoIWFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgIHJldHVybiB0aGlzLl9ydHMgPT09IC1fdGlueU51bSA/IDAgOiB0aGlzLl9ydHM7IC8vIHJlY29yZGVkIHRpbWVTY2FsZS4gU3BlY2lhbCBjYXNlOiBpZiBzb21lb25lIGNhbGxzIHJldmVyc2UoKSBvbiBhbiBhbmltYXRpb24gd2l0aCB0aW1lU2NhbGUgb2YgMCwgd2UgYXNzaWduIGl0IC1fdGlueU51bSB0byByZW1lbWJlciBpdCdzIHJldmVyc2VkLlxuICAgIH1cblxuICAgIGlmICh0aGlzLl9ydHMgPT09IHZhbHVlKSB7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICB2YXIgdFRpbWUgPSB0aGlzLnBhcmVudCAmJiB0aGlzLl90cyA/IF9wYXJlbnRUb0NoaWxkVG90YWxUaW1lKHRoaXMucGFyZW50Ll90aW1lLCB0aGlzKSA6IHRoaXMuX3RUaW1lOyAvLyBtYWtlIHN1cmUgdG8gZG8gdGhlIHBhcmVudFRvQ2hpbGRUb3RhbFRpbWUoKSBCRUZPUkUgc2V0dGluZyB0aGUgbmV3IF90cyBiZWNhdXNlIHRoZSBvbGQgb25lIG11c3QgYmUgdXNlZCBpbiB0aGF0IGNhbGN1bGF0aW9uLlxuICAgIC8vIGZ1dHVyZSBhZGRpdGlvbj8gVXAgc2lkZTogZmFzdCBhbmQgbWluaW1hbCBmaWxlIHNpemUuIERvd24gc2lkZTogb25seSB3b3JrcyBvbiB0aGlzIGFuaW1hdGlvbjsgaWYgYSB0aW1lbGluZSBpcyByZXZlcnNlZCwgZm9yIGV4YW1wbGUsIGl0cyBjaGlsZHJlbnMnIG9uUmV2ZXJzZSB3b3VsZG4ndCBnZXQgY2FsbGVkLlxuICAgIC8vKCt2YWx1ZSA8IDAgJiYgdGhpcy5fcnRzID49IDApICYmIF9jYWxsYmFjayh0aGlzLCBcIm9uUmV2ZXJzZVwiLCB0cnVlKTtcbiAgICAvLyBwcmlvcml0aXplIHJlbmRlcmluZyB3aGVyZSB0aGUgcGFyZW50J3MgcGxheWhlYWQgbGluZXMgdXAgaW5zdGVhZCBvZiB0aGlzLl90VGltZSBiZWNhdXNlIHRoZXJlIGNvdWxkIGJlIGEgdHdlZW4gdGhhdCdzIGFuaW1hdGluZyBhbm90aGVyIHR3ZWVuJ3MgdGltZVNjYWxlIGluIHRoZSBzYW1lIHJlbmRlcmluZyBsb29wIChzYW1lIHBhcmVudCksIHRodXMgaWYgdGhlIHRpbWVTY2FsZSB0d2VlbiByZW5kZXJzIGZpcnN0LCBpdCB3b3VsZCBhbHRlciBfc3RhcnQgQkVGT1JFIF90VGltZSB3YXMgc2V0IG9uIHRoYXQgdGljayAoaW4gdGhlIHJlbmRlcmluZyBsb29wKSwgZWZmZWN0aXZlbHkgZnJlZXppbmcgaXQgdW50aWwgdGhlIHRpbWVTY2FsZSB0d2VlbiBmaW5pc2hlcy5cblxuICAgIHRoaXMuX3J0cyA9ICt2YWx1ZSB8fCAwO1xuICAgIHRoaXMuX3RzID0gdGhpcy5fcHMgfHwgdmFsdWUgPT09IC1fdGlueU51bSA/IDAgOiB0aGlzLl9ydHM7IC8vIF90cyBpcyB0aGUgZnVuY3Rpb25hbCB0aW1lU2NhbGUgd2hpY2ggd291bGQgYmUgMCBpZiB0aGUgYW5pbWF0aW9uIGlzIHBhdXNlZC5cblxuICAgIHRoaXMudG90YWxUaW1lKF9jbGFtcCgtTWF0aC5hYnModGhpcy5fZGVsYXkpLCB0aGlzLl90RHVyLCB0VGltZSksIHN1cHByZXNzRXZlbnRzICE9PSBmYWxzZSk7XG5cbiAgICBfc2V0RW5kKHRoaXMpOyAvLyBpZiBwYXJlbnQuc21vb3RoQ2hpbGRUaW1pbmcgd2FzIGZhbHNlLCB0aGUgZW5kIHRpbWUgZGlkbid0IGdldCB1cGRhdGVkIGluIHRoZSBfYWxpZ25QbGF5aGVhZCgpIG1ldGhvZCwgc28gZG8gaXQgaGVyZS5cblxuXG4gICAgcmV0dXJuIF9yZWNhY2hlQW5jZXN0b3JzKHRoaXMpO1xuICB9O1xuXG4gIF9wcm90by5wYXVzZWQgPSBmdW5jdGlvbiBwYXVzZWQodmFsdWUpIHtcbiAgICBpZiAoIWFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgIHJldHVybiB0aGlzLl9wcztcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fcHMgIT09IHZhbHVlKSB7XG4gICAgICB0aGlzLl9wcyA9IHZhbHVlO1xuXG4gICAgICBpZiAodmFsdWUpIHtcbiAgICAgICAgdGhpcy5fcFRpbWUgPSB0aGlzLl90VGltZSB8fCBNYXRoLm1heCgtdGhpcy5fZGVsYXksIHRoaXMucmF3VGltZSgpKTsgLy8gaWYgdGhlIHBhdXNlIG9jY3VycyBkdXJpbmcgdGhlIGRlbGF5IHBoYXNlLCBtYWtlIHN1cmUgdGhhdCdzIGZhY3RvcmVkIGluIHdoZW4gcmVzdW1pbmcuXG5cbiAgICAgICAgdGhpcy5fdHMgPSB0aGlzLl9hY3QgPSAwOyAvLyBfdHMgaXMgdGhlIGZ1bmN0aW9uYWwgdGltZVNjYWxlLCBzbyBhIHBhdXNlZCB0d2VlbiB3b3VsZCBlZmZlY3RpdmVseSBoYXZlIGEgdGltZVNjYWxlIG9mIDAuIFdlIHJlY29yZCB0aGUgXCJyZWFsXCIgdGltZVNjYWxlIGFzIF9ydHMgKHJlY29yZGVkIHRpbWUgc2NhbGUpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBfd2FrZSgpO1xuXG4gICAgICAgIHRoaXMuX3RzID0gdGhpcy5fcnRzOyAvL29ubHkgZGVmZXIgdG8gX3BUaW1lIChwYXVzZVRpbWUpIGlmIHRUaW1lIGlzIHplcm8uIFJlbWVtYmVyLCBzb21lb25lIGNvdWxkIHBhdXNlKCkgYW4gYW5pbWF0aW9uLCB0aGVuIHNjcnViIHRoZSBwbGF5aGVhZCBhbmQgcmVzdW1lKCkuIElmIHRoZSBwYXJlbnQgZG9lc24ndCBoYXZlIHNtb290aENoaWxkVGltaW5nLCB3ZSByZW5kZXIgYXQgdGhlIHJhd1RpbWUoKSBiZWNhdXNlIHRoZSBzdGFydFRpbWUgd29uJ3QgZ2V0IHVwZGF0ZWQuXG5cbiAgICAgICAgdGhpcy50b3RhbFRpbWUodGhpcy5wYXJlbnQgJiYgIXRoaXMucGFyZW50LnNtb290aENoaWxkVGltaW5nID8gdGhpcy5yYXdUaW1lKCkgOiB0aGlzLl90VGltZSB8fCB0aGlzLl9wVGltZSwgdGhpcy5wcm9ncmVzcygpID09PSAxICYmIE1hdGguYWJzKHRoaXMuX3pUaW1lKSAhPT0gX3RpbnlOdW0gJiYgKHRoaXMuX3RUaW1lIC09IF90aW55TnVtKSk7IC8vIGVkZ2UgY2FzZTogYW5pbWF0aW9uLnByb2dyZXNzKDEpLnBhdXNlKCkucGxheSgpIHdvdWxkbid0IHJlbmRlciBhZ2FpbiBiZWNhdXNlIHRoZSBwbGF5aGVhZCBpcyBhbHJlYWR5IGF0IHRoZSBlbmQsIGJ1dCB0aGUgY2FsbCB0byB0b3RhbFRpbWUoKSBiZWxvdyB3aWxsIGFkZCBpdCBiYWNrIHRvIGl0cyBwYXJlbnQuLi5hbmQgbm90IHJlbW92ZSBpdCBhZ2FpbiAoc2luY2UgcmVtb3Zpbmcgb25seSBoYXBwZW5zIHVwb24gcmVuZGVyaW5nIGF0IGEgbmV3IHRpbWUpLiBPZmZzZXR0aW5nIHRoZSBfdFRpbWUgc2xpZ2h0bHkgaXMgZG9uZSBzaW1wbHkgdG8gY2F1c2UgdGhlIGZpbmFsIHJlbmRlciBpbiB0b3RhbFRpbWUoKSB0aGF0J2xsIHBvcCBpdCBvZmYgaXRzIHRpbWVsaW5lIChpZiBhdXRvUmVtb3ZlQ2hpbGRyZW4gaXMgdHJ1ZSwgb2YgY291cnNlKS4gQ2hlY2sgdG8gbWFrZSBzdXJlIF96VGltZSBpc24ndCAtX3RpbnlOdW0gdG8gYXZvaWQgYW4gZWRnZSBjYXNlIHdoZXJlIHRoZSBwbGF5aGVhZCBpcyBwdXNoZWQgdG8gdGhlIGVuZCBidXQgSU5TSURFIGEgdHdlZW4vY2FsbGJhY2ssIHRoZSB0aW1lbGluZSBpdHNlbGYgaXMgcGF1c2VkIHRodXMgaGFsdGluZyByZW5kZXJpbmcgYW5kIGxlYXZpbmcgYSBmZXcgdW5yZW5kZXJlZC4gV2hlbiByZXN1bWluZywgaXQgd291bGRuJ3QgcmVuZGVyIHRob3NlIG90aGVyd2lzZS5cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfTtcblxuICBfcHJvdG8uc3RhcnRUaW1lID0gZnVuY3Rpb24gc3RhcnRUaW1lKHZhbHVlKSB7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgIHRoaXMuX3N0YXJ0ID0gdmFsdWU7XG4gICAgICB2YXIgcGFyZW50ID0gdGhpcy5wYXJlbnQgfHwgdGhpcy5fZHA7XG4gICAgICBwYXJlbnQgJiYgKHBhcmVudC5fc29ydCB8fCAhdGhpcy5wYXJlbnQpICYmIF9hZGRUb1RpbWVsaW5lKHBhcmVudCwgdGhpcywgdmFsdWUgLSB0aGlzLl9kZWxheSk7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5fc3RhcnQ7XG4gIH07XG5cbiAgX3Byb3RvLmVuZFRpbWUgPSBmdW5jdGlvbiBlbmRUaW1lKGluY2x1ZGVSZXBlYXRzKSB7XG4gICAgcmV0dXJuIHRoaXMuX3N0YXJ0ICsgKF9pc05vdEZhbHNlKGluY2x1ZGVSZXBlYXRzKSA/IHRoaXMudG90YWxEdXJhdGlvbigpIDogdGhpcy5kdXJhdGlvbigpKSAvIE1hdGguYWJzKHRoaXMuX3RzIHx8IDEpO1xuICB9O1xuXG4gIF9wcm90by5yYXdUaW1lID0gZnVuY3Rpb24gcmF3VGltZSh3cmFwUmVwZWF0cykge1xuICAgIHZhciBwYXJlbnQgPSB0aGlzLnBhcmVudCB8fCB0aGlzLl9kcDsgLy8gX2RwID0gZGV0YWNoZWQgcGFyZW50XG5cbiAgICByZXR1cm4gIXBhcmVudCA/IHRoaXMuX3RUaW1lIDogd3JhcFJlcGVhdHMgJiYgKCF0aGlzLl90cyB8fCB0aGlzLl9yZXBlYXQgJiYgdGhpcy5fdGltZSAmJiB0aGlzLnRvdGFsUHJvZ3Jlc3MoKSA8IDEpID8gdGhpcy5fdFRpbWUgJSAodGhpcy5fZHVyICsgdGhpcy5fckRlbGF5KSA6ICF0aGlzLl90cyA/IHRoaXMuX3RUaW1lIDogX3BhcmVudFRvQ2hpbGRUb3RhbFRpbWUocGFyZW50LnJhd1RpbWUod3JhcFJlcGVhdHMpLCB0aGlzKTtcbiAgfTtcblxuICBfcHJvdG8ucmV2ZXJ0ID0gZnVuY3Rpb24gcmV2ZXJ0KGNvbmZpZykge1xuICAgIGlmIChjb25maWcgPT09IHZvaWQgMCkge1xuICAgICAgY29uZmlnID0gX3JldmVydENvbmZpZztcbiAgICB9XG5cbiAgICB2YXIgcHJldklzUmV2ZXJ0aW5nID0gX3JldmVydGluZztcbiAgICBfcmV2ZXJ0aW5nID0gY29uZmlnO1xuXG4gICAgaWYgKHRoaXMuX2luaXR0ZWQgfHwgdGhpcy5fc3RhcnRBdCkge1xuICAgICAgdGhpcy50aW1lbGluZSAmJiB0aGlzLnRpbWVsaW5lLnJldmVydChjb25maWcpO1xuICAgICAgdGhpcy50b3RhbFRpbWUoLTAuMDEsIGNvbmZpZy5zdXBwcmVzc0V2ZW50cyk7XG4gICAgfVxuXG4gICAgdGhpcy5kYXRhICE9PSBcIm5lc3RlZFwiICYmIGNvbmZpZy5raWxsICE9PSBmYWxzZSAmJiB0aGlzLmtpbGwoKTtcbiAgICBfcmV2ZXJ0aW5nID0gcHJldklzUmV2ZXJ0aW5nO1xuICAgIHJldHVybiB0aGlzO1xuICB9O1xuXG4gIF9wcm90by5nbG9iYWxUaW1lID0gZnVuY3Rpb24gZ2xvYmFsVGltZShyYXdUaW1lKSB7XG4gICAgdmFyIGFuaW1hdGlvbiA9IHRoaXMsXG4gICAgICAgIHRpbWUgPSBhcmd1bWVudHMubGVuZ3RoID8gcmF3VGltZSA6IGFuaW1hdGlvbi5yYXdUaW1lKCk7XG5cbiAgICB3aGlsZSAoYW5pbWF0aW9uKSB7XG4gICAgICB0aW1lID0gYW5pbWF0aW9uLl9zdGFydCArIHRpbWUgLyAoTWF0aC5hYnMoYW5pbWF0aW9uLl90cykgfHwgMSk7XG4gICAgICBhbmltYXRpb24gPSBhbmltYXRpb24uX2RwO1xuICAgIH1cblxuICAgIHJldHVybiAhdGhpcy5wYXJlbnQgJiYgdGhpcy5fc2F0ID8gdGhpcy5fc2F0Lmdsb2JhbFRpbWUocmF3VGltZSkgOiB0aW1lOyAvLyB0aGUgX3N0YXJ0QXQgdHdlZW5zIGZvciAuZnJvbVRvKCkgYW5kIC5mcm9tKCkgdGhhdCBoYXZlIGltbWVkaWF0ZVJlbmRlciBzaG91bGQgYWx3YXlzIGJlIEZJUlNUIGluIHRoZSB0aW1lbGluZSAoaW1wb3J0YW50IGZvciBjb250ZXh0LnJldmVydCgpKS4gXCJfc2F0XCIgc3RhbmRzIGZvciBfc3RhcnRBdFR3ZWVuLCByZWZlcnJpbmcgdG8gdGhlIHBhcmVudCB0d2VlbiB0aGF0IGNyZWF0ZWQgdGhlIF9zdGFydEF0LiBXZSBtdXN0IGRpc2Nlcm4gaWYgdGhhdCB0d2VlbiBoYWQgaW1tZWRpYXRlUmVuZGVyIHNvIHRoYXQgd2UgY2FuIGtub3cgd2hldGhlciBvciBub3QgdG8gcHJpb3JpdGl6ZSBpdCBpbiByZXZlcnQoKS5cbiAgfTtcblxuICBfcHJvdG8ucmVwZWF0ID0gZnVuY3Rpb24gcmVwZWF0KHZhbHVlKSB7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgIHRoaXMuX3JlcGVhdCA9IHZhbHVlID09PSBJbmZpbml0eSA/IC0yIDogdmFsdWU7XG4gICAgICByZXR1cm4gX29uVXBkYXRlVG90YWxEdXJhdGlvbih0aGlzKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5fcmVwZWF0ID09PSAtMiA/IEluZmluaXR5IDogdGhpcy5fcmVwZWF0O1xuICB9O1xuXG4gIF9wcm90by5yZXBlYXREZWxheSA9IGZ1bmN0aW9uIHJlcGVhdERlbGF5KHZhbHVlKSB7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgIHZhciB0aW1lID0gdGhpcy5fdGltZTtcbiAgICAgIHRoaXMuX3JEZWxheSA9IHZhbHVlO1xuXG4gICAgICBfb25VcGRhdGVUb3RhbER1cmF0aW9uKHRoaXMpO1xuXG4gICAgICByZXR1cm4gdGltZSA/IHRoaXMudGltZSh0aW1lKSA6IHRoaXM7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuX3JEZWxheTtcbiAgfTtcblxuICBfcHJvdG8ueW95byA9IGZ1bmN0aW9uIHlveW8odmFsdWUpIHtcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgdGhpcy5feW95byA9IHZhbHVlO1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuX3lveW87XG4gIH07XG5cbiAgX3Byb3RvLnNlZWsgPSBmdW5jdGlvbiBzZWVrKHBvc2l0aW9uLCBzdXBwcmVzc0V2ZW50cykge1xuICAgIHJldHVybiB0aGlzLnRvdGFsVGltZShfcGFyc2VQb3NpdGlvbih0aGlzLCBwb3NpdGlvbiksIF9pc05vdEZhbHNlKHN1cHByZXNzRXZlbnRzKSk7XG4gIH07XG5cbiAgX3Byb3RvLnJlc3RhcnQgPSBmdW5jdGlvbiByZXN0YXJ0KGluY2x1ZGVEZWxheSwgc3VwcHJlc3NFdmVudHMpIHtcbiAgICByZXR1cm4gdGhpcy5wbGF5KCkudG90YWxUaW1lKGluY2x1ZGVEZWxheSA/IC10aGlzLl9kZWxheSA6IDAsIF9pc05vdEZhbHNlKHN1cHByZXNzRXZlbnRzKSk7XG4gIH07XG5cbiAgX3Byb3RvLnBsYXkgPSBmdW5jdGlvbiBwbGF5KGZyb20sIHN1cHByZXNzRXZlbnRzKSB7XG4gICAgZnJvbSAhPSBudWxsICYmIHRoaXMuc2Vlayhmcm9tLCBzdXBwcmVzc0V2ZW50cyk7XG4gICAgcmV0dXJuIHRoaXMucmV2ZXJzZWQoZmFsc2UpLnBhdXNlZChmYWxzZSk7XG4gIH07XG5cbiAgX3Byb3RvLnJldmVyc2UgPSBmdW5jdGlvbiByZXZlcnNlKGZyb20sIHN1cHByZXNzRXZlbnRzKSB7XG4gICAgZnJvbSAhPSBudWxsICYmIHRoaXMuc2Vlayhmcm9tIHx8IHRoaXMudG90YWxEdXJhdGlvbigpLCBzdXBwcmVzc0V2ZW50cyk7XG4gICAgcmV0dXJuIHRoaXMucmV2ZXJzZWQodHJ1ZSkucGF1c2VkKGZhbHNlKTtcbiAgfTtcblxuICBfcHJvdG8ucGF1c2UgPSBmdW5jdGlvbiBwYXVzZShhdFRpbWUsIHN1cHByZXNzRXZlbnRzKSB7XG4gICAgYXRUaW1lICE9IG51bGwgJiYgdGhpcy5zZWVrKGF0VGltZSwgc3VwcHJlc3NFdmVudHMpO1xuICAgIHJldHVybiB0aGlzLnBhdXNlZCh0cnVlKTtcbiAgfTtcblxuICBfcHJvdG8ucmVzdW1lID0gZnVuY3Rpb24gcmVzdW1lKCkge1xuICAgIHJldHVybiB0aGlzLnBhdXNlZChmYWxzZSk7XG4gIH07XG5cbiAgX3Byb3RvLnJldmVyc2VkID0gZnVuY3Rpb24gcmV2ZXJzZWQodmFsdWUpIHtcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgISF2YWx1ZSAhPT0gdGhpcy5yZXZlcnNlZCgpICYmIHRoaXMudGltZVNjYWxlKC10aGlzLl9ydHMgfHwgKHZhbHVlID8gLV90aW55TnVtIDogMCkpOyAvLyBpbiBjYXNlIHRpbWVTY2FsZSBpcyB6ZXJvLCByZXZlcnNpbmcgd291bGQgaGF2ZSBubyBlZmZlY3Qgc28gd2UgdXNlIF90aW55TnVtLlxuXG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5fcnRzIDwgMDtcbiAgfTtcblxuICBfcHJvdG8uaW52YWxpZGF0ZSA9IGZ1bmN0aW9uIGludmFsaWRhdGUoKSB7XG4gICAgdGhpcy5faW5pdHRlZCA9IHRoaXMuX2FjdCA9IDA7XG4gICAgdGhpcy5felRpbWUgPSAtX3RpbnlOdW07XG4gICAgcmV0dXJuIHRoaXM7XG4gIH07XG5cbiAgX3Byb3RvLmlzQWN0aXZlID0gZnVuY3Rpb24gaXNBY3RpdmUoKSB7XG4gICAgdmFyIHBhcmVudCA9IHRoaXMucGFyZW50IHx8IHRoaXMuX2RwLFxuICAgICAgICBzdGFydCA9IHRoaXMuX3N0YXJ0LFxuICAgICAgICByYXdUaW1lO1xuICAgIHJldHVybiAhISghcGFyZW50IHx8IHRoaXMuX3RzICYmIHRoaXMuX2luaXR0ZWQgJiYgcGFyZW50LmlzQWN0aXZlKCkgJiYgKHJhd1RpbWUgPSBwYXJlbnQucmF3VGltZSh0cnVlKSkgPj0gc3RhcnQgJiYgcmF3VGltZSA8IHRoaXMuZW5kVGltZSh0cnVlKSAtIF90aW55TnVtKTtcbiAgfTtcblxuICBfcHJvdG8uZXZlbnRDYWxsYmFjayA9IGZ1bmN0aW9uIGV2ZW50Q2FsbGJhY2sodHlwZSwgY2FsbGJhY2ssIHBhcmFtcykge1xuICAgIHZhciB2YXJzID0gdGhpcy52YXJzO1xuXG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICBpZiAoIWNhbGxiYWNrKSB7XG4gICAgICAgIGRlbGV0ZSB2YXJzW3R5cGVdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFyc1t0eXBlXSA9IGNhbGxiYWNrO1xuICAgICAgICBwYXJhbXMgJiYgKHZhcnNbdHlwZSArIFwiUGFyYW1zXCJdID0gcGFyYW1zKTtcbiAgICAgICAgdHlwZSA9PT0gXCJvblVwZGF0ZVwiICYmICh0aGlzLl9vblVwZGF0ZSA9IGNhbGxiYWNrKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgcmV0dXJuIHZhcnNbdHlwZV07XG4gIH07XG5cbiAgX3Byb3RvLnRoZW4gPSBmdW5jdGlvbiB0aGVuKG9uRnVsZmlsbGVkKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbiAocmVzb2x2ZSkge1xuICAgICAgdmFyIGYgPSBfaXNGdW5jdGlvbihvbkZ1bGZpbGxlZCkgPyBvbkZ1bGZpbGxlZCA6IF9wYXNzVGhyb3VnaCxcbiAgICAgICAgICBfcmVzb2x2ZSA9IGZ1bmN0aW9uIF9yZXNvbHZlKCkge1xuICAgICAgICB2YXIgX3RoZW4gPSBzZWxmLnRoZW47XG4gICAgICAgIHNlbGYudGhlbiA9IG51bGw7IC8vIHRlbXBvcmFyaWx5IG51bGwgdGhlIHRoZW4oKSBtZXRob2QgdG8gYXZvaWQgYW4gaW5maW5pdGUgbG9vcCAoc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9ncmVlbnNvY2svR1NBUC9pc3N1ZXMvMzIyKVxuXG4gICAgICAgIF9pc0Z1bmN0aW9uKGYpICYmIChmID0gZihzZWxmKSkgJiYgKGYudGhlbiB8fCBmID09PSBzZWxmKSAmJiAoc2VsZi50aGVuID0gX3RoZW4pO1xuICAgICAgICByZXNvbHZlKGYpO1xuICAgICAgICBzZWxmLnRoZW4gPSBfdGhlbjtcbiAgICAgIH07XG5cbiAgICAgIGlmIChzZWxmLl9pbml0dGVkICYmIHNlbGYudG90YWxQcm9ncmVzcygpID09PSAxICYmIHNlbGYuX3RzID49IDAgfHwgIXNlbGYuX3RUaW1lICYmIHNlbGYuX3RzIDwgMCkge1xuICAgICAgICBfcmVzb2x2ZSgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc2VsZi5fcHJvbSA9IF9yZXNvbHZlO1xuICAgICAgfVxuICAgIH0pO1xuICB9O1xuXG4gIF9wcm90by5raWxsID0gZnVuY3Rpb24ga2lsbCgpIHtcbiAgICBfaW50ZXJydXB0KHRoaXMpO1xuICB9O1xuXG4gIHJldHVybiBBbmltYXRpb247XG59KCk7XG5cbl9zZXREZWZhdWx0cyhBbmltYXRpb24ucHJvdG90eXBlLCB7XG4gIF90aW1lOiAwLFxuICBfc3RhcnQ6IDAsXG4gIF9lbmQ6IDAsXG4gIF90VGltZTogMCxcbiAgX3REdXI6IDAsXG4gIF9kaXJ0eTogMCxcbiAgX3JlcGVhdDogMCxcbiAgX3lveW86IGZhbHNlLFxuICBwYXJlbnQ6IG51bGwsXG4gIF9pbml0dGVkOiBmYWxzZSxcbiAgX3JEZWxheTogMCxcbiAgX3RzOiAxLFxuICBfZHA6IDAsXG4gIHJhdGlvOiAwLFxuICBfelRpbWU6IC1fdGlueU51bSxcbiAgX3Byb206IDAsXG4gIF9wczogZmFsc2UsXG4gIF9ydHM6IDFcbn0pO1xuLypcbiAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqIFRJTUVMSU5FXG4gKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKi9cblxuXG5leHBvcnQgdmFyIFRpbWVsaW5lID0gLyojX19QVVJFX18qL2Z1bmN0aW9uIChfQW5pbWF0aW9uKSB7XG4gIF9pbmhlcml0c0xvb3NlKFRpbWVsaW5lLCBfQW5pbWF0aW9uKTtcblxuICBmdW5jdGlvbiBUaW1lbGluZSh2YXJzLCBwb3NpdGlvbikge1xuICAgIHZhciBfdGhpcztcblxuICAgIGlmICh2YXJzID09PSB2b2lkIDApIHtcbiAgICAgIHZhcnMgPSB7fTtcbiAgICB9XG5cbiAgICBfdGhpcyA9IF9BbmltYXRpb24uY2FsbCh0aGlzLCB2YXJzKSB8fCB0aGlzO1xuICAgIF90aGlzLmxhYmVscyA9IHt9O1xuICAgIF90aGlzLnNtb290aENoaWxkVGltaW5nID0gISF2YXJzLnNtb290aENoaWxkVGltaW5nO1xuICAgIF90aGlzLmF1dG9SZW1vdmVDaGlsZHJlbiA9ICEhdmFycy5hdXRvUmVtb3ZlQ2hpbGRyZW47XG4gICAgX3RoaXMuX3NvcnQgPSBfaXNOb3RGYWxzZSh2YXJzLnNvcnRDaGlsZHJlbik7XG4gICAgX2dsb2JhbFRpbWVsaW5lICYmIF9hZGRUb1RpbWVsaW5lKHZhcnMucGFyZW50IHx8IF9nbG9iYWxUaW1lbGluZSwgX2Fzc2VydFRoaXNJbml0aWFsaXplZChfdGhpcyksIHBvc2l0aW9uKTtcbiAgICB2YXJzLnJldmVyc2VkICYmIF90aGlzLnJldmVyc2UoKTtcbiAgICB2YXJzLnBhdXNlZCAmJiBfdGhpcy5wYXVzZWQodHJ1ZSk7XG4gICAgdmFycy5zY3JvbGxUcmlnZ2VyICYmIF9zY3JvbGxUcmlnZ2VyKF9hc3NlcnRUaGlzSW5pdGlhbGl6ZWQoX3RoaXMpLCB2YXJzLnNjcm9sbFRyaWdnZXIpO1xuICAgIHJldHVybiBfdGhpcztcbiAgfVxuXG4gIHZhciBfcHJvdG8yID0gVGltZWxpbmUucHJvdG90eXBlO1xuXG4gIF9wcm90bzIudG8gPSBmdW5jdGlvbiB0byh0YXJnZXRzLCB2YXJzLCBwb3NpdGlvbikge1xuICAgIF9jcmVhdGVUd2VlblR5cGUoMCwgYXJndW1lbnRzLCB0aGlzKTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9O1xuXG4gIF9wcm90bzIuZnJvbSA9IGZ1bmN0aW9uIGZyb20odGFyZ2V0cywgdmFycywgcG9zaXRpb24pIHtcbiAgICBfY3JlYXRlVHdlZW5UeXBlKDEsIGFyZ3VtZW50cywgdGhpcyk7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfTtcblxuICBfcHJvdG8yLmZyb21UbyA9IGZ1bmN0aW9uIGZyb21Ubyh0YXJnZXRzLCBmcm9tVmFycywgdG9WYXJzLCBwb3NpdGlvbikge1xuICAgIF9jcmVhdGVUd2VlblR5cGUoMiwgYXJndW1lbnRzLCB0aGlzKTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9O1xuXG4gIF9wcm90bzIuc2V0ID0gZnVuY3Rpb24gc2V0KHRhcmdldHMsIHZhcnMsIHBvc2l0aW9uKSB7XG4gICAgdmFycy5kdXJhdGlvbiA9IDA7XG4gICAgdmFycy5wYXJlbnQgPSB0aGlzO1xuICAgIF9pbmhlcml0RGVmYXVsdHModmFycykucmVwZWF0RGVsYXkgfHwgKHZhcnMucmVwZWF0ID0gMCk7XG4gICAgdmFycy5pbW1lZGlhdGVSZW5kZXIgPSAhIXZhcnMuaW1tZWRpYXRlUmVuZGVyO1xuICAgIG5ldyBUd2Vlbih0YXJnZXRzLCB2YXJzLCBfcGFyc2VQb3NpdGlvbih0aGlzLCBwb3NpdGlvbiksIDEpO1xuICAgIHJldHVybiB0aGlzO1xuICB9O1xuXG4gIF9wcm90bzIuY2FsbCA9IGZ1bmN0aW9uIGNhbGwoY2FsbGJhY2ssIHBhcmFtcywgcG9zaXRpb24pIHtcbiAgICByZXR1cm4gX2FkZFRvVGltZWxpbmUodGhpcywgVHdlZW4uZGVsYXllZENhbGwoMCwgY2FsbGJhY2ssIHBhcmFtcyksIHBvc2l0aW9uKTtcbiAgfSAvL09OTFkgZm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHkhIE1heWJlIGRlbGV0ZT9cbiAgO1xuXG4gIF9wcm90bzIuc3RhZ2dlclRvID0gZnVuY3Rpb24gc3RhZ2dlclRvKHRhcmdldHMsIGR1cmF0aW9uLCB2YXJzLCBzdGFnZ2VyLCBwb3NpdGlvbiwgb25Db21wbGV0ZUFsbCwgb25Db21wbGV0ZUFsbFBhcmFtcykge1xuICAgIHZhcnMuZHVyYXRpb24gPSBkdXJhdGlvbjtcbiAgICB2YXJzLnN0YWdnZXIgPSB2YXJzLnN0YWdnZXIgfHwgc3RhZ2dlcjtcbiAgICB2YXJzLm9uQ29tcGxldGUgPSBvbkNvbXBsZXRlQWxsO1xuICAgIHZhcnMub25Db21wbGV0ZVBhcmFtcyA9IG9uQ29tcGxldGVBbGxQYXJhbXM7XG4gICAgdmFycy5wYXJlbnQgPSB0aGlzO1xuICAgIG5ldyBUd2Vlbih0YXJnZXRzLCB2YXJzLCBfcGFyc2VQb3NpdGlvbih0aGlzLCBwb3NpdGlvbikpO1xuICAgIHJldHVybiB0aGlzO1xuICB9O1xuXG4gIF9wcm90bzIuc3RhZ2dlckZyb20gPSBmdW5jdGlvbiBzdGFnZ2VyRnJvbSh0YXJnZXRzLCBkdXJhdGlvbiwgdmFycywgc3RhZ2dlciwgcG9zaXRpb24sIG9uQ29tcGxldGVBbGwsIG9uQ29tcGxldGVBbGxQYXJhbXMpIHtcbiAgICB2YXJzLnJ1bkJhY2t3YXJkcyA9IDE7XG4gICAgX2luaGVyaXREZWZhdWx0cyh2YXJzKS5pbW1lZGlhdGVSZW5kZXIgPSBfaXNOb3RGYWxzZSh2YXJzLmltbWVkaWF0ZVJlbmRlcik7XG4gICAgcmV0dXJuIHRoaXMuc3RhZ2dlclRvKHRhcmdldHMsIGR1cmF0aW9uLCB2YXJzLCBzdGFnZ2VyLCBwb3NpdGlvbiwgb25Db21wbGV0ZUFsbCwgb25Db21wbGV0ZUFsbFBhcmFtcyk7XG4gIH07XG5cbiAgX3Byb3RvMi5zdGFnZ2VyRnJvbVRvID0gZnVuY3Rpb24gc3RhZ2dlckZyb21Ubyh0YXJnZXRzLCBkdXJhdGlvbiwgZnJvbVZhcnMsIHRvVmFycywgc3RhZ2dlciwgcG9zaXRpb24sIG9uQ29tcGxldGVBbGwsIG9uQ29tcGxldGVBbGxQYXJhbXMpIHtcbiAgICB0b1ZhcnMuc3RhcnRBdCA9IGZyb21WYXJzO1xuICAgIF9pbmhlcml0RGVmYXVsdHModG9WYXJzKS5pbW1lZGlhdGVSZW5kZXIgPSBfaXNOb3RGYWxzZSh0b1ZhcnMuaW1tZWRpYXRlUmVuZGVyKTtcbiAgICByZXR1cm4gdGhpcy5zdGFnZ2VyVG8odGFyZ2V0cywgZHVyYXRpb24sIHRvVmFycywgc3RhZ2dlciwgcG9zaXRpb24sIG9uQ29tcGxldGVBbGwsIG9uQ29tcGxldGVBbGxQYXJhbXMpO1xuICB9O1xuXG4gIF9wcm90bzIucmVuZGVyID0gZnVuY3Rpb24gcmVuZGVyKHRvdGFsVGltZSwgc3VwcHJlc3NFdmVudHMsIGZvcmNlKSB7XG4gICAgdmFyIHByZXZUaW1lID0gdGhpcy5fdGltZSxcbiAgICAgICAgdER1ciA9IHRoaXMuX2RpcnR5ID8gdGhpcy50b3RhbER1cmF0aW9uKCkgOiB0aGlzLl90RHVyLFxuICAgICAgICBkdXIgPSB0aGlzLl9kdXIsXG4gICAgICAgIHRUaW1lID0gdG90YWxUaW1lIDw9IDAgPyAwIDogX3JvdW5kUHJlY2lzZSh0b3RhbFRpbWUpLFxuICAgICAgICAvLyBpZiBhIHBhdXNlZCB0aW1lbGluZSBpcyByZXN1bWVkIChvciBpdHMgX3N0YXJ0IGlzIHVwZGF0ZWQgZm9yIGFub3RoZXIgcmVhc29uLi4ud2hpY2ggcm91bmRzIGl0KSwgdGhhdCBjb3VsZCByZXN1bHQgaW4gdGhlIHBsYXloZWFkIHNoaWZ0aW5nIGEgKip0aW55KiogYW1vdW50IGFuZCBhIHplcm8tZHVyYXRpb24gY2hpbGQgYXQgdGhhdCBzcG90IG1heSBnZXQgcmVuZGVyZWQgYXQgYSBkaWZmZXJlbnQgcmF0aW8sIGxpa2UgaXRzIHRvdGFsVGltZSBpbiByZW5kZXIoKSBtYXkgYmUgMWUtMTcgaW5zdGVhZCBvZiAwLCBmb3IgZXhhbXBsZS5cbiAgICBjcm9zc2luZ1N0YXJ0ID0gdGhpcy5felRpbWUgPCAwICE9PSB0b3RhbFRpbWUgPCAwICYmICh0aGlzLl9pbml0dGVkIHx8ICFkdXIpLFxuICAgICAgICB0aW1lLFxuICAgICAgICBjaGlsZCxcbiAgICAgICAgbmV4dCxcbiAgICAgICAgaXRlcmF0aW9uLFxuICAgICAgICBjeWNsZUR1cmF0aW9uLFxuICAgICAgICBwcmV2UGF1c2VkLFxuICAgICAgICBwYXVzZVR3ZWVuLFxuICAgICAgICB0aW1lU2NhbGUsXG4gICAgICAgIHByZXZTdGFydCxcbiAgICAgICAgcHJldkl0ZXJhdGlvbixcbiAgICAgICAgeW95byxcbiAgICAgICAgaXNZb3lvO1xuICAgIHRoaXMgIT09IF9nbG9iYWxUaW1lbGluZSAmJiB0VGltZSA+IHREdXIgJiYgdG90YWxUaW1lID49IDAgJiYgKHRUaW1lID0gdER1cik7XG5cbiAgICBpZiAodFRpbWUgIT09IHRoaXMuX3RUaW1lIHx8IGZvcmNlIHx8IGNyb3NzaW5nU3RhcnQpIHtcbiAgICAgIGlmIChwcmV2VGltZSAhPT0gdGhpcy5fdGltZSAmJiBkdXIpIHtcbiAgICAgICAgLy9pZiB0b3RhbER1cmF0aW9uKCkgZmluZHMgYSBjaGlsZCB3aXRoIGEgbmVnYXRpdmUgc3RhcnRUaW1lIGFuZCBzbW9vdGhDaGlsZFRpbWluZyBpcyB0cnVlLCB0aGluZ3MgZ2V0IHNoaWZ0ZWQgYXJvdW5kIGludGVybmFsbHkgc28gd2UgbmVlZCB0byBhZGp1c3QgdGhlIHRpbWUgYWNjb3JkaW5nbHkuIEZvciBleGFtcGxlLCBpZiBhIHR3ZWVuIHN0YXJ0cyBhdCAtMzAgd2UgbXVzdCBzaGlmdCBFVkVSWVRISU5HIGZvcndhcmQgMzAgc2Vjb25kcyBhbmQgbW92ZSB0aGlzIHRpbWVsaW5lJ3Mgc3RhcnRUaW1lIGJhY2t3YXJkIGJ5IDMwIHNlY29uZHMgc28gdGhhdCB0aGluZ3MgYWxpZ24gd2l0aCB0aGUgcGxheWhlYWQgKG5vIGp1bXApLlxuICAgICAgICB0VGltZSArPSB0aGlzLl90aW1lIC0gcHJldlRpbWU7XG4gICAgICAgIHRvdGFsVGltZSArPSB0aGlzLl90aW1lIC0gcHJldlRpbWU7XG4gICAgICB9XG5cbiAgICAgIHRpbWUgPSB0VGltZTtcbiAgICAgIHByZXZTdGFydCA9IHRoaXMuX3N0YXJ0O1xuICAgICAgdGltZVNjYWxlID0gdGhpcy5fdHM7XG4gICAgICBwcmV2UGF1c2VkID0gIXRpbWVTY2FsZTtcblxuICAgICAgaWYgKGNyb3NzaW5nU3RhcnQpIHtcbiAgICAgICAgZHVyIHx8IChwcmV2VGltZSA9IHRoaXMuX3pUaW1lKTsgLy93aGVuIHRoZSBwbGF5aGVhZCBhcnJpdmVzIGF0IEVYQUNUTFkgdGltZSAwIChyaWdodCBvbiB0b3ApIG9mIGEgemVyby1kdXJhdGlvbiB0aW1lbGluZSwgd2UgbmVlZCB0byBkaXNjZXJuIGlmIGV2ZW50cyBhcmUgc3VwcHJlc3NlZCBzbyB0aGF0IHdoZW4gdGhlIHBsYXloZWFkIG1vdmVzIGFnYWluIChuZXh0IHRpbWUpLCBpdCdsbCB0cmlnZ2VyIHRoZSBjYWxsYmFjay4gSWYgZXZlbnRzIGFyZSBOT1Qgc3VwcHJlc3NlZCwgb2J2aW91c2x5IHRoZSBjYWxsYmFjayB3b3VsZCBiZSB0cmlnZ2VyZWQgaW4gdGhpcyByZW5kZXIuIEJhc2ljYWxseSwgdGhlIGNhbGxiYWNrIHNob3VsZCBmaXJlIGVpdGhlciB3aGVuIHRoZSBwbGF5aGVhZCBBUlJJVkVTIG9yIExFQVZFUyB0aGlzIGV4YWN0IHNwb3QsIG5vdCBib3RoLiBJbWFnaW5lIGRvaW5nIGEgdGltZWxpbmUuc2VlaygwKSBhbmQgdGhlcmUncyBhIGNhbGxiYWNrIHRoYXQgc2l0cyBhdCAwLiBTaW5jZSBldmVudHMgYXJlIHN1cHByZXNzZWQgb24gdGhhdCBzZWVrKCkgYnkgZGVmYXVsdCwgbm90aGluZyB3aWxsIGZpcmUsIGJ1dCB3aGVuIHRoZSBwbGF5aGVhZCBtb3ZlcyBvZmYgb2YgdGhhdCBwb3NpdGlvbiwgdGhlIGNhbGxiYWNrIHNob3VsZCBmaXJlLiBUaGlzIGJlaGF2aW9yIGlzIHdoYXQgcGVvcGxlIGludHVpdGl2ZWx5IGV4cGVjdC5cblxuICAgICAgICAodG90YWxUaW1lIHx8ICFzdXBwcmVzc0V2ZW50cykgJiYgKHRoaXMuX3pUaW1lID0gdG90YWxUaW1lKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuX3JlcGVhdCkge1xuICAgICAgICAvL2FkanVzdCB0aGUgdGltZSBmb3IgcmVwZWF0cyBhbmQgeW95b3NcbiAgICAgICAgeW95byA9IHRoaXMuX3lveW87XG4gICAgICAgIGN5Y2xlRHVyYXRpb24gPSBkdXIgKyB0aGlzLl9yRGVsYXk7XG5cbiAgICAgICAgaWYgKHRoaXMuX3JlcGVhdCA8IC0xICYmIHRvdGFsVGltZSA8IDApIHtcbiAgICAgICAgICByZXR1cm4gdGhpcy50b3RhbFRpbWUoY3ljbGVEdXJhdGlvbiAqIDEwMCArIHRvdGFsVGltZSwgc3VwcHJlc3NFdmVudHMsIGZvcmNlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRpbWUgPSBfcm91bmRQcmVjaXNlKHRUaW1lICUgY3ljbGVEdXJhdGlvbik7IC8vcm91bmQgdG8gYXZvaWQgZmxvYXRpbmcgcG9pbnQgZXJyb3JzLiAoNCAlIDAuOCBzaG91bGQgYmUgMCBidXQgc29tZSBicm93c2VycyByZXBvcnQgaXQgYXMgMC43OTk5OTk5OSEpXG5cbiAgICAgICAgaWYgKHRUaW1lID09PSB0RHVyKSB7XG4gICAgICAgICAgLy8gdGhlIHREdXIgPT09IHRUaW1lIGlzIGZvciBlZGdlIGNhc2VzIHdoZXJlIHRoZXJlJ3MgYSBsZW5ndGh5IGRlY2ltYWwgb24gdGhlIGR1cmF0aW9uIGFuZCBpdCBtYXkgcmVhY2ggdGhlIHZlcnkgZW5kIGJ1dCB0aGUgdGltZSBpcyByZW5kZXJlZCBhcyBub3QtcXVpdGUtdGhlcmUgKHJlbWVtYmVyLCB0RHVyIGlzIHJvdW5kZWQgdG8gNCBkZWNpbWFscyB3aGVyZWFzIGR1ciBpc24ndClcbiAgICAgICAgICBpdGVyYXRpb24gPSB0aGlzLl9yZXBlYXQ7XG4gICAgICAgICAgdGltZSA9IGR1cjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBpdGVyYXRpb24gPSB+fih0VGltZSAvIGN5Y2xlRHVyYXRpb24pO1xuXG4gICAgICAgICAgaWYgKGl0ZXJhdGlvbiAmJiBpdGVyYXRpb24gPT09IHRUaW1lIC8gY3ljbGVEdXJhdGlvbikge1xuICAgICAgICAgICAgdGltZSA9IGR1cjtcbiAgICAgICAgICAgIGl0ZXJhdGlvbi0tO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRpbWUgPiBkdXIgJiYgKHRpbWUgPSBkdXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcHJldkl0ZXJhdGlvbiA9IF9hbmltYXRpb25DeWNsZSh0aGlzLl90VGltZSwgY3ljbGVEdXJhdGlvbik7XG4gICAgICAgICFwcmV2VGltZSAmJiB0aGlzLl90VGltZSAmJiBwcmV2SXRlcmF0aW9uICE9PSBpdGVyYXRpb24gJiYgdGhpcy5fdFRpbWUgLSBwcmV2SXRlcmF0aW9uICogY3ljbGVEdXJhdGlvbiAtIHRoaXMuX2R1ciA8PSAwICYmIChwcmV2SXRlcmF0aW9uID0gaXRlcmF0aW9uKTsgLy8gZWRnZSBjYXNlIC0gaWYgc29tZW9uZSBkb2VzIGFkZFBhdXNlKCkgYXQgdGhlIHZlcnkgYmVnaW5uaW5nIG9mIGEgcmVwZWF0aW5nIHRpbWVsaW5lLCB0aGF0IHBhdXNlIGlzIHRlY2huaWNhbGx5IGF0IHRoZSBzYW1lIHNwb3QgYXMgdGhlIGVuZCB3aGljaCBjYXVzZXMgdGhpcy5fdGltZSB0byBnZXQgc2V0IHRvIDAgd2hlbiB0aGUgdG90YWxUaW1lIHdvdWxkIG5vcm1hbGx5IHBsYWNlIHRoZSBwbGF5aGVhZCBhdCB0aGUgZW5kLiBTZWUgaHR0cHM6Ly9nc2FwLmNvbS9mb3J1bXMvdG9waWMvMjM4MjMtY2xvc2luZy1uYXYtYW5pbWF0aW9uLW5vdC13b3JraW5nLW9uLWllLWFuZC1pcGhvbmUtNi1tYXliZS1vdGhlci1vbGRlci1icm93c2VyLz90YWI9Y29tbWVudHMjY29tbWVudC0xMTMwMDUgYWxzbywgdGhpcy5fdFRpbWUgLSBwcmV2SXRlcmF0aW9uICogY3ljbGVEdXJhdGlvbiAtIHRoaXMuX2R1ciA8PSAwIGp1c3QgY2hlY2tzIHRvIG1ha2Ugc3VyZSBpdCB3YXNuJ3QgcHJldmlvdXNseSBpbiB0aGUgXCJyZXBlYXREZWxheVwiIHBvcnRpb25cblxuICAgICAgICBpZiAoeW95byAmJiBpdGVyYXRpb24gJiAxKSB7XG4gICAgICAgICAgdGltZSA9IGR1ciAtIHRpbWU7XG4gICAgICAgICAgaXNZb3lvID0gMTtcbiAgICAgICAgfVxuICAgICAgICAvKlxuICAgICAgICBtYWtlIHN1cmUgY2hpbGRyZW4gYXQgdGhlIGVuZC9iZWdpbm5pbmcgb2YgdGhlIHRpbWVsaW5lIGFyZSByZW5kZXJlZCBwcm9wZXJseS4gSWYsIGZvciBleGFtcGxlLFxuICAgICAgICBhIDMtc2Vjb25kIGxvbmcgdGltZWxpbmUgcmVuZGVyZWQgYXQgMi45IHNlY29uZHMgcHJldmlvdXNseSwgYW5kIG5vdyByZW5kZXJzIGF0IDMuMiBzZWNvbmRzICh3aGljaFxuICAgICAgICB3b3VsZCBnZXQgdHJhbnNsYXRlZCB0byAyLjggc2Vjb25kcyBpZiB0aGUgdGltZWxpbmUgeW95b3Mgb3IgMC4yIHNlY29uZHMgaWYgaXQganVzdCByZXBlYXRzKSwgdGhlcmVcbiAgICAgICAgY291bGQgYmUgYSBjYWxsYmFjayBvciBhIHNob3J0IHR3ZWVuIHRoYXQncyBhdCAyLjk1IG9yIDMgc2Vjb25kcyBpbiB3aGljaCB3b3VsZG4ndCByZW5kZXIuIFNvXG4gICAgICAgIHdlIG5lZWQgdG8gcHVzaCB0aGUgdGltZWxpbmUgdG8gdGhlIGVuZCAoYW5kL29yIGJlZ2lubmluZyBkZXBlbmRpbmcgb24gaXRzIHlveW8gdmFsdWUpLiBBbHNvIHdlIG11c3RcbiAgICAgICAgZW5zdXJlIHRoYXQgemVyby1kdXJhdGlvbiB0d2VlbnMgYXQgdGhlIHZlcnkgYmVnaW5uaW5nIG9yIGVuZCBvZiB0aGUgVGltZWxpbmUgd29yay5cbiAgICAgICAgKi9cblxuXG4gICAgICAgIGlmIChpdGVyYXRpb24gIT09IHByZXZJdGVyYXRpb24gJiYgIXRoaXMuX2xvY2spIHtcbiAgICAgICAgICB2YXIgcmV3aW5kaW5nID0geW95byAmJiBwcmV2SXRlcmF0aW9uICYgMSxcbiAgICAgICAgICAgICAgZG9lc1dyYXAgPSByZXdpbmRpbmcgPT09ICh5b3lvICYmIGl0ZXJhdGlvbiAmIDEpO1xuICAgICAgICAgIGl0ZXJhdGlvbiA8IHByZXZJdGVyYXRpb24gJiYgKHJld2luZGluZyA9ICFyZXdpbmRpbmcpO1xuICAgICAgICAgIHByZXZUaW1lID0gcmV3aW5kaW5nID8gMCA6IHRUaW1lICUgZHVyID8gZHVyIDogdFRpbWU7IC8vIGlmIHRoZSBwbGF5aGVhZCBpcyBsYW5kaW5nIGV4YWN0bHkgYXQgdGhlIGVuZCBvZiBhbiBpdGVyYXRpb24sIHVzZSB0aGF0IHRvdGFsVGltZSByYXRoZXIgdGhhbiBvbmx5IHRoZSBkdXJhdGlvbiwgb3RoZXJ3aXNlIGl0J2xsIHNraXAgdGhlIDJuZCByZW5kZXIgc2luY2UgaXQncyBlZmZlY3RpdmVseSBhdCB0aGUgc2FtZSB0aW1lLlxuXG4gICAgICAgICAgdGhpcy5fbG9jayA9IDE7XG4gICAgICAgICAgdGhpcy5yZW5kZXIocHJldlRpbWUgfHwgKGlzWW95byA/IDAgOiBfcm91bmRQcmVjaXNlKGl0ZXJhdGlvbiAqIGN5Y2xlRHVyYXRpb24pKSwgc3VwcHJlc3NFdmVudHMsICFkdXIpLl9sb2NrID0gMDtcbiAgICAgICAgICB0aGlzLl90VGltZSA9IHRUaW1lOyAvLyBpZiBhIHVzZXIgZ2V0cyB0aGUgaXRlcmF0aW9uKCkgaW5zaWRlIHRoZSBvblJlcGVhdCwgZm9yIGV4YW1wbGUsIGl0IHNob3VsZCBiZSBhY2N1cmF0ZS5cblxuICAgICAgICAgICFzdXBwcmVzc0V2ZW50cyAmJiB0aGlzLnBhcmVudCAmJiBfY2FsbGJhY2sodGhpcywgXCJvblJlcGVhdFwiKTtcbiAgICAgICAgICB0aGlzLnZhcnMucmVwZWF0UmVmcmVzaCAmJiAhaXNZb3lvICYmICh0aGlzLmludmFsaWRhdGUoKS5fbG9jayA9IDEpO1xuXG4gICAgICAgICAgaWYgKHByZXZUaW1lICYmIHByZXZUaW1lICE9PSB0aGlzLl90aW1lIHx8IHByZXZQYXVzZWQgIT09ICF0aGlzLl90cyB8fCB0aGlzLnZhcnMub25SZXBlYXQgJiYgIXRoaXMucGFyZW50ICYmICF0aGlzLl9hY3QpIHtcbiAgICAgICAgICAgIC8vIGlmIHByZXZUaW1lIGlzIDAgYW5kIHdlIHJlbmRlciBhdCB0aGUgdmVyeSBlbmQsIF90aW1lIHdpbGwgYmUgdGhlIGVuZCwgdGh1cyB3b24ndCBtYXRjaC4gU28gaW4gdGhpcyBlZGdlIGNhc2UsIHByZXZUaW1lIHdvbid0IG1hdGNoIF90aW1lIGJ1dCB0aGF0J3Mgb2theS4gSWYgaXQgZ2V0cyBraWxsZWQgaW4gdGhlIG9uUmVwZWF0LCBlamVjdCBhcyB3ZWxsLlxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZHVyID0gdGhpcy5fZHVyOyAvLyBpbiBjYXNlIHRoZSBkdXJhdGlvbiBjaGFuZ2VkIGluIHRoZSBvblJlcGVhdFxuXG4gICAgICAgICAgdER1ciA9IHRoaXMuX3REdXI7XG5cbiAgICAgICAgICBpZiAoZG9lc1dyYXApIHtcbiAgICAgICAgICAgIHRoaXMuX2xvY2sgPSAyO1xuICAgICAgICAgICAgcHJldlRpbWUgPSByZXdpbmRpbmcgPyBkdXIgOiAtMC4wMDAxO1xuICAgICAgICAgICAgdGhpcy5yZW5kZXIocHJldlRpbWUsIHRydWUpO1xuICAgICAgICAgICAgdGhpcy52YXJzLnJlcGVhdFJlZnJlc2ggJiYgIWlzWW95byAmJiB0aGlzLmludmFsaWRhdGUoKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLl9sb2NrID0gMDtcblxuICAgICAgICAgIGlmICghdGhpcy5fdHMgJiYgIXByZXZQYXVzZWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICAgIH0gLy9pbiBvcmRlciBmb3IgeW95b0Vhc2UgdG8gd29yayBwcm9wZXJseSB3aGVuIHRoZXJlJ3MgYSBzdGFnZ2VyLCB3ZSBtdXN0IHN3YXAgb3V0IHRoZSBlYXNlIGluIGVhY2ggc3ViLXR3ZWVuLlxuXG5cbiAgICAgICAgICBfcHJvcGFnYXRlWW95b0Vhc2UodGhpcywgaXNZb3lvKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5faGFzUGF1c2UgJiYgIXRoaXMuX2ZvcmNpbmcgJiYgdGhpcy5fbG9jayA8IDIpIHtcbiAgICAgICAgcGF1c2VUd2VlbiA9IF9maW5kTmV4dFBhdXNlVHdlZW4odGhpcywgX3JvdW5kUHJlY2lzZShwcmV2VGltZSksIF9yb3VuZFByZWNpc2UodGltZSkpO1xuXG4gICAgICAgIGlmIChwYXVzZVR3ZWVuKSB7XG4gICAgICAgICAgdFRpbWUgLT0gdGltZSAtICh0aW1lID0gcGF1c2VUd2Vlbi5fc3RhcnQpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHRoaXMuX3RUaW1lID0gdFRpbWU7XG4gICAgICB0aGlzLl90aW1lID0gdGltZTtcbiAgICAgIHRoaXMuX2FjdCA9ICF0aW1lU2NhbGU7IC8vYXMgbG9uZyBhcyBpdCdzIG5vdCBwYXVzZWQsIGZvcmNlIGl0IHRvIGJlIGFjdGl2ZSBzbyB0aGF0IGlmIHRoZSB1c2VyIHJlbmRlcnMgaW5kZXBlbmRlbnQgb2YgdGhlIHBhcmVudCB0aW1lbGluZSwgaXQnbGwgYmUgZm9yY2VkIHRvIHJlLXJlbmRlciBvbiB0aGUgbmV4dCB0aWNrLlxuXG4gICAgICBpZiAoIXRoaXMuX2luaXR0ZWQpIHtcbiAgICAgICAgdGhpcy5fb25VcGRhdGUgPSB0aGlzLnZhcnMub25VcGRhdGU7XG4gICAgICAgIHRoaXMuX2luaXR0ZWQgPSAxO1xuICAgICAgICB0aGlzLl96VGltZSA9IHRvdGFsVGltZTtcbiAgICAgICAgcHJldlRpbWUgPSAwOyAvLyB1cG9uIGluaXQsIHRoZSBwbGF5aGVhZCBzaG91bGQgYWx3YXlzIGdvIGZvcndhcmQ7IHNvbWVvbmUgY291bGQgaW52YWxpZGF0ZSgpIGEgY29tcGxldGVkIHRpbWVsaW5lIGFuZCB0aGVuIGlmIHRoZXkgcmVzdGFydCgpLCB0aGF0IHdvdWxkIG1ha2UgY2hpbGQgdHdlZW5zIHJlbmRlciBpbiByZXZlcnNlIG9yZGVyIHdoaWNoIGNvdWxkIGxvY2sgaW4gdGhlIHdyb25nIHN0YXJ0aW5nIHZhbHVlcyBpZiB0aGV5IGJ1aWxkIG9uIGVhY2ggb3RoZXIsIGxpa2UgdGwudG8ob2JqLCB7eDogMTAwfSkudG8ob2JqLCB7eDogMH0pLlxuICAgICAgfVxuXG4gICAgICBpZiAoIXByZXZUaW1lICYmIHRpbWUgJiYgIXN1cHByZXNzRXZlbnRzICYmICFpdGVyYXRpb24pIHtcbiAgICAgICAgX2NhbGxiYWNrKHRoaXMsIFwib25TdGFydFwiKTtcblxuICAgICAgICBpZiAodGhpcy5fdFRpbWUgIT09IHRUaW1lKSB7XG4gICAgICAgICAgLy8gaW4gY2FzZSB0aGUgb25TdGFydCB0cmlnZ2VyZWQgYSByZW5kZXIgYXQgYSBkaWZmZXJlbnQgc3BvdCwgZWplY3QuIExpa2UgaWYgc29tZW9uZSBkaWQgYW5pbWF0aW9uLnBhdXNlKDAuNSkgb3Igc29tZXRoaW5nIGluc2lkZSB0aGUgb25TdGFydC5cbiAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGltZSA+PSBwcmV2VGltZSAmJiB0b3RhbFRpbWUgPj0gMCkge1xuICAgICAgICBjaGlsZCA9IHRoaXMuX2ZpcnN0O1xuXG4gICAgICAgIHdoaWxlIChjaGlsZCkge1xuICAgICAgICAgIG5leHQgPSBjaGlsZC5fbmV4dDtcblxuICAgICAgICAgIGlmICgoY2hpbGQuX2FjdCB8fCB0aW1lID49IGNoaWxkLl9zdGFydCkgJiYgY2hpbGQuX3RzICYmIHBhdXNlVHdlZW4gIT09IGNoaWxkKSB7XG4gICAgICAgICAgICBpZiAoY2hpbGQucGFyZW50ICE9PSB0aGlzKSB7XG4gICAgICAgICAgICAgIC8vIGFuIGV4dHJlbWUgZWRnZSBjYXNlIC0gdGhlIGNoaWxkJ3MgcmVuZGVyIGNvdWxkIGRvIHNvbWV0aGluZyBsaWtlIGtpbGwoKSB0aGUgXCJuZXh0XCIgb25lIGluIHRoZSBsaW5rZWQgbGlzdCwgb3IgcmVwYXJlbnQgaXQuIEluIHRoYXQgY2FzZSB3ZSBtdXN0IHJlLWluaXRpYXRlIHRoZSB3aG9sZSByZW5kZXIgdG8gYmUgc2FmZS5cbiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVuZGVyKHRvdGFsVGltZSwgc3VwcHJlc3NFdmVudHMsIGZvcmNlKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY2hpbGQucmVuZGVyKGNoaWxkLl90cyA+IDAgPyAodGltZSAtIGNoaWxkLl9zdGFydCkgKiBjaGlsZC5fdHMgOiAoY2hpbGQuX2RpcnR5ID8gY2hpbGQudG90YWxEdXJhdGlvbigpIDogY2hpbGQuX3REdXIpICsgKHRpbWUgLSBjaGlsZC5fc3RhcnQpICogY2hpbGQuX3RzLCBzdXBwcmVzc0V2ZW50cywgZm9yY2UpO1xuXG4gICAgICAgICAgICBpZiAodGltZSAhPT0gdGhpcy5fdGltZSB8fCAhdGhpcy5fdHMgJiYgIXByZXZQYXVzZWQpIHtcbiAgICAgICAgICAgICAgLy9pbiBjYXNlIGEgdHdlZW4gcGF1c2VzIG9yIHNlZWtzIHRoZSB0aW1lbGluZSB3aGVuIHJlbmRlcmluZywgbGlrZSBpbnNpZGUgb2YgYW4gb25VcGRhdGUvb25Db21wbGV0ZVxuICAgICAgICAgICAgICBwYXVzZVR3ZWVuID0gMDtcbiAgICAgICAgICAgICAgbmV4dCAmJiAodFRpbWUgKz0gdGhpcy5felRpbWUgPSAtX3RpbnlOdW0pOyAvLyBpdCBkaWRuJ3QgZmluaXNoIHJlbmRlcmluZywgc28gZmxhZyB6VGltZSBhcyBuZWdhdGl2ZSBzbyB0aGF0IHNvIHRoYXQgdGhlIG5leHQgdGltZSByZW5kZXIoKSBpcyBjYWxsZWQgaXQnbGwgYmUgZm9yY2VkICh0byByZW5kZXIgYW55IHJlbWFpbmluZyBjaGlsZHJlbilcblxuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjaGlsZCA9IG5leHQ7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNoaWxkID0gdGhpcy5fbGFzdDtcbiAgICAgICAgdmFyIGFkanVzdGVkVGltZSA9IHRvdGFsVGltZSA8IDAgPyB0b3RhbFRpbWUgOiB0aW1lOyAvL3doZW4gdGhlIHBsYXloZWFkIGdvZXMgYmFja3dhcmQgYmV5b25kIHRoZSBzdGFydCBvZiB0aGlzIHRpbWVsaW5lLCB3ZSBtdXN0IHBhc3MgdGhhdCBpbmZvcm1hdGlvbiBkb3duIHRvIHRoZSBjaGlsZCBhbmltYXRpb25zIHNvIHRoYXQgemVyby1kdXJhdGlvbiB0d2VlbnMga25vdyB3aGV0aGVyIHRvIHJlbmRlciB0aGVpciBzdGFydGluZyBvciBlbmRpbmcgdmFsdWVzLlxuXG4gICAgICAgIHdoaWxlIChjaGlsZCkge1xuICAgICAgICAgIG5leHQgPSBjaGlsZC5fcHJldjtcblxuICAgICAgICAgIGlmICgoY2hpbGQuX2FjdCB8fCBhZGp1c3RlZFRpbWUgPD0gY2hpbGQuX2VuZCkgJiYgY2hpbGQuX3RzICYmIHBhdXNlVHdlZW4gIT09IGNoaWxkKSB7XG4gICAgICAgICAgICBpZiAoY2hpbGQucGFyZW50ICE9PSB0aGlzKSB7XG4gICAgICAgICAgICAgIC8vIGFuIGV4dHJlbWUgZWRnZSBjYXNlIC0gdGhlIGNoaWxkJ3MgcmVuZGVyIGNvdWxkIGRvIHNvbWV0aGluZyBsaWtlIGtpbGwoKSB0aGUgXCJuZXh0XCIgb25lIGluIHRoZSBsaW5rZWQgbGlzdCwgb3IgcmVwYXJlbnQgaXQuIEluIHRoYXQgY2FzZSB3ZSBtdXN0IHJlLWluaXRpYXRlIHRoZSB3aG9sZSByZW5kZXIgdG8gYmUgc2FmZS5cbiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVuZGVyKHRvdGFsVGltZSwgc3VwcHJlc3NFdmVudHMsIGZvcmNlKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY2hpbGQucmVuZGVyKGNoaWxkLl90cyA+IDAgPyAoYWRqdXN0ZWRUaW1lIC0gY2hpbGQuX3N0YXJ0KSAqIGNoaWxkLl90cyA6IChjaGlsZC5fZGlydHkgPyBjaGlsZC50b3RhbER1cmF0aW9uKCkgOiBjaGlsZC5fdER1cikgKyAoYWRqdXN0ZWRUaW1lIC0gY2hpbGQuX3N0YXJ0KSAqIGNoaWxkLl90cywgc3VwcHJlc3NFdmVudHMsIGZvcmNlIHx8IF9yZXZlcnRpbmcgJiYgKGNoaWxkLl9pbml0dGVkIHx8IGNoaWxkLl9zdGFydEF0KSk7IC8vIGlmIHJldmVydGluZywgd2Ugc2hvdWxkIGFsd2F5cyBmb3JjZSByZW5kZXJzIG9mIGluaXR0ZWQgdHdlZW5zIChidXQgcmVtZW1iZXIgdGhhdCAuZnJvbVRvKCkgb3IgLmZyb20oKSBtYXkgaGF2ZSBhIF9zdGFydEF0IGJ1dCBub3QgX2luaXR0ZWQgeWV0KS4gSWYsIGZvciBleGFtcGxlLCBhIC5mcm9tVG8oKSB0d2VlbiB3aXRoIGEgc3RhZ2dlciAod2hpY2ggY3JlYXRlcyBhbiBpbnRlcm5hbCB0aW1lbGluZSkgZ2V0cyByZXZlcnRlZCBCRUZPUkUgc29tZSBvZiBpdHMgY2hpbGQgdHdlZW5zIHJlbmRlciBmb3IgdGhlIGZpcnN0IHRpbWUsIGl0IG1heSBub3QgcHJvcGVybHkgdHJpZ2dlciB0aGVtIHRvIHJldmVydC5cblxuICAgICAgICAgICAgaWYgKHRpbWUgIT09IHRoaXMuX3RpbWUgfHwgIXRoaXMuX3RzICYmICFwcmV2UGF1c2VkKSB7XG4gICAgICAgICAgICAgIC8vaW4gY2FzZSBhIHR3ZWVuIHBhdXNlcyBvciBzZWVrcyB0aGUgdGltZWxpbmUgd2hlbiByZW5kZXJpbmcsIGxpa2UgaW5zaWRlIG9mIGFuIG9uVXBkYXRlL29uQ29tcGxldGVcbiAgICAgICAgICAgICAgcGF1c2VUd2VlbiA9IDA7XG4gICAgICAgICAgICAgIG5leHQgJiYgKHRUaW1lICs9IHRoaXMuX3pUaW1lID0gYWRqdXN0ZWRUaW1lID8gLV90aW55TnVtIDogX3RpbnlOdW0pOyAvLyBpdCBkaWRuJ3QgZmluaXNoIHJlbmRlcmluZywgc28gYWRqdXN0IHpUaW1lIHNvIHRoYXQgc28gdGhhdCB0aGUgbmV4dCB0aW1lIHJlbmRlcigpIGlzIGNhbGxlZCBpdCdsbCBiZSBmb3JjZWQgKHRvIHJlbmRlciBhbnkgcmVtYWluaW5nIGNoaWxkcmVuKVxuXG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGNoaWxkID0gbmV4dDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAocGF1c2VUd2VlbiAmJiAhc3VwcHJlc3NFdmVudHMpIHtcbiAgICAgICAgdGhpcy5wYXVzZSgpO1xuICAgICAgICBwYXVzZVR3ZWVuLnJlbmRlcih0aW1lID49IHByZXZUaW1lID8gMCA6IC1fdGlueU51bSkuX3pUaW1lID0gdGltZSA+PSBwcmV2VGltZSA/IDEgOiAtMTtcblxuICAgICAgICBpZiAodGhpcy5fdHMpIHtcbiAgICAgICAgICAvL3RoZSBjYWxsYmFjayByZXN1bWVkIHBsYXliYWNrISBTbyBzaW5jZSB3ZSBtYXkgaGF2ZSBoZWxkIGJhY2sgdGhlIHBsYXloZWFkIGR1ZSB0byB3aGVyZSB0aGUgcGF1c2UgaXMgcG9zaXRpb25lZCwgZ28gYWhlYWQgYW5kIGp1bXAgdG8gd2hlcmUgaXQncyBTVVBQT1NFRCB0byBiZSAoaWYgbm8gcGF1c2UgaGFwcGVuZWQpLlxuICAgICAgICAgIHRoaXMuX3N0YXJ0ID0gcHJldlN0YXJ0OyAvL2lmIHRoZSBwYXVzZSB3YXMgYXQgYW4gZWFybGllciB0aW1lIGFuZCB0aGUgdXNlciByZXN1bWVkIGluIHRoZSBjYWxsYmFjaywgaXQgY291bGQgcmVwb3NpdGlvbiB0aGUgdGltZWxpbmUgKGNoYW5naW5nIGl0cyBzdGFydFRpbWUpLCB0aHJvd2luZyB0aGluZ3Mgb2ZmIHNsaWdodGx5LCBzbyB3ZSBtYWtlIHN1cmUgdGhlIF9zdGFydCBkb2Vzbid0IHNoaWZ0LlxuXG4gICAgICAgICAgX3NldEVuZCh0aGlzKTtcblxuICAgICAgICAgIHJldHVybiB0aGlzLnJlbmRlcih0b3RhbFRpbWUsIHN1cHByZXNzRXZlbnRzLCBmb3JjZSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdGhpcy5fb25VcGRhdGUgJiYgIXN1cHByZXNzRXZlbnRzICYmIF9jYWxsYmFjayh0aGlzLCBcIm9uVXBkYXRlXCIsIHRydWUpO1xuICAgICAgaWYgKHRUaW1lID09PSB0RHVyICYmIHRoaXMuX3RUaW1lID49IHRoaXMudG90YWxEdXJhdGlvbigpIHx8ICF0VGltZSAmJiBwcmV2VGltZSkgaWYgKHByZXZTdGFydCA9PT0gdGhpcy5fc3RhcnQgfHwgTWF0aC5hYnModGltZVNjYWxlKSAhPT0gTWF0aC5hYnModGhpcy5fdHMpKSBpZiAoIXRoaXMuX2xvY2spIHtcbiAgICAgICAgLy8gcmVtZW1iZXIsIGEgY2hpbGQncyBjYWxsYmFjayBtYXkgYWx0ZXIgdGhpcyB0aW1lbGluZSdzIHBsYXloZWFkIG9yIHRpbWVTY2FsZSB3aGljaCBpcyB3aHkgd2UgbmVlZCB0byBhZGQgc29tZSBvZiB0aGVzZSBjaGVja3MuXG4gICAgICAgICh0b3RhbFRpbWUgfHwgIWR1cikgJiYgKHRUaW1lID09PSB0RHVyICYmIHRoaXMuX3RzID4gMCB8fCAhdFRpbWUgJiYgdGhpcy5fdHMgPCAwKSAmJiBfcmVtb3ZlRnJvbVBhcmVudCh0aGlzLCAxKTsgLy8gZG9uJ3QgcmVtb3ZlIGlmIHRoZSB0aW1lbGluZSBpcyByZXZlcnNlZCBhbmQgdGhlIHBsYXloZWFkIGlzbid0IGF0IDAsIG90aGVyd2lzZSB0bC5wcm9ncmVzcygxKS5yZXZlcnNlKCkgd29uJ3Qgd29yay4gT25seSByZW1vdmUgaWYgdGhlIHBsYXloZWFkIGlzIGF0IHRoZSBlbmQgYW5kIHRpbWVTY2FsZSBpcyBwb3NpdGl2ZSwgb3IgaWYgdGhlIHBsYXloZWFkIGlzIGF0IDAgYW5kIHRoZSB0aW1lU2NhbGUgaXMgbmVnYXRpdmUuXG5cbiAgICAgICAgaWYgKCFzdXBwcmVzc0V2ZW50cyAmJiAhKHRvdGFsVGltZSA8IDAgJiYgIXByZXZUaW1lKSAmJiAodFRpbWUgfHwgcHJldlRpbWUgfHwgIXREdXIpKSB7XG4gICAgICAgICAgX2NhbGxiYWNrKHRoaXMsIHRUaW1lID09PSB0RHVyICYmIHRvdGFsVGltZSA+PSAwID8gXCJvbkNvbXBsZXRlXCIgOiBcIm9uUmV2ZXJzZUNvbXBsZXRlXCIsIHRydWUpO1xuXG4gICAgICAgICAgdGhpcy5fcHJvbSAmJiAhKHRUaW1lIDwgdER1ciAmJiB0aGlzLnRpbWVTY2FsZSgpID4gMCkgJiYgdGhpcy5fcHJvbSgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH07XG5cbiAgX3Byb3RvMi5hZGQgPSBmdW5jdGlvbiBhZGQoY2hpbGQsIHBvc2l0aW9uKSB7XG4gICAgdmFyIF90aGlzMiA9IHRoaXM7XG5cbiAgICBfaXNOdW1iZXIocG9zaXRpb24pIHx8IChwb3NpdGlvbiA9IF9wYXJzZVBvc2l0aW9uKHRoaXMsIHBvc2l0aW9uLCBjaGlsZCkpO1xuXG4gICAgaWYgKCEoY2hpbGQgaW5zdGFuY2VvZiBBbmltYXRpb24pKSB7XG4gICAgICBpZiAoX2lzQXJyYXkoY2hpbGQpKSB7XG4gICAgICAgIGNoaWxkLmZvckVhY2goZnVuY3Rpb24gKG9iaikge1xuICAgICAgICAgIHJldHVybiBfdGhpczIuYWRkKG9iaiwgcG9zaXRpb24pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICB9XG5cbiAgICAgIGlmIChfaXNTdHJpbmcoY2hpbGQpKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmFkZExhYmVsKGNoaWxkLCBwb3NpdGlvbik7XG4gICAgICB9XG5cbiAgICAgIGlmIChfaXNGdW5jdGlvbihjaGlsZCkpIHtcbiAgICAgICAgY2hpbGQgPSBUd2Vlbi5kZWxheWVkQ2FsbCgwLCBjaGlsZCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcyAhPT0gY2hpbGQgPyBfYWRkVG9UaW1lbGluZSh0aGlzLCBjaGlsZCwgcG9zaXRpb24pIDogdGhpczsgLy9kb24ndCBhbGxvdyBhIHRpbWVsaW5lIHRvIGJlIGFkZGVkIHRvIGl0c2VsZiBhcyBhIGNoaWxkIVxuICB9O1xuXG4gIF9wcm90bzIuZ2V0Q2hpbGRyZW4gPSBmdW5jdGlvbiBnZXRDaGlsZHJlbihuZXN0ZWQsIHR3ZWVucywgdGltZWxpbmVzLCBpZ25vcmVCZWZvcmVUaW1lKSB7XG4gICAgaWYgKG5lc3RlZCA9PT0gdm9pZCAwKSB7XG4gICAgICBuZXN0ZWQgPSB0cnVlO1xuICAgIH1cblxuICAgIGlmICh0d2VlbnMgPT09IHZvaWQgMCkge1xuICAgICAgdHdlZW5zID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBpZiAodGltZWxpbmVzID09PSB2b2lkIDApIHtcbiAgICAgIHRpbWVsaW5lcyA9IHRydWU7XG4gICAgfVxuXG4gICAgaWYgKGlnbm9yZUJlZm9yZVRpbWUgPT09IHZvaWQgMCkge1xuICAgICAgaWdub3JlQmVmb3JlVGltZSA9IC1fYmlnTnVtO1xuICAgIH1cblxuICAgIHZhciBhID0gW10sXG4gICAgICAgIGNoaWxkID0gdGhpcy5fZmlyc3Q7XG5cbiAgICB3aGlsZSAoY2hpbGQpIHtcbiAgICAgIGlmIChjaGlsZC5fc3RhcnQgPj0gaWdub3JlQmVmb3JlVGltZSkge1xuICAgICAgICBpZiAoY2hpbGQgaW5zdGFuY2VvZiBUd2Vlbikge1xuICAgICAgICAgIHR3ZWVucyAmJiBhLnB1c2goY2hpbGQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRpbWVsaW5lcyAmJiBhLnB1c2goY2hpbGQpO1xuICAgICAgICAgIG5lc3RlZCAmJiBhLnB1c2guYXBwbHkoYSwgY2hpbGQuZ2V0Q2hpbGRyZW4odHJ1ZSwgdHdlZW5zLCB0aW1lbGluZXMpKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjaGlsZCA9IGNoaWxkLl9uZXh0O1xuICAgIH1cblxuICAgIHJldHVybiBhO1xuICB9O1xuXG4gIF9wcm90bzIuZ2V0QnlJZCA9IGZ1bmN0aW9uIGdldEJ5SWQoaWQpIHtcbiAgICB2YXIgYW5pbWF0aW9ucyA9IHRoaXMuZ2V0Q2hpbGRyZW4oMSwgMSwgMSksXG4gICAgICAgIGkgPSBhbmltYXRpb25zLmxlbmd0aDtcblxuICAgIHdoaWxlIChpLS0pIHtcbiAgICAgIGlmIChhbmltYXRpb25zW2ldLnZhcnMuaWQgPT09IGlkKSB7XG4gICAgICAgIHJldHVybiBhbmltYXRpb25zW2ldO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICBfcHJvdG8yLnJlbW92ZSA9IGZ1bmN0aW9uIHJlbW92ZShjaGlsZCkge1xuICAgIGlmIChfaXNTdHJpbmcoY2hpbGQpKSB7XG4gICAgICByZXR1cm4gdGhpcy5yZW1vdmVMYWJlbChjaGlsZCk7XG4gICAgfVxuXG4gICAgaWYgKF9pc0Z1bmN0aW9uKGNoaWxkKSkge1xuICAgICAgcmV0dXJuIHRoaXMua2lsbFR3ZWVuc09mKGNoaWxkKTtcbiAgICB9XG5cbiAgICBfcmVtb3ZlTGlua2VkTGlzdEl0ZW0odGhpcywgY2hpbGQpO1xuXG4gICAgaWYgKGNoaWxkID09PSB0aGlzLl9yZWNlbnQpIHtcbiAgICAgIHRoaXMuX3JlY2VudCA9IHRoaXMuX2xhc3Q7XG4gICAgfVxuXG4gICAgcmV0dXJuIF91bmNhY2hlKHRoaXMpO1xuICB9O1xuXG4gIF9wcm90bzIudG90YWxUaW1lID0gZnVuY3Rpb24gdG90YWxUaW1lKF90b3RhbFRpbWUyLCBzdXBwcmVzc0V2ZW50cykge1xuICAgIGlmICghYXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgcmV0dXJuIHRoaXMuX3RUaW1lO1xuICAgIH1cblxuICAgIHRoaXMuX2ZvcmNpbmcgPSAxO1xuXG4gICAgaWYgKCF0aGlzLl9kcCAmJiB0aGlzLl90cykge1xuICAgICAgLy9zcGVjaWFsIGNhc2UgZm9yIHRoZSBnbG9iYWwgdGltZWxpbmUgKG9yIGFueSBvdGhlciB0aGF0IGhhcyBubyBwYXJlbnQgb3IgZGV0YWNoZWQgcGFyZW50KS5cbiAgICAgIHRoaXMuX3N0YXJ0ID0gX3JvdW5kUHJlY2lzZShfdGlja2VyLnRpbWUgLSAodGhpcy5fdHMgPiAwID8gX3RvdGFsVGltZTIgLyB0aGlzLl90cyA6ICh0aGlzLnRvdGFsRHVyYXRpb24oKSAtIF90b3RhbFRpbWUyKSAvIC10aGlzLl90cykpO1xuICAgIH1cblxuICAgIF9BbmltYXRpb24ucHJvdG90eXBlLnRvdGFsVGltZS5jYWxsKHRoaXMsIF90b3RhbFRpbWUyLCBzdXBwcmVzc0V2ZW50cyk7XG5cbiAgICB0aGlzLl9mb3JjaW5nID0gMDtcbiAgICByZXR1cm4gdGhpcztcbiAgfTtcblxuICBfcHJvdG8yLmFkZExhYmVsID0gZnVuY3Rpb24gYWRkTGFiZWwobGFiZWwsIHBvc2l0aW9uKSB7XG4gICAgdGhpcy5sYWJlbHNbbGFiZWxdID0gX3BhcnNlUG9zaXRpb24odGhpcywgcG9zaXRpb24pO1xuICAgIHJldHVybiB0aGlzO1xuICB9O1xuXG4gIF9wcm90bzIucmVtb3ZlTGFiZWwgPSBmdW5jdGlvbiByZW1vdmVMYWJlbChsYWJlbCkge1xuICAgIGRlbGV0ZSB0aGlzLmxhYmVsc1tsYWJlbF07XG4gICAgcmV0dXJuIHRoaXM7XG4gIH07XG5cbiAgX3Byb3RvMi5hZGRQYXVzZSA9IGZ1bmN0aW9uIGFkZFBhdXNlKHBvc2l0aW9uLCBjYWxsYmFjaywgcGFyYW1zKSB7XG4gICAgdmFyIHQgPSBUd2Vlbi5kZWxheWVkQ2FsbCgwLCBjYWxsYmFjayB8fCBfZW1wdHlGdW5jLCBwYXJhbXMpO1xuICAgIHQuZGF0YSA9IFwiaXNQYXVzZVwiO1xuICAgIHRoaXMuX2hhc1BhdXNlID0gMTtcbiAgICByZXR1cm4gX2FkZFRvVGltZWxpbmUodGhpcywgdCwgX3BhcnNlUG9zaXRpb24odGhpcywgcG9zaXRpb24pKTtcbiAgfTtcblxuICBfcHJvdG8yLnJlbW92ZVBhdXNlID0gZnVuY3Rpb24gcmVtb3ZlUGF1c2UocG9zaXRpb24pIHtcbiAgICB2YXIgY2hpbGQgPSB0aGlzLl9maXJzdDtcbiAgICBwb3NpdGlvbiA9IF9wYXJzZVBvc2l0aW9uKHRoaXMsIHBvc2l0aW9uKTtcblxuICAgIHdoaWxlIChjaGlsZCkge1xuICAgICAgaWYgKGNoaWxkLl9zdGFydCA9PT0gcG9zaXRpb24gJiYgY2hpbGQuZGF0YSA9PT0gXCJpc1BhdXNlXCIpIHtcbiAgICAgICAgX3JlbW92ZUZyb21QYXJlbnQoY2hpbGQpO1xuICAgICAgfVxuXG4gICAgICBjaGlsZCA9IGNoaWxkLl9uZXh0O1xuICAgIH1cbiAgfTtcblxuICBfcHJvdG8yLmtpbGxUd2VlbnNPZiA9IGZ1bmN0aW9uIGtpbGxUd2VlbnNPZih0YXJnZXRzLCBwcm9wcywgb25seUFjdGl2ZSkge1xuICAgIHZhciB0d2VlbnMgPSB0aGlzLmdldFR3ZWVuc09mKHRhcmdldHMsIG9ubHlBY3RpdmUpLFxuICAgICAgICBpID0gdHdlZW5zLmxlbmd0aDtcblxuICAgIHdoaWxlIChpLS0pIHtcbiAgICAgIF9vdmVyd3JpdGluZ1R3ZWVuICE9PSB0d2VlbnNbaV0gJiYgdHdlZW5zW2ldLmtpbGwodGFyZ2V0cywgcHJvcHMpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9O1xuXG4gIF9wcm90bzIuZ2V0VHdlZW5zT2YgPSBmdW5jdGlvbiBnZXRUd2VlbnNPZih0YXJnZXRzLCBvbmx5QWN0aXZlKSB7XG4gICAgdmFyIGEgPSBbXSxcbiAgICAgICAgcGFyc2VkVGFyZ2V0cyA9IHRvQXJyYXkodGFyZ2V0cyksXG4gICAgICAgIGNoaWxkID0gdGhpcy5fZmlyc3QsXG4gICAgICAgIGlzR2xvYmFsVGltZSA9IF9pc051bWJlcihvbmx5QWN0aXZlKSxcbiAgICAgICAgLy8gYSBudW1iZXIgaXMgaW50ZXJwcmV0ZWQgYXMgYSBnbG9iYWwgdGltZS4gSWYgdGhlIGFuaW1hdGlvbiBzcGFuc1xuICAgIGNoaWxkcmVuO1xuXG4gICAgd2hpbGUgKGNoaWxkKSB7XG4gICAgICBpZiAoY2hpbGQgaW5zdGFuY2VvZiBUd2Vlbikge1xuICAgICAgICBpZiAoX2FycmF5Q29udGFpbnNBbnkoY2hpbGQuX3RhcmdldHMsIHBhcnNlZFRhcmdldHMpICYmIChpc0dsb2JhbFRpbWUgPyAoIV9vdmVyd3JpdGluZ1R3ZWVuIHx8IGNoaWxkLl9pbml0dGVkICYmIGNoaWxkLl90cykgJiYgY2hpbGQuZ2xvYmFsVGltZSgwKSA8PSBvbmx5QWN0aXZlICYmIGNoaWxkLmdsb2JhbFRpbWUoY2hpbGQudG90YWxEdXJhdGlvbigpKSA+IG9ubHlBY3RpdmUgOiAhb25seUFjdGl2ZSB8fCBjaGlsZC5pc0FjdGl2ZSgpKSkge1xuICAgICAgICAgIC8vIG5vdGU6IGlmIHRoaXMgaXMgZm9yIG92ZXJ3cml0aW5nLCBpdCBzaG91bGQgb25seSBiZSBmb3IgdHdlZW5zIHRoYXQgYXJlbid0IHBhdXNlZCBhbmQgYXJlIGluaXR0ZWQuXG4gICAgICAgICAgYS5wdXNoKGNoaWxkKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICgoY2hpbGRyZW4gPSBjaGlsZC5nZXRUd2VlbnNPZihwYXJzZWRUYXJnZXRzLCBvbmx5QWN0aXZlKSkubGVuZ3RoKSB7XG4gICAgICAgIGEucHVzaC5hcHBseShhLCBjaGlsZHJlbik7XG4gICAgICB9XG5cbiAgICAgIGNoaWxkID0gY2hpbGQuX25leHQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIGE7XG4gIH0gLy8gcG90ZW50aWFsIGZ1dHVyZSBmZWF0dXJlIC0gdGFyZ2V0cygpIG9uIHRpbWVsaW5lc1xuICAvLyB0YXJnZXRzKCkge1xuICAvLyBcdGxldCByZXN1bHQgPSBbXTtcbiAgLy8gXHR0aGlzLmdldENoaWxkcmVuKHRydWUsIHRydWUsIGZhbHNlKS5mb3JFYWNoKHQgPT4gcmVzdWx0LnB1c2goLi4udC50YXJnZXRzKCkpKTtcbiAgLy8gXHRyZXR1cm4gcmVzdWx0LmZpbHRlcigodiwgaSkgPT4gcmVzdWx0LmluZGV4T2YodikgPT09IGkpO1xuICAvLyB9XG4gIDtcblxuICBfcHJvdG8yLnR3ZWVuVG8gPSBmdW5jdGlvbiB0d2VlblRvKHBvc2l0aW9uLCB2YXJzKSB7XG4gICAgdmFycyA9IHZhcnMgfHwge307XG5cbiAgICB2YXIgdGwgPSB0aGlzLFxuICAgICAgICBlbmRUaW1lID0gX3BhcnNlUG9zaXRpb24odGwsIHBvc2l0aW9uKSxcbiAgICAgICAgX3ZhcnMgPSB2YXJzLFxuICAgICAgICBzdGFydEF0ID0gX3ZhcnMuc3RhcnRBdCxcbiAgICAgICAgX29uU3RhcnQgPSBfdmFycy5vblN0YXJ0LFxuICAgICAgICBvblN0YXJ0UGFyYW1zID0gX3ZhcnMub25TdGFydFBhcmFtcyxcbiAgICAgICAgaW1tZWRpYXRlUmVuZGVyID0gX3ZhcnMuaW1tZWRpYXRlUmVuZGVyLFxuICAgICAgICBpbml0dGVkLFxuICAgICAgICB0d2VlbiA9IFR3ZWVuLnRvKHRsLCBfc2V0RGVmYXVsdHMoe1xuICAgICAgZWFzZTogdmFycy5lYXNlIHx8IFwibm9uZVwiLFxuICAgICAgbGF6eTogZmFsc2UsXG4gICAgICBpbW1lZGlhdGVSZW5kZXI6IGZhbHNlLFxuICAgICAgdGltZTogZW5kVGltZSxcbiAgICAgIG92ZXJ3cml0ZTogXCJhdXRvXCIsXG4gICAgICBkdXJhdGlvbjogdmFycy5kdXJhdGlvbiB8fCBNYXRoLmFicygoZW5kVGltZSAtIChzdGFydEF0ICYmIFwidGltZVwiIGluIHN0YXJ0QXQgPyBzdGFydEF0LnRpbWUgOiB0bC5fdGltZSkpIC8gdGwudGltZVNjYWxlKCkpIHx8IF90aW55TnVtLFxuICAgICAgb25TdGFydDogZnVuY3Rpb24gb25TdGFydCgpIHtcbiAgICAgICAgdGwucGF1c2UoKTtcblxuICAgICAgICBpZiAoIWluaXR0ZWQpIHtcbiAgICAgICAgICB2YXIgZHVyYXRpb24gPSB2YXJzLmR1cmF0aW9uIHx8IE1hdGguYWJzKChlbmRUaW1lIC0gKHN0YXJ0QXQgJiYgXCJ0aW1lXCIgaW4gc3RhcnRBdCA/IHN0YXJ0QXQudGltZSA6IHRsLl90aW1lKSkgLyB0bC50aW1lU2NhbGUoKSk7XG4gICAgICAgICAgdHdlZW4uX2R1ciAhPT0gZHVyYXRpb24gJiYgX3NldER1cmF0aW9uKHR3ZWVuLCBkdXJhdGlvbiwgMCwgMSkucmVuZGVyKHR3ZWVuLl90aW1lLCB0cnVlLCB0cnVlKTtcbiAgICAgICAgICBpbml0dGVkID0gMTtcbiAgICAgICAgfVxuXG4gICAgICAgIF9vblN0YXJ0ICYmIF9vblN0YXJ0LmFwcGx5KHR3ZWVuLCBvblN0YXJ0UGFyYW1zIHx8IFtdKTsgLy9pbiBjYXNlIHRoZSB1c2VyIGhhZCBhbiBvblN0YXJ0IGluIHRoZSB2YXJzIC0gd2UgZG9uJ3Qgd2FudCB0byBvdmVyd3JpdGUgaXQuXG4gICAgICB9XG4gICAgfSwgdmFycykpO1xuXG4gICAgcmV0dXJuIGltbWVkaWF0ZVJlbmRlciA/IHR3ZWVuLnJlbmRlcigwKSA6IHR3ZWVuO1xuICB9O1xuXG4gIF9wcm90bzIudHdlZW5Gcm9tVG8gPSBmdW5jdGlvbiB0d2VlbkZyb21Ubyhmcm9tUG9zaXRpb24sIHRvUG9zaXRpb24sIHZhcnMpIHtcbiAgICByZXR1cm4gdGhpcy50d2VlblRvKHRvUG9zaXRpb24sIF9zZXREZWZhdWx0cyh7XG4gICAgICBzdGFydEF0OiB7XG4gICAgICAgIHRpbWU6IF9wYXJzZVBvc2l0aW9uKHRoaXMsIGZyb21Qb3NpdGlvbilcbiAgICAgIH1cbiAgICB9LCB2YXJzKSk7XG4gIH07XG5cbiAgX3Byb3RvMi5yZWNlbnQgPSBmdW5jdGlvbiByZWNlbnQoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3JlY2VudDtcbiAgfTtcblxuICBfcHJvdG8yLm5leHRMYWJlbCA9IGZ1bmN0aW9uIG5leHRMYWJlbChhZnRlclRpbWUpIHtcbiAgICBpZiAoYWZ0ZXJUaW1lID09PSB2b2lkIDApIHtcbiAgICAgIGFmdGVyVGltZSA9IHRoaXMuX3RpbWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIF9nZXRMYWJlbEluRGlyZWN0aW9uKHRoaXMsIF9wYXJzZVBvc2l0aW9uKHRoaXMsIGFmdGVyVGltZSkpO1xuICB9O1xuXG4gIF9wcm90bzIucHJldmlvdXNMYWJlbCA9IGZ1bmN0aW9uIHByZXZpb3VzTGFiZWwoYmVmb3JlVGltZSkge1xuICAgIGlmIChiZWZvcmVUaW1lID09PSB2b2lkIDApIHtcbiAgICAgIGJlZm9yZVRpbWUgPSB0aGlzLl90aW1lO1xuICAgIH1cblxuICAgIHJldHVybiBfZ2V0TGFiZWxJbkRpcmVjdGlvbih0aGlzLCBfcGFyc2VQb3NpdGlvbih0aGlzLCBiZWZvcmVUaW1lKSwgMSk7XG4gIH07XG5cbiAgX3Byb3RvMi5jdXJyZW50TGFiZWwgPSBmdW5jdGlvbiBjdXJyZW50TGFiZWwodmFsdWUpIHtcbiAgICByZXR1cm4gYXJndW1lbnRzLmxlbmd0aCA/IHRoaXMuc2Vlayh2YWx1ZSwgdHJ1ZSkgOiB0aGlzLnByZXZpb3VzTGFiZWwodGhpcy5fdGltZSArIF90aW55TnVtKTtcbiAgfTtcblxuICBfcHJvdG8yLnNoaWZ0Q2hpbGRyZW4gPSBmdW5jdGlvbiBzaGlmdENoaWxkcmVuKGFtb3VudCwgYWRqdXN0TGFiZWxzLCBpZ25vcmVCZWZvcmVUaW1lKSB7XG4gICAgaWYgKGlnbm9yZUJlZm9yZVRpbWUgPT09IHZvaWQgMCkge1xuICAgICAgaWdub3JlQmVmb3JlVGltZSA9IDA7XG4gICAgfVxuXG4gICAgdmFyIGNoaWxkID0gdGhpcy5fZmlyc3QsXG4gICAgICAgIGxhYmVscyA9IHRoaXMubGFiZWxzLFxuICAgICAgICBwO1xuXG4gICAgd2hpbGUgKGNoaWxkKSB7XG4gICAgICBpZiAoY2hpbGQuX3N0YXJ0ID49IGlnbm9yZUJlZm9yZVRpbWUpIHtcbiAgICAgICAgY2hpbGQuX3N0YXJ0ICs9IGFtb3VudDtcbiAgICAgICAgY2hpbGQuX2VuZCArPSBhbW91bnQ7XG4gICAgICB9XG5cbiAgICAgIGNoaWxkID0gY2hpbGQuX25leHQ7XG4gICAgfVxuXG4gICAgaWYgKGFkanVzdExhYmVscykge1xuICAgICAgZm9yIChwIGluIGxhYmVscykge1xuICAgICAgICBpZiAobGFiZWxzW3BdID49IGlnbm9yZUJlZm9yZVRpbWUpIHtcbiAgICAgICAgICBsYWJlbHNbcF0gKz0gYW1vdW50O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIF91bmNhY2hlKHRoaXMpO1xuICB9O1xuXG4gIF9wcm90bzIuaW52YWxpZGF0ZSA9IGZ1bmN0aW9uIGludmFsaWRhdGUoc29mdCkge1xuICAgIHZhciBjaGlsZCA9IHRoaXMuX2ZpcnN0O1xuICAgIHRoaXMuX2xvY2sgPSAwO1xuXG4gICAgd2hpbGUgKGNoaWxkKSB7XG4gICAgICBjaGlsZC5pbnZhbGlkYXRlKHNvZnQpO1xuICAgICAgY2hpbGQgPSBjaGlsZC5fbmV4dDtcbiAgICB9XG5cbiAgICByZXR1cm4gX0FuaW1hdGlvbi5wcm90b3R5cGUuaW52YWxpZGF0ZS5jYWxsKHRoaXMsIHNvZnQpO1xuICB9O1xuXG4gIF9wcm90bzIuY2xlYXIgPSBmdW5jdGlvbiBjbGVhcihpbmNsdWRlTGFiZWxzKSB7XG4gICAgaWYgKGluY2x1ZGVMYWJlbHMgPT09IHZvaWQgMCkge1xuICAgICAgaW5jbHVkZUxhYmVscyA9IHRydWU7XG4gICAgfVxuXG4gICAgdmFyIGNoaWxkID0gdGhpcy5fZmlyc3QsXG4gICAgICAgIG5leHQ7XG5cbiAgICB3aGlsZSAoY2hpbGQpIHtcbiAgICAgIG5leHQgPSBjaGlsZC5fbmV4dDtcbiAgICAgIHRoaXMucmVtb3ZlKGNoaWxkKTtcbiAgICAgIGNoaWxkID0gbmV4dDtcbiAgICB9XG5cbiAgICB0aGlzLl9kcCAmJiAodGhpcy5fdGltZSA9IHRoaXMuX3RUaW1lID0gdGhpcy5fcFRpbWUgPSAwKTtcbiAgICBpbmNsdWRlTGFiZWxzICYmICh0aGlzLmxhYmVscyA9IHt9KTtcbiAgICByZXR1cm4gX3VuY2FjaGUodGhpcyk7XG4gIH07XG5cbiAgX3Byb3RvMi50b3RhbER1cmF0aW9uID0gZnVuY3Rpb24gdG90YWxEdXJhdGlvbih2YWx1ZSkge1xuICAgIHZhciBtYXggPSAwLFxuICAgICAgICBzZWxmID0gdGhpcyxcbiAgICAgICAgY2hpbGQgPSBzZWxmLl9sYXN0LFxuICAgICAgICBwcmV2U3RhcnQgPSBfYmlnTnVtLFxuICAgICAgICBwcmV2LFxuICAgICAgICBzdGFydCxcbiAgICAgICAgcGFyZW50O1xuXG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgIHJldHVybiBzZWxmLnRpbWVTY2FsZSgoc2VsZi5fcmVwZWF0IDwgMCA/IHNlbGYuZHVyYXRpb24oKSA6IHNlbGYudG90YWxEdXJhdGlvbigpKSAvIChzZWxmLnJldmVyc2VkKCkgPyAtdmFsdWUgOiB2YWx1ZSkpO1xuICAgIH1cblxuICAgIGlmIChzZWxmLl9kaXJ0eSkge1xuICAgICAgcGFyZW50ID0gc2VsZi5wYXJlbnQ7XG5cbiAgICAgIHdoaWxlIChjaGlsZCkge1xuICAgICAgICBwcmV2ID0gY2hpbGQuX3ByZXY7IC8vcmVjb3JkIGl0IGhlcmUgaW4gY2FzZSB0aGUgdHdlZW4gY2hhbmdlcyBwb3NpdGlvbiBpbiB0aGUgc2VxdWVuY2UuLi5cblxuICAgICAgICBjaGlsZC5fZGlydHkgJiYgY2hpbGQudG90YWxEdXJhdGlvbigpOyAvL2NvdWxkIGNoYW5nZSB0aGUgdHdlZW4uX3N0YXJ0VGltZSwgc28gbWFrZSBzdXJlIHRoZSBhbmltYXRpb24ncyBjYWNoZSBpcyBjbGVhbiBiZWZvcmUgYW5hbHl6aW5nIGl0LlxuXG4gICAgICAgIHN0YXJ0ID0gY2hpbGQuX3N0YXJ0O1xuXG4gICAgICAgIGlmIChzdGFydCA+IHByZXZTdGFydCAmJiBzZWxmLl9zb3J0ICYmIGNoaWxkLl90cyAmJiAhc2VsZi5fbG9jaykge1xuICAgICAgICAgIC8vaW4gY2FzZSBvbmUgb2YgdGhlIHR3ZWVucyBzaGlmdGVkIG91dCBvZiBvcmRlciwgaXQgbmVlZHMgdG8gYmUgcmUtaW5zZXJ0ZWQgaW50byB0aGUgY29ycmVjdCBwb3NpdGlvbiBpbiB0aGUgc2VxdWVuY2VcbiAgICAgICAgICBzZWxmLl9sb2NrID0gMTsgLy9wcmV2ZW50IGVuZGxlc3MgcmVjdXJzaXZlIGNhbGxzIC0gdGhlcmUgYXJlIG1ldGhvZHMgdGhhdCBnZXQgdHJpZ2dlcmVkIHRoYXQgY2hlY2sgZHVyYXRpb24vdG90YWxEdXJhdGlvbiB3aGVuIHdlIGFkZCgpLlxuXG4gICAgICAgICAgX2FkZFRvVGltZWxpbmUoc2VsZiwgY2hpbGQsIHN0YXJ0IC0gY2hpbGQuX2RlbGF5LCAxKS5fbG9jayA9IDA7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcHJldlN0YXJ0ID0gc3RhcnQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoc3RhcnQgPCAwICYmIGNoaWxkLl90cykge1xuICAgICAgICAgIC8vY2hpbGRyZW4gYXJlbid0IGFsbG93ZWQgdG8gaGF2ZSBuZWdhdGl2ZSBzdGFydFRpbWVzIHVubGVzcyBzbW9vdGhDaGlsZFRpbWluZyBpcyB0cnVlLCBzbyBhZGp1c3QgaGVyZSBpZiBvbmUgaXMgZm91bmQuXG4gICAgICAgICAgbWF4IC09IHN0YXJ0O1xuXG4gICAgICAgICAgaWYgKCFwYXJlbnQgJiYgIXNlbGYuX2RwIHx8IHBhcmVudCAmJiBwYXJlbnQuc21vb3RoQ2hpbGRUaW1pbmcpIHtcbiAgICAgICAgICAgIHNlbGYuX3N0YXJ0ICs9IHN0YXJ0IC8gc2VsZi5fdHM7XG4gICAgICAgICAgICBzZWxmLl90aW1lIC09IHN0YXJ0O1xuICAgICAgICAgICAgc2VsZi5fdFRpbWUgLT0gc3RhcnQ7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgc2VsZi5zaGlmdENoaWxkcmVuKC1zdGFydCwgZmFsc2UsIC0xZTk5OSk7XG4gICAgICAgICAgcHJldlN0YXJ0ID0gMDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNoaWxkLl9lbmQgPiBtYXggJiYgY2hpbGQuX3RzICYmIChtYXggPSBjaGlsZC5fZW5kKTtcbiAgICAgICAgY2hpbGQgPSBwcmV2O1xuICAgICAgfVxuXG4gICAgICBfc2V0RHVyYXRpb24oc2VsZiwgc2VsZiA9PT0gX2dsb2JhbFRpbWVsaW5lICYmIHNlbGYuX3RpbWUgPiBtYXggPyBzZWxmLl90aW1lIDogbWF4LCAxLCAxKTtcblxuICAgICAgc2VsZi5fZGlydHkgPSAwO1xuICAgIH1cblxuICAgIHJldHVybiBzZWxmLl90RHVyO1xuICB9O1xuXG4gIFRpbWVsaW5lLnVwZGF0ZVJvb3QgPSBmdW5jdGlvbiB1cGRhdGVSb290KHRpbWUpIHtcbiAgICBpZiAoX2dsb2JhbFRpbWVsaW5lLl90cykge1xuICAgICAgX2xhenlTYWZlUmVuZGVyKF9nbG9iYWxUaW1lbGluZSwgX3BhcmVudFRvQ2hpbGRUb3RhbFRpbWUodGltZSwgX2dsb2JhbFRpbWVsaW5lKSk7XG5cbiAgICAgIF9sYXN0UmVuZGVyZWRGcmFtZSA9IF90aWNrZXIuZnJhbWU7XG4gICAgfVxuXG4gICAgaWYgKF90aWNrZXIuZnJhbWUgPj0gX25leHRHQ0ZyYW1lKSB7XG4gICAgICBfbmV4dEdDRnJhbWUgKz0gX2NvbmZpZy5hdXRvU2xlZXAgfHwgMTIwO1xuICAgICAgdmFyIGNoaWxkID0gX2dsb2JhbFRpbWVsaW5lLl9maXJzdDtcbiAgICAgIGlmICghY2hpbGQgfHwgIWNoaWxkLl90cykgaWYgKF9jb25maWcuYXV0b1NsZWVwICYmIF90aWNrZXIuX2xpc3RlbmVycy5sZW5ndGggPCAyKSB7XG4gICAgICAgIHdoaWxlIChjaGlsZCAmJiAhY2hpbGQuX3RzKSB7XG4gICAgICAgICAgY2hpbGQgPSBjaGlsZC5fbmV4dDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNoaWxkIHx8IF90aWNrZXIuc2xlZXAoKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgcmV0dXJuIFRpbWVsaW5lO1xufShBbmltYXRpb24pO1xuXG5fc2V0RGVmYXVsdHMoVGltZWxpbmUucHJvdG90eXBlLCB7XG4gIF9sb2NrOiAwLFxuICBfaGFzUGF1c2U6IDAsXG4gIF9mb3JjaW5nOiAwXG59KTtcblxudmFyIF9hZGRDb21wbGV4U3RyaW5nUHJvcFR3ZWVuID0gZnVuY3Rpb24gX2FkZENvbXBsZXhTdHJpbmdQcm9wVHdlZW4odGFyZ2V0LCBwcm9wLCBzdGFydCwgZW5kLCBzZXR0ZXIsIHN0cmluZ0ZpbHRlciwgZnVuY1BhcmFtKSB7XG4gIC8vbm90ZTogd2UgY2FsbCBfYWRkQ29tcGxleFN0cmluZ1Byb3BUd2Vlbi5jYWxsKHR3ZWVuSW5zdGFuY2UuLi4pIHRvIGVuc3VyZSB0aGF0IGl0J3Mgc2NvcGVkIHByb3Blcmx5LiBXZSBtYXkgY2FsbCBpdCBmcm9tIHdpdGhpbiBhIHBsdWdpbiB0b28sIHRodXMgXCJ0aGlzXCIgd291bGQgcmVmZXIgdG8gdGhlIHBsdWdpbi5cbiAgdmFyIHB0ID0gbmV3IFByb3BUd2Vlbih0aGlzLl9wdCwgdGFyZ2V0LCBwcm9wLCAwLCAxLCBfcmVuZGVyQ29tcGxleFN0cmluZywgbnVsbCwgc2V0dGVyKSxcbiAgICAgIGluZGV4ID0gMCxcbiAgICAgIG1hdGNoSW5kZXggPSAwLFxuICAgICAgcmVzdWx0LFxuICAgICAgc3RhcnROdW1zLFxuICAgICAgY29sb3IsXG4gICAgICBlbmROdW0sXG4gICAgICBjaHVuayxcbiAgICAgIHN0YXJ0TnVtLFxuICAgICAgaGFzUmFuZG9tLFxuICAgICAgYTtcbiAgcHQuYiA9IHN0YXJ0O1xuICBwdC5lID0gZW5kO1xuICBzdGFydCArPSBcIlwiOyAvL2Vuc3VyZSB2YWx1ZXMgYXJlIHN0cmluZ3NcblxuICBlbmQgKz0gXCJcIjtcblxuICBpZiAoaGFzUmFuZG9tID0gfmVuZC5pbmRleE9mKFwicmFuZG9tKFwiKSkge1xuICAgIGVuZCA9IF9yZXBsYWNlUmFuZG9tKGVuZCk7XG4gIH1cblxuICBpZiAoc3RyaW5nRmlsdGVyKSB7XG4gICAgYSA9IFtzdGFydCwgZW5kXTtcbiAgICBzdHJpbmdGaWx0ZXIoYSwgdGFyZ2V0LCBwcm9wKTsgLy9wYXNzIGFuIGFycmF5IHdpdGggdGhlIHN0YXJ0aW5nIGFuZCBlbmRpbmcgdmFsdWVzIGFuZCBsZXQgdGhlIGZpbHRlciBkbyB3aGF0ZXZlciBpdCBuZWVkcyB0byB0aGUgdmFsdWVzLlxuXG4gICAgc3RhcnQgPSBhWzBdO1xuICAgIGVuZCA9IGFbMV07XG4gIH1cblxuICBzdGFydE51bXMgPSBzdGFydC5tYXRjaChfY29tcGxleFN0cmluZ051bUV4cCkgfHwgW107XG5cbiAgd2hpbGUgKHJlc3VsdCA9IF9jb21wbGV4U3RyaW5nTnVtRXhwLmV4ZWMoZW5kKSkge1xuICAgIGVuZE51bSA9IHJlc3VsdFswXTtcbiAgICBjaHVuayA9IGVuZC5zdWJzdHJpbmcoaW5kZXgsIHJlc3VsdC5pbmRleCk7XG5cbiAgICBpZiAoY29sb3IpIHtcbiAgICAgIGNvbG9yID0gKGNvbG9yICsgMSkgJSA1O1xuICAgIH0gZWxzZSBpZiAoY2h1bmsuc3Vic3RyKC01KSA9PT0gXCJyZ2JhKFwiKSB7XG4gICAgICBjb2xvciA9IDE7XG4gICAgfVxuXG4gICAgaWYgKGVuZE51bSAhPT0gc3RhcnROdW1zW21hdGNoSW5kZXgrK10pIHtcbiAgICAgIHN0YXJ0TnVtID0gcGFyc2VGbG9hdChzdGFydE51bXNbbWF0Y2hJbmRleCAtIDFdKSB8fCAwOyAvL3RoZXNlIG5lc3RlZCBQcm9wVHdlZW5zIGFyZSBoYW5kbGVkIGluIGEgc3BlY2lhbCB3YXkgLSB3ZSdsbCBuZXZlciBhY3R1YWxseSBjYWxsIGEgcmVuZGVyIG9yIHNldHRlciBtZXRob2Qgb24gdGhlbS4gV2UnbGwganVzdCBsb29wIHRocm91Z2ggdGhlbSBpbiB0aGUgcGFyZW50IGNvbXBsZXggc3RyaW5nIFByb3BUd2VlbidzIHJlbmRlciBtZXRob2QuXG5cbiAgICAgIHB0Ll9wdCA9IHtcbiAgICAgICAgX25leHQ6IHB0Ll9wdCxcbiAgICAgICAgcDogY2h1bmsgfHwgbWF0Y2hJbmRleCA9PT0gMSA/IGNodW5rIDogXCIsXCIsXG4gICAgICAgIC8vbm90ZTogU1ZHIHNwZWMgYWxsb3dzIG9taXNzaW9uIG9mIGNvbW1hL3NwYWNlIHdoZW4gYSBuZWdhdGl2ZSBzaWduIGlzIHdlZGdlZCBiZXR3ZWVuIHR3byBudW1iZXJzLCBsaWtlIDIuNS01LjMgaW5zdGVhZCBvZiAyLjUsLTUuMyBidXQgd2hlbiB0d2VlbmluZywgdGhlIG5lZ2F0aXZlIHZhbHVlIG1heSBzd2l0Y2ggdG8gcG9zaXRpdmUsIHNvIHdlIGluc2VydCB0aGUgY29tbWEganVzdCBpbiBjYXNlLlxuICAgICAgICBzOiBzdGFydE51bSxcbiAgICAgICAgYzogZW5kTnVtLmNoYXJBdCgxKSA9PT0gXCI9XCIgPyBfcGFyc2VSZWxhdGl2ZShzdGFydE51bSwgZW5kTnVtKSAtIHN0YXJ0TnVtIDogcGFyc2VGbG9hdChlbmROdW0pIC0gc3RhcnROdW0sXG4gICAgICAgIG06IGNvbG9yICYmIGNvbG9yIDwgNCA/IE1hdGgucm91bmQgOiAwXG4gICAgICB9O1xuICAgICAgaW5kZXggPSBfY29tcGxleFN0cmluZ051bUV4cC5sYXN0SW5kZXg7XG4gICAgfVxuICB9XG5cbiAgcHQuYyA9IGluZGV4IDwgZW5kLmxlbmd0aCA/IGVuZC5zdWJzdHJpbmcoaW5kZXgsIGVuZC5sZW5ndGgpIDogXCJcIjsgLy93ZSB1c2UgdGhlIFwiY1wiIG9mIHRoZSBQcm9wVHdlZW4gdG8gc3RvcmUgdGhlIGZpbmFsIHBhcnQgb2YgdGhlIHN0cmluZyAoYWZ0ZXIgdGhlIGxhc3QgbnVtYmVyKVxuXG4gIHB0LmZwID0gZnVuY1BhcmFtO1xuXG4gIGlmIChfcmVsRXhwLnRlc3QoZW5kKSB8fCBoYXNSYW5kb20pIHtcbiAgICBwdC5lID0gMDsgLy9pZiB0aGUgZW5kIHN0cmluZyBjb250YWlucyByZWxhdGl2ZSB2YWx1ZXMgb3IgZHluYW1pYyByYW5kb20oLi4uKSB2YWx1ZXMsIGRlbGV0ZSB0aGUgZW5kIGl0IHNvIHRoYXQgb24gdGhlIGZpbmFsIHJlbmRlciB3ZSBkb24ndCBhY3R1YWxseSBzZXQgaXQgdG8gdGhlIHN0cmluZyB3aXRoICs9IG9yIC09IGNoYXJhY3RlcnMgKGZvcmNlcyBpdCB0byB1c2UgdGhlIGNhbGN1bGF0ZWQgdmFsdWUpLlxuICB9XG5cbiAgdGhpcy5fcHQgPSBwdDsgLy9zdGFydCB0aGUgbGlua2VkIGxpc3Qgd2l0aCB0aGlzIG5ldyBQcm9wVHdlZW4uIFJlbWVtYmVyLCB3ZSBjYWxsIF9hZGRDb21wbGV4U3RyaW5nUHJvcFR3ZWVuLmNhbGwodHdlZW5JbnN0YW5jZS4uLikgdG8gZW5zdXJlIHRoYXQgaXQncyBzY29wZWQgcHJvcGVybHkuIFdlIG1heSBjYWxsIGl0IGZyb20gd2l0aGluIGEgcGx1Z2luIHRvbywgdGh1cyBcInRoaXNcIiB3b3VsZCByZWZlciB0byB0aGUgcGx1Z2luLlxuXG4gIHJldHVybiBwdDtcbn0sXG4gICAgX2FkZFByb3BUd2VlbiA9IGZ1bmN0aW9uIF9hZGRQcm9wVHdlZW4odGFyZ2V0LCBwcm9wLCBzdGFydCwgZW5kLCBpbmRleCwgdGFyZ2V0cywgbW9kaWZpZXIsIHN0cmluZ0ZpbHRlciwgZnVuY1BhcmFtLCBvcHRpb25hbCkge1xuICBfaXNGdW5jdGlvbihlbmQpICYmIChlbmQgPSBlbmQoaW5kZXggfHwgMCwgdGFyZ2V0LCB0YXJnZXRzKSk7XG4gIHZhciBjdXJyZW50VmFsdWUgPSB0YXJnZXRbcHJvcF0sXG4gICAgICBwYXJzZWRTdGFydCA9IHN0YXJ0ICE9PSBcImdldFwiID8gc3RhcnQgOiAhX2lzRnVuY3Rpb24oY3VycmVudFZhbHVlKSA/IGN1cnJlbnRWYWx1ZSA6IGZ1bmNQYXJhbSA/IHRhcmdldFtwcm9wLmluZGV4T2YoXCJzZXRcIikgfHwgIV9pc0Z1bmN0aW9uKHRhcmdldFtcImdldFwiICsgcHJvcC5zdWJzdHIoMyldKSA/IHByb3AgOiBcImdldFwiICsgcHJvcC5zdWJzdHIoMyldKGZ1bmNQYXJhbSkgOiB0YXJnZXRbcHJvcF0oKSxcbiAgICAgIHNldHRlciA9ICFfaXNGdW5jdGlvbihjdXJyZW50VmFsdWUpID8gX3NldHRlclBsYWluIDogZnVuY1BhcmFtID8gX3NldHRlckZ1bmNXaXRoUGFyYW0gOiBfc2V0dGVyRnVuYyxcbiAgICAgIHB0O1xuXG4gIGlmIChfaXNTdHJpbmcoZW5kKSkge1xuICAgIGlmICh+ZW5kLmluZGV4T2YoXCJyYW5kb20oXCIpKSB7XG4gICAgICBlbmQgPSBfcmVwbGFjZVJhbmRvbShlbmQpO1xuICAgIH1cblxuICAgIGlmIChlbmQuY2hhckF0KDEpID09PSBcIj1cIikge1xuICAgICAgcHQgPSBfcGFyc2VSZWxhdGl2ZShwYXJzZWRTdGFydCwgZW5kKSArIChnZXRVbml0KHBhcnNlZFN0YXJ0KSB8fCAwKTtcblxuICAgICAgaWYgKHB0IHx8IHB0ID09PSAwKSB7XG4gICAgICAgIC8vIHRvIGF2b2lkIGlzTmFOLCBsaWtlIGlmIHNvbWVvbmUgcGFzc2VzIGluIGEgdmFsdWUgbGlrZSBcIiE9IHdoYXRldmVyXCJcbiAgICAgICAgZW5kID0gcHQ7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgaWYgKCFvcHRpb25hbCB8fCBwYXJzZWRTdGFydCAhPT0gZW5kIHx8IF9mb3JjZUFsbFByb3BUd2VlbnMpIHtcbiAgICBpZiAoIWlzTmFOKHBhcnNlZFN0YXJ0ICogZW5kKSAmJiBlbmQgIT09IFwiXCIpIHtcbiAgICAgIC8vIGZ1biBmYWN0OiBhbnkgbnVtYmVyIG11bHRpcGxpZWQgYnkgXCJcIiBpcyBldmFsdWF0ZWQgYXMgdGhlIG51bWJlciAwIVxuICAgICAgcHQgPSBuZXcgUHJvcFR3ZWVuKHRoaXMuX3B0LCB0YXJnZXQsIHByb3AsICtwYXJzZWRTdGFydCB8fCAwLCBlbmQgLSAocGFyc2VkU3RhcnQgfHwgMCksIHR5cGVvZiBjdXJyZW50VmFsdWUgPT09IFwiYm9vbGVhblwiID8gX3JlbmRlckJvb2xlYW4gOiBfcmVuZGVyUGxhaW4sIDAsIHNldHRlcik7XG4gICAgICBmdW5jUGFyYW0gJiYgKHB0LmZwID0gZnVuY1BhcmFtKTtcbiAgICAgIG1vZGlmaWVyICYmIHB0Lm1vZGlmaWVyKG1vZGlmaWVyLCB0aGlzLCB0YXJnZXQpO1xuICAgICAgcmV0dXJuIHRoaXMuX3B0ID0gcHQ7XG4gICAgfVxuXG4gICAgIWN1cnJlbnRWYWx1ZSAmJiAhKHByb3AgaW4gdGFyZ2V0KSAmJiBfbWlzc2luZ1BsdWdpbihwcm9wLCBlbmQpO1xuICAgIHJldHVybiBfYWRkQ29tcGxleFN0cmluZ1Byb3BUd2Vlbi5jYWxsKHRoaXMsIHRhcmdldCwgcHJvcCwgcGFyc2VkU3RhcnQsIGVuZCwgc2V0dGVyLCBzdHJpbmdGaWx0ZXIgfHwgX2NvbmZpZy5zdHJpbmdGaWx0ZXIsIGZ1bmNQYXJhbSk7XG4gIH1cbn0sXG4gICAgLy9jcmVhdGVzIGEgY29weSBvZiB0aGUgdmFycyBvYmplY3QgYW5kIHByb2Nlc3NlcyBhbnkgZnVuY3Rpb24tYmFzZWQgdmFsdWVzIChwdXR0aW5nIHRoZSByZXN1bHRpbmcgdmFsdWVzIGRpcmVjdGx5IGludG8gdGhlIGNvcHkpIGFzIHdlbGwgYXMgc3RyaW5ncyB3aXRoIFwicmFuZG9tKClcIiBpbiB0aGVtLiBJdCBkb2VzIE5PVCBwcm9jZXNzIHJlbGF0aXZlIHZhbHVlcy5cbl9wcm9jZXNzVmFycyA9IGZ1bmN0aW9uIF9wcm9jZXNzVmFycyh2YXJzLCBpbmRleCwgdGFyZ2V0LCB0YXJnZXRzLCB0d2Vlbikge1xuICBfaXNGdW5jdGlvbih2YXJzKSAmJiAodmFycyA9IF9wYXJzZUZ1bmNPclN0cmluZyh2YXJzLCB0d2VlbiwgaW5kZXgsIHRhcmdldCwgdGFyZ2V0cykpO1xuXG4gIGlmICghX2lzT2JqZWN0KHZhcnMpIHx8IHZhcnMuc3R5bGUgJiYgdmFycy5ub2RlVHlwZSB8fCBfaXNBcnJheSh2YXJzKSB8fCBfaXNUeXBlZEFycmF5KHZhcnMpKSB7XG4gICAgcmV0dXJuIF9pc1N0cmluZyh2YXJzKSA/IF9wYXJzZUZ1bmNPclN0cmluZyh2YXJzLCB0d2VlbiwgaW5kZXgsIHRhcmdldCwgdGFyZ2V0cykgOiB2YXJzO1xuICB9XG5cbiAgdmFyIGNvcHkgPSB7fSxcbiAgICAgIHA7XG5cbiAgZm9yIChwIGluIHZhcnMpIHtcbiAgICBjb3B5W3BdID0gX3BhcnNlRnVuY09yU3RyaW5nKHZhcnNbcF0sIHR3ZWVuLCBpbmRleCwgdGFyZ2V0LCB0YXJnZXRzKTtcbiAgfVxuXG4gIHJldHVybiBjb3B5O1xufSxcbiAgICBfY2hlY2tQbHVnaW4gPSBmdW5jdGlvbiBfY2hlY2tQbHVnaW4ocHJvcGVydHksIHZhcnMsIHR3ZWVuLCBpbmRleCwgdGFyZ2V0LCB0YXJnZXRzKSB7XG4gIHZhciBwbHVnaW4sIHB0LCBwdExvb2t1cCwgaTtcblxuICBpZiAoX3BsdWdpbnNbcHJvcGVydHldICYmIChwbHVnaW4gPSBuZXcgX3BsdWdpbnNbcHJvcGVydHldKCkpLmluaXQodGFyZ2V0LCBwbHVnaW4ucmF3VmFycyA/IHZhcnNbcHJvcGVydHldIDogX3Byb2Nlc3NWYXJzKHZhcnNbcHJvcGVydHldLCBpbmRleCwgdGFyZ2V0LCB0YXJnZXRzLCB0d2VlbiksIHR3ZWVuLCBpbmRleCwgdGFyZ2V0cykgIT09IGZhbHNlKSB7XG4gICAgdHdlZW4uX3B0ID0gcHQgPSBuZXcgUHJvcFR3ZWVuKHR3ZWVuLl9wdCwgdGFyZ2V0LCBwcm9wZXJ0eSwgMCwgMSwgcGx1Z2luLnJlbmRlciwgcGx1Z2luLCAwLCBwbHVnaW4ucHJpb3JpdHkpO1xuXG4gICAgaWYgKHR3ZWVuICE9PSBfcXVpY2tUd2Vlbikge1xuICAgICAgcHRMb29rdXAgPSB0d2Vlbi5fcHRMb29rdXBbdHdlZW4uX3RhcmdldHMuaW5kZXhPZih0YXJnZXQpXTsgLy9ub3RlOiB3ZSBjYW4ndCB1c2UgdHdlZW4uX3B0TG9va3VwW2luZGV4XSBiZWNhdXNlIGZvciBzdGFnZ2VyZWQgdHdlZW5zLCB0aGUgaW5kZXggZnJvbSB0aGUgZnVsbFRhcmdldHMgYXJyYXkgd29uJ3QgbWF0Y2ggd2hhdCBpdCBpcyBpbiBlYWNoIGluZGl2aWR1YWwgdHdlZW4gdGhhdCBzcGF3bnMgZnJvbSB0aGUgc3RhZ2dlci5cblxuICAgICAgaSA9IHBsdWdpbi5fcHJvcHMubGVuZ3RoO1xuXG4gICAgICB3aGlsZSAoaS0tKSB7XG4gICAgICAgIHB0TG9va3VwW3BsdWdpbi5fcHJvcHNbaV1dID0gcHQ7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHBsdWdpbjtcbn0sXG4gICAgX292ZXJ3cml0aW5nVHdlZW4sXG4gICAgLy9zdG9yZSBhIHJlZmVyZW5jZSB0ZW1wb3JhcmlseSBzbyB3ZSBjYW4gYXZvaWQgb3ZlcndyaXRpbmcgaXRzZWxmLlxuX2ZvcmNlQWxsUHJvcFR3ZWVucyxcbiAgICBfaW5pdFR3ZWVuID0gZnVuY3Rpb24gX2luaXRUd2Vlbih0d2VlbiwgdGltZSwgdFRpbWUpIHtcbiAgdmFyIHZhcnMgPSB0d2Vlbi52YXJzLFxuICAgICAgZWFzZSA9IHZhcnMuZWFzZSxcbiAgICAgIHN0YXJ0QXQgPSB2YXJzLnN0YXJ0QXQsXG4gICAgICBpbW1lZGlhdGVSZW5kZXIgPSB2YXJzLmltbWVkaWF0ZVJlbmRlcixcbiAgICAgIGxhenkgPSB2YXJzLmxhenksXG4gICAgICBvblVwZGF0ZSA9IHZhcnMub25VcGRhdGUsXG4gICAgICBydW5CYWNrd2FyZHMgPSB2YXJzLnJ1bkJhY2t3YXJkcyxcbiAgICAgIHlveW9FYXNlID0gdmFycy55b3lvRWFzZSxcbiAgICAgIGtleWZyYW1lcyA9IHZhcnMua2V5ZnJhbWVzLFxuICAgICAgYXV0b1JldmVydCA9IHZhcnMuYXV0b1JldmVydCxcbiAgICAgIGR1ciA9IHR3ZWVuLl9kdXIsXG4gICAgICBwcmV2U3RhcnRBdCA9IHR3ZWVuLl9zdGFydEF0LFxuICAgICAgdGFyZ2V0cyA9IHR3ZWVuLl90YXJnZXRzLFxuICAgICAgcGFyZW50ID0gdHdlZW4ucGFyZW50LFxuICAgICAgZnVsbFRhcmdldHMgPSBwYXJlbnQgJiYgcGFyZW50LmRhdGEgPT09IFwibmVzdGVkXCIgPyBwYXJlbnQudmFycy50YXJnZXRzIDogdGFyZ2V0cyxcbiAgICAgIGF1dG9PdmVyd3JpdGUgPSB0d2Vlbi5fb3ZlcndyaXRlID09PSBcImF1dG9cIiAmJiAhX3N1cHByZXNzT3ZlcndyaXRlcyxcbiAgICAgIHRsID0gdHdlZW4udGltZWxpbmUsXG4gICAgICBjbGVhblZhcnMsXG4gICAgICBpLFxuICAgICAgcCxcbiAgICAgIHB0LFxuICAgICAgdGFyZ2V0LFxuICAgICAgaGFzUHJpb3JpdHksXG4gICAgICBnc0RhdGEsXG4gICAgICBoYXJuZXNzLFxuICAgICAgcGx1Z2luLFxuICAgICAgcHRMb29rdXAsXG4gICAgICBpbmRleCxcbiAgICAgIGhhcm5lc3NWYXJzLFxuICAgICAgb3ZlcndyaXR0ZW47XG4gIHRsICYmICgha2V5ZnJhbWVzIHx8ICFlYXNlKSAmJiAoZWFzZSA9IFwibm9uZVwiKTtcbiAgdHdlZW4uX2Vhc2UgPSBfcGFyc2VFYXNlKGVhc2UsIF9kZWZhdWx0cy5lYXNlKTtcbiAgdHdlZW4uX3lFYXNlID0geW95b0Vhc2UgPyBfaW52ZXJ0RWFzZShfcGFyc2VFYXNlKHlveW9FYXNlID09PSB0cnVlID8gZWFzZSA6IHlveW9FYXNlLCBfZGVmYXVsdHMuZWFzZSkpIDogMDtcblxuICBpZiAoeW95b0Vhc2UgJiYgdHdlZW4uX3lveW8gJiYgIXR3ZWVuLl9yZXBlYXQpIHtcbiAgICAvL3RoZXJlIG11c3QgaGF2ZSBiZWVuIGEgcGFyZW50IHRpbWVsaW5lIHdpdGggeW95bzp0cnVlIHRoYXQgaXMgY3VycmVudGx5IGluIGl0cyB5b3lvIHBoYXNlLCBzbyBmbGlwIHRoZSBlYXNlcy5cbiAgICB5b3lvRWFzZSA9IHR3ZWVuLl95RWFzZTtcbiAgICB0d2Vlbi5feUVhc2UgPSB0d2Vlbi5fZWFzZTtcbiAgICB0d2Vlbi5fZWFzZSA9IHlveW9FYXNlO1xuICB9XG5cbiAgdHdlZW4uX2Zyb20gPSAhdGwgJiYgISF2YXJzLnJ1bkJhY2t3YXJkczsgLy9uZXN0ZWQgdGltZWxpbmVzIHNob3VsZCBuZXZlciBydW4gYmFja3dhcmRzIC0gdGhlIGJhY2t3YXJkcy1uZXNzIGlzIGluIHRoZSBjaGlsZCB0d2VlbnMuXG5cbiAgaWYgKCF0bCB8fCBrZXlmcmFtZXMgJiYgIXZhcnMuc3RhZ2dlcikge1xuICAgIC8vaWYgdGhlcmUncyBhbiBpbnRlcm5hbCB0aW1lbGluZSwgc2tpcCBhbGwgdGhlIHBhcnNpbmcgYmVjYXVzZSB3ZSBwYXNzZWQgdGhhdCB0YXNrIGRvd24gdGhlIGNoYWluLlxuICAgIGhhcm5lc3MgPSB0YXJnZXRzWzBdID8gX2dldENhY2hlKHRhcmdldHNbMF0pLmhhcm5lc3MgOiAwO1xuICAgIGhhcm5lc3NWYXJzID0gaGFybmVzcyAmJiB2YXJzW2hhcm5lc3MucHJvcF07IC8vc29tZW9uZSBtYXkgbmVlZCB0byBzcGVjaWZ5IENTUy1zcGVjaWZpYyB2YWx1ZXMgQU5EIG5vbi1DU1MgdmFsdWVzLCBsaWtlIGlmIHRoZSBlbGVtZW50IGhhcyBhbiBcInhcIiBwcm9wZXJ0eSBwbHVzIGl0J3MgYSBzdGFuZGFyZCBET00gZWxlbWVudC4gV2UgYWxsb3cgcGVvcGxlIHRvIGRpc3Rpbmd1aXNoIGJ5IHdyYXBwaW5nIHBsdWdpbi1zcGVjaWZpYyBzdHVmZiBpbiBhIGNzczp7fSBvYmplY3QgZm9yIGV4YW1wbGUuXG5cbiAgICBjbGVhblZhcnMgPSBfY29weUV4Y2x1ZGluZyh2YXJzLCBfcmVzZXJ2ZWRQcm9wcyk7XG5cbiAgICBpZiAocHJldlN0YXJ0QXQpIHtcbiAgICAgIHByZXZTdGFydEF0Ll96VGltZSA8IDAgJiYgcHJldlN0YXJ0QXQucHJvZ3Jlc3MoMSk7IC8vIGluIGNhc2UgaXQncyBhIGxhenkgc3RhcnRBdCB0aGF0IGhhc24ndCByZW5kZXJlZCB5ZXQuXG5cbiAgICAgIHRpbWUgPCAwICYmIHJ1bkJhY2t3YXJkcyAmJiBpbW1lZGlhdGVSZW5kZXIgJiYgIWF1dG9SZXZlcnQgPyBwcmV2U3RhcnRBdC5yZW5kZXIoLTEsIHRydWUpIDogcHJldlN0YXJ0QXQucmV2ZXJ0KHJ1bkJhY2t3YXJkcyAmJiBkdXIgPyBfcmV2ZXJ0Q29uZmlnTm9LaWxsIDogX3N0YXJ0QXRSZXZlcnRDb25maWcpOyAvLyBpZiBpdCdzIGEgXCJzdGFydEF0XCIgKG5vdCBcImZyb20oKVwiIG9yIHJ1bkJhY2t3YXJkczogdHJ1ZSksIHdlIG9ubHkgbmVlZCB0byBkbyBhIHNoYWxsb3cgcmV2ZXJ0IChrZWVwIHRyYW5zZm9ybXMgY2FjaGVkIGluIENTU1BsdWdpbilcbiAgICAgIC8vIGRvbid0IGp1c3QgX3JlbW92ZUZyb21QYXJlbnQocHJldlN0YXJ0QXQucmVuZGVyKC0xLCB0cnVlKSkgYmVjYXVzZSB0aGF0J2xsIGxlYXZlIGlubGluZSBzdHlsZXMuIFdlJ3JlIGNyZWF0aW5nIGEgbmV3IF9zdGFydEF0IGZvciBcInN0YXJ0QXRcIiB0d2VlbnMgdGhhdCByZS1jYXB0dXJlIHRoaW5ncyB0byBlbnN1cmUgdGhhdCBpZiB0aGUgcHJlLXR3ZWVuIHZhbHVlcyBjaGFuZ2VkIHNpbmNlIHRoZSB0d2VlbiB3YXMgY3JlYXRlZCwgdGhleSdyZSByZWNvcmRlZC5cblxuICAgICAgcHJldlN0YXJ0QXQuX2xhenkgPSAwO1xuICAgIH1cblxuICAgIGlmIChzdGFydEF0KSB7XG4gICAgICBfcmVtb3ZlRnJvbVBhcmVudCh0d2Vlbi5fc3RhcnRBdCA9IFR3ZWVuLnNldCh0YXJnZXRzLCBfc2V0RGVmYXVsdHMoe1xuICAgICAgICBkYXRhOiBcImlzU3RhcnRcIixcbiAgICAgICAgb3ZlcndyaXRlOiBmYWxzZSxcbiAgICAgICAgcGFyZW50OiBwYXJlbnQsXG4gICAgICAgIGltbWVkaWF0ZVJlbmRlcjogdHJ1ZSxcbiAgICAgICAgbGF6eTogIXByZXZTdGFydEF0ICYmIF9pc05vdEZhbHNlKGxhenkpLFxuICAgICAgICBzdGFydEF0OiBudWxsLFxuICAgICAgICBkZWxheTogMCxcbiAgICAgICAgb25VcGRhdGU6IG9uVXBkYXRlICYmIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByZXR1cm4gX2NhbGxiYWNrKHR3ZWVuLCBcIm9uVXBkYXRlXCIpO1xuICAgICAgICB9LFxuICAgICAgICBzdGFnZ2VyOiAwXG4gICAgICB9LCBzdGFydEF0KSkpOyAvL2NvcHkgdGhlIHByb3BlcnRpZXMvdmFsdWVzIGludG8gYSBuZXcgb2JqZWN0IHRvIGF2b2lkIGNvbGxpc2lvbnMsIGxpa2UgdmFyIHRvID0ge3g6MH0sIGZyb20gPSB7eDo1MDB9OyB0aW1lbGluZS5mcm9tVG8oZSwgZnJvbSwgdG8pLmZyb21UbyhlLCB0bywgZnJvbSk7XG5cblxuICAgICAgdHdlZW4uX3N0YXJ0QXQuX2RwID0gMDsgLy8gZG9uJ3QgYWxsb3cgaXQgdG8gZ2V0IHB1dCBiYWNrIGludG8gcm9vdCB0aW1lbGluZSEgTGlrZSB3aGVuIHJldmVydCgpIGlzIGNhbGxlZCBhbmQgdG90YWxUaW1lKCkgZ2V0cyBzZXQuXG5cbiAgICAgIHR3ZWVuLl9zdGFydEF0Ll9zYXQgPSB0d2VlbjsgLy8gdXNlZCBpbiBnbG9iYWxUaW1lKCkuIF9zYXQgc3RhbmRzIGZvciBfc3RhcnRBdFR3ZWVuXG5cbiAgICAgIHRpbWUgPCAwICYmIChfcmV2ZXJ0aW5nIHx8ICFpbW1lZGlhdGVSZW5kZXIgJiYgIWF1dG9SZXZlcnQpICYmIHR3ZWVuLl9zdGFydEF0LnJldmVydChfcmV2ZXJ0Q29uZmlnTm9LaWxsKTsgLy8gcmFyZSBlZGdlIGNhc2UsIGxpa2UgaWYgYSByZW5kZXIgaXMgZm9yY2VkIGluIHRoZSBuZWdhdGl2ZSBkaXJlY3Rpb24gb2YgYSBub24taW5pdHRlZCB0d2Vlbi5cblxuICAgICAgaWYgKGltbWVkaWF0ZVJlbmRlcikge1xuICAgICAgICBpZiAoZHVyICYmIHRpbWUgPD0gMCAmJiB0VGltZSA8PSAwKSB7XG4gICAgICAgICAgLy8gY2hlY2sgdFRpbWUgaGVyZSBiZWNhdXNlIGluIHRoZSBjYXNlIG9mIGEgeW95byB0d2VlbiB3aG9zZSBwbGF5aGVhZCBnZXRzIHB1c2hlZCB0byB0aGUgZW5kIGxpa2UgdHdlZW4ucHJvZ3Jlc3MoMSksIHdlIHNob3VsZCBhbGxvdyBpdCB0aHJvdWdoIHNvIHRoYXQgdGhlIG9uQ29tcGxldGUgZ2V0cyBmaXJlZCBwcm9wZXJseS5cbiAgICAgICAgICB0aW1lICYmICh0d2Vlbi5felRpbWUgPSB0aW1lKTtcbiAgICAgICAgICByZXR1cm47IC8vd2Ugc2tpcCBpbml0aWFsaXphdGlvbiBoZXJlIHNvIHRoYXQgb3ZlcndyaXRpbmcgZG9lc24ndCBvY2N1ciB1bnRpbCB0aGUgdHdlZW4gYWN0dWFsbHkgYmVnaW5zLiBPdGhlcndpc2UsIGlmIHlvdSBjcmVhdGUgc2V2ZXJhbCBpbW1lZGlhdGVSZW5kZXI6dHJ1ZSB0d2VlbnMgb2YgdGhlIHNhbWUgdGFyZ2V0L3Byb3BlcnRpZXMgdG8gZHJvcCBpbnRvIGEgVGltZWxpbmUsIHRoZSBsYXN0IG9uZSBjcmVhdGVkIHdvdWxkIG92ZXJ3cml0ZSB0aGUgZmlyc3Qgb25lcyBiZWNhdXNlIHRoZXkgZGlkbid0IGdldCBwbGFjZWQgaW50byB0aGUgdGltZWxpbmUgeWV0IGJlZm9yZSB0aGUgZmlyc3QgcmVuZGVyIG9jY3VycyBhbmQga2lja3MgaW4gb3ZlcndyaXRpbmcuXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHJ1bkJhY2t3YXJkcyAmJiBkdXIpIHtcbiAgICAgIC8vZnJvbSgpIHR3ZWVucyBtdXN0IGJlIGhhbmRsZWQgdW5pcXVlbHk6IHRoZWlyIGJlZ2lubmluZyB2YWx1ZXMgbXVzdCBiZSByZW5kZXJlZCBidXQgd2UgZG9uJ3Qgd2FudCBvdmVyd3JpdGluZyB0byBvY2N1ciB5ZXQgKHdoZW4gdGltZSBpcyBzdGlsbCAwKS4gV2FpdCB1bnRpbCB0aGUgdHdlZW4gYWN0dWFsbHkgYmVnaW5zIGJlZm9yZSBkb2luZyBhbGwgdGhlIHJvdXRpbmVzIGxpa2Ugb3ZlcndyaXRpbmcuIEF0IHRoYXQgdGltZSwgd2Ugc2hvdWxkIHJlbmRlciBhdCB0aGUgRU5EIG9mIHRoZSB0d2VlbiB0byBlbnN1cmUgdGhhdCB0aGluZ3MgaW5pdGlhbGl6ZSBjb3JyZWN0bHkgKHJlbWVtYmVyLCBmcm9tKCkgdHdlZW5zIGdvIGJhY2t3YXJkcylcbiAgICAgIGlmICghcHJldlN0YXJ0QXQpIHtcbiAgICAgICAgdGltZSAmJiAoaW1tZWRpYXRlUmVuZGVyID0gZmFsc2UpOyAvL2luIHJhcmUgY2FzZXMgKGxpa2UgaWYgYSBmcm9tKCkgdHdlZW4gcnVucyBhbmQgdGhlbiBpcyBpbnZhbGlkYXRlKCktZWQpLCBpbW1lZGlhdGVSZW5kZXIgY291bGQgYmUgdHJ1ZSBidXQgdGhlIGluaXRpYWwgZm9yY2VkLXJlbmRlciBnZXRzIHNraXBwZWQsIHNvIHRoZXJlJ3Mgbm8gbmVlZCB0byBmb3JjZSB0aGUgcmVuZGVyIGluIHRoaXMgY29udGV4dCB3aGVuIHRoZSBfdGltZSBpcyBncmVhdGVyIHRoYW4gMFxuXG4gICAgICAgIHAgPSBfc2V0RGVmYXVsdHMoe1xuICAgICAgICAgIG92ZXJ3cml0ZTogZmFsc2UsXG4gICAgICAgICAgZGF0YTogXCJpc0Zyb21TdGFydFwiLFxuICAgICAgICAgIC8vd2UgdGFnIHRoZSB0d2VlbiB3aXRoIGFzIFwiaXNGcm9tU3RhcnRcIiBzbyB0aGF0IGlmIFtpbnNpZGUgYSBwbHVnaW5dIHdlIG5lZWQgdG8gb25seSBkbyBzb21ldGhpbmcgYXQgdGhlIHZlcnkgRU5EIG9mIGEgdHdlZW4sIHdlIGhhdmUgYSB3YXkgb2YgaWRlbnRpZnlpbmcgdGhpcyB0d2VlbiBhcyBtZXJlbHkgdGhlIG9uZSB0aGF0J3Mgc2V0dGluZyB0aGUgYmVnaW5uaW5nIHZhbHVlcyBmb3IgYSBcImZyb20oKVwiIHR3ZWVuLiBGb3IgZXhhbXBsZSwgY2xlYXJQcm9wcyBpbiBDU1NQbHVnaW4gc2hvdWxkIG9ubHkgZ2V0IGFwcGxpZWQgYXQgdGhlIHZlcnkgRU5EIG9mIGEgdHdlZW4gYW5kIHdpdGhvdXQgdGhpcyB0YWcsIGZyb20oLi4ue2hlaWdodDoxMDAsIGNsZWFyUHJvcHM6XCJoZWlnaHRcIiwgZGVsYXk6MX0pIHdvdWxkIHdpcGUgdGhlIGhlaWdodCBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSB0d2VlbiBhbmQgYWZ0ZXIgMSBzZWNvbmQsIGl0J2Qga2ljayBiYWNrIGluLlxuICAgICAgICAgIGxhenk6IGltbWVkaWF0ZVJlbmRlciAmJiAhcHJldlN0YXJ0QXQgJiYgX2lzTm90RmFsc2UobGF6eSksXG4gICAgICAgICAgaW1tZWRpYXRlUmVuZGVyOiBpbW1lZGlhdGVSZW5kZXIsXG4gICAgICAgICAgLy96ZXJvLWR1cmF0aW9uIHR3ZWVucyByZW5kZXIgaW1tZWRpYXRlbHkgYnkgZGVmYXVsdCwgYnV0IGlmIHdlJ3JlIG5vdCBzcGVjaWZpY2FsbHkgaW5zdHJ1Y3RlZCB0byByZW5kZXIgdGhpcyB0d2VlbiBpbW1lZGlhdGVseSwgd2Ugc2hvdWxkIHNraXAgdGhpcyBhbmQgbWVyZWx5IF9pbml0KCkgdG8gcmVjb3JkIHRoZSBzdGFydGluZyB2YWx1ZXMgKHJlbmRlcmluZyB0aGVtIGltbWVkaWF0ZWx5IHdvdWxkIHB1c2ggdGhlbSB0byBjb21wbGV0aW9uIHdoaWNoIGlzIHdhc3RlZnVsIGluIHRoYXQgY2FzZSAtIHdlJ2QgaGF2ZSB0byByZW5kZXIoLTEpIGltbWVkaWF0ZWx5IGFmdGVyKVxuICAgICAgICAgIHN0YWdnZXI6IDAsXG4gICAgICAgICAgcGFyZW50OiBwYXJlbnQgLy9lbnN1cmVzIHRoYXQgbmVzdGVkIHR3ZWVucyB0aGF0IGhhZCBhIHN0YWdnZXIgYXJlIGhhbmRsZWQgcHJvcGVybHksIGxpa2UgZ3NhcC5mcm9tKFwiLmNsYXNzXCIsIHt5OiBnc2FwLnV0aWxzLndyYXAoWy0xMDAsMTAwXSksIHN0YWdnZXI6IDAuNX0pXG5cbiAgICAgICAgfSwgY2xlYW5WYXJzKTtcbiAgICAgICAgaGFybmVzc1ZhcnMgJiYgKHBbaGFybmVzcy5wcm9wXSA9IGhhcm5lc3NWYXJzKTsgLy8gaW4gY2FzZSBzb21lb25lIGRvZXMgc29tZXRoaW5nIGxpa2UgLmZyb20oLi4uLCB7Y3NzOnt9fSlcblxuICAgICAgICBfcmVtb3ZlRnJvbVBhcmVudCh0d2Vlbi5fc3RhcnRBdCA9IFR3ZWVuLnNldCh0YXJnZXRzLCBwKSk7XG5cbiAgICAgICAgdHdlZW4uX3N0YXJ0QXQuX2RwID0gMDsgLy8gZG9uJ3QgYWxsb3cgaXQgdG8gZ2V0IHB1dCBiYWNrIGludG8gcm9vdCB0aW1lbGluZSFcblxuICAgICAgICB0d2Vlbi5fc3RhcnRBdC5fc2F0ID0gdHdlZW47IC8vIHVzZWQgaW4gZ2xvYmFsVGltZSgpXG5cbiAgICAgICAgdGltZSA8IDAgJiYgKF9yZXZlcnRpbmcgPyB0d2Vlbi5fc3RhcnRBdC5yZXZlcnQoX3JldmVydENvbmZpZ05vS2lsbCkgOiB0d2Vlbi5fc3RhcnRBdC5yZW5kZXIoLTEsIHRydWUpKTtcbiAgICAgICAgdHdlZW4uX3pUaW1lID0gdGltZTtcblxuICAgICAgICBpZiAoIWltbWVkaWF0ZVJlbmRlcikge1xuICAgICAgICAgIF9pbml0VHdlZW4odHdlZW4uX3N0YXJ0QXQsIF90aW55TnVtLCBfdGlueU51bSk7IC8vZW5zdXJlcyB0aGF0IHRoZSBpbml0aWFsIHZhbHVlcyBhcmUgcmVjb3JkZWRcblxuICAgICAgICB9IGVsc2UgaWYgKCF0aW1lKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgdHdlZW4uX3B0ID0gdHdlZW4uX3B0Q2FjaGUgPSAwO1xuICAgIGxhenkgPSBkdXIgJiYgX2lzTm90RmFsc2UobGF6eSkgfHwgbGF6eSAmJiAhZHVyO1xuXG4gICAgZm9yIChpID0gMDsgaSA8IHRhcmdldHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHRhcmdldCA9IHRhcmdldHNbaV07XG4gICAgICBnc0RhdGEgPSB0YXJnZXQuX2dzYXAgfHwgX2hhcm5lc3ModGFyZ2V0cylbaV0uX2dzYXA7XG4gICAgICB0d2Vlbi5fcHRMb29rdXBbaV0gPSBwdExvb2t1cCA9IHt9O1xuICAgICAgX2xhenlMb29rdXBbZ3NEYXRhLmlkXSAmJiBfbGF6eVR3ZWVucy5sZW5ndGggJiYgX2xhenlSZW5kZXIoKTsgLy9pZiBvdGhlciB0d2VlbnMgb2YgdGhlIHNhbWUgdGFyZ2V0IGhhdmUgcmVjZW50bHkgaW5pdHRlZCBidXQgaGF2ZW4ndCByZW5kZXJlZCB5ZXQsIHdlJ3ZlIGdvdCB0byBmb3JjZSB0aGUgcmVuZGVyIHNvIHRoYXQgdGhlIHN0YXJ0aW5nIHZhbHVlcyBhcmUgY29ycmVjdCAoaW1hZ2luZSBwb3B1bGF0aW5nIGEgdGltZWxpbmUgd2l0aCBhIGJ1bmNoIG9mIHNlcXVlbnRpYWwgdHdlZW5zIGFuZCB0aGVuIGp1bXBpbmcgdG8gdGhlIGVuZClcblxuICAgICAgaW5kZXggPSBmdWxsVGFyZ2V0cyA9PT0gdGFyZ2V0cyA/IGkgOiBmdWxsVGFyZ2V0cy5pbmRleE9mKHRhcmdldCk7XG5cbiAgICAgIGlmIChoYXJuZXNzICYmIChwbHVnaW4gPSBuZXcgaGFybmVzcygpKS5pbml0KHRhcmdldCwgaGFybmVzc1ZhcnMgfHwgY2xlYW5WYXJzLCB0d2VlbiwgaW5kZXgsIGZ1bGxUYXJnZXRzKSAhPT0gZmFsc2UpIHtcbiAgICAgICAgdHdlZW4uX3B0ID0gcHQgPSBuZXcgUHJvcFR3ZWVuKHR3ZWVuLl9wdCwgdGFyZ2V0LCBwbHVnaW4ubmFtZSwgMCwgMSwgcGx1Z2luLnJlbmRlciwgcGx1Z2luLCAwLCBwbHVnaW4ucHJpb3JpdHkpO1xuXG4gICAgICAgIHBsdWdpbi5fcHJvcHMuZm9yRWFjaChmdW5jdGlvbiAobmFtZSkge1xuICAgICAgICAgIHB0TG9va3VwW25hbWVdID0gcHQ7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHBsdWdpbi5wcmlvcml0eSAmJiAoaGFzUHJpb3JpdHkgPSAxKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFoYXJuZXNzIHx8IGhhcm5lc3NWYXJzKSB7XG4gICAgICAgIGZvciAocCBpbiBjbGVhblZhcnMpIHtcbiAgICAgICAgICBpZiAoX3BsdWdpbnNbcF0gJiYgKHBsdWdpbiA9IF9jaGVja1BsdWdpbihwLCBjbGVhblZhcnMsIHR3ZWVuLCBpbmRleCwgdGFyZ2V0LCBmdWxsVGFyZ2V0cykpKSB7XG4gICAgICAgICAgICBwbHVnaW4ucHJpb3JpdHkgJiYgKGhhc1ByaW9yaXR5ID0gMSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHB0TG9va3VwW3BdID0gcHQgPSBfYWRkUHJvcFR3ZWVuLmNhbGwodHdlZW4sIHRhcmdldCwgcCwgXCJnZXRcIiwgY2xlYW5WYXJzW3BdLCBpbmRleCwgZnVsbFRhcmdldHMsIDAsIHZhcnMuc3RyaW5nRmlsdGVyKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdHdlZW4uX29wICYmIHR3ZWVuLl9vcFtpXSAmJiB0d2Vlbi5raWxsKHRhcmdldCwgdHdlZW4uX29wW2ldKTtcblxuICAgICAgaWYgKGF1dG9PdmVyd3JpdGUgJiYgdHdlZW4uX3B0KSB7XG4gICAgICAgIF9vdmVyd3JpdGluZ1R3ZWVuID0gdHdlZW47XG5cbiAgICAgICAgX2dsb2JhbFRpbWVsaW5lLmtpbGxUd2VlbnNPZih0YXJnZXQsIHB0TG9va3VwLCB0d2Vlbi5nbG9iYWxUaW1lKHRpbWUpKTsgLy8gbWFrZSBzdXJlIHRoZSBvdmVyd3JpdGluZyBkb2Vzbid0IG92ZXJ3cml0ZSBUSElTIHR3ZWVuISEhXG5cblxuICAgICAgICBvdmVyd3JpdHRlbiA9ICF0d2Vlbi5wYXJlbnQ7XG4gICAgICAgIF9vdmVyd3JpdGluZ1R3ZWVuID0gMDtcbiAgICAgIH1cblxuICAgICAgdHdlZW4uX3B0ICYmIGxhenkgJiYgKF9sYXp5TG9va3VwW2dzRGF0YS5pZF0gPSAxKTtcbiAgICB9XG5cbiAgICBoYXNQcmlvcml0eSAmJiBfc29ydFByb3BUd2VlbnNCeVByaW9yaXR5KHR3ZWVuKTtcbiAgICB0d2Vlbi5fb25Jbml0ICYmIHR3ZWVuLl9vbkluaXQodHdlZW4pOyAvL3BsdWdpbnMgbGlrZSBSb3VuZFByb3BzIG11c3Qgd2FpdCB1bnRpbCBBTEwgb2YgdGhlIFByb3BUd2VlbnMgYXJlIGluc3RhbnRpYXRlZC4gSW4gdGhlIHBsdWdpbidzIGluaXQoKSBmdW5jdGlvbiwgaXQgc2V0cyB0aGUgX29uSW5pdCBvbiB0aGUgdHdlZW4gaW5zdGFuY2UuIE1heSBub3QgYmUgcHJldHR5L2ludHVpdGl2ZSwgYnV0IGl0J3MgZmFzdCBhbmQga2VlcHMgZmlsZSBzaXplIGRvd24uXG4gIH1cblxuICB0d2Vlbi5fb25VcGRhdGUgPSBvblVwZGF0ZTtcbiAgdHdlZW4uX2luaXR0ZWQgPSAoIXR3ZWVuLl9vcCB8fCB0d2Vlbi5fcHQpICYmICFvdmVyd3JpdHRlbjsgLy8gaWYgb3ZlcndyaXR0ZW5Qcm9wcyByZXN1bHRlZCBpbiB0aGUgZW50aXJlIHR3ZWVuIGJlaW5nIGtpbGxlZCwgZG8gTk9UIGZsYWcgaXQgYXMgaW5pdHRlZCBvciBlbHNlIGl0IG1heSByZW5kZXIgZm9yIG9uZSB0aWNrLlxuXG4gIGtleWZyYW1lcyAmJiB0aW1lIDw9IDAgJiYgdGwucmVuZGVyKF9iaWdOdW0sIHRydWUsIHRydWUpOyAvLyBpZiB0aGVyZSdzIGEgMCUga2V5ZnJhbWUsIGl0J2xsIHJlbmRlciBpbiB0aGUgXCJiZWZvcmVcIiBzdGF0ZSBmb3IgYW55IHN0YWdnZXJlZC9kZWxheWVkIGFuaW1hdGlvbnMgdGh1cyB3aGVuIHRoZSBmb2xsb3dpbmcgdHdlZW4gaW5pdGlhbGl6ZXMsIGl0J2xsIHVzZSB0aGUgXCJiZWZvcmVcIiBzdGF0ZSBpbnN0ZWFkIG9mIHRoZSBcImFmdGVyXCIgc3RhdGUgYXMgdGhlIGluaXRpYWwgdmFsdWVzLlxufSxcbiAgICBfdXBkYXRlUHJvcFR3ZWVucyA9IGZ1bmN0aW9uIF91cGRhdGVQcm9wVHdlZW5zKHR3ZWVuLCBwcm9wZXJ0eSwgdmFsdWUsIHN0YXJ0LCBzdGFydElzUmVsYXRpdmUsIHJhdGlvLCB0aW1lLCBza2lwUmVjdXJzaW9uKSB7XG4gIHZhciBwdENhY2hlID0gKHR3ZWVuLl9wdCAmJiB0d2Vlbi5fcHRDYWNoZSB8fCAodHdlZW4uX3B0Q2FjaGUgPSB7fSkpW3Byb3BlcnR5XSxcbiAgICAgIHB0LFxuICAgICAgcm9vdFBULFxuICAgICAgbG9va3VwLFxuICAgICAgaTtcblxuICBpZiAoIXB0Q2FjaGUpIHtcbiAgICBwdENhY2hlID0gdHdlZW4uX3B0Q2FjaGVbcHJvcGVydHldID0gW107XG4gICAgbG9va3VwID0gdHdlZW4uX3B0TG9va3VwO1xuICAgIGkgPSB0d2Vlbi5fdGFyZ2V0cy5sZW5ndGg7XG5cbiAgICB3aGlsZSAoaS0tKSB7XG4gICAgICBwdCA9IGxvb2t1cFtpXVtwcm9wZXJ0eV07XG5cbiAgICAgIGlmIChwdCAmJiBwdC5kICYmIHB0LmQuX3B0KSB7XG4gICAgICAgIC8vIGl0J3MgYSBwbHVnaW4sIHNvIGZpbmQgdGhlIG5lc3RlZCBQcm9wVHdlZW5cbiAgICAgICAgcHQgPSBwdC5kLl9wdDtcblxuICAgICAgICB3aGlsZSAocHQgJiYgcHQucCAhPT0gcHJvcGVydHkgJiYgcHQuZnAgIT09IHByb3BlcnR5KSB7XG4gICAgICAgICAgLy8gXCJmcFwiIGlzIGZ1bmN0aW9uUGFyYW0gZm9yIHRoaW5ncyBsaWtlIHNldHRpbmcgQ1NTIHZhcmlhYmxlcyB3aGljaCByZXF1aXJlIC5zZXRQcm9wZXJ0eShcIi0tdmFyLW5hbWVcIiwgdmFsdWUpXG4gICAgICAgICAgcHQgPSBwdC5fbmV4dDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoIXB0KSB7XG4gICAgICAgIC8vIHRoZXJlIGlzIG5vIFByb3BUd2VlbiBhc3NvY2lhdGVkIHdpdGggdGhhdCBwcm9wZXJ0eSwgc28gd2UgbXVzdCBGT1JDRSBvbmUgdG8gYmUgY3JlYXRlZCBhbmQgZGl0Y2ggb3V0IG9mIHRoaXNcbiAgICAgICAgLy8gaWYgdGhlIHR3ZWVuIGhhcyBvdGhlciBwcm9wZXJ0aWVzIHRoYXQgYWxyZWFkeSByZW5kZXJlZCBhdCBuZXcgcG9zaXRpb25zLCB3ZSdkIG5vcm1hbGx5IGhhdmUgdG8gcmV3aW5kIHRvIHB1dCB0aGVtIGJhY2sgbGlrZSB0d2Vlbi5yZW5kZXIoMCwgdHJ1ZSkgYmVmb3JlIGZvcmNpbmcgYW4gX2luaXRUd2VlbigpLCBidXQgdGhhdCBjYW4gY3JlYXRlIGFub3RoZXIgZWRnZSBjYXNlIGxpa2UgdHdlZW5pbmcgYSB0aW1lbGluZSdzIHByb2dyZXNzIHdvdWxkIHRyaWdnZXIgb25VcGRhdGVzIHRvIGZpcmUgd2hpY2ggY291bGQgbW92ZSBvdGhlciB0aGluZ3MgYXJvdW5kLiBJdCdzIGJldHRlciB0byBqdXN0IGluZm9ybSB1c2VycyB0aGF0IC5yZXNldFRvKCkgc2hvdWxkIE9OTFkgYmUgdXNlZCBmb3IgdHdlZW5zIHRoYXQgYWxyZWFkeSBoYXZlIHRoYXQgcHJvcGVydHkuIEZvciBleGFtcGxlLCB5b3UgY2FuJ3QgZ3NhcC50byguLi57IHk6IDAgfSkgYW5kIHRoZW4gdHdlZW4ucmVzdFRvKFwieFwiLCAyMDApIGZvciBleGFtcGxlLlxuICAgICAgICBfZm9yY2VBbGxQcm9wVHdlZW5zID0gMTsgLy8gb3RoZXJ3aXNlLCB3aGVuIHdlIF9hZGRQcm9wVHdlZW4oKSBhbmQgaXQgZmluZHMgbm8gY2hhbmdlIGJldHdlZW4gdGhlIHN0YXJ0IGFuZCBlbmQgdmFsdWVzLCBpdCBza2lwcyBjcmVhdGluZyBhIFByb3BUd2VlbiAoZm9yIGVmZmljaWVuY3kuLi53aHkgdHdlZW4gd2hlbiB0aGVyZSdzIG5vIGRpZmZlcmVuY2U/KSBidXQgaW4gdGhpcyBjYXNlIHdlIE5FRUQgdGhhdCBQcm9wVHdlZW4gY3JlYXRlZCBzbyB3ZSBjYW4gZWRpdCBpdC5cblxuICAgICAgICB0d2Vlbi52YXJzW3Byb3BlcnR5XSA9IFwiKz0wXCI7XG5cbiAgICAgICAgX2luaXRUd2Vlbih0d2VlbiwgdGltZSk7XG5cbiAgICAgICAgX2ZvcmNlQWxsUHJvcFR3ZWVucyA9IDA7XG4gICAgICAgIHJldHVybiBza2lwUmVjdXJzaW9uID8gX3dhcm4ocHJvcGVydHkgKyBcIiBub3QgZWxpZ2libGUgZm9yIHJlc2V0XCIpIDogMTsgLy8gaWYgc29tZW9uZSB0cmllcyB0byBkbyBhIHF1aWNrVG8oKSBvbiBhIHNwZWNpYWwgcHJvcGVydHkgbGlrZSBib3JkZXJSYWRpdXMgd2hpY2ggbXVzdCBnZXQgc3BsaXQgaW50byA0IGRpZmZlcmVudCBwcm9wZXJ0aWVzLCB0aGF0J3Mgbm90IGVsaWdpYmxlIGZvciAucmVzZXRUbygpLlxuICAgICAgfVxuXG4gICAgICBwdENhY2hlLnB1c2gocHQpO1xuICAgIH1cbiAgfVxuXG4gIGkgPSBwdENhY2hlLmxlbmd0aDtcblxuICB3aGlsZSAoaS0tKSB7XG4gICAgcm9vdFBUID0gcHRDYWNoZVtpXTtcbiAgICBwdCA9IHJvb3RQVC5fcHQgfHwgcm9vdFBUOyAvLyBjb21wbGV4IHZhbHVlcyBtYXkgaGF2ZSBuZXN0ZWQgUHJvcFR3ZWVucy4gV2Ugb25seSBhY2NvbW1vZGF0ZSB0aGUgRklSU1QgdmFsdWUuXG5cbiAgICBwdC5zID0gKHN0YXJ0IHx8IHN0YXJ0ID09PSAwKSAmJiAhc3RhcnRJc1JlbGF0aXZlID8gc3RhcnQgOiBwdC5zICsgKHN0YXJ0IHx8IDApICsgcmF0aW8gKiBwdC5jO1xuICAgIHB0LmMgPSB2YWx1ZSAtIHB0LnM7XG4gICAgcm9vdFBULmUgJiYgKHJvb3RQVC5lID0gX3JvdW5kKHZhbHVlKSArIGdldFVuaXQocm9vdFBULmUpKTsgLy8gbWFpbmx5IGZvciBDU1NQbHVnaW4gKGVuZCB2YWx1ZSlcblxuICAgIHJvb3RQVC5iICYmIChyb290UFQuYiA9IHB0LnMgKyBnZXRVbml0KHJvb3RQVC5iKSk7IC8vIChiZWdpbm5pbmcgdmFsdWUpXG4gIH1cbn0sXG4gICAgX2FkZEFsaWFzZXNUb1ZhcnMgPSBmdW5jdGlvbiBfYWRkQWxpYXNlc1RvVmFycyh0YXJnZXRzLCB2YXJzKSB7XG4gIHZhciBoYXJuZXNzID0gdGFyZ2V0c1swXSA/IF9nZXRDYWNoZSh0YXJnZXRzWzBdKS5oYXJuZXNzIDogMCxcbiAgICAgIHByb3BlcnR5QWxpYXNlcyA9IGhhcm5lc3MgJiYgaGFybmVzcy5hbGlhc2VzLFxuICAgICAgY29weSxcbiAgICAgIHAsXG4gICAgICBpLFxuICAgICAgYWxpYXNlcztcblxuICBpZiAoIXByb3BlcnR5QWxpYXNlcykge1xuICAgIHJldHVybiB2YXJzO1xuICB9XG5cbiAgY29weSA9IF9tZXJnZSh7fSwgdmFycyk7XG5cbiAgZm9yIChwIGluIHByb3BlcnR5QWxpYXNlcykge1xuICAgIGlmIChwIGluIGNvcHkpIHtcbiAgICAgIGFsaWFzZXMgPSBwcm9wZXJ0eUFsaWFzZXNbcF0uc3BsaXQoXCIsXCIpO1xuICAgICAgaSA9IGFsaWFzZXMubGVuZ3RoO1xuXG4gICAgICB3aGlsZSAoaS0tKSB7XG4gICAgICAgIGNvcHlbYWxpYXNlc1tpXV0gPSBjb3B5W3BdO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBjb3B5O1xufSxcbiAgICAvLyBwYXJzZXMgbXVsdGlwbGUgZm9ybWF0cywgbGlrZSB7XCIwJVwiOiB7eDogMTAwfSwge1wiNTAlXCI6IHt4OiAtMjB9fSBhbmQgeyB4OiB7XCIwJVwiOiAxMDAsIFwiNTAlXCI6IC0yMH0gfSwgYW5kIGFuIFwiZWFzZVwiIGNhbiBiZSBzZXQgb24gYW55IG9iamVjdC4gV2UgcG9wdWxhdGUgYW4gXCJhbGxQcm9wc1wiIG9iamVjdCB3aXRoIGFuIEFycmF5IGZvciBlYWNoIHByb3BlcnR5LCBsaWtlIHt4OiBbe30sIHt9XSwgeTpbe30sIHt9XX0gd2l0aCBkYXRhIGZvciBlYWNoIHByb3BlcnR5IHR3ZWVuLiBUaGUgb2JqZWN0cyBoYXZlIGEgXCJ0XCIgKHRpbWUpLCBcInZcIiwgKHZhbHVlKSwgYW5kIFwiZVwiIChlYXNlKSBwcm9wZXJ0eS4gVGhpcyBhbGxvd3MgdXMgdG8gcGllY2UgdG9nZXRoZXIgYSB0aW1lbGluZSBsYXRlci5cbl9wYXJzZUtleWZyYW1lID0gZnVuY3Rpb24gX3BhcnNlS2V5ZnJhbWUocHJvcCwgb2JqLCBhbGxQcm9wcywgZWFzZUVhY2gpIHtcbiAgdmFyIGVhc2UgPSBvYmouZWFzZSB8fCBlYXNlRWFjaCB8fCBcInBvd2VyMS5pbk91dFwiLFxuICAgICAgcCxcbiAgICAgIGE7XG5cbiAgaWYgKF9pc0FycmF5KG9iaikpIHtcbiAgICBhID0gYWxsUHJvcHNbcHJvcF0gfHwgKGFsbFByb3BzW3Byb3BdID0gW10pOyAvLyB0ID0gdGltZSAob3V0IG9mIDEwMCksIHYgPSB2YWx1ZSwgZSA9IGVhc2VcblxuICAgIG9iai5mb3JFYWNoKGZ1bmN0aW9uICh2YWx1ZSwgaSkge1xuICAgICAgcmV0dXJuIGEucHVzaCh7XG4gICAgICAgIHQ6IGkgLyAob2JqLmxlbmd0aCAtIDEpICogMTAwLFxuICAgICAgICB2OiB2YWx1ZSxcbiAgICAgICAgZTogZWFzZVxuICAgICAgfSk7XG4gICAgfSk7XG4gIH0gZWxzZSB7XG4gICAgZm9yIChwIGluIG9iaikge1xuICAgICAgYSA9IGFsbFByb3BzW3BdIHx8IChhbGxQcm9wc1twXSA9IFtdKTtcbiAgICAgIHAgPT09IFwiZWFzZVwiIHx8IGEucHVzaCh7XG4gICAgICAgIHQ6IHBhcnNlRmxvYXQocHJvcCksXG4gICAgICAgIHY6IG9ialtwXSxcbiAgICAgICAgZTogZWFzZVxuICAgICAgfSk7XG4gICAgfVxuICB9XG59LFxuICAgIF9wYXJzZUZ1bmNPclN0cmluZyA9IGZ1bmN0aW9uIF9wYXJzZUZ1bmNPclN0cmluZyh2YWx1ZSwgdHdlZW4sIGksIHRhcmdldCwgdGFyZ2V0cykge1xuICByZXR1cm4gX2lzRnVuY3Rpb24odmFsdWUpID8gdmFsdWUuY2FsbCh0d2VlbiwgaSwgdGFyZ2V0LCB0YXJnZXRzKSA6IF9pc1N0cmluZyh2YWx1ZSkgJiYgfnZhbHVlLmluZGV4T2YoXCJyYW5kb20oXCIpID8gX3JlcGxhY2VSYW5kb20odmFsdWUpIDogdmFsdWU7XG59LFxuICAgIF9zdGFnZ2VyVHdlZW5Qcm9wcyA9IF9jYWxsYmFja05hbWVzICsgXCJyZXBlYXQscmVwZWF0RGVsYXkseW95byxyZXBlYXRSZWZyZXNoLHlveW9FYXNlLGF1dG9SZXZlcnRcIixcbiAgICBfc3RhZ2dlclByb3BzVG9Ta2lwID0ge307XG5cbl9mb3JFYWNoTmFtZShfc3RhZ2dlclR3ZWVuUHJvcHMgKyBcIixpZCxzdGFnZ2VyLGRlbGF5LGR1cmF0aW9uLHBhdXNlZCxzY3JvbGxUcmlnZ2VyXCIsIGZ1bmN0aW9uIChuYW1lKSB7XG4gIHJldHVybiBfc3RhZ2dlclByb3BzVG9Ta2lwW25hbWVdID0gMTtcbn0pO1xuLypcbiAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiBUV0VFTlxuICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqL1xuXG5cbmV4cG9ydCB2YXIgVHdlZW4gPSAvKiNfX1BVUkVfXyovZnVuY3Rpb24gKF9BbmltYXRpb24yKSB7XG4gIF9pbmhlcml0c0xvb3NlKFR3ZWVuLCBfQW5pbWF0aW9uMik7XG5cbiAgZnVuY3Rpb24gVHdlZW4odGFyZ2V0cywgdmFycywgcG9zaXRpb24sIHNraXBJbmhlcml0KSB7XG4gICAgdmFyIF90aGlzMztcblxuICAgIGlmICh0eXBlb2YgdmFycyA9PT0gXCJudW1iZXJcIikge1xuICAgICAgcG9zaXRpb24uZHVyYXRpb24gPSB2YXJzO1xuICAgICAgdmFycyA9IHBvc2l0aW9uO1xuICAgICAgcG9zaXRpb24gPSBudWxsO1xuICAgIH1cblxuICAgIF90aGlzMyA9IF9BbmltYXRpb24yLmNhbGwodGhpcywgc2tpcEluaGVyaXQgPyB2YXJzIDogX2luaGVyaXREZWZhdWx0cyh2YXJzKSkgfHwgdGhpcztcbiAgICB2YXIgX3RoaXMzJHZhcnMgPSBfdGhpczMudmFycyxcbiAgICAgICAgZHVyYXRpb24gPSBfdGhpczMkdmFycy5kdXJhdGlvbixcbiAgICAgICAgZGVsYXkgPSBfdGhpczMkdmFycy5kZWxheSxcbiAgICAgICAgaW1tZWRpYXRlUmVuZGVyID0gX3RoaXMzJHZhcnMuaW1tZWRpYXRlUmVuZGVyLFxuICAgICAgICBzdGFnZ2VyID0gX3RoaXMzJHZhcnMuc3RhZ2dlcixcbiAgICAgICAgb3ZlcndyaXRlID0gX3RoaXMzJHZhcnMub3ZlcndyaXRlLFxuICAgICAgICBrZXlmcmFtZXMgPSBfdGhpczMkdmFycy5rZXlmcmFtZXMsXG4gICAgICAgIGRlZmF1bHRzID0gX3RoaXMzJHZhcnMuZGVmYXVsdHMsXG4gICAgICAgIHNjcm9sbFRyaWdnZXIgPSBfdGhpczMkdmFycy5zY3JvbGxUcmlnZ2VyLFxuICAgICAgICB5b3lvRWFzZSA9IF90aGlzMyR2YXJzLnlveW9FYXNlLFxuICAgICAgICBwYXJlbnQgPSB2YXJzLnBhcmVudCB8fCBfZ2xvYmFsVGltZWxpbmUsXG4gICAgICAgIHBhcnNlZFRhcmdldHMgPSAoX2lzQXJyYXkodGFyZ2V0cykgfHwgX2lzVHlwZWRBcnJheSh0YXJnZXRzKSA/IF9pc051bWJlcih0YXJnZXRzWzBdKSA6IFwibGVuZ3RoXCIgaW4gdmFycykgPyBbdGFyZ2V0c10gOiB0b0FycmF5KHRhcmdldHMpLFxuICAgICAgICB0bCxcbiAgICAgICAgaSxcbiAgICAgICAgY29weSxcbiAgICAgICAgbCxcbiAgICAgICAgcCxcbiAgICAgICAgY3VyVGFyZ2V0LFxuICAgICAgICBzdGFnZ2VyRnVuYyxcbiAgICAgICAgc3RhZ2dlclZhcnNUb01lcmdlO1xuICAgIF90aGlzMy5fdGFyZ2V0cyA9IHBhcnNlZFRhcmdldHMubGVuZ3RoID8gX2hhcm5lc3MocGFyc2VkVGFyZ2V0cykgOiBfd2FybihcIkdTQVAgdGFyZ2V0IFwiICsgdGFyZ2V0cyArIFwiIG5vdCBmb3VuZC4gaHR0cHM6Ly9nc2FwLmNvbVwiLCAhX2NvbmZpZy5udWxsVGFyZ2V0V2FybikgfHwgW107XG4gICAgX3RoaXMzLl9wdExvb2t1cCA9IFtdOyAvL1Byb3BUd2VlbiBsb29rdXAuIEFuIGFycmF5IGNvbnRhaW5pbmcgYW4gb2JqZWN0IGZvciBlYWNoIHRhcmdldCwgaGF2aW5nIGtleXMgZm9yIGVhY2ggdHdlZW5pbmcgcHJvcGVydHlcblxuICAgIF90aGlzMy5fb3ZlcndyaXRlID0gb3ZlcndyaXRlO1xuXG4gICAgaWYgKGtleWZyYW1lcyB8fCBzdGFnZ2VyIHx8IF9pc0Z1bmNPclN0cmluZyhkdXJhdGlvbikgfHwgX2lzRnVuY09yU3RyaW5nKGRlbGF5KSkge1xuICAgICAgdmFycyA9IF90aGlzMy52YXJzO1xuICAgICAgdGwgPSBfdGhpczMudGltZWxpbmUgPSBuZXcgVGltZWxpbmUoe1xuICAgICAgICBkYXRhOiBcIm5lc3RlZFwiLFxuICAgICAgICBkZWZhdWx0czogZGVmYXVsdHMgfHwge30sXG4gICAgICAgIHRhcmdldHM6IHBhcmVudCAmJiBwYXJlbnQuZGF0YSA9PT0gXCJuZXN0ZWRcIiA/IHBhcmVudC52YXJzLnRhcmdldHMgOiBwYXJzZWRUYXJnZXRzXG4gICAgICB9KTsgLy8gd2UgbmVlZCB0byBzdG9yZSB0aGUgdGFyZ2V0cyBiZWNhdXNlIGZvciBzdGFnZ2VycyBhbmQga2V5ZnJhbWVzLCB3ZSBlbmQgdXAgY3JlYXRpbmcgYW4gaW5kaXZpZHVhbCB0d2VlbiBmb3IgZWFjaCBidXQgZnVuY3Rpb24tYmFzZWQgdmFsdWVzIG5lZWQgdG8ga25vdyB0aGUgaW5kZXggYW5kIHRoZSB3aG9sZSBBcnJheSBvZiB0YXJnZXRzLlxuXG4gICAgICB0bC5raWxsKCk7XG4gICAgICB0bC5wYXJlbnQgPSB0bC5fZHAgPSBfYXNzZXJ0VGhpc0luaXRpYWxpemVkKF90aGlzMyk7XG4gICAgICB0bC5fc3RhcnQgPSAwO1xuXG4gICAgICBpZiAoc3RhZ2dlciB8fCBfaXNGdW5jT3JTdHJpbmcoZHVyYXRpb24pIHx8IF9pc0Z1bmNPclN0cmluZyhkZWxheSkpIHtcbiAgICAgICAgbCA9IHBhcnNlZFRhcmdldHMubGVuZ3RoO1xuICAgICAgICBzdGFnZ2VyRnVuYyA9IHN0YWdnZXIgJiYgZGlzdHJpYnV0ZShzdGFnZ2VyKTtcblxuICAgICAgICBpZiAoX2lzT2JqZWN0KHN0YWdnZXIpKSB7XG4gICAgICAgICAgLy91c2VycyBjYW4gcGFzcyBpbiBjYWxsYmFja3MgbGlrZSBvblN0YXJ0L29uQ29tcGxldGUgaW4gdGhlIHN0YWdnZXIgb2JqZWN0LiBUaGVzZSBzaG91bGQgZmlyZSB3aXRoIGVhY2ggaW5kaXZpZHVhbCB0d2Vlbi5cbiAgICAgICAgICBmb3IgKHAgaW4gc3RhZ2dlcikge1xuICAgICAgICAgICAgaWYgKH5fc3RhZ2dlclR3ZWVuUHJvcHMuaW5kZXhPZihwKSkge1xuICAgICAgICAgICAgICBzdGFnZ2VyVmFyc1RvTWVyZ2UgfHwgKHN0YWdnZXJWYXJzVG9NZXJnZSA9IHt9KTtcbiAgICAgICAgICAgICAgc3RhZ2dlclZhcnNUb01lcmdlW3BdID0gc3RhZ2dlcltwXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgICAgY29weSA9IF9jb3B5RXhjbHVkaW5nKHZhcnMsIF9zdGFnZ2VyUHJvcHNUb1NraXApO1xuICAgICAgICAgIGNvcHkuc3RhZ2dlciA9IDA7XG4gICAgICAgICAgeW95b0Vhc2UgJiYgKGNvcHkueW95b0Vhc2UgPSB5b3lvRWFzZSk7XG4gICAgICAgICAgc3RhZ2dlclZhcnNUb01lcmdlICYmIF9tZXJnZShjb3B5LCBzdGFnZ2VyVmFyc1RvTWVyZ2UpO1xuICAgICAgICAgIGN1clRhcmdldCA9IHBhcnNlZFRhcmdldHNbaV07IC8vZG9uJ3QganVzdCBjb3B5IGR1cmF0aW9uIG9yIGRlbGF5IGJlY2F1c2UgaWYgdGhleSdyZSBhIHN0cmluZyBvciBmdW5jdGlvbiwgd2UnZCBlbmQgdXAgaW4gYW4gaW5maW5pdGUgbG9vcCBiZWNhdXNlIF9pc0Z1bmNPclN0cmluZygpIHdvdWxkIGV2YWx1YXRlIGFzIHRydWUgaW4gdGhlIGNoaWxkIHR3ZWVucywgZW50ZXJpbmcgdGhpcyBsb29wLCBldGMuIFNvIHdlIHBhcnNlIHRoZSB2YWx1ZSBzdHJhaWdodCBmcm9tIHZhcnMgYW5kIGRlZmF1bHQgdG8gMC5cblxuICAgICAgICAgIGNvcHkuZHVyYXRpb24gPSArX3BhcnNlRnVuY09yU3RyaW5nKGR1cmF0aW9uLCBfYXNzZXJ0VGhpc0luaXRpYWxpemVkKF90aGlzMyksIGksIGN1clRhcmdldCwgcGFyc2VkVGFyZ2V0cyk7XG4gICAgICAgICAgY29weS5kZWxheSA9ICgrX3BhcnNlRnVuY09yU3RyaW5nKGRlbGF5LCBfYXNzZXJ0VGhpc0luaXRpYWxpemVkKF90aGlzMyksIGksIGN1clRhcmdldCwgcGFyc2VkVGFyZ2V0cykgfHwgMCkgLSBfdGhpczMuX2RlbGF5O1xuXG4gICAgICAgICAgaWYgKCFzdGFnZ2VyICYmIGwgPT09IDEgJiYgY29weS5kZWxheSkge1xuICAgICAgICAgICAgLy8gaWYgc29tZW9uZSBkb2VzIGRlbGF5OlwicmFuZG9tKDEsIDUpXCIsIHJlcGVhdDotMSwgZm9yIGV4YW1wbGUsIHRoZSBkZWxheSBzaG91bGRuJ3QgYmUgaW5zaWRlIHRoZSByZXBlYXQuXG4gICAgICAgICAgICBfdGhpczMuX2RlbGF5ID0gZGVsYXkgPSBjb3B5LmRlbGF5O1xuICAgICAgICAgICAgX3RoaXMzLl9zdGFydCArPSBkZWxheTtcbiAgICAgICAgICAgIGNvcHkuZGVsYXkgPSAwO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRsLnRvKGN1clRhcmdldCwgY29weSwgc3RhZ2dlckZ1bmMgPyBzdGFnZ2VyRnVuYyhpLCBjdXJUYXJnZXQsIHBhcnNlZFRhcmdldHMpIDogMCk7XG4gICAgICAgICAgdGwuX2Vhc2UgPSBfZWFzZU1hcC5ub25lO1xuICAgICAgICB9XG5cbiAgICAgICAgdGwuZHVyYXRpb24oKSA/IGR1cmF0aW9uID0gZGVsYXkgPSAwIDogX3RoaXMzLnRpbWVsaW5lID0gMDsgLy8gaWYgdGhlIHRpbWVsaW5lJ3MgZHVyYXRpb24gaXMgMCwgd2UgZG9uJ3QgbmVlZCBhIHRpbWVsaW5lIGludGVybmFsbHkhXG4gICAgICB9IGVsc2UgaWYgKGtleWZyYW1lcykge1xuICAgICAgICBfaW5oZXJpdERlZmF1bHRzKF9zZXREZWZhdWx0cyh0bC52YXJzLmRlZmF1bHRzLCB7XG4gICAgICAgICAgZWFzZTogXCJub25lXCJcbiAgICAgICAgfSkpO1xuXG4gICAgICAgIHRsLl9lYXNlID0gX3BhcnNlRWFzZShrZXlmcmFtZXMuZWFzZSB8fCB2YXJzLmVhc2UgfHwgXCJub25lXCIpO1xuICAgICAgICB2YXIgdGltZSA9IDAsXG4gICAgICAgICAgICBhLFxuICAgICAgICAgICAga2YsXG4gICAgICAgICAgICB2O1xuXG4gICAgICAgIGlmIChfaXNBcnJheShrZXlmcmFtZXMpKSB7XG4gICAgICAgICAga2V5ZnJhbWVzLmZvckVhY2goZnVuY3Rpb24gKGZyYW1lKSB7XG4gICAgICAgICAgICByZXR1cm4gdGwudG8ocGFyc2VkVGFyZ2V0cywgZnJhbWUsIFwiPlwiKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgICB0bC5kdXJhdGlvbigpOyAvLyB0byBlbnN1cmUgdGwuX2R1ciBpcyBjYWNoZWQgYmVjYXVzZSB3ZSB0YXAgaW50byBpdCBmb3IgcGVyZm9ybWFuY2UgcHVycG9zZXMgaW4gdGhlIHJlbmRlcigpIG1ldGhvZC5cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb3B5ID0ge307XG5cbiAgICAgICAgICBmb3IgKHAgaW4ga2V5ZnJhbWVzKSB7XG4gICAgICAgICAgICBwID09PSBcImVhc2VcIiB8fCBwID09PSBcImVhc2VFYWNoXCIgfHwgX3BhcnNlS2V5ZnJhbWUocCwga2V5ZnJhbWVzW3BdLCBjb3B5LCBrZXlmcmFtZXMuZWFzZUVhY2gpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGZvciAocCBpbiBjb3B5KSB7XG4gICAgICAgICAgICBhID0gY29weVtwXS5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgICAgICAgIHJldHVybiBhLnQgLSBiLnQ7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHRpbWUgPSAwO1xuXG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgYS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICBrZiA9IGFbaV07XG4gICAgICAgICAgICAgIHYgPSB7XG4gICAgICAgICAgICAgICAgZWFzZToga2YuZSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogKGtmLnQgLSAoaSA/IGFbaSAtIDFdLnQgOiAwKSkgLyAxMDAgKiBkdXJhdGlvblxuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICB2W3BdID0ga2YudjtcbiAgICAgICAgICAgICAgdGwudG8ocGFyc2VkVGFyZ2V0cywgdiwgdGltZSk7XG4gICAgICAgICAgICAgIHRpbWUgKz0gdi5kdXJhdGlvbjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0bC5kdXJhdGlvbigpIDwgZHVyYXRpb24gJiYgdGwudG8oe30sIHtcbiAgICAgICAgICAgIGR1cmF0aW9uOiBkdXJhdGlvbiAtIHRsLmR1cmF0aW9uKClcbiAgICAgICAgICB9KTsgLy8gaW4gY2FzZSBrZXlmcmFtZXMgZGlkbid0IGdvIHRvIDEwMCVcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBkdXJhdGlvbiB8fCBfdGhpczMuZHVyYXRpb24oZHVyYXRpb24gPSB0bC5kdXJhdGlvbigpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgX3RoaXMzLnRpbWVsaW5lID0gMDsgLy9zcGVlZCBvcHRpbWl6YXRpb24sIGZhc3RlciBsb29rdXBzIChubyBnb2luZyB1cCB0aGUgcHJvdG90eXBlIGNoYWluKVxuICAgIH1cblxuICAgIGlmIChvdmVyd3JpdGUgPT09IHRydWUgJiYgIV9zdXBwcmVzc092ZXJ3cml0ZXMpIHtcbiAgICAgIF9vdmVyd3JpdGluZ1R3ZWVuID0gX2Fzc2VydFRoaXNJbml0aWFsaXplZChfdGhpczMpO1xuXG4gICAgICBfZ2xvYmFsVGltZWxpbmUua2lsbFR3ZWVuc09mKHBhcnNlZFRhcmdldHMpO1xuXG4gICAgICBfb3ZlcndyaXRpbmdUd2VlbiA9IDA7XG4gICAgfVxuXG4gICAgX2FkZFRvVGltZWxpbmUocGFyZW50LCBfYXNzZXJ0VGhpc0luaXRpYWxpemVkKF90aGlzMyksIHBvc2l0aW9uKTtcblxuICAgIHZhcnMucmV2ZXJzZWQgJiYgX3RoaXMzLnJldmVyc2UoKTtcbiAgICB2YXJzLnBhdXNlZCAmJiBfdGhpczMucGF1c2VkKHRydWUpO1xuXG4gICAgaWYgKGltbWVkaWF0ZVJlbmRlciB8fCAhZHVyYXRpb24gJiYgIWtleWZyYW1lcyAmJiBfdGhpczMuX3N0YXJ0ID09PSBfcm91bmRQcmVjaXNlKHBhcmVudC5fdGltZSkgJiYgX2lzTm90RmFsc2UoaW1tZWRpYXRlUmVuZGVyKSAmJiBfaGFzTm9QYXVzZWRBbmNlc3RvcnMoX2Fzc2VydFRoaXNJbml0aWFsaXplZChfdGhpczMpKSAmJiBwYXJlbnQuZGF0YSAhPT0gXCJuZXN0ZWRcIikge1xuICAgICAgX3RoaXMzLl90VGltZSA9IC1fdGlueU51bTsgLy9mb3JjZXMgYSByZW5kZXIgd2l0aG91dCBoYXZpbmcgdG8gc2V0IHRoZSByZW5kZXIoKSBcImZvcmNlXCIgcGFyYW1ldGVyIHRvIHRydWUgYmVjYXVzZSB3ZSB3YW50IHRvIGFsbG93IGxhenlpbmcgYnkgZGVmYXVsdCAodXNpbmcgdGhlIFwiZm9yY2VcIiBwYXJhbWV0ZXIgYWx3YXlzIGZvcmNlcyBhbiBpbW1lZGlhdGUgZnVsbCByZW5kZXIpXG5cbiAgICAgIF90aGlzMy5yZW5kZXIoTWF0aC5tYXgoMCwgLWRlbGF5KSB8fCAwKTsgLy9pbiBjYXNlIGRlbGF5IGlzIG5lZ2F0aXZlXG5cbiAgICB9XG5cbiAgICBzY3JvbGxUcmlnZ2VyICYmIF9zY3JvbGxUcmlnZ2VyKF9hc3NlcnRUaGlzSW5pdGlhbGl6ZWQoX3RoaXMzKSwgc2Nyb2xsVHJpZ2dlcik7XG4gICAgcmV0dXJuIF90aGlzMztcbiAgfVxuXG4gIHZhciBfcHJvdG8zID0gVHdlZW4ucHJvdG90eXBlO1xuXG4gIF9wcm90bzMucmVuZGVyID0gZnVuY3Rpb24gcmVuZGVyKHRvdGFsVGltZSwgc3VwcHJlc3NFdmVudHMsIGZvcmNlKSB7XG4gICAgdmFyIHByZXZUaW1lID0gdGhpcy5fdGltZSxcbiAgICAgICAgdER1ciA9IHRoaXMuX3REdXIsXG4gICAgICAgIGR1ciA9IHRoaXMuX2R1cixcbiAgICAgICAgaXNOZWdhdGl2ZSA9IHRvdGFsVGltZSA8IDAsXG4gICAgICAgIHRUaW1lID0gdG90YWxUaW1lID4gdER1ciAtIF90aW55TnVtICYmICFpc05lZ2F0aXZlID8gdER1ciA6IHRvdGFsVGltZSA8IF90aW55TnVtID8gMCA6IHRvdGFsVGltZSxcbiAgICAgICAgdGltZSxcbiAgICAgICAgcHQsXG4gICAgICAgIGl0ZXJhdGlvbixcbiAgICAgICAgY3ljbGVEdXJhdGlvbixcbiAgICAgICAgcHJldkl0ZXJhdGlvbixcbiAgICAgICAgaXNZb3lvLFxuICAgICAgICByYXRpbyxcbiAgICAgICAgdGltZWxpbmUsXG4gICAgICAgIHlveW9FYXNlO1xuXG4gICAgaWYgKCFkdXIpIHtcbiAgICAgIF9yZW5kZXJaZXJvRHVyYXRpb25Ud2Vlbih0aGlzLCB0b3RhbFRpbWUsIHN1cHByZXNzRXZlbnRzLCBmb3JjZSk7XG4gICAgfSBlbHNlIGlmICh0VGltZSAhPT0gdGhpcy5fdFRpbWUgfHwgIXRvdGFsVGltZSB8fCBmb3JjZSB8fCAhdGhpcy5faW5pdHRlZCAmJiB0aGlzLl90VGltZSB8fCB0aGlzLl9zdGFydEF0ICYmIHRoaXMuX3pUaW1lIDwgMCAhPT0gaXNOZWdhdGl2ZSkge1xuICAgICAgLy90aGlzIHNlbnNlcyBpZiB3ZSdyZSBjcm9zc2luZyBvdmVyIHRoZSBzdGFydCB0aW1lLCBpbiB3aGljaCBjYXNlIHdlIG11c3QgcmVjb3JkIF96VGltZSBhbmQgZm9yY2UgdGhlIHJlbmRlciwgYnV0IHdlIGRvIGl0IGluIHRoaXMgbGVuZ3RoeSBjb25kaXRpb25hbCB3YXkgZm9yIHBlcmZvcm1hbmNlIHJlYXNvbnMgKHVzdWFsbHkgd2UgY2FuIHNraXAgdGhlIGNhbGN1bGF0aW9ucyk6IHRoaXMuX2luaXR0ZWQgJiYgKHRoaXMuX3pUaW1lIDwgMCkgIT09ICh0b3RhbFRpbWUgPCAwKVxuICAgICAgdGltZSA9IHRUaW1lO1xuICAgICAgdGltZWxpbmUgPSB0aGlzLnRpbWVsaW5lO1xuXG4gICAgICBpZiAodGhpcy5fcmVwZWF0KSB7XG4gICAgICAgIC8vYWRqdXN0IHRoZSB0aW1lIGZvciByZXBlYXRzIGFuZCB5b3lvc1xuICAgICAgICBjeWNsZUR1cmF0aW9uID0gZHVyICsgdGhpcy5fckRlbGF5O1xuXG4gICAgICAgIGlmICh0aGlzLl9yZXBlYXQgPCAtMSAmJiBpc05lZ2F0aXZlKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMudG90YWxUaW1lKGN5Y2xlRHVyYXRpb24gKiAxMDAgKyB0b3RhbFRpbWUsIHN1cHByZXNzRXZlbnRzLCBmb3JjZSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aW1lID0gX3JvdW5kUHJlY2lzZSh0VGltZSAlIGN5Y2xlRHVyYXRpb24pOyAvL3JvdW5kIHRvIGF2b2lkIGZsb2F0aW5nIHBvaW50IGVycm9ycy4gKDQgJSAwLjggc2hvdWxkIGJlIDAgYnV0IHNvbWUgYnJvd3NlcnMgcmVwb3J0IGl0IGFzIDAuNzk5OTk5OTkhKVxuXG4gICAgICAgIGlmICh0VGltZSA9PT0gdER1cikge1xuICAgICAgICAgIC8vIHRoZSB0RHVyID09PSB0VGltZSBpcyBmb3IgZWRnZSBjYXNlcyB3aGVyZSB0aGVyZSdzIGEgbGVuZ3RoeSBkZWNpbWFsIG9uIHRoZSBkdXJhdGlvbiBhbmQgaXQgbWF5IHJlYWNoIHRoZSB2ZXJ5IGVuZCBidXQgdGhlIHRpbWUgaXMgcmVuZGVyZWQgYXMgbm90LXF1aXRlLXRoZXJlIChyZW1lbWJlciwgdER1ciBpcyByb3VuZGVkIHRvIDQgZGVjaW1hbHMgd2hlcmVhcyBkdXIgaXNuJ3QpXG4gICAgICAgICAgaXRlcmF0aW9uID0gdGhpcy5fcmVwZWF0O1xuICAgICAgICAgIHRpbWUgPSBkdXI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaXRlcmF0aW9uID0gfn4odFRpbWUgLyBjeWNsZUR1cmF0aW9uKTtcblxuICAgICAgICAgIGlmIChpdGVyYXRpb24gJiYgaXRlcmF0aW9uID09PSBfcm91bmRQcmVjaXNlKHRUaW1lIC8gY3ljbGVEdXJhdGlvbikpIHtcbiAgICAgICAgICAgIHRpbWUgPSBkdXI7XG4gICAgICAgICAgICBpdGVyYXRpb24tLTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aW1lID4gZHVyICYmICh0aW1lID0gZHVyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlzWW95byA9IHRoaXMuX3lveW8gJiYgaXRlcmF0aW9uICYgMTtcblxuICAgICAgICBpZiAoaXNZb3lvKSB7XG4gICAgICAgICAgeW95b0Vhc2UgPSB0aGlzLl95RWFzZTtcbiAgICAgICAgICB0aW1lID0gZHVyIC0gdGltZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHByZXZJdGVyYXRpb24gPSBfYW5pbWF0aW9uQ3ljbGUodGhpcy5fdFRpbWUsIGN5Y2xlRHVyYXRpb24pO1xuXG4gICAgICAgIGlmICh0aW1lID09PSBwcmV2VGltZSAmJiAhZm9yY2UgJiYgdGhpcy5faW5pdHRlZCAmJiBpdGVyYXRpb24gPT09IHByZXZJdGVyYXRpb24pIHtcbiAgICAgICAgICAvL2NvdWxkIGJlIGR1cmluZyB0aGUgcmVwZWF0RGVsYXkgcGFydC4gTm8gbmVlZCB0byByZW5kZXIgYW5kIGZpcmUgY2FsbGJhY2tzLlxuICAgICAgICAgIHRoaXMuX3RUaW1lID0gdFRpbWU7XG4gICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaXRlcmF0aW9uICE9PSBwcmV2SXRlcmF0aW9uKSB7XG4gICAgICAgICAgdGltZWxpbmUgJiYgdGhpcy5feUVhc2UgJiYgX3Byb3BhZ2F0ZVlveW9FYXNlKHRpbWVsaW5lLCBpc1lveW8pOyAvL3JlcGVhdFJlZnJlc2ggZnVuY3Rpb25hbGl0eVxuXG4gICAgICAgICAgaWYgKHRoaXMudmFycy5yZXBlYXRSZWZyZXNoICYmICFpc1lveW8gJiYgIXRoaXMuX2xvY2sgJiYgdGhpcy5fdGltZSAhPT0gY3ljbGVEdXJhdGlvbiAmJiB0aGlzLl9pbml0dGVkKSB7XG4gICAgICAgICAgICAvLyB0aGlzLl90aW1lIHdpbGwgPT09IGN5Y2xlRHVyYXRpb24gd2hlbiB3ZSByZW5kZXIgYXQgRVhBQ1RMWSB0aGUgZW5kIG9mIGFuIGl0ZXJhdGlvbi4gV2l0aG91dCB0aGlzIGNvbmRpdGlvbiwgaXQnZCBvZnRlbiBkbyB0aGUgcmVwZWF0UmVmcmVzaCByZW5kZXIgVFdJQ0UgKGFnYWluIG9uIHRoZSB2ZXJ5IG5leHQgdGljaykuXG4gICAgICAgICAgICB0aGlzLl9sb2NrID0gZm9yY2UgPSAxOyAvL2ZvcmNlLCBvdGhlcndpc2UgaWYgbGF6eSBpcyB0cnVlLCB0aGUgX2F0dGVtcHRJbml0VHdlZW4oKSB3aWxsIHJldHVybiBhbmQgd2UnbGwganVtcCBvdXQgYW5kIGdldCBjYXVnaHQgYm91bmNpbmcgb24gZWFjaCB0aWNrLlxuXG4gICAgICAgICAgICB0aGlzLnJlbmRlcihfcm91bmRQcmVjaXNlKGN5Y2xlRHVyYXRpb24gKiBpdGVyYXRpb24pLCB0cnVlKS5pbnZhbGlkYXRlKCkuX2xvY2sgPSAwO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoIXRoaXMuX2luaXR0ZWQpIHtcbiAgICAgICAgaWYgKF9hdHRlbXB0SW5pdFR3ZWVuKHRoaXMsIGlzTmVnYXRpdmUgPyB0b3RhbFRpbWUgOiB0aW1lLCBmb3JjZSwgc3VwcHJlc3NFdmVudHMsIHRUaW1lKSkge1xuICAgICAgICAgIHRoaXMuX3RUaW1lID0gMDsgLy8gaW4gY29uc3RydWN0b3IgaWYgaW1tZWRpYXRlUmVuZGVyIGlzIHRydWUsIHdlIHNldCBfdFRpbWUgdG8gLV90aW55TnVtIHRvIGhhdmUgdGhlIHBsYXloZWFkIGNyb3NzIHRoZSBzdGFydGluZyBwb2ludCBidXQgd2UgY2FuJ3QgbGVhdmUgX3RUaW1lIGFzIGEgbmVnYXRpdmUgbnVtYmVyLlxuXG4gICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocHJldlRpbWUgIT09IHRoaXMuX3RpbWUgJiYgIShmb3JjZSAmJiB0aGlzLnZhcnMucmVwZWF0UmVmcmVzaCAmJiBpdGVyYXRpb24gIT09IHByZXZJdGVyYXRpb24pKSB7XG4gICAgICAgICAgLy8gcmFyZSBlZGdlIGNhc2UgLSBkdXJpbmcgaW5pdGlhbGl6YXRpb24sIGFuIG9uVXBkYXRlIGluIHRoZSBfc3RhcnRBdCAoLmZyb21UbygpKSBtaWdodCBmb3JjZSB0aGlzIHR3ZWVuIHRvIHJlbmRlciBhdCBhIGRpZmZlcmVudCBzcG90IGluIHdoaWNoIGNhc2Ugd2Ugc2hvdWxkIGRpdGNoIHRoaXMgcmVuZGVyKCkgY2FsbCBzbyB0aGF0IGl0IGRvZXNuJ3QgcmV2ZXJ0IHRoZSB2YWx1ZXMuIEJ1dCB3ZSBhbHNvIGRvbid0IHdhbnQgdG8gZHVtcCBpZiB3ZSdyZSBkb2luZyBhIHJlcGVhdFJlZnJlc2ggcmVuZGVyIVxuICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGR1ciAhPT0gdGhpcy5fZHVyKSB7XG4gICAgICAgICAgLy8gd2hpbGUgaW5pdHRpbmcsIGEgcGx1Z2luIGxpa2UgSW5lcnRpYVBsdWdpbiBtaWdodCBhbHRlciB0aGUgZHVyYXRpb24sIHNvIHJlcnVuIGZyb20gdGhlIHN0YXJ0IHRvIGVuc3VyZSBldmVyeXRoaW5nIHJlbmRlcnMgYXMgaXQgc2hvdWxkLlxuICAgICAgICAgIHJldHVybiB0aGlzLnJlbmRlcih0b3RhbFRpbWUsIHN1cHByZXNzRXZlbnRzLCBmb3JjZSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdGhpcy5fdFRpbWUgPSB0VGltZTtcbiAgICAgIHRoaXMuX3RpbWUgPSB0aW1lO1xuXG4gICAgICBpZiAoIXRoaXMuX2FjdCAmJiB0aGlzLl90cykge1xuICAgICAgICB0aGlzLl9hY3QgPSAxOyAvL2FzIGxvbmcgYXMgaXQncyBub3QgcGF1c2VkLCBmb3JjZSBpdCB0byBiZSBhY3RpdmUgc28gdGhhdCBpZiB0aGUgdXNlciByZW5kZXJzIGluZGVwZW5kZW50IG9mIHRoZSBwYXJlbnQgdGltZWxpbmUsIGl0J2xsIGJlIGZvcmNlZCB0byByZS1yZW5kZXIgb24gdGhlIG5leHQgdGljay5cblxuICAgICAgICB0aGlzLl9sYXp5ID0gMDtcbiAgICAgIH1cblxuICAgICAgdGhpcy5yYXRpbyA9IHJhdGlvID0gKHlveW9FYXNlIHx8IHRoaXMuX2Vhc2UpKHRpbWUgLyBkdXIpO1xuXG4gICAgICBpZiAodGhpcy5fZnJvbSkge1xuICAgICAgICB0aGlzLnJhdGlvID0gcmF0aW8gPSAxIC0gcmF0aW87XG4gICAgICB9XG5cbiAgICAgIGlmICh0aW1lICYmICFwcmV2VGltZSAmJiAhc3VwcHJlc3NFdmVudHMgJiYgIWl0ZXJhdGlvbikge1xuICAgICAgICBfY2FsbGJhY2sodGhpcywgXCJvblN0YXJ0XCIpO1xuXG4gICAgICAgIGlmICh0aGlzLl90VGltZSAhPT0gdFRpbWUpIHtcbiAgICAgICAgICAvLyBpbiBjYXNlIHRoZSBvblN0YXJ0IHRyaWdnZXJlZCBhIHJlbmRlciBhdCBhIGRpZmZlcmVudCBzcG90LCBlamVjdC4gTGlrZSBpZiBzb21lb25lIGRpZCBhbmltYXRpb24ucGF1c2UoMC41KSBvciBzb21ldGhpbmcgaW5zaWRlIHRoZSBvblN0YXJ0LlxuICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHB0ID0gdGhpcy5fcHQ7XG5cbiAgICAgIHdoaWxlIChwdCkge1xuICAgICAgICBwdC5yKHJhdGlvLCBwdC5kKTtcbiAgICAgICAgcHQgPSBwdC5fbmV4dDtcbiAgICAgIH1cblxuICAgICAgdGltZWxpbmUgJiYgdGltZWxpbmUucmVuZGVyKHRvdGFsVGltZSA8IDAgPyB0b3RhbFRpbWUgOiB0aW1lbGluZS5fZHVyICogdGltZWxpbmUuX2Vhc2UodGltZSAvIHRoaXMuX2R1ciksIHN1cHByZXNzRXZlbnRzLCBmb3JjZSkgfHwgdGhpcy5fc3RhcnRBdCAmJiAodGhpcy5felRpbWUgPSB0b3RhbFRpbWUpO1xuXG4gICAgICBpZiAodGhpcy5fb25VcGRhdGUgJiYgIXN1cHByZXNzRXZlbnRzKSB7XG4gICAgICAgIGlzTmVnYXRpdmUgJiYgX3Jld2luZFN0YXJ0QXQodGhpcywgdG90YWxUaW1lLCBzdXBwcmVzc0V2ZW50cywgZm9yY2UpOyAvL25vdGU6IGZvciBwZXJmb3JtYW5jZSByZWFzb25zLCB3ZSB0dWNrIHRoaXMgY29uZGl0aW9uYWwgbG9naWMgaW5zaWRlIGxlc3MgdHJhdmVsZWQgYXJlYXMgKG1vc3QgdHdlZW5zIGRvbid0IGhhdmUgYW4gb25VcGRhdGUpLiBXZSdkIGp1c3QgaGF2ZSBpdCBhdCB0aGUgZW5kIGJlZm9yZSB0aGUgb25Db21wbGV0ZSwgYnV0IHRoZSB2YWx1ZXMgc2hvdWxkIGJlIHVwZGF0ZWQgYmVmb3JlIGFueSBvblVwZGF0ZSBpcyBjYWxsZWQsIHNvIHdlIEFMU08gcHV0IGl0IGhlcmUgYW5kIHRoZW4gaWYgaXQncyBub3QgY2FsbGVkLCB3ZSBkbyBzbyBsYXRlciBuZWFyIHRoZSBvbkNvbXBsZXRlLlxuXG4gICAgICAgIF9jYWxsYmFjayh0aGlzLCBcIm9uVXBkYXRlXCIpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLl9yZXBlYXQgJiYgaXRlcmF0aW9uICE9PSBwcmV2SXRlcmF0aW9uICYmIHRoaXMudmFycy5vblJlcGVhdCAmJiAhc3VwcHJlc3NFdmVudHMgJiYgdGhpcy5wYXJlbnQgJiYgX2NhbGxiYWNrKHRoaXMsIFwib25SZXBlYXRcIik7XG5cbiAgICAgIGlmICgodFRpbWUgPT09IHRoaXMuX3REdXIgfHwgIXRUaW1lKSAmJiB0aGlzLl90VGltZSA9PT0gdFRpbWUpIHtcbiAgICAgICAgaXNOZWdhdGl2ZSAmJiAhdGhpcy5fb25VcGRhdGUgJiYgX3Jld2luZFN0YXJ0QXQodGhpcywgdG90YWxUaW1lLCB0cnVlLCB0cnVlKTtcbiAgICAgICAgKHRvdGFsVGltZSB8fCAhZHVyKSAmJiAodFRpbWUgPT09IHRoaXMuX3REdXIgJiYgdGhpcy5fdHMgPiAwIHx8ICF0VGltZSAmJiB0aGlzLl90cyA8IDApICYmIF9yZW1vdmVGcm9tUGFyZW50KHRoaXMsIDEpOyAvLyBkb24ndCByZW1vdmUgaWYgd2UncmUgcmVuZGVyaW5nIGF0IGV4YWN0bHkgYSB0aW1lIG9mIDAsIGFzIHRoZXJlIGNvdWxkIGJlIGF1dG9SZXZlcnQgdmFsdWVzIHRoYXQgc2hvdWxkIGdldCBzZXQgb24gdGhlIG5leHQgdGljayAoaWYgdGhlIHBsYXloZWFkIGdvZXMgYmFja3dhcmQgYmV5b25kIHRoZSBzdGFydFRpbWUsIG5lZ2F0aXZlIHRvdGFsVGltZSkuIERvbid0IHJlbW92ZSBpZiB0aGUgdGltZWxpbmUgaXMgcmV2ZXJzZWQgYW5kIHRoZSBwbGF5aGVhZCBpc24ndCBhdCAwLCBvdGhlcndpc2UgdGwucHJvZ3Jlc3MoMSkucmV2ZXJzZSgpIHdvbid0IHdvcmsuIE9ubHkgcmVtb3ZlIGlmIHRoZSBwbGF5aGVhZCBpcyBhdCB0aGUgZW5kIGFuZCB0aW1lU2NhbGUgaXMgcG9zaXRpdmUsIG9yIGlmIHRoZSBwbGF5aGVhZCBpcyBhdCAwIGFuZCB0aGUgdGltZVNjYWxlIGlzIG5lZ2F0aXZlLlxuXG4gICAgICAgIGlmICghc3VwcHJlc3NFdmVudHMgJiYgIShpc05lZ2F0aXZlICYmICFwcmV2VGltZSkgJiYgKHRUaW1lIHx8IHByZXZUaW1lIHx8IGlzWW95bykpIHtcbiAgICAgICAgICAvLyBpZiBwcmV2VGltZSBhbmQgdFRpbWUgYXJlIHplcm8sIHdlIHNob3VsZG4ndCBmaXJlIHRoZSBvblJldmVyc2VDb21wbGV0ZS4gVGhpcyBjb3VsZCBoYXBwZW4gaWYgeW91IGdzYXAudG8oLi4uIHtwYXVzZWQ6dHJ1ZX0pLnBsYXkoKTtcbiAgICAgICAgICBfY2FsbGJhY2sodGhpcywgdFRpbWUgPT09IHREdXIgPyBcIm9uQ29tcGxldGVcIiA6IFwib25SZXZlcnNlQ29tcGxldGVcIiwgdHJ1ZSk7XG5cbiAgICAgICAgICB0aGlzLl9wcm9tICYmICEodFRpbWUgPCB0RHVyICYmIHRoaXMudGltZVNjYWxlKCkgPiAwKSAmJiB0aGlzLl9wcm9tKCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfTtcblxuICBfcHJvdG8zLnRhcmdldHMgPSBmdW5jdGlvbiB0YXJnZXRzKCkge1xuICAgIHJldHVybiB0aGlzLl90YXJnZXRzO1xuICB9O1xuXG4gIF9wcm90bzMuaW52YWxpZGF0ZSA9IGZ1bmN0aW9uIGludmFsaWRhdGUoc29mdCkge1xuICAgIC8vIFwic29mdFwiIGdpdmVzIHVzIGEgd2F5IHRvIGNsZWFyIG91dCBldmVyeXRoaW5nIEVYQ0VQVCB0aGUgcmVjb3JkZWQgcHJlLVwiZnJvbVwiIHBvcnRpb24gb2YgZnJvbSgpIHR3ZWVucy4gT3RoZXJ3aXNlLCBmb3IgZXhhbXBsZSwgaWYgeW91IHR3ZWVuLnByb2dyZXNzKDEpLnJlbmRlcigwLCB0cnVlIHRydWUpLmludmFsaWRhdGUoKSwgdGhlIFwiZnJvbVwiIHZhbHVlcyB3b3VsZCBwZXJzaXN0IGFuZCB0aGVuIG9uIHRoZSBuZXh0IHJlbmRlciwgdGhlIGZyb20oKSB0d2VlbnMgd291bGQgaW5pdGlhbGl6ZSBhbmQgdGhlIGN1cnJlbnQgdmFsdWUgd291bGQgbWF0Y2ggdGhlIFwiZnJvbVwiIHZhbHVlcywgdGh1cyBhbmltYXRlIGZyb20gdGhlIHNhbWUgdmFsdWUgdG8gdGhlIHNhbWUgdmFsdWUgKG5vIGFuaW1hdGlvbikuIFdlIHRhcCBpbnRvIHRoaXMgaW4gU2Nyb2xsVHJpZ2dlcidzIHJlZnJlc2goKSB3aGVyZSB3ZSBtdXN0IHB1c2ggYSB0d2VlbiB0byBjb21wbGV0aW9uIGFuZCB0aGVuIGJhY2sgYWdhaW4gYnV0IGhvbm9yIGl0cyBpbml0IHN0YXRlIGluIGNhc2UgdGhlIHR3ZWVuIGlzIGRlcGVuZGVudCBvbiBhbm90aGVyIHR3ZWVuIGZ1cnRoZXIgdXAgb24gdGhlIHBhZ2UuXG4gICAgKCFzb2Z0IHx8ICF0aGlzLnZhcnMucnVuQmFja3dhcmRzKSAmJiAodGhpcy5fc3RhcnRBdCA9IDApO1xuICAgIHRoaXMuX3B0ID0gdGhpcy5fb3AgPSB0aGlzLl9vblVwZGF0ZSA9IHRoaXMuX2xhenkgPSB0aGlzLnJhdGlvID0gMDtcbiAgICB0aGlzLl9wdExvb2t1cCA9IFtdO1xuICAgIHRoaXMudGltZWxpbmUgJiYgdGhpcy50aW1lbGluZS5pbnZhbGlkYXRlKHNvZnQpO1xuICAgIHJldHVybiBfQW5pbWF0aW9uMi5wcm90b3R5cGUuaW52YWxpZGF0ZS5jYWxsKHRoaXMsIHNvZnQpO1xuICB9O1xuXG4gIF9wcm90bzMucmVzZXRUbyA9IGZ1bmN0aW9uIHJlc2V0VG8ocHJvcGVydHksIHZhbHVlLCBzdGFydCwgc3RhcnRJc1JlbGF0aXZlLCBza2lwUmVjdXJzaW9uKSB7XG4gICAgX3RpY2tlckFjdGl2ZSB8fCBfdGlja2VyLndha2UoKTtcbiAgICB0aGlzLl90cyB8fCB0aGlzLnBsYXkoKTtcbiAgICB2YXIgdGltZSA9IE1hdGgubWluKHRoaXMuX2R1ciwgKHRoaXMuX2RwLl90aW1lIC0gdGhpcy5fc3RhcnQpICogdGhpcy5fdHMpLFxuICAgICAgICByYXRpbztcbiAgICB0aGlzLl9pbml0dGVkIHx8IF9pbml0VHdlZW4odGhpcywgdGltZSk7XG4gICAgcmF0aW8gPSB0aGlzLl9lYXNlKHRpbWUgLyB0aGlzLl9kdXIpOyAvLyBkb24ndCBqdXN0IGdldCB0d2Vlbi5yYXRpbyBiZWNhdXNlIGl0IG1heSBub3QgaGF2ZSByZW5kZXJlZCB5ZXQuXG4gICAgLy8gcG9zc2libGUgZnV0dXJlIGFkZGl0aW9uIHRvIGFsbG93IGFuIG9iamVjdCB3aXRoIG11bHRpcGxlIHZhbHVlcyB0byB1cGRhdGUsIGxpa2UgdHdlZW4ucmVzZXRUbyh7eDogMTAwLCB5OiAyMDB9KTsgQXQgdGhpcyBwb2ludCwgaXQgZG9lc24ndCBzZWVtIHdvcnRoIHRoZSBhZGRlZCBrYiBnaXZlbiB0aGUgZmFjdCB0aGF0IG1vc3QgdXNlcnMgd2lsbCBsaWtlbHkgb3B0IGZvciB0aGUgY29udmVuaWVudCBnc2FwLnF1aWNrVG8oKSB3YXkgb2YgaW50ZXJhY3Rpbmcgd2l0aCB0aGlzIG1ldGhvZC5cbiAgICAvLyBpZiAoX2lzT2JqZWN0KHByb3BlcnR5KSkgeyAvLyBwZXJmb3JtYW5jZSBvcHRpbWl6YXRpb25cbiAgICAvLyBcdGZvciAocCBpbiBwcm9wZXJ0eSkge1xuICAgIC8vIFx0XHRpZiAoX3VwZGF0ZVByb3BUd2VlbnModGhpcywgcCwgcHJvcGVydHlbcF0sIHZhbHVlID8gdmFsdWVbcF0gOiBudWxsLCBzdGFydCwgcmF0aW8sIHRpbWUpKSB7XG4gICAgLy8gXHRcdFx0cmV0dXJuIHRoaXMucmVzZXRUbyhwcm9wZXJ0eSwgdmFsdWUsIHN0YXJ0LCBzdGFydElzUmVsYXRpdmUpOyAvLyBpZiBhIFByb3BUd2VlbiB3YXNuJ3QgZm91bmQgZm9yIHRoZSBwcm9wZXJ0eSwgaXQnbGwgZ2V0IGZvcmNlZCB3aXRoIGEgcmUtaW5pdGlhbGl6YXRpb24gc28gd2UgbmVlZCB0byBqdW1wIG91dCBhbmQgc3RhcnQgb3ZlciBhZ2Fpbi5cbiAgICAvLyBcdFx0fVxuICAgIC8vIFx0fVxuICAgIC8vIH0gZWxzZSB7XG5cbiAgICBpZiAoX3VwZGF0ZVByb3BUd2VlbnModGhpcywgcHJvcGVydHksIHZhbHVlLCBzdGFydCwgc3RhcnRJc1JlbGF0aXZlLCByYXRpbywgdGltZSwgc2tpcFJlY3Vyc2lvbikpIHtcbiAgICAgIHJldHVybiB0aGlzLnJlc2V0VG8ocHJvcGVydHksIHZhbHVlLCBzdGFydCwgc3RhcnRJc1JlbGF0aXZlLCAxKTsgLy8gaWYgYSBQcm9wVHdlZW4gd2Fzbid0IGZvdW5kIGZvciB0aGUgcHJvcGVydHksIGl0J2xsIGdldCBmb3JjZWQgd2l0aCBhIHJlLWluaXRpYWxpemF0aW9uIHNvIHdlIG5lZWQgdG8ganVtcCBvdXQgYW5kIHN0YXJ0IG92ZXIgYWdhaW4uXG4gICAgfSAvL31cblxuXG4gICAgX2FsaWduUGxheWhlYWQodGhpcywgMCk7XG5cbiAgICB0aGlzLnBhcmVudCB8fCBfYWRkTGlua2VkTGlzdEl0ZW0odGhpcy5fZHAsIHRoaXMsIFwiX2ZpcnN0XCIsIFwiX2xhc3RcIiwgdGhpcy5fZHAuX3NvcnQgPyBcIl9zdGFydFwiIDogMCk7XG4gICAgcmV0dXJuIHRoaXMucmVuZGVyKDApO1xuICB9O1xuXG4gIF9wcm90bzMua2lsbCA9IGZ1bmN0aW9uIGtpbGwodGFyZ2V0cywgdmFycykge1xuICAgIGlmICh2YXJzID09PSB2b2lkIDApIHtcbiAgICAgIHZhcnMgPSBcImFsbFwiO1xuICAgIH1cblxuICAgIGlmICghdGFyZ2V0cyAmJiAoIXZhcnMgfHwgdmFycyA9PT0gXCJhbGxcIikpIHtcbiAgICAgIHRoaXMuX2xhenkgPSB0aGlzLl9wdCA9IDA7XG4gICAgICByZXR1cm4gdGhpcy5wYXJlbnQgPyBfaW50ZXJydXB0KHRoaXMpIDogdGhpcztcbiAgICB9XG5cbiAgICBpZiAodGhpcy50aW1lbGluZSkge1xuICAgICAgdmFyIHREdXIgPSB0aGlzLnRpbWVsaW5lLnRvdGFsRHVyYXRpb24oKTtcbiAgICAgIHRoaXMudGltZWxpbmUua2lsbFR3ZWVuc09mKHRhcmdldHMsIHZhcnMsIF9vdmVyd3JpdGluZ1R3ZWVuICYmIF9vdmVyd3JpdGluZ1R3ZWVuLnZhcnMub3ZlcndyaXRlICE9PSB0cnVlKS5fZmlyc3QgfHwgX2ludGVycnVwdCh0aGlzKTsgLy8gaWYgbm90aGluZyBpcyBsZWZ0IHR3ZWVuaW5nLCBpbnRlcnJ1cHQuXG5cbiAgICAgIHRoaXMucGFyZW50ICYmIHREdXIgIT09IHRoaXMudGltZWxpbmUudG90YWxEdXJhdGlvbigpICYmIF9zZXREdXJhdGlvbih0aGlzLCB0aGlzLl9kdXIgKiB0aGlzLnRpbWVsaW5lLl90RHVyIC8gdER1ciwgMCwgMSk7IC8vIGlmIGEgbmVzdGVkIHR3ZWVuIGlzIGtpbGxlZCB0aGF0IGNoYW5nZXMgdGhlIGR1cmF0aW9uLCBpdCBzaG91bGQgYWZmZWN0IHRoaXMgdHdlZW4ncyBkdXJhdGlvbi4gV2UgbXVzdCB1c2UgdGhlIHJhdGlvLCB0aG91Z2gsIGJlY2F1c2Ugc29tZXRpbWVzIHRoZSBpbnRlcm5hbCB0aW1lbGluZSBpcyBzdHJldGNoZWQgbGlrZSBmb3Iga2V5ZnJhbWVzIHdoZXJlIHRoZXkgZG9uJ3QgYWxsIGFkZCB1cCB0byB3aGF0ZXZlciB0aGUgcGFyZW50IHR3ZWVuJ3MgZHVyYXRpb24gd2FzIHNldCB0by5cblxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgdmFyIHBhcnNlZFRhcmdldHMgPSB0aGlzLl90YXJnZXRzLFxuICAgICAgICBraWxsaW5nVGFyZ2V0cyA9IHRhcmdldHMgPyB0b0FycmF5KHRhcmdldHMpIDogcGFyc2VkVGFyZ2V0cyxcbiAgICAgICAgcHJvcFR3ZWVuTG9va3VwID0gdGhpcy5fcHRMb29rdXAsXG4gICAgICAgIGZpcnN0UFQgPSB0aGlzLl9wdCxcbiAgICAgICAgb3ZlcndyaXR0ZW5Qcm9wcyxcbiAgICAgICAgY3VyTG9va3VwLFxuICAgICAgICBjdXJPdmVyd3JpdGVQcm9wcyxcbiAgICAgICAgcHJvcHMsXG4gICAgICAgIHAsXG4gICAgICAgIHB0LFxuICAgICAgICBpO1xuXG4gICAgaWYgKCghdmFycyB8fCB2YXJzID09PSBcImFsbFwiKSAmJiBfYXJyYXlzTWF0Y2gocGFyc2VkVGFyZ2V0cywga2lsbGluZ1RhcmdldHMpKSB7XG4gICAgICB2YXJzID09PSBcImFsbFwiICYmICh0aGlzLl9wdCA9IDApO1xuICAgICAgcmV0dXJuIF9pbnRlcnJ1cHQodGhpcyk7XG4gICAgfVxuXG4gICAgb3ZlcndyaXR0ZW5Qcm9wcyA9IHRoaXMuX29wID0gdGhpcy5fb3AgfHwgW107XG5cbiAgICBpZiAodmFycyAhPT0gXCJhbGxcIikge1xuICAgICAgLy9zbyBwZW9wbGUgY2FuIHBhc3MgaW4gYSBjb21tYS1kZWxpbWl0ZWQgbGlzdCBvZiBwcm9wZXJ0eSBuYW1lc1xuICAgICAgaWYgKF9pc1N0cmluZyh2YXJzKSkge1xuICAgICAgICBwID0ge307XG5cbiAgICAgICAgX2ZvckVhY2hOYW1lKHZhcnMsIGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgICAgcmV0dXJuIHBbbmFtZV0gPSAxO1xuICAgICAgICB9KTtcblxuICAgICAgICB2YXJzID0gcDtcbiAgICAgIH1cblxuICAgICAgdmFycyA9IF9hZGRBbGlhc2VzVG9WYXJzKHBhcnNlZFRhcmdldHMsIHZhcnMpO1xuICAgIH1cblxuICAgIGkgPSBwYXJzZWRUYXJnZXRzLmxlbmd0aDtcblxuICAgIHdoaWxlIChpLS0pIHtcbiAgICAgIGlmICh+a2lsbGluZ1RhcmdldHMuaW5kZXhPZihwYXJzZWRUYXJnZXRzW2ldKSkge1xuICAgICAgICBjdXJMb29rdXAgPSBwcm9wVHdlZW5Mb29rdXBbaV07XG5cbiAgICAgICAgaWYgKHZhcnMgPT09IFwiYWxsXCIpIHtcbiAgICAgICAgICBvdmVyd3JpdHRlblByb3BzW2ldID0gdmFycztcbiAgICAgICAgICBwcm9wcyA9IGN1ckxvb2t1cDtcbiAgICAgICAgICBjdXJPdmVyd3JpdGVQcm9wcyA9IHt9O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGN1ck92ZXJ3cml0ZVByb3BzID0gb3ZlcndyaXR0ZW5Qcm9wc1tpXSA9IG92ZXJ3cml0dGVuUHJvcHNbaV0gfHwge307XG4gICAgICAgICAgcHJvcHMgPSB2YXJzO1xuICAgICAgICB9XG5cbiAgICAgICAgZm9yIChwIGluIHByb3BzKSB7XG4gICAgICAgICAgcHQgPSBjdXJMb29rdXAgJiYgY3VyTG9va3VwW3BdO1xuXG4gICAgICAgICAgaWYgKHB0KSB7XG4gICAgICAgICAgICBpZiAoIShcImtpbGxcIiBpbiBwdC5kKSB8fCBwdC5kLmtpbGwocCkgPT09IHRydWUpIHtcbiAgICAgICAgICAgICAgX3JlbW92ZUxpbmtlZExpc3RJdGVtKHRoaXMsIHB0LCBcIl9wdFwiKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZGVsZXRlIGN1ckxvb2t1cFtwXTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoY3VyT3ZlcndyaXRlUHJvcHMgIT09IFwiYWxsXCIpIHtcbiAgICAgICAgICAgIGN1ck92ZXJ3cml0ZVByb3BzW3BdID0gMTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLl9pbml0dGVkICYmICF0aGlzLl9wdCAmJiBmaXJzdFBUICYmIF9pbnRlcnJ1cHQodGhpcyk7IC8vaWYgYWxsIHR3ZWVuaW5nIHByb3BlcnRpZXMgYXJlIGtpbGxlZCwga2lsbCB0aGUgdHdlZW4uIFdpdGhvdXQgdGhpcyBsaW5lLCBpZiB0aGVyZSdzIGEgdHdlZW4gd2l0aCBtdWx0aXBsZSB0YXJnZXRzIGFuZCB0aGVuIHlvdSBraWxsVHdlZW5zT2YoKSBlYWNoIHRhcmdldCBpbmRpdmlkdWFsbHksIHRoZSB0d2VlbiB3b3VsZCB0ZWNobmljYWxseSBzdGlsbCByZW1haW4gYWN0aXZlIGFuZCBmaXJlIGl0cyBvbkNvbXBsZXRlIGV2ZW4gdGhvdWdoIHRoZXJlIGFyZW4ndCBhbnkgbW9yZSBwcm9wZXJ0aWVzIHR3ZWVuaW5nLlxuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH07XG5cbiAgVHdlZW4udG8gPSBmdW5jdGlvbiB0byh0YXJnZXRzLCB2YXJzKSB7XG4gICAgcmV0dXJuIG5ldyBUd2Vlbih0YXJnZXRzLCB2YXJzLCBhcmd1bWVudHNbMl0pO1xuICB9O1xuXG4gIFR3ZWVuLmZyb20gPSBmdW5jdGlvbiBmcm9tKHRhcmdldHMsIHZhcnMpIHtcbiAgICByZXR1cm4gX2NyZWF0ZVR3ZWVuVHlwZSgxLCBhcmd1bWVudHMpO1xuICB9O1xuXG4gIFR3ZWVuLmRlbGF5ZWRDYWxsID0gZnVuY3Rpb24gZGVsYXllZENhbGwoZGVsYXksIGNhbGxiYWNrLCBwYXJhbXMsIHNjb3BlKSB7XG4gICAgcmV0dXJuIG5ldyBUd2VlbihjYWxsYmFjaywgMCwge1xuICAgICAgaW1tZWRpYXRlUmVuZGVyOiBmYWxzZSxcbiAgICAgIGxhenk6IGZhbHNlLFxuICAgICAgb3ZlcndyaXRlOiBmYWxzZSxcbiAgICAgIGRlbGF5OiBkZWxheSxcbiAgICAgIG9uQ29tcGxldGU6IGNhbGxiYWNrLFxuICAgICAgb25SZXZlcnNlQ29tcGxldGU6IGNhbGxiYWNrLFxuICAgICAgb25Db21wbGV0ZVBhcmFtczogcGFyYW1zLFxuICAgICAgb25SZXZlcnNlQ29tcGxldGVQYXJhbXM6IHBhcmFtcyxcbiAgICAgIGNhbGxiYWNrU2NvcGU6IHNjb3BlXG4gICAgfSk7IC8vIHdlIG11c3QgdXNlIG9uUmV2ZXJzZUNvbXBsZXRlIHRvbyBmb3IgdGhpbmdzIGxpa2UgdGltZWxpbmUuYWRkKCgpID0+IHsuLi59KSB3aGljaCBzaG91bGQgYmUgdHJpZ2dlcmVkIGluIEJPVEggZGlyZWN0aW9ucyAoZm9yd2FyZCBhbmQgcmV2ZXJzZSlcbiAgfTtcblxuICBUd2Vlbi5mcm9tVG8gPSBmdW5jdGlvbiBmcm9tVG8odGFyZ2V0cywgZnJvbVZhcnMsIHRvVmFycykge1xuICAgIHJldHVybiBfY3JlYXRlVHdlZW5UeXBlKDIsIGFyZ3VtZW50cyk7XG4gIH07XG5cbiAgVHdlZW4uc2V0ID0gZnVuY3Rpb24gc2V0KHRhcmdldHMsIHZhcnMpIHtcbiAgICB2YXJzLmR1cmF0aW9uID0gMDtcbiAgICB2YXJzLnJlcGVhdERlbGF5IHx8ICh2YXJzLnJlcGVhdCA9IDApO1xuICAgIHJldHVybiBuZXcgVHdlZW4odGFyZ2V0cywgdmFycyk7XG4gIH07XG5cbiAgVHdlZW4ua2lsbFR3ZWVuc09mID0gZnVuY3Rpb24ga2lsbFR3ZWVuc09mKHRhcmdldHMsIHByb3BzLCBvbmx5QWN0aXZlKSB7XG4gICAgcmV0dXJuIF9nbG9iYWxUaW1lbGluZS5raWxsVHdlZW5zT2YodGFyZ2V0cywgcHJvcHMsIG9ubHlBY3RpdmUpO1xuICB9O1xuXG4gIHJldHVybiBUd2Vlbjtcbn0oQW5pbWF0aW9uKTtcblxuX3NldERlZmF1bHRzKFR3ZWVuLnByb3RvdHlwZSwge1xuICBfdGFyZ2V0czogW10sXG4gIF9sYXp5OiAwLFxuICBfc3RhcnRBdDogMCxcbiAgX29wOiAwLFxuICBfb25Jbml0OiAwXG59KTsgLy9hZGQgdGhlIHBlcnRpbmVudCB0aW1lbGluZSBtZXRob2RzIHRvIFR3ZWVuIGluc3RhbmNlcyBzbyB0aGF0IHVzZXJzIGNhbiBjaGFpbiBjb252ZW5pZW50bHkgYW5kIGNyZWF0ZSBhIHRpbWVsaW5lIGF1dG9tYXRpY2FsbHkuIChyZW1vdmVkIGR1ZSB0byBjb25jZXJucyB0aGF0IGl0J2QgdWx0aW1hdGVseSBhZGQgdG8gbW9yZSBjb25mdXNpb24gZXNwZWNpYWxseSBmb3IgYmVnaW5uZXJzKVxuLy8gX2ZvckVhY2hOYW1lKFwidG8sZnJvbSxmcm9tVG8sc2V0LGNhbGwsYWRkLGFkZExhYmVsLGFkZFBhdXNlXCIsIG5hbWUgPT4ge1xuLy8gXHRUd2Vlbi5wcm90b3R5cGVbbmFtZV0gPSBmdW5jdGlvbigpIHtcbi8vIFx0XHRsZXQgdGwgPSBuZXcgVGltZWxpbmUoKTtcbi8vIFx0XHRyZXR1cm4gX2FkZFRvVGltZWxpbmUodGwsIHRoaXMpW25hbWVdLmFwcGx5KHRsLCB0b0FycmF5KGFyZ3VtZW50cykpO1xuLy8gXHR9XG4vLyB9KTtcbi8vZm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHkuIExldmVyYWdlIHRoZSB0aW1lbGluZSBjYWxscy5cblxuXG5fZm9yRWFjaE5hbWUoXCJzdGFnZ2VyVG8sc3RhZ2dlckZyb20sc3RhZ2dlckZyb21Ub1wiLCBmdW5jdGlvbiAobmFtZSkge1xuICBUd2VlbltuYW1lXSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgdGwgPSBuZXcgVGltZWxpbmUoKSxcbiAgICAgICAgcGFyYW1zID0gX3NsaWNlLmNhbGwoYXJndW1lbnRzLCAwKTtcblxuICAgIHBhcmFtcy5zcGxpY2UobmFtZSA9PT0gXCJzdGFnZ2VyRnJvbVRvXCIgPyA1IDogNCwgMCwgMCk7XG4gICAgcmV0dXJuIHRsW25hbWVdLmFwcGx5KHRsLCBwYXJhbXMpO1xuICB9O1xufSk7XG4vKlxuICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqIFBST1BUV0VFTlxuICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqL1xuXG5cbnZhciBfc2V0dGVyUGxhaW4gPSBmdW5jdGlvbiBfc2V0dGVyUGxhaW4odGFyZ2V0LCBwcm9wZXJ0eSwgdmFsdWUpIHtcbiAgcmV0dXJuIHRhcmdldFtwcm9wZXJ0eV0gPSB2YWx1ZTtcbn0sXG4gICAgX3NldHRlckZ1bmMgPSBmdW5jdGlvbiBfc2V0dGVyRnVuYyh0YXJnZXQsIHByb3BlcnR5LCB2YWx1ZSkge1xuICByZXR1cm4gdGFyZ2V0W3Byb3BlcnR5XSh2YWx1ZSk7XG59LFxuICAgIF9zZXR0ZXJGdW5jV2l0aFBhcmFtID0gZnVuY3Rpb24gX3NldHRlckZ1bmNXaXRoUGFyYW0odGFyZ2V0LCBwcm9wZXJ0eSwgdmFsdWUsIGRhdGEpIHtcbiAgcmV0dXJuIHRhcmdldFtwcm9wZXJ0eV0oZGF0YS5mcCwgdmFsdWUpO1xufSxcbiAgICBfc2V0dGVyQXR0cmlidXRlID0gZnVuY3Rpb24gX3NldHRlckF0dHJpYnV0ZSh0YXJnZXQsIHByb3BlcnR5LCB2YWx1ZSkge1xuICByZXR1cm4gdGFyZ2V0LnNldEF0dHJpYnV0ZShwcm9wZXJ0eSwgdmFsdWUpO1xufSxcbiAgICBfZ2V0U2V0dGVyID0gZnVuY3Rpb24gX2dldFNldHRlcih0YXJnZXQsIHByb3BlcnR5KSB7XG4gIHJldHVybiBfaXNGdW5jdGlvbih0YXJnZXRbcHJvcGVydHldKSA/IF9zZXR0ZXJGdW5jIDogX2lzVW5kZWZpbmVkKHRhcmdldFtwcm9wZXJ0eV0pICYmIHRhcmdldC5zZXRBdHRyaWJ1dGUgPyBfc2V0dGVyQXR0cmlidXRlIDogX3NldHRlclBsYWluO1xufSxcbiAgICBfcmVuZGVyUGxhaW4gPSBmdW5jdGlvbiBfcmVuZGVyUGxhaW4ocmF0aW8sIGRhdGEpIHtcbiAgcmV0dXJuIGRhdGEuc2V0KGRhdGEudCwgZGF0YS5wLCBNYXRoLnJvdW5kKChkYXRhLnMgKyBkYXRhLmMgKiByYXRpbykgKiAxMDAwMDAwKSAvIDEwMDAwMDAsIGRhdGEpO1xufSxcbiAgICBfcmVuZGVyQm9vbGVhbiA9IGZ1bmN0aW9uIF9yZW5kZXJCb29sZWFuKHJhdGlvLCBkYXRhKSB7XG4gIHJldHVybiBkYXRhLnNldChkYXRhLnQsIGRhdGEucCwgISEoZGF0YS5zICsgZGF0YS5jICogcmF0aW8pLCBkYXRhKTtcbn0sXG4gICAgX3JlbmRlckNvbXBsZXhTdHJpbmcgPSBmdW5jdGlvbiBfcmVuZGVyQ29tcGxleFN0cmluZyhyYXRpbywgZGF0YSkge1xuICB2YXIgcHQgPSBkYXRhLl9wdCxcbiAgICAgIHMgPSBcIlwiO1xuXG4gIGlmICghcmF0aW8gJiYgZGF0YS5iKSB7XG4gICAgLy9iID0gYmVnaW5uaW5nIHN0cmluZ1xuICAgIHMgPSBkYXRhLmI7XG4gIH0gZWxzZSBpZiAocmF0aW8gPT09IDEgJiYgZGF0YS5lKSB7XG4gICAgLy9lID0gZW5kaW5nIHN0cmluZ1xuICAgIHMgPSBkYXRhLmU7XG4gIH0gZWxzZSB7XG4gICAgd2hpbGUgKHB0KSB7XG4gICAgICBzID0gcHQucCArIChwdC5tID8gcHQubShwdC5zICsgcHQuYyAqIHJhdGlvKSA6IE1hdGgucm91bmQoKHB0LnMgKyBwdC5jICogcmF0aW8pICogMTAwMDApIC8gMTAwMDApICsgczsgLy93ZSB1c2UgdGhlIFwicFwiIHByb3BlcnR5IGZvciB0aGUgdGV4dCBpbmJldHdlZW4gKGxpa2UgYSBzdWZmaXgpLiBBbmQgaW4gdGhlIGNvbnRleHQgb2YgYSBjb21wbGV4IHN0cmluZywgdGhlIG1vZGlmaWVyIChtKSBpcyB0eXBpY2FsbHkganVzdCBNYXRoLnJvdW5kKCksIGxpa2UgZm9yIFJHQiBjb2xvcnMuXG5cbiAgICAgIHB0ID0gcHQuX25leHQ7XG4gICAgfVxuXG4gICAgcyArPSBkYXRhLmM7IC8vd2UgdXNlIHRoZSBcImNcIiBvZiB0aGUgUHJvcFR3ZWVuIHRvIHN0b3JlIHRoZSBmaW5hbCBjaHVuayBvZiBub24tbnVtZXJpYyB0ZXh0LlxuICB9XG5cbiAgZGF0YS5zZXQoZGF0YS50LCBkYXRhLnAsIHMsIGRhdGEpO1xufSxcbiAgICBfcmVuZGVyUHJvcFR3ZWVucyA9IGZ1bmN0aW9uIF9yZW5kZXJQcm9wVHdlZW5zKHJhdGlvLCBkYXRhKSB7XG4gIHZhciBwdCA9IGRhdGEuX3B0O1xuXG4gIHdoaWxlIChwdCkge1xuICAgIHB0LnIocmF0aW8sIHB0LmQpO1xuICAgIHB0ID0gcHQuX25leHQ7XG4gIH1cbn0sXG4gICAgX2FkZFBsdWdpbk1vZGlmaWVyID0gZnVuY3Rpb24gX2FkZFBsdWdpbk1vZGlmaWVyKG1vZGlmaWVyLCB0d2VlbiwgdGFyZ2V0LCBwcm9wZXJ0eSkge1xuICB2YXIgcHQgPSB0aGlzLl9wdCxcbiAgICAgIG5leHQ7XG5cbiAgd2hpbGUgKHB0KSB7XG4gICAgbmV4dCA9IHB0Ll9uZXh0O1xuICAgIHB0LnAgPT09IHByb3BlcnR5ICYmIHB0Lm1vZGlmaWVyKG1vZGlmaWVyLCB0d2VlbiwgdGFyZ2V0KTtcbiAgICBwdCA9IG5leHQ7XG4gIH1cbn0sXG4gICAgX2tpbGxQcm9wVHdlZW5zT2YgPSBmdW5jdGlvbiBfa2lsbFByb3BUd2VlbnNPZihwcm9wZXJ0eSkge1xuICB2YXIgcHQgPSB0aGlzLl9wdCxcbiAgICAgIGhhc05vbkRlcGVuZGVudFJlbWFpbmluZyxcbiAgICAgIG5leHQ7XG5cbiAgd2hpbGUgKHB0KSB7XG4gICAgbmV4dCA9IHB0Ll9uZXh0O1xuXG4gICAgaWYgKHB0LnAgPT09IHByb3BlcnR5ICYmICFwdC5vcCB8fCBwdC5vcCA9PT0gcHJvcGVydHkpIHtcbiAgICAgIF9yZW1vdmVMaW5rZWRMaXN0SXRlbSh0aGlzLCBwdCwgXCJfcHRcIik7XG4gICAgfSBlbHNlIGlmICghcHQuZGVwKSB7XG4gICAgICBoYXNOb25EZXBlbmRlbnRSZW1haW5pbmcgPSAxO1xuICAgIH1cblxuICAgIHB0ID0gbmV4dDtcbiAgfVxuXG4gIHJldHVybiAhaGFzTm9uRGVwZW5kZW50UmVtYWluaW5nO1xufSxcbiAgICBfc2V0dGVyV2l0aE1vZGlmaWVyID0gZnVuY3Rpb24gX3NldHRlcldpdGhNb2RpZmllcih0YXJnZXQsIHByb3BlcnR5LCB2YWx1ZSwgZGF0YSkge1xuICBkYXRhLm1TZXQodGFyZ2V0LCBwcm9wZXJ0eSwgZGF0YS5tLmNhbGwoZGF0YS50d2VlbiwgdmFsdWUsIGRhdGEubXQpLCBkYXRhKTtcbn0sXG4gICAgX3NvcnRQcm9wVHdlZW5zQnlQcmlvcml0eSA9IGZ1bmN0aW9uIF9zb3J0UHJvcFR3ZWVuc0J5UHJpb3JpdHkocGFyZW50KSB7XG4gIHZhciBwdCA9IHBhcmVudC5fcHQsXG4gICAgICBuZXh0LFxuICAgICAgcHQyLFxuICAgICAgZmlyc3QsXG4gICAgICBsYXN0OyAvL3NvcnRzIHRoZSBQcm9wVHdlZW4gbGlua2VkIGxpc3QgaW4gb3JkZXIgb2YgcHJpb3JpdHkgYmVjYXVzZSBzb21lIHBsdWdpbnMgbmVlZCB0byBkbyB0aGVpciB3b3JrIGFmdGVyIEFMTCBvZiB0aGUgUHJvcFR3ZWVucyB3ZXJlIGNyZWF0ZWQgKGxpa2UgUm91bmRQcm9wc1BsdWdpbiBhbmQgTW9kaWZpZXJzUGx1Z2luKVxuXG4gIHdoaWxlIChwdCkge1xuICAgIG5leHQgPSBwdC5fbmV4dDtcbiAgICBwdDIgPSBmaXJzdDtcblxuICAgIHdoaWxlIChwdDIgJiYgcHQyLnByID4gcHQucHIpIHtcbiAgICAgIHB0MiA9IHB0Mi5fbmV4dDtcbiAgICB9XG5cbiAgICBpZiAocHQuX3ByZXYgPSBwdDIgPyBwdDIuX3ByZXYgOiBsYXN0KSB7XG4gICAgICBwdC5fcHJldi5fbmV4dCA9IHB0O1xuICAgIH0gZWxzZSB7XG4gICAgICBmaXJzdCA9IHB0O1xuICAgIH1cblxuICAgIGlmIChwdC5fbmV4dCA9IHB0Mikge1xuICAgICAgcHQyLl9wcmV2ID0gcHQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxhc3QgPSBwdDtcbiAgICB9XG5cbiAgICBwdCA9IG5leHQ7XG4gIH1cblxuICBwYXJlbnQuX3B0ID0gZmlyc3Q7XG59OyAvL1Byb3BUd2VlbiBrZXk6IHQgPSB0YXJnZXQsIHAgPSBwcm9wLCByID0gcmVuZGVyZXIsIGQgPSBkYXRhLCBzID0gc3RhcnQsIGMgPSBjaGFuZ2UsIG9wID0gb3ZlcndyaXRlUHJvcGVydHkgKE9OTFkgcG9wdWxhdGVkIHdoZW4gaXQncyBkaWZmZXJlbnQgdGhhbiBwKSwgcHIgPSBwcmlvcml0eSwgX25leHQvX3ByZXYgZm9yIHRoZSBsaW5rZWQgbGlzdCBzaWJsaW5ncywgc2V0ID0gc2V0dGVyLCBtID0gbW9kaWZpZXIsIG1TZXQgPSBtb2RpZmllclNldHRlciAodGhlIG9yaWdpbmFsIHNldHRlciwgYmVmb3JlIGEgbW9kaWZpZXIgd2FzIGFkZGVkKVxuXG5cbmV4cG9ydCB2YXIgUHJvcFR3ZWVuID0gLyojX19QVVJFX18qL2Z1bmN0aW9uICgpIHtcbiAgZnVuY3Rpb24gUHJvcFR3ZWVuKG5leHQsIHRhcmdldCwgcHJvcCwgc3RhcnQsIGNoYW5nZSwgcmVuZGVyZXIsIGRhdGEsIHNldHRlciwgcHJpb3JpdHkpIHtcbiAgICB0aGlzLnQgPSB0YXJnZXQ7XG4gICAgdGhpcy5zID0gc3RhcnQ7XG4gICAgdGhpcy5jID0gY2hhbmdlO1xuICAgIHRoaXMucCA9IHByb3A7XG4gICAgdGhpcy5yID0gcmVuZGVyZXIgfHwgX3JlbmRlclBsYWluO1xuICAgIHRoaXMuZCA9IGRhdGEgfHwgdGhpcztcbiAgICB0aGlzLnNldCA9IHNldHRlciB8fCBfc2V0dGVyUGxhaW47XG4gICAgdGhpcy5wciA9IHByaW9yaXR5IHx8IDA7XG4gICAgdGhpcy5fbmV4dCA9IG5leHQ7XG5cbiAgICBpZiAobmV4dCkge1xuICAgICAgbmV4dC5fcHJldiA9IHRoaXM7XG4gICAgfVxuICB9XG5cbiAgdmFyIF9wcm90bzQgPSBQcm9wVHdlZW4ucHJvdG90eXBlO1xuXG4gIF9wcm90bzQubW9kaWZpZXIgPSBmdW5jdGlvbiBtb2RpZmllcihmdW5jLCB0d2VlbiwgdGFyZ2V0KSB7XG4gICAgdGhpcy5tU2V0ID0gdGhpcy5tU2V0IHx8IHRoaXMuc2V0OyAvL2luIGNhc2UgaXQgd2FzIGFscmVhZHkgc2V0IChhIFByb3BUd2VlbiBjYW4gb25seSBoYXZlIG9uZSBtb2RpZmllcilcblxuICAgIHRoaXMuc2V0ID0gX3NldHRlcldpdGhNb2RpZmllcjtcbiAgICB0aGlzLm0gPSBmdW5jO1xuICAgIHRoaXMubXQgPSB0YXJnZXQ7IC8vbW9kaWZpZXIgdGFyZ2V0XG5cbiAgICB0aGlzLnR3ZWVuID0gdHdlZW47XG4gIH07XG5cbiAgcmV0dXJuIFByb3BUd2Vlbjtcbn0oKTsgLy9Jbml0aWFsaXphdGlvbiB0YXNrc1xuXG5fZm9yRWFjaE5hbWUoX2NhbGxiYWNrTmFtZXMgKyBcInBhcmVudCxkdXJhdGlvbixlYXNlLGRlbGF5LG92ZXJ3cml0ZSxydW5CYWNrd2FyZHMsc3RhcnRBdCx5b3lvLGltbWVkaWF0ZVJlbmRlcixyZXBlYXQscmVwZWF0RGVsYXksZGF0YSxwYXVzZWQscmV2ZXJzZWQsbGF6eSxjYWxsYmFja1Njb3BlLHN0cmluZ0ZpbHRlcixpZCx5b3lvRWFzZSxzdGFnZ2VyLGluaGVyaXQscmVwZWF0UmVmcmVzaCxrZXlmcmFtZXMsYXV0b1JldmVydCxzY3JvbGxUcmlnZ2VyXCIsIGZ1bmN0aW9uIChuYW1lKSB7XG4gIHJldHVybiBfcmVzZXJ2ZWRQcm9wc1tuYW1lXSA9IDE7XG59KTtcblxuX2dsb2JhbHMuVHdlZW5NYXggPSBfZ2xvYmFscy5Ud2VlbkxpdGUgPSBUd2Vlbjtcbl9nbG9iYWxzLlRpbWVsaW5lTGl0ZSA9IF9nbG9iYWxzLlRpbWVsaW5lTWF4ID0gVGltZWxpbmU7XG5fZ2xvYmFsVGltZWxpbmUgPSBuZXcgVGltZWxpbmUoe1xuICBzb3J0Q2hpbGRyZW46IGZhbHNlLFxuICBkZWZhdWx0czogX2RlZmF1bHRzLFxuICBhdXRvUmVtb3ZlQ2hpbGRyZW46IHRydWUsXG4gIGlkOiBcInJvb3RcIixcbiAgc21vb3RoQ2hpbGRUaW1pbmc6IHRydWVcbn0pO1xuX2NvbmZpZy5zdHJpbmdGaWx0ZXIgPSBfY29sb3JTdHJpbmdGaWx0ZXI7XG5cbnZhciBfbWVkaWEgPSBbXSxcbiAgICBfbGlzdGVuZXJzID0ge30sXG4gICAgX2VtcHR5QXJyYXkgPSBbXSxcbiAgICBfbGFzdE1lZGlhVGltZSA9IDAsXG4gICAgX2NvbnRleHRJRCA9IDAsXG4gICAgX2Rpc3BhdGNoID0gZnVuY3Rpb24gX2Rpc3BhdGNoKHR5cGUpIHtcbiAgcmV0dXJuIChfbGlzdGVuZXJzW3R5cGVdIHx8IF9lbXB0eUFycmF5KS5tYXAoZnVuY3Rpb24gKGYpIHtcbiAgICByZXR1cm4gZigpO1xuICB9KTtcbn0sXG4gICAgX29uTWVkaWFDaGFuZ2UgPSBmdW5jdGlvbiBfb25NZWRpYUNoYW5nZSgpIHtcbiAgdmFyIHRpbWUgPSBEYXRlLm5vdygpLFxuICAgICAgbWF0Y2hlcyA9IFtdO1xuXG4gIGlmICh0aW1lIC0gX2xhc3RNZWRpYVRpbWUgPiAyKSB7XG4gICAgX2Rpc3BhdGNoKFwibWF0Y2hNZWRpYUluaXRcIik7XG5cbiAgICBfbWVkaWEuZm9yRWFjaChmdW5jdGlvbiAoYykge1xuICAgICAgdmFyIHF1ZXJpZXMgPSBjLnF1ZXJpZXMsXG4gICAgICAgICAgY29uZGl0aW9ucyA9IGMuY29uZGl0aW9ucyxcbiAgICAgICAgICBtYXRjaCxcbiAgICAgICAgICBwLFxuICAgICAgICAgIGFueU1hdGNoLFxuICAgICAgICAgIHRvZ2dsZWQ7XG5cbiAgICAgIGZvciAocCBpbiBxdWVyaWVzKSB7XG4gICAgICAgIG1hdGNoID0gX3dpbi5tYXRjaE1lZGlhKHF1ZXJpZXNbcF0pLm1hdGNoZXM7IC8vIEZpcmVmb3ggZG9lc24ndCB1cGRhdGUgdGhlIFwibWF0Y2hlc1wiIHByb3BlcnR5IG9mIHRoZSBNZWRpYVF1ZXJ5TGlzdCBvYmplY3QgY29ycmVjdGx5IC0gaXQgb25seSBkb2VzIHNvIGFzIGl0IGNhbGxzIGl0cyBjaGFuZ2UgaGFuZGxlciAtIHNvIHdlIG11c3QgcmUtY3JlYXRlIGEgbWVkaWEgcXVlcnkgaGVyZSB0byBlbnN1cmUgaXQncyBhY2N1cmF0ZS5cblxuICAgICAgICBtYXRjaCAmJiAoYW55TWF0Y2ggPSAxKTtcblxuICAgICAgICBpZiAobWF0Y2ggIT09IGNvbmRpdGlvbnNbcF0pIHtcbiAgICAgICAgICBjb25kaXRpb25zW3BdID0gbWF0Y2g7XG4gICAgICAgICAgdG9nZ2xlZCA9IDE7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHRvZ2dsZWQpIHtcbiAgICAgICAgYy5yZXZlcnQoKTtcbiAgICAgICAgYW55TWF0Y2ggJiYgbWF0Y2hlcy5wdXNoKGMpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgX2Rpc3BhdGNoKFwibWF0Y2hNZWRpYVJldmVydFwiKTtcblxuICAgIG1hdGNoZXMuZm9yRWFjaChmdW5jdGlvbiAoYykge1xuICAgICAgcmV0dXJuIGMub25NYXRjaChjLCBmdW5jdGlvbiAoZnVuYykge1xuICAgICAgICByZXR1cm4gYy5hZGQobnVsbCwgZnVuYyk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBfbGFzdE1lZGlhVGltZSA9IHRpbWU7XG5cbiAgICBfZGlzcGF0Y2goXCJtYXRjaE1lZGlhXCIpO1xuICB9XG59O1xuXG52YXIgQ29udGV4dCA9IC8qI19fUFVSRV9fKi9mdW5jdGlvbiAoKSB7XG4gIGZ1bmN0aW9uIENvbnRleHQoZnVuYywgc2NvcGUpIHtcbiAgICB0aGlzLnNlbGVjdG9yID0gc2NvcGUgJiYgc2VsZWN0b3Ioc2NvcGUpO1xuICAgIHRoaXMuZGF0YSA9IFtdO1xuICAgIHRoaXMuX3IgPSBbXTsgLy8gcmV0dXJuZWQvY2xlYW51cCBmdW5jdGlvbnNcblxuICAgIHRoaXMuaXNSZXZlcnRlZCA9IGZhbHNlO1xuICAgIHRoaXMuaWQgPSBfY29udGV4dElEKys7IC8vIHRvIHdvcmsgYXJvdW5kIGlzc3VlcyB0aGF0IGZyYW1ld29ya3MgbGlrZSBWdWUgY2F1c2UgYnkgbWFraW5nIHRoaW5ncyBpbnRvIFByb3hpZXMgd2hpY2ggbWFrZSBpdCBpbXBvc3NpYmxlIHRvIGRvIHNvbWV0aGluZyBsaWtlIF9tZWRpYS5pbmRleE9mKHRoaXMpIGJlY2F1c2UgXCJ0aGlzXCIgd291bGQgbm8gbG9uZ2VyIHJlZmVyIHRvIHRoZSBDb250ZXh0IGluc3RhbmNlIGl0c2VsZiAtIGl0J2QgcmVmZXIgdG8gYSBQcm94eSEgV2UgbmVlZGVkIGEgd2F5IHRvIGlkZW50aWZ5IHRoZSBjb250ZXh0IHVuaXF1ZWx5XG5cbiAgICBmdW5jICYmIHRoaXMuYWRkKGZ1bmMpO1xuICB9XG5cbiAgdmFyIF9wcm90bzUgPSBDb250ZXh0LnByb3RvdHlwZTtcblxuICBfcHJvdG81LmFkZCA9IGZ1bmN0aW9uIGFkZChuYW1lLCBmdW5jLCBzY29wZSkge1xuICAgIC8vIHBvc3NpYmxlIGZ1dHVyZSBhZGRpdGlvbiBpZiB3ZSBuZWVkIHRoZSBhYmlsaXR5IHRvIGFkZCgpIGFuIGFuaW1hdGlvbiB0byBhIGNvbnRleHQgYW5kIGZvciB3aGF0ZXZlciByZWFzb24gY2Fubm90IGNyZWF0ZSB0aGF0IGFuaW1hdGlvbiBpbnNpZGUgb2YgYSBjb250ZXh0LmFkZCgoKSA9PiB7Li4ufSkgZnVuY3Rpb24uXG4gICAgLy8gaWYgKG5hbWUgJiYgX2lzRnVuY3Rpb24obmFtZS5yZXZlcnQpKSB7XG4gICAgLy8gXHR0aGlzLmRhdGEucHVzaChuYW1lKTtcbiAgICAvLyBcdHJldHVybiAobmFtZS5fY3R4ID0gdGhpcyk7XG4gICAgLy8gfVxuICAgIGlmIChfaXNGdW5jdGlvbihuYW1lKSkge1xuICAgICAgc2NvcGUgPSBmdW5jO1xuICAgICAgZnVuYyA9IG5hbWU7XG4gICAgICBuYW1lID0gX2lzRnVuY3Rpb247XG4gICAgfVxuXG4gICAgdmFyIHNlbGYgPSB0aGlzLFxuICAgICAgICBmID0gZnVuY3Rpb24gZigpIHtcbiAgICAgIHZhciBwcmV2ID0gX2NvbnRleHQsXG4gICAgICAgICAgcHJldlNlbGVjdG9yID0gc2VsZi5zZWxlY3RvcixcbiAgICAgICAgICByZXN1bHQ7XG4gICAgICBwcmV2ICYmIHByZXYgIT09IHNlbGYgJiYgcHJldi5kYXRhLnB1c2goc2VsZik7XG4gICAgICBzY29wZSAmJiAoc2VsZi5zZWxlY3RvciA9IHNlbGVjdG9yKHNjb3BlKSk7XG4gICAgICBfY29udGV4dCA9IHNlbGY7XG4gICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KHNlbGYsIGFyZ3VtZW50cyk7XG4gICAgICBfaXNGdW5jdGlvbihyZXN1bHQpICYmIHNlbGYuX3IucHVzaChyZXN1bHQpO1xuICAgICAgX2NvbnRleHQgPSBwcmV2O1xuICAgICAgc2VsZi5zZWxlY3RvciA9IHByZXZTZWxlY3RvcjtcbiAgICAgIHNlbGYuaXNSZXZlcnRlZCA9IGZhbHNlO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xuXG4gICAgc2VsZi5sYXN0ID0gZjtcbiAgICByZXR1cm4gbmFtZSA9PT0gX2lzRnVuY3Rpb24gPyBmKHNlbGYsIGZ1bmN0aW9uIChmdW5jKSB7XG4gICAgICByZXR1cm4gc2VsZi5hZGQobnVsbCwgZnVuYyk7XG4gICAgfSkgOiBuYW1lID8gc2VsZltuYW1lXSA9IGYgOiBmO1xuICB9O1xuXG4gIF9wcm90bzUuaWdub3JlID0gZnVuY3Rpb24gaWdub3JlKGZ1bmMpIHtcbiAgICB2YXIgcHJldiA9IF9jb250ZXh0O1xuICAgIF9jb250ZXh0ID0gbnVsbDtcbiAgICBmdW5jKHRoaXMpO1xuICAgIF9jb250ZXh0ID0gcHJldjtcbiAgfTtcblxuICBfcHJvdG81LmdldFR3ZWVucyA9IGZ1bmN0aW9uIGdldFR3ZWVucygpIHtcbiAgICB2YXIgYSA9IFtdO1xuICAgIHRoaXMuZGF0YS5mb3JFYWNoKGZ1bmN0aW9uIChlKSB7XG4gICAgICByZXR1cm4gZSBpbnN0YW5jZW9mIENvbnRleHQgPyBhLnB1c2guYXBwbHkoYSwgZS5nZXRUd2VlbnMoKSkgOiBlIGluc3RhbmNlb2YgVHdlZW4gJiYgIShlLnBhcmVudCAmJiBlLnBhcmVudC5kYXRhID09PSBcIm5lc3RlZFwiKSAmJiBhLnB1c2goZSk7XG4gICAgfSk7XG4gICAgcmV0dXJuIGE7XG4gIH07XG5cbiAgX3Byb3RvNS5jbGVhciA9IGZ1bmN0aW9uIGNsZWFyKCkge1xuICAgIHRoaXMuX3IubGVuZ3RoID0gdGhpcy5kYXRhLmxlbmd0aCA9IDA7XG4gIH07XG5cbiAgX3Byb3RvNS5raWxsID0gZnVuY3Rpb24ga2lsbChyZXZlcnQsIG1hdGNoTWVkaWEpIHtcbiAgICB2YXIgX3RoaXM0ID0gdGhpcztcblxuICAgIGlmIChyZXZlcnQpIHtcbiAgICAgIChmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB0d2VlbnMgPSBfdGhpczQuZ2V0VHdlZW5zKCksXG4gICAgICAgICAgICBpID0gX3RoaXM0LmRhdGEubGVuZ3RoLFxuICAgICAgICAgICAgdDtcblxuICAgICAgICB3aGlsZSAoaS0tKSB7XG4gICAgICAgICAgLy8gRmxpcCBwbHVnaW4gdHdlZW5zIGFyZSB2ZXJ5IGRpZmZlcmVudCBpbiB0aGF0IHRoZXkgc2hvdWxkIGFjdHVhbGx5IGJlIHB1c2hlZCB0byB0aGVpciBlbmQuIFRoZSBwbHVnaW4gcmVwbGFjZXMgdGhlIHRpbWVsaW5lJ3MgLnJldmVydCgpIG1ldGhvZCB0byBkbyBleGFjdGx5IHRoYXQuIEJ1dCB3ZSBhbHNvIG5lZWQgdG8gcmVtb3ZlIGFueSBvZiB0aG9zZSBuZXN0ZWQgdHdlZW5zIGluc2lkZSB0aGUgZmxpcCB0aW1lbGluZSBzbyB0aGF0IHRoZXkgZG9uJ3QgZ2V0IGluZGl2aWR1YWxseSByZXZlcnRlZC5cbiAgICAgICAgICB0ID0gX3RoaXM0LmRhdGFbaV07XG5cbiAgICAgICAgICBpZiAodC5kYXRhID09PSBcImlzRmxpcFwiKSB7XG4gICAgICAgICAgICB0LnJldmVydCgpO1xuICAgICAgICAgICAgdC5nZXRDaGlsZHJlbih0cnVlLCB0cnVlLCBmYWxzZSkuZm9yRWFjaChmdW5jdGlvbiAodHdlZW4pIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHR3ZWVucy5zcGxpY2UodHdlZW5zLmluZGV4T2YodHdlZW4pLCAxKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSAvLyBzYXZlIGFzIGFuIG9iamVjdCBzbyB0aGF0IHdlIGNhbiBjYWNoZSB0aGUgZ2xvYmFsVGltZSBmb3IgZWFjaCB0d2VlbiB0byBvcHRpbWl6ZSBwZXJmb3JtYW5jZSBkdXJpbmcgdGhlIHNvcnRcblxuXG4gICAgICAgIHR3ZWVucy5tYXAoZnVuY3Rpb24gKHQpIHtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgZzogdC5fZHVyIHx8IHQuX2RlbGF5IHx8IHQuX3NhdCAmJiAhdC5fc2F0LnZhcnMuaW1tZWRpYXRlUmVuZGVyID8gdC5nbG9iYWxUaW1lKDApIDogLUluZmluaXR5LFxuICAgICAgICAgICAgdDogdFxuICAgICAgICAgIH07XG4gICAgICAgIH0pLnNvcnQoZnVuY3Rpb24gKGEsIGIpIHtcbiAgICAgICAgICByZXR1cm4gYi5nIC0gYS5nIHx8IC1JbmZpbml0eTtcbiAgICAgICAgfSkuZm9yRWFjaChmdW5jdGlvbiAobykge1xuICAgICAgICAgIHJldHVybiBvLnQucmV2ZXJ0KHJldmVydCk7XG4gICAgICAgIH0pOyAvLyBub3RlOiBhbGwgb2YgdGhlIF9zdGFydEF0IHR3ZWVucyBzaG91bGQgYmUgcmV2ZXJ0ZWQgaW4gcmV2ZXJzZSBvcmRlciB0aGF0IHRoZXkgd2VyZSBjcmVhdGVkLCBhbmQgdGhleSdsbCBhbGwgaGF2ZSB0aGUgc2FtZSBnbG9iYWxUaW1lICgtMSkgc28gdGhlIFwiIHx8IC0xXCIgaW4gdGhlIHNvcnQga2VlcHMgdGhlIG9yZGVyIHByb3Blcmx5LlxuXG4gICAgICAgIGkgPSBfdGhpczQuZGF0YS5sZW5ndGg7XG5cbiAgICAgICAgd2hpbGUgKGktLSkge1xuICAgICAgICAgIC8vIG1ha2Ugc3VyZSB3ZSBsb29wIGJhY2t3YXJkcyBzbyB0aGF0LCBmb3IgZXhhbXBsZSwgU3BsaXRUZXh0cyB0aGF0IHdlcmUgY3JlYXRlZCBsYXRlciBvbiB0aGUgc2FtZSBlbGVtZW50IGdldCByZXZlcnRlZCBmaXJzdFxuICAgICAgICAgIHQgPSBfdGhpczQuZGF0YVtpXTtcblxuICAgICAgICAgIGlmICh0IGluc3RhbmNlb2YgVGltZWxpbmUpIHtcbiAgICAgICAgICAgIGlmICh0LmRhdGEgIT09IFwibmVzdGVkXCIpIHtcbiAgICAgICAgICAgICAgdC5zY3JvbGxUcmlnZ2VyICYmIHQuc2Nyb2xsVHJpZ2dlci5yZXZlcnQoKTtcbiAgICAgICAgICAgICAgdC5raWxsKCk7IC8vIGRvbid0IHJldmVydCgpIHRoZSB0aW1lbGluZSBiZWNhdXNlIHRoYXQncyBkdXBsaWNhdGluZyBlZmZvcnRzIHNpbmNlIHdlIGFscmVhZHkgcmV2ZXJ0ZWQgYWxsIHRoZSB0d2VlbnNcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgISh0IGluc3RhbmNlb2YgVHdlZW4pICYmIHQucmV2ZXJ0ICYmIHQucmV2ZXJ0KHJldmVydCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgX3RoaXM0Ll9yLmZvckVhY2goZnVuY3Rpb24gKGYpIHtcbiAgICAgICAgICByZXR1cm4gZihyZXZlcnQsIF90aGlzNCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIF90aGlzNC5pc1JldmVydGVkID0gdHJ1ZTtcbiAgICAgIH0pKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuZGF0YS5mb3JFYWNoKGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHJldHVybiBlLmtpbGwgJiYgZS5raWxsKCk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICB0aGlzLmNsZWFyKCk7XG5cbiAgICBpZiAobWF0Y2hNZWRpYSkge1xuICAgICAgdmFyIGkgPSBfbWVkaWEubGVuZ3RoO1xuXG4gICAgICB3aGlsZSAoaS0tKSB7XG4gICAgICAgIC8vIHByZXZpb3VzbHksIHdlIGNoZWNrZWQgX21lZGlhLmluZGV4T2YodGhpcyksIGJ1dCBzb21lIGZyYW1ld29ya3MgbGlrZSBWdWUgZW5mb3JjZSBQcm94eSBvYmplY3RzIHRoYXQgbWFrZSBpdCBpbXBvc3NpYmxlIHRvIGdldCB0aGUgcHJvcGVyIHJlc3VsdCB0aGF0IHdheSwgc28gd2UgbXVzdCB1c2UgYSB1bmlxdWUgSUQgbnVtYmVyIGluc3RlYWQuXG4gICAgICAgIF9tZWRpYVtpXS5pZCA9PT0gdGhpcy5pZCAmJiBfbWVkaWEuc3BsaWNlKGksIDEpO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICBfcHJvdG81LnJldmVydCA9IGZ1bmN0aW9uIHJldmVydChjb25maWcpIHtcbiAgICB0aGlzLmtpbGwoY29uZmlnIHx8IHt9KTtcbiAgfTtcblxuICByZXR1cm4gQ29udGV4dDtcbn0oKTtcblxudmFyIE1hdGNoTWVkaWEgPSAvKiNfX1BVUkVfXyovZnVuY3Rpb24gKCkge1xuICBmdW5jdGlvbiBNYXRjaE1lZGlhKHNjb3BlKSB7XG4gICAgdGhpcy5jb250ZXh0cyA9IFtdO1xuICAgIHRoaXMuc2NvcGUgPSBzY29wZTtcbiAgICBfY29udGV4dCAmJiBfY29udGV4dC5kYXRhLnB1c2godGhpcyk7XG4gIH1cblxuICB2YXIgX3Byb3RvNiA9IE1hdGNoTWVkaWEucHJvdG90eXBlO1xuXG4gIF9wcm90bzYuYWRkID0gZnVuY3Rpb24gYWRkKGNvbmRpdGlvbnMsIGZ1bmMsIHNjb3BlKSB7XG4gICAgX2lzT2JqZWN0KGNvbmRpdGlvbnMpIHx8IChjb25kaXRpb25zID0ge1xuICAgICAgbWF0Y2hlczogY29uZGl0aW9uc1xuICAgIH0pO1xuICAgIHZhciBjb250ZXh0ID0gbmV3IENvbnRleHQoMCwgc2NvcGUgfHwgdGhpcy5zY29wZSksXG4gICAgICAgIGNvbmQgPSBjb250ZXh0LmNvbmRpdGlvbnMgPSB7fSxcbiAgICAgICAgbXEsXG4gICAgICAgIHAsXG4gICAgICAgIGFjdGl2ZTtcbiAgICBfY29udGV4dCAmJiAhY29udGV4dC5zZWxlY3RvciAmJiAoY29udGV4dC5zZWxlY3RvciA9IF9jb250ZXh0LnNlbGVjdG9yKTsgLy8gaW4gY2FzZSBhIGNvbnRleHQgaXMgY3JlYXRlZCBpbnNpZGUgYSBjb250ZXh0LiBMaWtlIGEgZ3NhcC5tYXRjaE1lZGlhKCkgdGhhdCdzIGluc2lkZSBhIHNjb3BlZCBnc2FwLmNvbnRleHQoKVxuXG4gICAgdGhpcy5jb250ZXh0cy5wdXNoKGNvbnRleHQpO1xuICAgIGZ1bmMgPSBjb250ZXh0LmFkZChcIm9uTWF0Y2hcIiwgZnVuYyk7XG4gICAgY29udGV4dC5xdWVyaWVzID0gY29uZGl0aW9ucztcblxuICAgIGZvciAocCBpbiBjb25kaXRpb25zKSB7XG4gICAgICBpZiAocCA9PT0gXCJhbGxcIikge1xuICAgICAgICBhY3RpdmUgPSAxO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbXEgPSBfd2luLm1hdGNoTWVkaWEoY29uZGl0aW9uc1twXSk7XG5cbiAgICAgICAgaWYgKG1xKSB7XG4gICAgICAgICAgX21lZGlhLmluZGV4T2YoY29udGV4dCkgPCAwICYmIF9tZWRpYS5wdXNoKGNvbnRleHQpO1xuICAgICAgICAgIChjb25kW3BdID0gbXEubWF0Y2hlcykgJiYgKGFjdGl2ZSA9IDEpO1xuICAgICAgICAgIG1xLmFkZExpc3RlbmVyID8gbXEuYWRkTGlzdGVuZXIoX29uTWVkaWFDaGFuZ2UpIDogbXEuYWRkRXZlbnRMaXN0ZW5lcihcImNoYW5nZVwiLCBfb25NZWRpYUNoYW5nZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBhY3RpdmUgJiYgZnVuYyhjb250ZXh0LCBmdW5jdGlvbiAoZikge1xuICAgICAgcmV0dXJuIGNvbnRleHQuYWRkKG51bGwsIGYpO1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9IC8vIHJlZnJlc2goKSB7XG4gIC8vIFx0bGV0IHRpbWUgPSBfbGFzdE1lZGlhVGltZSxcbiAgLy8gXHRcdG1lZGlhID0gX21lZGlhO1xuICAvLyBcdF9sYXN0TWVkaWFUaW1lID0gLTE7XG4gIC8vIFx0X21lZGlhID0gdGhpcy5jb250ZXh0cztcbiAgLy8gXHRfb25NZWRpYUNoYW5nZSgpO1xuICAvLyBcdF9sYXN0TWVkaWFUaW1lID0gdGltZTtcbiAgLy8gXHRfbWVkaWEgPSBtZWRpYTtcbiAgLy8gfVxuICA7XG5cbiAgX3Byb3RvNi5yZXZlcnQgPSBmdW5jdGlvbiByZXZlcnQoY29uZmlnKSB7XG4gICAgdGhpcy5raWxsKGNvbmZpZyB8fCB7fSk7XG4gIH07XG5cbiAgX3Byb3RvNi5raWxsID0gZnVuY3Rpb24ga2lsbChyZXZlcnQpIHtcbiAgICB0aGlzLmNvbnRleHRzLmZvckVhY2goZnVuY3Rpb24gKGMpIHtcbiAgICAgIHJldHVybiBjLmtpbGwocmV2ZXJ0LCB0cnVlKTtcbiAgICB9KTtcbiAgfTtcblxuICByZXR1cm4gTWF0Y2hNZWRpYTtcbn0oKTtcbi8qXG4gKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogR1NBUFxuICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqL1xuXG5cbnZhciBfZ3NhcCA9IHtcbiAgcmVnaXN0ZXJQbHVnaW46IGZ1bmN0aW9uIHJlZ2lzdGVyUGx1Z2luKCkge1xuICAgIGZvciAodmFyIF9sZW4yID0gYXJndW1lbnRzLmxlbmd0aCwgYXJncyA9IG5ldyBBcnJheShfbGVuMiksIF9rZXkyID0gMDsgX2tleTIgPCBfbGVuMjsgX2tleTIrKykge1xuICAgICAgYXJnc1tfa2V5Ml0gPSBhcmd1bWVudHNbX2tleTJdO1xuICAgIH1cblxuICAgIGFyZ3MuZm9yRWFjaChmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICByZXR1cm4gX2NyZWF0ZVBsdWdpbihjb25maWcpO1xuICAgIH0pO1xuICB9LFxuICB0aW1lbGluZTogZnVuY3Rpb24gdGltZWxpbmUodmFycykge1xuICAgIHJldHVybiBuZXcgVGltZWxpbmUodmFycyk7XG4gIH0sXG4gIGdldFR3ZWVuc09mOiBmdW5jdGlvbiBnZXRUd2VlbnNPZih0YXJnZXRzLCBvbmx5QWN0aXZlKSB7XG4gICAgcmV0dXJuIF9nbG9iYWxUaW1lbGluZS5nZXRUd2VlbnNPZih0YXJnZXRzLCBvbmx5QWN0aXZlKTtcbiAgfSxcbiAgZ2V0UHJvcGVydHk6IGZ1bmN0aW9uIGdldFByb3BlcnR5KHRhcmdldCwgcHJvcGVydHksIHVuaXQsIHVuY2FjaGUpIHtcbiAgICBfaXNTdHJpbmcodGFyZ2V0KSAmJiAodGFyZ2V0ID0gdG9BcnJheSh0YXJnZXQpWzBdKTsgLy9pbiBjYXNlIHNlbGVjdG9yIHRleHQgb3IgYW4gYXJyYXkgaXMgcGFzc2VkIGluXG5cbiAgICB2YXIgZ2V0dGVyID0gX2dldENhY2hlKHRhcmdldCB8fCB7fSkuZ2V0LFxuICAgICAgICBmb3JtYXQgPSB1bml0ID8gX3Bhc3NUaHJvdWdoIDogX251bWVyaWNJZlBvc3NpYmxlO1xuXG4gICAgdW5pdCA9PT0gXCJuYXRpdmVcIiAmJiAodW5pdCA9IFwiXCIpO1xuICAgIHJldHVybiAhdGFyZ2V0ID8gdGFyZ2V0IDogIXByb3BlcnR5ID8gZnVuY3Rpb24gKHByb3BlcnR5LCB1bml0LCB1bmNhY2hlKSB7XG4gICAgICByZXR1cm4gZm9ybWF0KChfcGx1Z2luc1twcm9wZXJ0eV0gJiYgX3BsdWdpbnNbcHJvcGVydHldLmdldCB8fCBnZXR0ZXIpKHRhcmdldCwgcHJvcGVydHksIHVuaXQsIHVuY2FjaGUpKTtcbiAgICB9IDogZm9ybWF0KChfcGx1Z2luc1twcm9wZXJ0eV0gJiYgX3BsdWdpbnNbcHJvcGVydHldLmdldCB8fCBnZXR0ZXIpKHRhcmdldCwgcHJvcGVydHksIHVuaXQsIHVuY2FjaGUpKTtcbiAgfSxcbiAgcXVpY2tTZXR0ZXI6IGZ1bmN0aW9uIHF1aWNrU2V0dGVyKHRhcmdldCwgcHJvcGVydHksIHVuaXQpIHtcbiAgICB0YXJnZXQgPSB0b0FycmF5KHRhcmdldCk7XG5cbiAgICBpZiAodGFyZ2V0Lmxlbmd0aCA+IDEpIHtcbiAgICAgIHZhciBzZXR0ZXJzID0gdGFyZ2V0Lm1hcChmdW5jdGlvbiAodCkge1xuICAgICAgICByZXR1cm4gZ3NhcC5xdWlja1NldHRlcih0LCBwcm9wZXJ0eSwgdW5pdCk7XG4gICAgICB9KSxcbiAgICAgICAgICBsID0gc2V0dGVycy5sZW5ndGg7XG4gICAgICByZXR1cm4gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgIHZhciBpID0gbDtcblxuICAgICAgICB3aGlsZSAoaS0tKSB7XG4gICAgICAgICAgc2V0dGVyc1tpXSh2YWx1ZSk7XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgfVxuXG4gICAgdGFyZ2V0ID0gdGFyZ2V0WzBdIHx8IHt9O1xuXG4gICAgdmFyIFBsdWdpbiA9IF9wbHVnaW5zW3Byb3BlcnR5XSxcbiAgICAgICAgY2FjaGUgPSBfZ2V0Q2FjaGUodGFyZ2V0KSxcbiAgICAgICAgcCA9IGNhY2hlLmhhcm5lc3MgJiYgKGNhY2hlLmhhcm5lc3MuYWxpYXNlcyB8fCB7fSlbcHJvcGVydHldIHx8IHByb3BlcnR5LFxuICAgICAgICAvLyBpbiBjYXNlIGl0J3MgYW4gYWxpYXMsIGxpa2UgXCJyb3RhdGVcIiBmb3IgXCJyb3RhdGlvblwiLlxuICAgIHNldHRlciA9IFBsdWdpbiA/IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgdmFyIHAgPSBuZXcgUGx1Z2luKCk7XG4gICAgICBfcXVpY2tUd2Vlbi5fcHQgPSAwO1xuICAgICAgcC5pbml0KHRhcmdldCwgdW5pdCA/IHZhbHVlICsgdW5pdCA6IHZhbHVlLCBfcXVpY2tUd2VlbiwgMCwgW3RhcmdldF0pO1xuICAgICAgcC5yZW5kZXIoMSwgcCk7XG4gICAgICBfcXVpY2tUd2Vlbi5fcHQgJiYgX3JlbmRlclByb3BUd2VlbnMoMSwgX3F1aWNrVHdlZW4pO1xuICAgIH0gOiBjYWNoZS5zZXQodGFyZ2V0LCBwKTtcblxuICAgIHJldHVybiBQbHVnaW4gPyBzZXR0ZXIgOiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgIHJldHVybiBzZXR0ZXIodGFyZ2V0LCBwLCB1bml0ID8gdmFsdWUgKyB1bml0IDogdmFsdWUsIGNhY2hlLCAxKTtcbiAgICB9O1xuICB9LFxuICBxdWlja1RvOiBmdW5jdGlvbiBxdWlja1RvKHRhcmdldCwgcHJvcGVydHksIHZhcnMpIHtcbiAgICB2YXIgX21lcmdlMjtcblxuICAgIHZhciB0d2VlbiA9IGdzYXAudG8odGFyZ2V0LCBfbWVyZ2UoKF9tZXJnZTIgPSB7fSwgX21lcmdlMltwcm9wZXJ0eV0gPSBcIis9MC4xXCIsIF9tZXJnZTIucGF1c2VkID0gdHJ1ZSwgX21lcmdlMiksIHZhcnMgfHwge30pKSxcbiAgICAgICAgZnVuYyA9IGZ1bmN0aW9uIGZ1bmModmFsdWUsIHN0YXJ0LCBzdGFydElzUmVsYXRpdmUpIHtcbiAgICAgIHJldHVybiB0d2Vlbi5yZXNldFRvKHByb3BlcnR5LCB2YWx1ZSwgc3RhcnQsIHN0YXJ0SXNSZWxhdGl2ZSk7XG4gICAgfTtcblxuICAgIGZ1bmMudHdlZW4gPSB0d2VlbjtcbiAgICByZXR1cm4gZnVuYztcbiAgfSxcbiAgaXNUd2VlbmluZzogZnVuY3Rpb24gaXNUd2VlbmluZyh0YXJnZXRzKSB7XG4gICAgcmV0dXJuIF9nbG9iYWxUaW1lbGluZS5nZXRUd2VlbnNPZih0YXJnZXRzLCB0cnVlKS5sZW5ndGggPiAwO1xuICB9LFxuICBkZWZhdWx0czogZnVuY3Rpb24gZGVmYXVsdHModmFsdWUpIHtcbiAgICB2YWx1ZSAmJiB2YWx1ZS5lYXNlICYmICh2YWx1ZS5lYXNlID0gX3BhcnNlRWFzZSh2YWx1ZS5lYXNlLCBfZGVmYXVsdHMuZWFzZSkpO1xuICAgIHJldHVybiBfbWVyZ2VEZWVwKF9kZWZhdWx0cywgdmFsdWUgfHwge30pO1xuICB9LFxuICBjb25maWc6IGZ1bmN0aW9uIGNvbmZpZyh2YWx1ZSkge1xuICAgIHJldHVybiBfbWVyZ2VEZWVwKF9jb25maWcsIHZhbHVlIHx8IHt9KTtcbiAgfSxcbiAgcmVnaXN0ZXJFZmZlY3Q6IGZ1bmN0aW9uIHJlZ2lzdGVyRWZmZWN0KF9yZWYzKSB7XG4gICAgdmFyIG5hbWUgPSBfcmVmMy5uYW1lLFxuICAgICAgICBlZmZlY3QgPSBfcmVmMy5lZmZlY3QsXG4gICAgICAgIHBsdWdpbnMgPSBfcmVmMy5wbHVnaW5zLFxuICAgICAgICBkZWZhdWx0cyA9IF9yZWYzLmRlZmF1bHRzLFxuICAgICAgICBleHRlbmRUaW1lbGluZSA9IF9yZWYzLmV4dGVuZFRpbWVsaW5lO1xuICAgIChwbHVnaW5zIHx8IFwiXCIpLnNwbGl0KFwiLFwiKS5mb3JFYWNoKGZ1bmN0aW9uIChwbHVnaW5OYW1lKSB7XG4gICAgICByZXR1cm4gcGx1Z2luTmFtZSAmJiAhX3BsdWdpbnNbcGx1Z2luTmFtZV0gJiYgIV9nbG9iYWxzW3BsdWdpbk5hbWVdICYmIF93YXJuKG5hbWUgKyBcIiBlZmZlY3QgcmVxdWlyZXMgXCIgKyBwbHVnaW5OYW1lICsgXCIgcGx1Z2luLlwiKTtcbiAgICB9KTtcblxuICAgIF9lZmZlY3RzW25hbWVdID0gZnVuY3Rpb24gKHRhcmdldHMsIHZhcnMsIHRsKSB7XG4gICAgICByZXR1cm4gZWZmZWN0KHRvQXJyYXkodGFyZ2V0cyksIF9zZXREZWZhdWx0cyh2YXJzIHx8IHt9LCBkZWZhdWx0cyksIHRsKTtcbiAgICB9O1xuXG4gICAgaWYgKGV4dGVuZFRpbWVsaW5lKSB7XG4gICAgICBUaW1lbGluZS5wcm90b3R5cGVbbmFtZV0gPSBmdW5jdGlvbiAodGFyZ2V0cywgdmFycywgcG9zaXRpb24pIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYWRkKF9lZmZlY3RzW25hbWVdKHRhcmdldHMsIF9pc09iamVjdCh2YXJzKSA/IHZhcnMgOiAocG9zaXRpb24gPSB2YXJzKSAmJiB7fSwgdGhpcyksIHBvc2l0aW9uKTtcbiAgICAgIH07XG4gICAgfVxuICB9LFxuICByZWdpc3RlckVhc2U6IGZ1bmN0aW9uIHJlZ2lzdGVyRWFzZShuYW1lLCBlYXNlKSB7XG4gICAgX2Vhc2VNYXBbbmFtZV0gPSBfcGFyc2VFYXNlKGVhc2UpO1xuICB9LFxuICBwYXJzZUVhc2U6IGZ1bmN0aW9uIHBhcnNlRWFzZShlYXNlLCBkZWZhdWx0RWFzZSkge1xuICAgIHJldHVybiBhcmd1bWVudHMubGVuZ3RoID8gX3BhcnNlRWFzZShlYXNlLCBkZWZhdWx0RWFzZSkgOiBfZWFzZU1hcDtcbiAgfSxcbiAgZ2V0QnlJZDogZnVuY3Rpb24gZ2V0QnlJZChpZCkge1xuICAgIHJldHVybiBfZ2xvYmFsVGltZWxpbmUuZ2V0QnlJZChpZCk7XG4gIH0sXG4gIGV4cG9ydFJvb3Q6IGZ1bmN0aW9uIGV4cG9ydFJvb3QodmFycywgaW5jbHVkZURlbGF5ZWRDYWxscykge1xuICAgIGlmICh2YXJzID09PSB2b2lkIDApIHtcbiAgICAgIHZhcnMgPSB7fTtcbiAgICB9XG5cbiAgICB2YXIgdGwgPSBuZXcgVGltZWxpbmUodmFycyksXG4gICAgICAgIGNoaWxkLFxuICAgICAgICBuZXh0O1xuICAgIHRsLnNtb290aENoaWxkVGltaW5nID0gX2lzTm90RmFsc2UodmFycy5zbW9vdGhDaGlsZFRpbWluZyk7XG5cbiAgICBfZ2xvYmFsVGltZWxpbmUucmVtb3ZlKHRsKTtcblxuICAgIHRsLl9kcCA9IDA7IC8vb3RoZXJ3aXNlIGl0J2xsIGdldCByZS1hY3RpdmF0ZWQgd2hlbiBhZGRpbmcgY2hpbGRyZW4gYW5kIGJlIHJlLWludHJvZHVjZWQgaW50byBfZ2xvYmFsVGltZWxpbmUncyBsaW5rZWQgbGlzdCAodGhlbiBhZGRlZCB0byBpdHNlbGYpLlxuXG4gICAgdGwuX3RpbWUgPSB0bC5fdFRpbWUgPSBfZ2xvYmFsVGltZWxpbmUuX3RpbWU7XG4gICAgY2hpbGQgPSBfZ2xvYmFsVGltZWxpbmUuX2ZpcnN0O1xuXG4gICAgd2hpbGUgKGNoaWxkKSB7XG4gICAgICBuZXh0ID0gY2hpbGQuX25leHQ7XG5cbiAgICAgIGlmIChpbmNsdWRlRGVsYXllZENhbGxzIHx8ICEoIWNoaWxkLl9kdXIgJiYgY2hpbGQgaW5zdGFuY2VvZiBUd2VlbiAmJiBjaGlsZC52YXJzLm9uQ29tcGxldGUgPT09IGNoaWxkLl90YXJnZXRzWzBdKSkge1xuICAgICAgICBfYWRkVG9UaW1lbGluZSh0bCwgY2hpbGQsIGNoaWxkLl9zdGFydCAtIGNoaWxkLl9kZWxheSk7XG4gICAgICB9XG5cbiAgICAgIGNoaWxkID0gbmV4dDtcbiAgICB9XG5cbiAgICBfYWRkVG9UaW1lbGluZShfZ2xvYmFsVGltZWxpbmUsIHRsLCAwKTtcblxuICAgIHJldHVybiB0bDtcbiAgfSxcbiAgY29udGV4dDogZnVuY3Rpb24gY29udGV4dChmdW5jLCBzY29wZSkge1xuICAgIHJldHVybiBmdW5jID8gbmV3IENvbnRleHQoZnVuYywgc2NvcGUpIDogX2NvbnRleHQ7XG4gIH0sXG4gIG1hdGNoTWVkaWE6IGZ1bmN0aW9uIG1hdGNoTWVkaWEoc2NvcGUpIHtcbiAgICByZXR1cm4gbmV3IE1hdGNoTWVkaWEoc2NvcGUpO1xuICB9LFxuICBtYXRjaE1lZGlhUmVmcmVzaDogZnVuY3Rpb24gbWF0Y2hNZWRpYVJlZnJlc2goKSB7XG4gICAgcmV0dXJuIF9tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uIChjKSB7XG4gICAgICB2YXIgY29uZCA9IGMuY29uZGl0aW9ucyxcbiAgICAgICAgICBmb3VuZCxcbiAgICAgICAgICBwO1xuXG4gICAgICBmb3IgKHAgaW4gY29uZCkge1xuICAgICAgICBpZiAoY29uZFtwXSkge1xuICAgICAgICAgIGNvbmRbcF0gPSBmYWxzZTtcbiAgICAgICAgICBmb3VuZCA9IDE7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgZm91bmQgJiYgYy5yZXZlcnQoKTtcbiAgICB9KSB8fCBfb25NZWRpYUNoYW5nZSgpO1xuICB9LFxuICBhZGRFdmVudExpc3RlbmVyOiBmdW5jdGlvbiBhZGRFdmVudExpc3RlbmVyKHR5cGUsIGNhbGxiYWNrKSB7XG4gICAgdmFyIGEgPSBfbGlzdGVuZXJzW3R5cGVdIHx8IChfbGlzdGVuZXJzW3R5cGVdID0gW10pO1xuICAgIH5hLmluZGV4T2YoY2FsbGJhY2spIHx8IGEucHVzaChjYWxsYmFjayk7XG4gIH0sXG4gIHJlbW92ZUV2ZW50TGlzdGVuZXI6IGZ1bmN0aW9uIHJlbW92ZUV2ZW50TGlzdGVuZXIodHlwZSwgY2FsbGJhY2spIHtcbiAgICB2YXIgYSA9IF9saXN0ZW5lcnNbdHlwZV0sXG4gICAgICAgIGkgPSBhICYmIGEuaW5kZXhPZihjYWxsYmFjayk7XG4gICAgaSA+PSAwICYmIGEuc3BsaWNlKGksIDEpO1xuICB9LFxuICB1dGlsczoge1xuICAgIHdyYXA6IHdyYXAsXG4gICAgd3JhcFlveW86IHdyYXBZb3lvLFxuICAgIGRpc3RyaWJ1dGU6IGRpc3RyaWJ1dGUsXG4gICAgcmFuZG9tOiByYW5kb20sXG4gICAgc25hcDogc25hcCxcbiAgICBub3JtYWxpemU6IG5vcm1hbGl6ZSxcbiAgICBnZXRVbml0OiBnZXRVbml0LFxuICAgIGNsYW1wOiBjbGFtcCxcbiAgICBzcGxpdENvbG9yOiBzcGxpdENvbG9yLFxuICAgIHRvQXJyYXk6IHRvQXJyYXksXG4gICAgc2VsZWN0b3I6IHNlbGVjdG9yLFxuICAgIG1hcFJhbmdlOiBtYXBSYW5nZSxcbiAgICBwaXBlOiBwaXBlLFxuICAgIHVuaXRpemU6IHVuaXRpemUsXG4gICAgaW50ZXJwb2xhdGU6IGludGVycG9sYXRlLFxuICAgIHNodWZmbGU6IHNodWZmbGVcbiAgfSxcbiAgaW5zdGFsbDogX2luc3RhbGwsXG4gIGVmZmVjdHM6IF9lZmZlY3RzLFxuICB0aWNrZXI6IF90aWNrZXIsXG4gIHVwZGF0ZVJvb3Q6IFRpbWVsaW5lLnVwZGF0ZVJvb3QsXG4gIHBsdWdpbnM6IF9wbHVnaW5zLFxuICBnbG9iYWxUaW1lbGluZTogX2dsb2JhbFRpbWVsaW5lLFxuICBjb3JlOiB7XG4gICAgUHJvcFR3ZWVuOiBQcm9wVHdlZW4sXG4gICAgZ2xvYmFsczogX2FkZEdsb2JhbCxcbiAgICBUd2VlbjogVHdlZW4sXG4gICAgVGltZWxpbmU6IFRpbWVsaW5lLFxuICAgIEFuaW1hdGlvbjogQW5pbWF0aW9uLFxuICAgIGdldENhY2hlOiBfZ2V0Q2FjaGUsXG4gICAgX3JlbW92ZUxpbmtlZExpc3RJdGVtOiBfcmVtb3ZlTGlua2VkTGlzdEl0ZW0sXG4gICAgcmV2ZXJ0aW5nOiBmdW5jdGlvbiByZXZlcnRpbmcoKSB7XG4gICAgICByZXR1cm4gX3JldmVydGluZztcbiAgICB9LFxuICAgIGNvbnRleHQ6IGZ1bmN0aW9uIGNvbnRleHQodG9BZGQpIHtcbiAgICAgIGlmICh0b0FkZCAmJiBfY29udGV4dCkge1xuICAgICAgICBfY29udGV4dC5kYXRhLnB1c2godG9BZGQpO1xuXG4gICAgICAgIHRvQWRkLl9jdHggPSBfY29udGV4dDtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIF9jb250ZXh0O1xuICAgIH0sXG4gICAgc3VwcHJlc3NPdmVyd3JpdGVzOiBmdW5jdGlvbiBzdXBwcmVzc092ZXJ3cml0ZXModmFsdWUpIHtcbiAgICAgIHJldHVybiBfc3VwcHJlc3NPdmVyd3JpdGVzID0gdmFsdWU7XG4gICAgfVxuICB9XG59O1xuXG5fZm9yRWFjaE5hbWUoXCJ0byxmcm9tLGZyb21UbyxkZWxheWVkQ2FsbCxzZXQsa2lsbFR3ZWVuc09mXCIsIGZ1bmN0aW9uIChuYW1lKSB7XG4gIHJldHVybiBfZ3NhcFtuYW1lXSA9IFR3ZWVuW25hbWVdO1xufSk7XG5cbl90aWNrZXIuYWRkKFRpbWVsaW5lLnVwZGF0ZVJvb3QpO1xuXG5fcXVpY2tUd2VlbiA9IF9nc2FwLnRvKHt9LCB7XG4gIGR1cmF0aW9uOiAwXG59KTsgLy8gLS0tLSBFWFRSQSBQTFVHSU5TIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbnZhciBfZ2V0UGx1Z2luUHJvcFR3ZWVuID0gZnVuY3Rpb24gX2dldFBsdWdpblByb3BUd2VlbihwbHVnaW4sIHByb3ApIHtcbiAgdmFyIHB0ID0gcGx1Z2luLl9wdDtcblxuICB3aGlsZSAocHQgJiYgcHQucCAhPT0gcHJvcCAmJiBwdC5vcCAhPT0gcHJvcCAmJiBwdC5mcCAhPT0gcHJvcCkge1xuICAgIHB0ID0gcHQuX25leHQ7XG4gIH1cblxuICByZXR1cm4gcHQ7XG59LFxuICAgIF9hZGRNb2RpZmllcnMgPSBmdW5jdGlvbiBfYWRkTW9kaWZpZXJzKHR3ZWVuLCBtb2RpZmllcnMpIHtcbiAgdmFyIHRhcmdldHMgPSB0d2Vlbi5fdGFyZ2V0cyxcbiAgICAgIHAsXG4gICAgICBpLFxuICAgICAgcHQ7XG5cbiAgZm9yIChwIGluIG1vZGlmaWVycykge1xuICAgIGkgPSB0YXJnZXRzLmxlbmd0aDtcblxuICAgIHdoaWxlIChpLS0pIHtcbiAgICAgIHB0ID0gdHdlZW4uX3B0TG9va3VwW2ldW3BdO1xuXG4gICAgICBpZiAocHQgJiYgKHB0ID0gcHQuZCkpIHtcbiAgICAgICAgaWYgKHB0Ll9wdCkge1xuICAgICAgICAgIC8vIGlzIGEgcGx1Z2luXG4gICAgICAgICAgcHQgPSBfZ2V0UGx1Z2luUHJvcFR3ZWVuKHB0LCBwKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHB0ICYmIHB0Lm1vZGlmaWVyICYmIHB0Lm1vZGlmaWVyKG1vZGlmaWVyc1twXSwgdHdlZW4sIHRhcmdldHNbaV0sIHApO1xuICAgICAgfVxuICAgIH1cbiAgfVxufSxcbiAgICBfYnVpbGRNb2RpZmllclBsdWdpbiA9IGZ1bmN0aW9uIF9idWlsZE1vZGlmaWVyUGx1Z2luKG5hbWUsIG1vZGlmaWVyKSB7XG4gIHJldHVybiB7XG4gICAgbmFtZTogbmFtZSxcbiAgICByYXdWYXJzOiAxLFxuICAgIC8vZG9uJ3QgcHJlLXByb2Nlc3MgZnVuY3Rpb24tYmFzZWQgdmFsdWVzIG9yIFwicmFuZG9tKClcIiBzdHJpbmdzLlxuICAgIGluaXQ6IGZ1bmN0aW9uIGluaXQodGFyZ2V0LCB2YXJzLCB0d2Vlbikge1xuICAgICAgdHdlZW4uX29uSW5pdCA9IGZ1bmN0aW9uICh0d2Vlbikge1xuICAgICAgICB2YXIgdGVtcCwgcDtcblxuICAgICAgICBpZiAoX2lzU3RyaW5nKHZhcnMpKSB7XG4gICAgICAgICAgdGVtcCA9IHt9O1xuXG4gICAgICAgICAgX2ZvckVhY2hOYW1lKHZhcnMsIGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgICAgICByZXR1cm4gdGVtcFtuYW1lXSA9IDE7XG4gICAgICAgICAgfSk7IC8vaWYgdGhlIHVzZXIgcGFzc2VzIGluIGEgY29tbWEtZGVsaW1pdGVkIGxpc3Qgb2YgcHJvcGVydHkgbmFtZXMgdG8gcm91bmRQcm9wcywgbGlrZSBcIngseVwiLCB3ZSByb3VuZCB0byB3aG9sZSBudW1iZXJzLlxuXG5cbiAgICAgICAgICB2YXJzID0gdGVtcDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChtb2RpZmllcikge1xuICAgICAgICAgIHRlbXAgPSB7fTtcblxuICAgICAgICAgIGZvciAocCBpbiB2YXJzKSB7XG4gICAgICAgICAgICB0ZW1wW3BdID0gbW9kaWZpZXIodmFyc1twXSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdmFycyA9IHRlbXA7XG4gICAgICAgIH1cblxuICAgICAgICBfYWRkTW9kaWZpZXJzKHR3ZWVuLCB2YXJzKTtcbiAgICAgIH07XG4gICAgfVxuICB9O1xufTsgLy9yZWdpc3RlciBjb3JlIHBsdWdpbnNcblxuXG5leHBvcnQgdmFyIGdzYXAgPSBfZ3NhcC5yZWdpc3RlclBsdWdpbih7XG4gIG5hbWU6IFwiYXR0clwiLFxuICBpbml0OiBmdW5jdGlvbiBpbml0KHRhcmdldCwgdmFycywgdHdlZW4sIGluZGV4LCB0YXJnZXRzKSB7XG4gICAgdmFyIHAsIHB0LCB2O1xuICAgIHRoaXMudHdlZW4gPSB0d2VlbjtcblxuICAgIGZvciAocCBpbiB2YXJzKSB7XG4gICAgICB2ID0gdGFyZ2V0LmdldEF0dHJpYnV0ZShwKSB8fCBcIlwiO1xuICAgICAgcHQgPSB0aGlzLmFkZCh0YXJnZXQsIFwic2V0QXR0cmlidXRlXCIsICh2IHx8IDApICsgXCJcIiwgdmFyc1twXSwgaW5kZXgsIHRhcmdldHMsIDAsIDAsIHApO1xuICAgICAgcHQub3AgPSBwO1xuICAgICAgcHQuYiA9IHY7IC8vIHJlY29yZCB0aGUgYmVnaW5uaW5nIHZhbHVlIHNvIHdlIGNhbiByZXZlcnQoKVxuXG4gICAgICB0aGlzLl9wcm9wcy5wdXNoKHApO1xuICAgIH1cbiAgfSxcbiAgcmVuZGVyOiBmdW5jdGlvbiByZW5kZXIocmF0aW8sIGRhdGEpIHtcbiAgICB2YXIgcHQgPSBkYXRhLl9wdDtcblxuICAgIHdoaWxlIChwdCkge1xuICAgICAgX3JldmVydGluZyA/IHB0LnNldChwdC50LCBwdC5wLCBwdC5iLCBwdCkgOiBwdC5yKHJhdGlvLCBwdC5kKTsgLy8gaWYgcmV2ZXJ0aW5nLCBnbyBiYWNrIHRvIHRoZSBvcmlnaW5hbCAocHQuYilcblxuICAgICAgcHQgPSBwdC5fbmV4dDtcbiAgICB9XG4gIH1cbn0sIHtcbiAgbmFtZTogXCJlbmRBcnJheVwiLFxuICBpbml0OiBmdW5jdGlvbiBpbml0KHRhcmdldCwgdmFsdWUpIHtcbiAgICB2YXIgaSA9IHZhbHVlLmxlbmd0aDtcblxuICAgIHdoaWxlIChpLS0pIHtcbiAgICAgIHRoaXMuYWRkKHRhcmdldCwgaSwgdGFyZ2V0W2ldIHx8IDAsIHZhbHVlW2ldLCAwLCAwLCAwLCAwLCAwLCAxKTtcbiAgICB9XG4gIH1cbn0sIF9idWlsZE1vZGlmaWVyUGx1Z2luKFwicm91bmRQcm9wc1wiLCBfcm91bmRNb2RpZmllciksIF9idWlsZE1vZGlmaWVyUGx1Z2luKFwibW9kaWZpZXJzXCIpLCBfYnVpbGRNb2RpZmllclBsdWdpbihcInNuYXBcIiwgc25hcCkpIHx8IF9nc2FwOyAvL3RvIHByZXZlbnQgdGhlIGNvcmUgcGx1Z2lucyBmcm9tIGJlaW5nIGRyb3BwZWQgdmlhIGFnZ3Jlc3NpdmUgdHJlZSBzaGFraW5nLCB3ZSBtdXN0IGluY2x1ZGUgdGhlbSBpbiB0aGUgdmFyaWFibGUgZGVjbGFyYXRpb24gaW4gdGhpcyB3YXkuXG5cblR3ZWVuLnZlcnNpb24gPSBUaW1lbGluZS52ZXJzaW9uID0gZ3NhcC52ZXJzaW9uID0gXCIzLjEyLjVcIjtcbl9jb3JlUmVhZHkgPSAxO1xuX3dpbmRvd0V4aXN0cygpICYmIF93YWtlKCk7XG52YXIgUG93ZXIwID0gX2Vhc2VNYXAuUG93ZXIwLFxuICAgIFBvd2VyMSA9IF9lYXNlTWFwLlBvd2VyMSxcbiAgICBQb3dlcjIgPSBfZWFzZU1hcC5Qb3dlcjIsXG4gICAgUG93ZXIzID0gX2Vhc2VNYXAuUG93ZXIzLFxuICAgIFBvd2VyNCA9IF9lYXNlTWFwLlBvd2VyNCxcbiAgICBMaW5lYXIgPSBfZWFzZU1hcC5MaW5lYXIsXG4gICAgUXVhZCA9IF9lYXNlTWFwLlF1YWQsXG4gICAgQ3ViaWMgPSBfZWFzZU1hcC5DdWJpYyxcbiAgICBRdWFydCA9IF9lYXNlTWFwLlF1YXJ0LFxuICAgIFF1aW50ID0gX2Vhc2VNYXAuUXVpbnQsXG4gICAgU3Ryb25nID0gX2Vhc2VNYXAuU3Ryb25nLFxuICAgIEVsYXN0aWMgPSBfZWFzZU1hcC5FbGFzdGljLFxuICAgIEJhY2sgPSBfZWFzZU1hcC5CYWNrLFxuICAgIFN0ZXBwZWRFYXNlID0gX2Vhc2VNYXAuU3RlcHBlZEVhc2UsXG4gICAgQm91bmNlID0gX2Vhc2VNYXAuQm91bmNlLFxuICAgIFNpbmUgPSBfZWFzZU1hcC5TaW5lLFxuICAgIEV4cG8gPSBfZWFzZU1hcC5FeHBvLFxuICAgIENpcmMgPSBfZWFzZU1hcC5DaXJjO1xuZXhwb3J0IHsgUG93ZXIwLCBQb3dlcjEsIFBvd2VyMiwgUG93ZXIzLCBQb3dlcjQsIExpbmVhciwgUXVhZCwgQ3ViaWMsIFF1YXJ0LCBRdWludCwgU3Ryb25nLCBFbGFzdGljLCBCYWNrLCBTdGVwcGVkRWFzZSwgQm91bmNlLCBTaW5lLCBFeHBvLCBDaXJjIH07XG5leHBvcnQgeyBUd2VlbiBhcyBUd2Vlbk1heCwgVHdlZW4gYXMgVHdlZW5MaXRlLCBUaW1lbGluZSBhcyBUaW1lbGluZU1heCwgVGltZWxpbmUgYXMgVGltZWxpbmVMaXRlLCBnc2FwIGFzIGRlZmF1bHQsIHdyYXAsIHdyYXBZb3lvLCBkaXN0cmlidXRlLCByYW5kb20sIHNuYXAsIG5vcm1hbGl6ZSwgZ2V0VW5pdCwgY2xhbXAsIHNwbGl0Q29sb3IsIHRvQXJyYXksIHNlbGVjdG9yLCBtYXBSYW5nZSwgcGlwZSwgdW5pdGl6ZSwgaW50ZXJwb2xhdGUsIHNodWZmbGUgfTsgLy9leHBvcnQgc29tZSBpbnRlcm5hbCBtZXRob2RzL29yb2plY3RzIGZvciB1c2UgaW4gQ1NTUGx1Z2luIHNvIHRoYXQgd2UgY2FuIGV4dGVybmFsaXplIHRoYXQgZmlsZSBhbmQgYWxsb3cgY3VzdG9tIGJ1aWxkcyB0aGF0IGV4Y2x1ZGUgaXQuXG5cbmV4cG9ydCB7IF9nZXRQcm9wZXJ0eSwgX251bUV4cCwgX251bVdpdGhVbml0RXhwLCBfaXNTdHJpbmcsIF9pc1VuZGVmaW5lZCwgX3JlbmRlckNvbXBsZXhTdHJpbmcsIF9yZWxFeHAsIF9zZXREZWZhdWx0cywgX3JlbW92ZUxpbmtlZExpc3RJdGVtLCBfZm9yRWFjaE5hbWUsIF9zb3J0UHJvcFR3ZWVuc0J5UHJpb3JpdHksIF9jb2xvclN0cmluZ0ZpbHRlciwgX3JlcGxhY2VSYW5kb20sIF9jaGVja1BsdWdpbiwgX3BsdWdpbnMsIF90aWNrZXIsIF9jb25maWcsIF9yb3VuZE1vZGlmaWVyLCBfcm91bmQsIF9taXNzaW5nUGx1Z2luLCBfZ2V0U2V0dGVyLCBfZ2V0Q2FjaGUsIF9jb2xvckV4cCwgX3BhcnNlUmVsYXRpdmUgfTsiLCIvKiFcbiAqIENTU1BsdWdpbiAzLjEyLjVcbiAqIGh0dHBzOi8vZ3NhcC5jb21cbiAqXG4gKiBDb3B5cmlnaHQgMjAwOC0yMDI0LCBHcmVlblNvY2suIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhdCBodHRwczovL2dzYXAuY29tL3N0YW5kYXJkLWxpY2Vuc2Ugb3IgZm9yXG4gKiBDbHViIEdTQVAgbWVtYmVycywgdGhlIGFncmVlbWVudCBpc3N1ZWQgd2l0aCB0aGF0IG1lbWJlcnNoaXAuXG4gKiBAYXV0aG9yOiBKYWNrIERveWxlLCBqYWNrQGdyZWVuc29jay5jb21cbiovXG5cbi8qIGVzbGludC1kaXNhYmxlICovXG5pbXBvcnQgeyBnc2FwLCBfZ2V0UHJvcGVydHksIF9udW1FeHAsIF9udW1XaXRoVW5pdEV4cCwgZ2V0VW5pdCwgX2lzU3RyaW5nLCBfaXNVbmRlZmluZWQsIF9yZW5kZXJDb21wbGV4U3RyaW5nLCBfcmVsRXhwLCBfZm9yRWFjaE5hbWUsIF9zb3J0UHJvcFR3ZWVuc0J5UHJpb3JpdHksIF9jb2xvclN0cmluZ0ZpbHRlciwgX2NoZWNrUGx1Z2luLCBfcmVwbGFjZVJhbmRvbSwgX3BsdWdpbnMsIEdTQ2FjaGUsIFByb3BUd2VlbiwgX2NvbmZpZywgX3RpY2tlciwgX3JvdW5kLCBfbWlzc2luZ1BsdWdpbiwgX2dldFNldHRlciwgX2dldENhY2hlLCBfY29sb3JFeHAsIF9wYXJzZVJlbGF0aXZlLCBfc2V0RGVmYXVsdHMsIF9yZW1vdmVMaW5rZWRMaXN0SXRlbSAvL2ZvciB0aGUgY29tbWVudGVkLW91dCBjbGFzc05hbWUgZmVhdHVyZS5cbn0gZnJvbSBcIi4vZ3NhcC1jb3JlLmpzXCI7XG5cbnZhciBfd2luLFxuICAgIF9kb2MsXG4gICAgX2RvY0VsZW1lbnQsXG4gICAgX3BsdWdpbkluaXR0ZWQsXG4gICAgX3RlbXBEaXYsXG4gICAgX3RlbXBEaXZTdHlsZXIsXG4gICAgX3JlY2VudFNldHRlclBsdWdpbixcbiAgICBfcmV2ZXJ0aW5nLFxuICAgIF93aW5kb3dFeGlzdHMgPSBmdW5jdGlvbiBfd2luZG93RXhpc3RzKCkge1xuICByZXR1cm4gdHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIjtcbn0sXG4gICAgX3RyYW5zZm9ybVByb3BzID0ge30sXG4gICAgX1JBRDJERUcgPSAxODAgLyBNYXRoLlBJLFxuICAgIF9ERUcyUkFEID0gTWF0aC5QSSAvIDE4MCxcbiAgICBfYXRhbjIgPSBNYXRoLmF0YW4yLFxuICAgIF9iaWdOdW0gPSAxZTgsXG4gICAgX2NhcHNFeHAgPSAvKFtBLVpdKS9nLFxuICAgIF9ob3Jpem9udGFsRXhwID0gLyhsZWZ0fHJpZ2h0fHdpZHRofG1hcmdpbnxwYWRkaW5nfHgpL2ksXG4gICAgX2NvbXBsZXhFeHAgPSAvW1xccyxcXChdXFxTLyxcbiAgICBfcHJvcGVydHlBbGlhc2VzID0ge1xuICBhdXRvQWxwaGE6IFwib3BhY2l0eSx2aXNpYmlsaXR5XCIsXG4gIHNjYWxlOiBcInNjYWxlWCxzY2FsZVlcIixcbiAgYWxwaGE6IFwib3BhY2l0eVwiXG59LFxuICAgIF9yZW5kZXJDU1NQcm9wID0gZnVuY3Rpb24gX3JlbmRlckNTU1Byb3AocmF0aW8sIGRhdGEpIHtcbiAgcmV0dXJuIGRhdGEuc2V0KGRhdGEudCwgZGF0YS5wLCBNYXRoLnJvdW5kKChkYXRhLnMgKyBkYXRhLmMgKiByYXRpbykgKiAxMDAwMCkgLyAxMDAwMCArIGRhdGEudSwgZGF0YSk7XG59LFxuICAgIF9yZW5kZXJQcm9wV2l0aEVuZCA9IGZ1bmN0aW9uIF9yZW5kZXJQcm9wV2l0aEVuZChyYXRpbywgZGF0YSkge1xuICByZXR1cm4gZGF0YS5zZXQoZGF0YS50LCBkYXRhLnAsIHJhdGlvID09PSAxID8gZGF0YS5lIDogTWF0aC5yb3VuZCgoZGF0YS5zICsgZGF0YS5jICogcmF0aW8pICogMTAwMDApIC8gMTAwMDAgKyBkYXRhLnUsIGRhdGEpO1xufSxcbiAgICBfcmVuZGVyQ1NTUHJvcFdpdGhCZWdpbm5pbmcgPSBmdW5jdGlvbiBfcmVuZGVyQ1NTUHJvcFdpdGhCZWdpbm5pbmcocmF0aW8sIGRhdGEpIHtcbiAgcmV0dXJuIGRhdGEuc2V0KGRhdGEudCwgZGF0YS5wLCByYXRpbyA/IE1hdGgucm91bmQoKGRhdGEucyArIGRhdGEuYyAqIHJhdGlvKSAqIDEwMDAwKSAvIDEwMDAwICsgZGF0YS51IDogZGF0YS5iLCBkYXRhKTtcbn0sXG4gICAgLy9pZiB1bml0cyBjaGFuZ2UsIHdlIG5lZWQgYSB3YXkgdG8gcmVuZGVyIHRoZSBvcmlnaW5hbCB1bml0L3ZhbHVlIHdoZW4gdGhlIHR3ZWVuIGdvZXMgYWxsIHRoZSB3YXkgYmFjayB0byB0aGUgYmVnaW5uaW5nIChyYXRpbzowKVxuX3JlbmRlclJvdW5kZWRDU1NQcm9wID0gZnVuY3Rpb24gX3JlbmRlclJvdW5kZWRDU1NQcm9wKHJhdGlvLCBkYXRhKSB7XG4gIHZhciB2YWx1ZSA9IGRhdGEucyArIGRhdGEuYyAqIHJhdGlvO1xuICBkYXRhLnNldChkYXRhLnQsIGRhdGEucCwgfn4odmFsdWUgKyAodmFsdWUgPCAwID8gLS41IDogLjUpKSArIGRhdGEudSwgZGF0YSk7XG59LFxuICAgIF9yZW5kZXJOb25Ud2VlbmluZ1ZhbHVlID0gZnVuY3Rpb24gX3JlbmRlck5vblR3ZWVuaW5nVmFsdWUocmF0aW8sIGRhdGEpIHtcbiAgcmV0dXJuIGRhdGEuc2V0KGRhdGEudCwgZGF0YS5wLCByYXRpbyA/IGRhdGEuZSA6IGRhdGEuYiwgZGF0YSk7XG59LFxuICAgIF9yZW5kZXJOb25Ud2VlbmluZ1ZhbHVlT25seUF0RW5kID0gZnVuY3Rpb24gX3JlbmRlck5vblR3ZWVuaW5nVmFsdWVPbmx5QXRFbmQocmF0aW8sIGRhdGEpIHtcbiAgcmV0dXJuIGRhdGEuc2V0KGRhdGEudCwgZGF0YS5wLCByYXRpbyAhPT0gMSA/IGRhdGEuYiA6IGRhdGEuZSwgZGF0YSk7XG59LFxuICAgIF9zZXR0ZXJDU1NTdHlsZSA9IGZ1bmN0aW9uIF9zZXR0ZXJDU1NTdHlsZSh0YXJnZXQsIHByb3BlcnR5LCB2YWx1ZSkge1xuICByZXR1cm4gdGFyZ2V0LnN0eWxlW3Byb3BlcnR5XSA9IHZhbHVlO1xufSxcbiAgICBfc2V0dGVyQ1NTUHJvcCA9IGZ1bmN0aW9uIF9zZXR0ZXJDU1NQcm9wKHRhcmdldCwgcHJvcGVydHksIHZhbHVlKSB7XG4gIHJldHVybiB0YXJnZXQuc3R5bGUuc2V0UHJvcGVydHkocHJvcGVydHksIHZhbHVlKTtcbn0sXG4gICAgX3NldHRlclRyYW5zZm9ybSA9IGZ1bmN0aW9uIF9zZXR0ZXJUcmFuc2Zvcm0odGFyZ2V0LCBwcm9wZXJ0eSwgdmFsdWUpIHtcbiAgcmV0dXJuIHRhcmdldC5fZ3NhcFtwcm9wZXJ0eV0gPSB2YWx1ZTtcbn0sXG4gICAgX3NldHRlclNjYWxlID0gZnVuY3Rpb24gX3NldHRlclNjYWxlKHRhcmdldCwgcHJvcGVydHksIHZhbHVlKSB7XG4gIHJldHVybiB0YXJnZXQuX2dzYXAuc2NhbGVYID0gdGFyZ2V0Ll9nc2FwLnNjYWxlWSA9IHZhbHVlO1xufSxcbiAgICBfc2V0dGVyU2NhbGVXaXRoUmVuZGVyID0gZnVuY3Rpb24gX3NldHRlclNjYWxlV2l0aFJlbmRlcih0YXJnZXQsIHByb3BlcnR5LCB2YWx1ZSwgZGF0YSwgcmF0aW8pIHtcbiAgdmFyIGNhY2hlID0gdGFyZ2V0Ll9nc2FwO1xuICBjYWNoZS5zY2FsZVggPSBjYWNoZS5zY2FsZVkgPSB2YWx1ZTtcbiAgY2FjaGUucmVuZGVyVHJhbnNmb3JtKHJhdGlvLCBjYWNoZSk7XG59LFxuICAgIF9zZXR0ZXJUcmFuc2Zvcm1XaXRoUmVuZGVyID0gZnVuY3Rpb24gX3NldHRlclRyYW5zZm9ybVdpdGhSZW5kZXIodGFyZ2V0LCBwcm9wZXJ0eSwgdmFsdWUsIGRhdGEsIHJhdGlvKSB7XG4gIHZhciBjYWNoZSA9IHRhcmdldC5fZ3NhcDtcbiAgY2FjaGVbcHJvcGVydHldID0gdmFsdWU7XG4gIGNhY2hlLnJlbmRlclRyYW5zZm9ybShyYXRpbywgY2FjaGUpO1xufSxcbiAgICBfdHJhbnNmb3JtUHJvcCA9IFwidHJhbnNmb3JtXCIsXG4gICAgX3RyYW5zZm9ybU9yaWdpblByb3AgPSBfdHJhbnNmb3JtUHJvcCArIFwiT3JpZ2luXCIsXG4gICAgX3NhdmVTdHlsZSA9IGZ1bmN0aW9uIF9zYXZlU3R5bGUocHJvcGVydHksIGlzTm90Q1NTKSB7XG4gIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgdmFyIHRhcmdldCA9IHRoaXMudGFyZ2V0LFxuICAgICAgc3R5bGUgPSB0YXJnZXQuc3R5bGUsXG4gICAgICBjYWNoZSA9IHRhcmdldC5fZ3NhcDtcblxuICBpZiAocHJvcGVydHkgaW4gX3RyYW5zZm9ybVByb3BzICYmIHN0eWxlKSB7XG4gICAgdGhpcy50Zm0gPSB0aGlzLnRmbSB8fCB7fTtcblxuICAgIGlmIChwcm9wZXJ0eSAhPT0gXCJ0cmFuc2Zvcm1cIikge1xuICAgICAgcHJvcGVydHkgPSBfcHJvcGVydHlBbGlhc2VzW3Byb3BlcnR5XSB8fCBwcm9wZXJ0eTtcbiAgICAgIH5wcm9wZXJ0eS5pbmRleE9mKFwiLFwiKSA/IHByb3BlcnR5LnNwbGl0KFwiLFwiKS5mb3JFYWNoKGZ1bmN0aW9uIChhKSB7XG4gICAgICAgIHJldHVybiBfdGhpcy50Zm1bYV0gPSBfZ2V0KHRhcmdldCwgYSk7XG4gICAgICB9KSA6IHRoaXMudGZtW3Byb3BlcnR5XSA9IGNhY2hlLnggPyBjYWNoZVtwcm9wZXJ0eV0gOiBfZ2V0KHRhcmdldCwgcHJvcGVydHkpOyAvLyBub3RlOiBzY2FsZSB3b3VsZCBtYXAgdG8gXCJzY2FsZVgsc2NhbGVZXCIsIHRodXMgd2UgbG9vcCBhbmQgYXBwbHkgdGhlbSBib3RoLlxuXG4gICAgICBwcm9wZXJ0eSA9PT0gX3RyYW5zZm9ybU9yaWdpblByb3AgJiYgKHRoaXMudGZtLnpPcmlnaW4gPSBjYWNoZS56T3JpZ2luKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIF9wcm9wZXJ0eUFsaWFzZXMudHJhbnNmb3JtLnNwbGl0KFwiLFwiKS5mb3JFYWNoKGZ1bmN0aW9uIChwKSB7XG4gICAgICAgIHJldHVybiBfc2F2ZVN0eWxlLmNhbGwoX3RoaXMsIHAsIGlzTm90Q1NTKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnByb3BzLmluZGV4T2YoX3RyYW5zZm9ybVByb3ApID49IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoY2FjaGUuc3ZnKSB7XG4gICAgICB0aGlzLnN2Z28gPSB0YXJnZXQuZ2V0QXR0cmlidXRlKFwiZGF0YS1zdmctb3JpZ2luXCIpO1xuICAgICAgdGhpcy5wcm9wcy5wdXNoKF90cmFuc2Zvcm1PcmlnaW5Qcm9wLCBpc05vdENTUywgXCJcIik7XG4gICAgfVxuXG4gICAgcHJvcGVydHkgPSBfdHJhbnNmb3JtUHJvcDtcbiAgfVxuXG4gIChzdHlsZSB8fCBpc05vdENTUykgJiYgdGhpcy5wcm9wcy5wdXNoKHByb3BlcnR5LCBpc05vdENTUywgc3R5bGVbcHJvcGVydHldKTtcbn0sXG4gICAgX3JlbW92ZUluZGVwZW5kZW50VHJhbnNmb3JtcyA9IGZ1bmN0aW9uIF9yZW1vdmVJbmRlcGVuZGVudFRyYW5zZm9ybXMoc3R5bGUpIHtcbiAgaWYgKHN0eWxlLnRyYW5zbGF0ZSkge1xuICAgIHN0eWxlLnJlbW92ZVByb3BlcnR5KFwidHJhbnNsYXRlXCIpO1xuICAgIHN0eWxlLnJlbW92ZVByb3BlcnR5KFwic2NhbGVcIik7XG4gICAgc3R5bGUucmVtb3ZlUHJvcGVydHkoXCJyb3RhdGVcIik7XG4gIH1cbn0sXG4gICAgX3JldmVydFN0eWxlID0gZnVuY3Rpb24gX3JldmVydFN0eWxlKCkge1xuICB2YXIgcHJvcHMgPSB0aGlzLnByb3BzLFxuICAgICAgdGFyZ2V0ID0gdGhpcy50YXJnZXQsXG4gICAgICBzdHlsZSA9IHRhcmdldC5zdHlsZSxcbiAgICAgIGNhY2hlID0gdGFyZ2V0Ll9nc2FwLFxuICAgICAgaSxcbiAgICAgIHA7XG5cbiAgZm9yIChpID0gMDsgaSA8IHByb3BzLmxlbmd0aDsgaSArPSAzKSB7XG4gICAgLy8gc3RvcmVkIGxpa2UgdGhpczogcHJvcGVydHksIGlzTm90Q1NTLCB2YWx1ZVxuICAgIHByb3BzW2kgKyAxXSA/IHRhcmdldFtwcm9wc1tpXV0gPSBwcm9wc1tpICsgMl0gOiBwcm9wc1tpICsgMl0gPyBzdHlsZVtwcm9wc1tpXV0gPSBwcm9wc1tpICsgMl0gOiBzdHlsZS5yZW1vdmVQcm9wZXJ0eShwcm9wc1tpXS5zdWJzdHIoMCwgMikgPT09IFwiLS1cIiA/IHByb3BzW2ldIDogcHJvcHNbaV0ucmVwbGFjZShfY2Fwc0V4cCwgXCItJDFcIikudG9Mb3dlckNhc2UoKSk7XG4gIH1cblxuICBpZiAodGhpcy50Zm0pIHtcbiAgICBmb3IgKHAgaW4gdGhpcy50Zm0pIHtcbiAgICAgIGNhY2hlW3BdID0gdGhpcy50Zm1bcF07XG4gICAgfVxuXG4gICAgaWYgKGNhY2hlLnN2Zykge1xuICAgICAgY2FjaGUucmVuZGVyVHJhbnNmb3JtKCk7XG4gICAgICB0YXJnZXQuc2V0QXR0cmlidXRlKFwiZGF0YS1zdmctb3JpZ2luXCIsIHRoaXMuc3ZnbyB8fCBcIlwiKTtcbiAgICB9XG5cbiAgICBpID0gX3JldmVydGluZygpO1xuXG4gICAgaWYgKCghaSB8fCAhaS5pc1N0YXJ0KSAmJiAhc3R5bGVbX3RyYW5zZm9ybVByb3BdKSB7XG4gICAgICBfcmVtb3ZlSW5kZXBlbmRlbnRUcmFuc2Zvcm1zKHN0eWxlKTtcblxuICAgICAgaWYgKGNhY2hlLnpPcmlnaW4gJiYgc3R5bGVbX3RyYW5zZm9ybU9yaWdpblByb3BdKSB7XG4gICAgICAgIHN0eWxlW190cmFuc2Zvcm1PcmlnaW5Qcm9wXSArPSBcIiBcIiArIGNhY2hlLnpPcmlnaW4gKyBcInB4XCI7IC8vIHNpbmNlIHdlJ3JlIHVuY2FjaGluZywgd2UgbXVzdCBwdXQgdGhlIHpPcmlnaW4gYmFjayBpbnRvIHRoZSB0cmFuc2Zvcm1PcmlnaW4gc28gdGhhdCB3ZSBjYW4gcHVsbCBpdCBvdXQgYWNjdXJhdGVseSB3aGVuIHdlIHBhcnNlIGFnYWluLiBPdGhlcndpc2UsIHdlJ2QgbG9zZSB0aGUgeiBwb3J0aW9uIG9mIHRoZSBvcmlnaW4gc2luY2Ugd2UgZXh0cmFjdCBpdCB0byBwcm90ZWN0IGZyb20gU2FmYXJpIGJ1Z3MuXG5cbiAgICAgICAgY2FjaGUuek9yaWdpbiA9IDA7XG4gICAgICAgIGNhY2hlLnJlbmRlclRyYW5zZm9ybSgpO1xuICAgICAgfVxuXG4gICAgICBjYWNoZS51bmNhY2hlID0gMTsgLy8gaWYgaXQncyBhIHN0YXJ0QXQgdGhhdCdzIGJlaW5nIHJldmVydGVkIGluIHRoZSBfaW5pdFR3ZWVuKCkgb2YgdGhlIGNvcmUsIHdlIGRvbid0IG5lZWQgdG8gdW5jYWNoZSB0cmFuc2Zvcm1zLiBUaGlzIGlzIHB1cmVseSBhIHBlcmZvcm1hbmNlIG9wdGltaXphdGlvbi5cbiAgICB9XG4gIH1cbn0sXG4gICAgX2dldFN0eWxlU2F2ZXIgPSBmdW5jdGlvbiBfZ2V0U3R5bGVTYXZlcih0YXJnZXQsIHByb3BlcnRpZXMpIHtcbiAgdmFyIHNhdmVyID0ge1xuICAgIHRhcmdldDogdGFyZ2V0LFxuICAgIHByb3BzOiBbXSxcbiAgICByZXZlcnQ6IF9yZXZlcnRTdHlsZSxcbiAgICBzYXZlOiBfc2F2ZVN0eWxlXG4gIH07XG4gIHRhcmdldC5fZ3NhcCB8fCBnc2FwLmNvcmUuZ2V0Q2FjaGUodGFyZ2V0KTsgLy8ganVzdCBtYWtlIHN1cmUgdGhlcmUncyBhIF9nc2FwIGNhY2hlIGRlZmluZWQgYmVjYXVzZSB3ZSByZWFkIGZyb20gaXQgaW4gX3NhdmVTdHlsZSgpIGFuZCBpdCdzIG1vcmUgZWZmaWNpZW50IHRvIGp1c3QgY2hlY2sgaXQgaGVyZSBvbmNlLlxuXG4gIHByb3BlcnRpZXMgJiYgcHJvcGVydGllcy5zcGxpdChcIixcIikuZm9yRWFjaChmdW5jdGlvbiAocCkge1xuICAgIHJldHVybiBzYXZlci5zYXZlKHApO1xuICB9KTtcbiAgcmV0dXJuIHNhdmVyO1xufSxcbiAgICBfc3VwcG9ydHMzRCxcbiAgICBfY3JlYXRlRWxlbWVudCA9IGZ1bmN0aW9uIF9jcmVhdGVFbGVtZW50KHR5cGUsIG5zKSB7XG4gIHZhciBlID0gX2RvYy5jcmVhdGVFbGVtZW50TlMgPyBfZG9jLmNyZWF0ZUVsZW1lbnROUygobnMgfHwgXCJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sXCIpLnJlcGxhY2UoL15odHRwcy8sIFwiaHR0cFwiKSwgdHlwZSkgOiBfZG9jLmNyZWF0ZUVsZW1lbnQodHlwZSk7IC8vc29tZSBzZXJ2ZXJzIHN3YXAgaW4gaHR0cHMgZm9yIGh0dHAgaW4gdGhlIG5hbWVzcGFjZSB3aGljaCBjYW4gYnJlYWsgdGhpbmdzLCBtYWtpbmcgXCJzdHlsZVwiIGluYWNjZXNzaWJsZS5cblxuICByZXR1cm4gZSAmJiBlLnN0eWxlID8gZSA6IF9kb2MuY3JlYXRlRWxlbWVudCh0eXBlKTsgLy9zb21lIGVudmlyb25tZW50cyB3b24ndCBhbGxvdyBhY2Nlc3MgdG8gdGhlIGVsZW1lbnQncyBzdHlsZSB3aGVuIGNyZWF0ZWQgd2l0aCBhIG5hbWVzcGFjZSBpbiB3aGljaCBjYXNlIHdlIGRlZmF1bHQgdG8gdGhlIHN0YW5kYXJkIGNyZWF0ZUVsZW1lbnQoKSB0byB3b3JrIGFyb3VuZCB0aGUgaXNzdWUuIEFsc28gbm90ZSB0aGF0IHdoZW4gR1NBUCBpcyBlbWJlZGRlZCBkaXJlY3RseSBpbnNpZGUgYW4gU1ZHIGZpbGUsIGNyZWF0ZUVsZW1lbnQoKSB3b24ndCBhbGxvdyBhY2Nlc3MgdG8gdGhlIHN0eWxlIG9iamVjdCBpbiBGaXJlZm94IChzZWUgaHR0cHM6Ly9nc2FwLmNvbS9mb3J1bXMvdG9waWMvMjAyMTUtcHJvYmxlbS11c2luZy10d2Vlbm1heC1pbi1zdGFuZGFsb25lLXNlbGYtY29udGFpbmluZy1zdmctZmlsZS1lcnItY2Fubm90LXNldC1wcm9wZXJ0eS1jc3N0ZXh0LW9mLXVuZGVmaW5lZC8pLlxufSxcbiAgICBfZ2V0Q29tcHV0ZWRQcm9wZXJ0eSA9IGZ1bmN0aW9uIF9nZXRDb21wdXRlZFByb3BlcnR5KHRhcmdldCwgcHJvcGVydHksIHNraXBQcmVmaXhGYWxsYmFjaykge1xuICB2YXIgY3MgPSBnZXRDb21wdXRlZFN0eWxlKHRhcmdldCk7XG4gIHJldHVybiBjc1twcm9wZXJ0eV0gfHwgY3MuZ2V0UHJvcGVydHlWYWx1ZShwcm9wZXJ0eS5yZXBsYWNlKF9jYXBzRXhwLCBcIi0kMVwiKS50b0xvd2VyQ2FzZSgpKSB8fCBjcy5nZXRQcm9wZXJ0eVZhbHVlKHByb3BlcnR5KSB8fCAhc2tpcFByZWZpeEZhbGxiYWNrICYmIF9nZXRDb21wdXRlZFByb3BlcnR5KHRhcmdldCwgX2NoZWNrUHJvcFByZWZpeChwcm9wZXJ0eSkgfHwgcHJvcGVydHksIDEpIHx8IFwiXCI7IC8vY3NzIHZhcmlhYmxlcyBtYXkgbm90IG5lZWQgY2FwcyBzd2FwcGVkIG91dCBmb3IgZGFzaGVzIGFuZCBsb3dlcmNhc2UuXG59LFxuICAgIF9wcmVmaXhlcyA9IFwiTyxNb3osbXMsTXMsV2Via2l0XCIuc3BsaXQoXCIsXCIpLFxuICAgIF9jaGVja1Byb3BQcmVmaXggPSBmdW5jdGlvbiBfY2hlY2tQcm9wUHJlZml4KHByb3BlcnR5LCBlbGVtZW50LCBwcmVmZXJQcmVmaXgpIHtcbiAgdmFyIGUgPSBlbGVtZW50IHx8IF90ZW1wRGl2LFxuICAgICAgcyA9IGUuc3R5bGUsXG4gICAgICBpID0gNTtcblxuICBpZiAocHJvcGVydHkgaW4gcyAmJiAhcHJlZmVyUHJlZml4KSB7XG4gICAgcmV0dXJuIHByb3BlcnR5O1xuICB9XG5cbiAgcHJvcGVydHkgPSBwcm9wZXJ0eS5jaGFyQXQoMCkudG9VcHBlckNhc2UoKSArIHByb3BlcnR5LnN1YnN0cigxKTtcblxuICB3aGlsZSAoaS0tICYmICEoX3ByZWZpeGVzW2ldICsgcHJvcGVydHkgaW4gcykpIHt9XG5cbiAgcmV0dXJuIGkgPCAwID8gbnVsbCA6IChpID09PSAzID8gXCJtc1wiIDogaSA+PSAwID8gX3ByZWZpeGVzW2ldIDogXCJcIikgKyBwcm9wZXJ0eTtcbn0sXG4gICAgX2luaXRDb3JlID0gZnVuY3Rpb24gX2luaXRDb3JlKCkge1xuICBpZiAoX3dpbmRvd0V4aXN0cygpICYmIHdpbmRvdy5kb2N1bWVudCkge1xuICAgIF93aW4gPSB3aW5kb3c7XG4gICAgX2RvYyA9IF93aW4uZG9jdW1lbnQ7XG4gICAgX2RvY0VsZW1lbnQgPSBfZG9jLmRvY3VtZW50RWxlbWVudDtcbiAgICBfdGVtcERpdiA9IF9jcmVhdGVFbGVtZW50KFwiZGl2XCIpIHx8IHtcbiAgICAgIHN0eWxlOiB7fVxuICAgIH07XG4gICAgX3RlbXBEaXZTdHlsZXIgPSBfY3JlYXRlRWxlbWVudChcImRpdlwiKTtcbiAgICBfdHJhbnNmb3JtUHJvcCA9IF9jaGVja1Byb3BQcmVmaXgoX3RyYW5zZm9ybVByb3ApO1xuICAgIF90cmFuc2Zvcm1PcmlnaW5Qcm9wID0gX3RyYW5zZm9ybVByb3AgKyBcIk9yaWdpblwiO1xuICAgIF90ZW1wRGl2LnN0eWxlLmNzc1RleHQgPSBcImJvcmRlci13aWR0aDowO2xpbmUtaGVpZ2h0OjA7cG9zaXRpb246YWJzb2x1dGU7cGFkZGluZzowXCI7IC8vbWFrZSBzdXJlIHRvIG92ZXJyaWRlIGNlcnRhaW4gcHJvcGVydGllcyB0aGF0IG1heSBjb250YW1pbmF0ZSBtZWFzdXJlbWVudHMsIGluIGNhc2UgdGhlIHVzZXIgaGFzIG92ZXJyZWFjaGluZyBzdHlsZSBzaGVldHMuXG5cbiAgICBfc3VwcG9ydHMzRCA9ICEhX2NoZWNrUHJvcFByZWZpeChcInBlcnNwZWN0aXZlXCIpO1xuICAgIF9yZXZlcnRpbmcgPSBnc2FwLmNvcmUucmV2ZXJ0aW5nO1xuICAgIF9wbHVnaW5Jbml0dGVkID0gMTtcbiAgfVxufSxcbiAgICBfZ2V0QkJveEhhY2sgPSBmdW5jdGlvbiBfZ2V0QkJveEhhY2soc3dhcElmUG9zc2libGUpIHtcbiAgLy93b3JrcyBhcm91bmQgaXNzdWVzIGluIHNvbWUgYnJvd3NlcnMgKGxpa2UgRmlyZWZveCkgdGhhdCBkb24ndCBjb3JyZWN0bHkgcmVwb3J0IGdldEJCb3goKSBvbiBTVkcgZWxlbWVudHMgaW5zaWRlIGEgPGRlZnM+IGVsZW1lbnQgYW5kL29yIDxtYXNrPi4gV2UgdHJ5IGNyZWF0aW5nIGFuIFNWRywgYWRkaW5nIGl0IHRvIHRoZSBkb2N1bWVudEVsZW1lbnQgYW5kIHRvc3MgdGhlIGVsZW1lbnQgaW4gdGhlcmUgc28gdGhhdCBpdCdzIGRlZmluaXRlbHkgcGFydCBvZiB0aGUgcmVuZGVyaW5nIHRyZWUsIHRoZW4gZ3JhYiB0aGUgYmJveCBhbmQgaWYgaXQgd29ya3MsIHdlIGFjdHVhbGx5IHN3YXAgb3V0IHRoZSBvcmlnaW5hbCBnZXRCQm94KCkgbWV0aG9kIGZvciBvdXIgb3duIHRoYXQgZG9lcyB0aGVzZSBleHRyYSBzdGVwcyB3aGVuZXZlciBnZXRCQm94IGlzIG5lZWRlZC4gVGhpcyBoZWxwcyBlbnN1cmUgdGhhdCBwZXJmb3JtYW5jZSBpcyBvcHRpbWFsIChvbmx5IGRvIGFsbCB0aGVzZSBleHRyYSBzdGVwcyB3aGVuIGFic29sdXRlbHkgbmVjZXNzYXJ5Li4ubW9zdCBlbGVtZW50cyBkb24ndCBuZWVkIGl0KS5cbiAgdmFyIHN2ZyA9IF9jcmVhdGVFbGVtZW50KFwic3ZnXCIsIHRoaXMub3duZXJTVkdFbGVtZW50ICYmIHRoaXMub3duZXJTVkdFbGVtZW50LmdldEF0dHJpYnV0ZShcInhtbG5zXCIpIHx8IFwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiksXG4gICAgICBvbGRQYXJlbnQgPSB0aGlzLnBhcmVudE5vZGUsXG4gICAgICBvbGRTaWJsaW5nID0gdGhpcy5uZXh0U2libGluZyxcbiAgICAgIG9sZENTUyA9IHRoaXMuc3R5bGUuY3NzVGV4dCxcbiAgICAgIGJib3g7XG5cbiAgX2RvY0VsZW1lbnQuYXBwZW5kQ2hpbGQoc3ZnKTtcblxuICBzdmcuYXBwZW5kQ2hpbGQodGhpcyk7XG4gIHRoaXMuc3R5bGUuZGlzcGxheSA9IFwiYmxvY2tcIjtcblxuICBpZiAoc3dhcElmUG9zc2libGUpIHtcbiAgICB0cnkge1xuICAgICAgYmJveCA9IHRoaXMuZ2V0QkJveCgpO1xuICAgICAgdGhpcy5fZ3NhcEJCb3ggPSB0aGlzLmdldEJCb3g7IC8vc3RvcmUgdGhlIG9yaWdpbmFsXG5cbiAgICAgIHRoaXMuZ2V0QkJveCA9IF9nZXRCQm94SGFjaztcbiAgICB9IGNhdGNoIChlKSB7fVxuICB9IGVsc2UgaWYgKHRoaXMuX2dzYXBCQm94KSB7XG4gICAgYmJveCA9IHRoaXMuX2dzYXBCQm94KCk7XG4gIH1cblxuICBpZiAob2xkUGFyZW50KSB7XG4gICAgaWYgKG9sZFNpYmxpbmcpIHtcbiAgICAgIG9sZFBhcmVudC5pbnNlcnRCZWZvcmUodGhpcywgb2xkU2libGluZyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIG9sZFBhcmVudC5hcHBlbmRDaGlsZCh0aGlzKTtcbiAgICB9XG4gIH1cblxuICBfZG9jRWxlbWVudC5yZW1vdmVDaGlsZChzdmcpO1xuXG4gIHRoaXMuc3R5bGUuY3NzVGV4dCA9IG9sZENTUztcbiAgcmV0dXJuIGJib3g7XG59LFxuICAgIF9nZXRBdHRyaWJ1dGVGYWxsYmFja3MgPSBmdW5jdGlvbiBfZ2V0QXR0cmlidXRlRmFsbGJhY2tzKHRhcmdldCwgYXR0cmlidXRlc0FycmF5KSB7XG4gIHZhciBpID0gYXR0cmlidXRlc0FycmF5Lmxlbmd0aDtcblxuICB3aGlsZSAoaS0tKSB7XG4gICAgaWYgKHRhcmdldC5oYXNBdHRyaWJ1dGUoYXR0cmlidXRlc0FycmF5W2ldKSkge1xuICAgICAgcmV0dXJuIHRhcmdldC5nZXRBdHRyaWJ1dGUoYXR0cmlidXRlc0FycmF5W2ldKTtcbiAgICB9XG4gIH1cbn0sXG4gICAgX2dldEJCb3ggPSBmdW5jdGlvbiBfZ2V0QkJveCh0YXJnZXQpIHtcbiAgdmFyIGJvdW5kcztcblxuICB0cnkge1xuICAgIGJvdW5kcyA9IHRhcmdldC5nZXRCQm94KCk7IC8vRmlyZWZveCB0aHJvd3MgZXJyb3JzIGlmIHlvdSB0cnkgY2FsbGluZyBnZXRCQm94KCkgb24gYW4gU1ZHIGVsZW1lbnQgdGhhdCdzIG5vdCByZW5kZXJlZCAobGlrZSBpbiBhIDxzeW1ib2w+IG9yIDxkZWZzPikuIGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTYxMjExOFxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGJvdW5kcyA9IF9nZXRCQm94SGFjay5jYWxsKHRhcmdldCwgdHJ1ZSk7XG4gIH1cblxuICBib3VuZHMgJiYgKGJvdW5kcy53aWR0aCB8fCBib3VuZHMuaGVpZ2h0KSB8fCB0YXJnZXQuZ2V0QkJveCA9PT0gX2dldEJCb3hIYWNrIHx8IChib3VuZHMgPSBfZ2V0QkJveEhhY2suY2FsbCh0YXJnZXQsIHRydWUpKTsgLy9zb21lIGJyb3dzZXJzIChsaWtlIEZpcmVmb3gpIG1pc3JlcG9ydCB0aGUgYm91bmRzIGlmIHRoZSBlbGVtZW50IGhhcyB6ZXJvIHdpZHRoIGFuZCBoZWlnaHQgKGl0IGp1c3QgYXNzdW1lcyBpdCdzIGF0IHg6MCwgeTowKSwgdGh1cyB3ZSBuZWVkIHRvIG1hbnVhbGx5IGdyYWIgdGhlIHBvc2l0aW9uIGluIHRoYXQgY2FzZS5cblxuICByZXR1cm4gYm91bmRzICYmICFib3VuZHMud2lkdGggJiYgIWJvdW5kcy54ICYmICFib3VuZHMueSA/IHtcbiAgICB4OiArX2dldEF0dHJpYnV0ZUZhbGxiYWNrcyh0YXJnZXQsIFtcInhcIiwgXCJjeFwiLCBcIngxXCJdKSB8fCAwLFxuICAgIHk6ICtfZ2V0QXR0cmlidXRlRmFsbGJhY2tzKHRhcmdldCwgW1wieVwiLCBcImN5XCIsIFwieTFcIl0pIHx8IDAsXG4gICAgd2lkdGg6IDAsXG4gICAgaGVpZ2h0OiAwXG4gIH0gOiBib3VuZHM7XG59LFxuICAgIF9pc1NWRyA9IGZ1bmN0aW9uIF9pc1NWRyhlKSB7XG4gIHJldHVybiAhIShlLmdldENUTSAmJiAoIWUucGFyZW50Tm9kZSB8fCBlLm93bmVyU1ZHRWxlbWVudCkgJiYgX2dldEJCb3goZSkpO1xufSxcbiAgICAvL3JlcG9ydHMgaWYgdGhlIGVsZW1lbnQgaXMgYW4gU1ZHIG9uIHdoaWNoIGdldEJCb3goKSBhY3R1YWxseSB3b3Jrc1xuX3JlbW92ZVByb3BlcnR5ID0gZnVuY3Rpb24gX3JlbW92ZVByb3BlcnR5KHRhcmdldCwgcHJvcGVydHkpIHtcbiAgaWYgKHByb3BlcnR5KSB7XG4gICAgdmFyIHN0eWxlID0gdGFyZ2V0LnN0eWxlLFxuICAgICAgICBmaXJzdDJDaGFycztcblxuICAgIGlmIChwcm9wZXJ0eSBpbiBfdHJhbnNmb3JtUHJvcHMgJiYgcHJvcGVydHkgIT09IF90cmFuc2Zvcm1PcmlnaW5Qcm9wKSB7XG4gICAgICBwcm9wZXJ0eSA9IF90cmFuc2Zvcm1Qcm9wO1xuICAgIH1cblxuICAgIGlmIChzdHlsZS5yZW1vdmVQcm9wZXJ0eSkge1xuICAgICAgZmlyc3QyQ2hhcnMgPSBwcm9wZXJ0eS5zdWJzdHIoMCwgMik7XG5cbiAgICAgIGlmIChmaXJzdDJDaGFycyA9PT0gXCJtc1wiIHx8IHByb3BlcnR5LnN1YnN0cigwLCA2KSA9PT0gXCJ3ZWJraXRcIikge1xuICAgICAgICAvL01pY3Jvc29mdCBhbmQgc29tZSBXZWJraXQgYnJvd3NlcnMgZG9uJ3QgY29uZm9ybSB0byB0aGUgc3RhbmRhcmQgb2YgY2FwaXRhbGl6aW5nIHRoZSBmaXJzdCBwcmVmaXggY2hhcmFjdGVyLCBzbyB3ZSBhZGp1c3Qgc28gdGhhdCB3aGVuIHdlIHByZWZpeCB0aGUgY2FwcyB3aXRoIGEgZGFzaCwgaXQncyBjb3JyZWN0IChvdGhlcndpc2UgaXQnZCBiZSBcIm1zLXRyYW5zZm9ybVwiIGluc3RlYWQgb2YgXCItbXMtdHJhbnNmb3JtXCIgZm9yIElFOSwgZm9yIGV4YW1wbGUpXG4gICAgICAgIHByb3BlcnR5ID0gXCItXCIgKyBwcm9wZXJ0eTtcbiAgICAgIH1cblxuICAgICAgc3R5bGUucmVtb3ZlUHJvcGVydHkoZmlyc3QyQ2hhcnMgPT09IFwiLS1cIiA/IHByb3BlcnR5IDogcHJvcGVydHkucmVwbGFjZShfY2Fwc0V4cCwgXCItJDFcIikudG9Mb3dlckNhc2UoKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vbm90ZTogb2xkIHZlcnNpb25zIG9mIElFIHVzZSBcInJlbW92ZUF0dHJpYnV0ZSgpXCIgaW5zdGVhZCBvZiBcInJlbW92ZVByb3BlcnR5KClcIlxuICAgICAgc3R5bGUucmVtb3ZlQXR0cmlidXRlKHByb3BlcnR5KTtcbiAgICB9XG4gIH1cbn0sXG4gICAgX2FkZE5vblR3ZWVuaW5nUFQgPSBmdW5jdGlvbiBfYWRkTm9uVHdlZW5pbmdQVChwbHVnaW4sIHRhcmdldCwgcHJvcGVydHksIGJlZ2lubmluZywgZW5kLCBvbmx5U2V0QXRFbmQpIHtcbiAgdmFyIHB0ID0gbmV3IFByb3BUd2VlbihwbHVnaW4uX3B0LCB0YXJnZXQsIHByb3BlcnR5LCAwLCAxLCBvbmx5U2V0QXRFbmQgPyBfcmVuZGVyTm9uVHdlZW5pbmdWYWx1ZU9ubHlBdEVuZCA6IF9yZW5kZXJOb25Ud2VlbmluZ1ZhbHVlKTtcbiAgcGx1Z2luLl9wdCA9IHB0O1xuICBwdC5iID0gYmVnaW5uaW5nO1xuICBwdC5lID0gZW5kO1xuXG4gIHBsdWdpbi5fcHJvcHMucHVzaChwcm9wZXJ0eSk7XG5cbiAgcmV0dXJuIHB0O1xufSxcbiAgICBfbm9uQ29udmVydGlibGVVbml0cyA9IHtcbiAgZGVnOiAxLFxuICByYWQ6IDEsXG4gIHR1cm46IDFcbn0sXG4gICAgX25vblN0YW5kYXJkTGF5b3V0cyA9IHtcbiAgZ3JpZDogMSxcbiAgZmxleDogMVxufSxcbiAgICAvL3Rha2VzIGEgc2luZ2xlIHZhbHVlIGxpa2UgMjBweCBhbmQgY29udmVydHMgaXQgdG8gdGhlIHVuaXQgc3BlY2lmaWVkLCBsaWtlIFwiJVwiLCByZXR1cm5pbmcgb25seSB0aGUgbnVtZXJpYyBhbW91bnQuXG5fY29udmVydFRvVW5pdCA9IGZ1bmN0aW9uIF9jb252ZXJ0VG9Vbml0KHRhcmdldCwgcHJvcGVydHksIHZhbHVlLCB1bml0KSB7XG4gIHZhciBjdXJWYWx1ZSA9IHBhcnNlRmxvYXQodmFsdWUpIHx8IDAsXG4gICAgICBjdXJVbml0ID0gKHZhbHVlICsgXCJcIikudHJpbSgpLnN1YnN0cigoY3VyVmFsdWUgKyBcIlwiKS5sZW5ndGgpIHx8IFwicHhcIixcbiAgICAgIC8vIHNvbWUgYnJvd3NlcnMgbGVhdmUgZXh0cmEgd2hpdGVzcGFjZSBhdCB0aGUgYmVnaW5uaW5nIG9mIENTUyB2YXJpYWJsZXMsIGhlbmNlIHRoZSBuZWVkIHRvIHRyaW0oKVxuICBzdHlsZSA9IF90ZW1wRGl2LnN0eWxlLFxuICAgICAgaG9yaXpvbnRhbCA9IF9ob3Jpem9udGFsRXhwLnRlc3QocHJvcGVydHkpLFxuICAgICAgaXNSb290U1ZHID0gdGFyZ2V0LnRhZ05hbWUudG9Mb3dlckNhc2UoKSA9PT0gXCJzdmdcIixcbiAgICAgIG1lYXN1cmVQcm9wZXJ0eSA9IChpc1Jvb3RTVkcgPyBcImNsaWVudFwiIDogXCJvZmZzZXRcIikgKyAoaG9yaXpvbnRhbCA/IFwiV2lkdGhcIiA6IFwiSGVpZ2h0XCIpLFxuICAgICAgYW1vdW50ID0gMTAwLFxuICAgICAgdG9QaXhlbHMgPSB1bml0ID09PSBcInB4XCIsXG4gICAgICB0b1BlcmNlbnQgPSB1bml0ID09PSBcIiVcIixcbiAgICAgIHB4LFxuICAgICAgcGFyZW50LFxuICAgICAgY2FjaGUsXG4gICAgICBpc1NWRztcblxuICBpZiAodW5pdCA9PT0gY3VyVW5pdCB8fCAhY3VyVmFsdWUgfHwgX25vbkNvbnZlcnRpYmxlVW5pdHNbdW5pdF0gfHwgX25vbkNvbnZlcnRpYmxlVW5pdHNbY3VyVW5pdF0pIHtcbiAgICByZXR1cm4gY3VyVmFsdWU7XG4gIH1cblxuICBjdXJVbml0ICE9PSBcInB4XCIgJiYgIXRvUGl4ZWxzICYmIChjdXJWYWx1ZSA9IF9jb252ZXJ0VG9Vbml0KHRhcmdldCwgcHJvcGVydHksIHZhbHVlLCBcInB4XCIpKTtcbiAgaXNTVkcgPSB0YXJnZXQuZ2V0Q1RNICYmIF9pc1NWRyh0YXJnZXQpO1xuXG4gIGlmICgodG9QZXJjZW50IHx8IGN1clVuaXQgPT09IFwiJVwiKSAmJiAoX3RyYW5zZm9ybVByb3BzW3Byb3BlcnR5XSB8fCB+cHJvcGVydHkuaW5kZXhPZihcImFkaXVzXCIpKSkge1xuICAgIHB4ID0gaXNTVkcgPyB0YXJnZXQuZ2V0QkJveCgpW2hvcml6b250YWwgPyBcIndpZHRoXCIgOiBcImhlaWdodFwiXSA6IHRhcmdldFttZWFzdXJlUHJvcGVydHldO1xuICAgIHJldHVybiBfcm91bmQodG9QZXJjZW50ID8gY3VyVmFsdWUgLyBweCAqIGFtb3VudCA6IGN1clZhbHVlIC8gMTAwICogcHgpO1xuICB9XG5cbiAgc3R5bGVbaG9yaXpvbnRhbCA/IFwid2lkdGhcIiA6IFwiaGVpZ2h0XCJdID0gYW1vdW50ICsgKHRvUGl4ZWxzID8gY3VyVW5pdCA6IHVuaXQpO1xuICBwYXJlbnQgPSB+cHJvcGVydHkuaW5kZXhPZihcImFkaXVzXCIpIHx8IHVuaXQgPT09IFwiZW1cIiAmJiB0YXJnZXQuYXBwZW5kQ2hpbGQgJiYgIWlzUm9vdFNWRyA/IHRhcmdldCA6IHRhcmdldC5wYXJlbnROb2RlO1xuXG4gIGlmIChpc1NWRykge1xuICAgIHBhcmVudCA9ICh0YXJnZXQub3duZXJTVkdFbGVtZW50IHx8IHt9KS5wYXJlbnROb2RlO1xuICB9XG5cbiAgaWYgKCFwYXJlbnQgfHwgcGFyZW50ID09PSBfZG9jIHx8ICFwYXJlbnQuYXBwZW5kQ2hpbGQpIHtcbiAgICBwYXJlbnQgPSBfZG9jLmJvZHk7XG4gIH1cblxuICBjYWNoZSA9IHBhcmVudC5fZ3NhcDtcblxuICBpZiAoY2FjaGUgJiYgdG9QZXJjZW50ICYmIGNhY2hlLndpZHRoICYmIGhvcml6b250YWwgJiYgY2FjaGUudGltZSA9PT0gX3RpY2tlci50aW1lICYmICFjYWNoZS51bmNhY2hlKSB7XG4gICAgcmV0dXJuIF9yb3VuZChjdXJWYWx1ZSAvIGNhY2hlLndpZHRoICogYW1vdW50KTtcbiAgfSBlbHNlIHtcbiAgICBpZiAodG9QZXJjZW50ICYmIChwcm9wZXJ0eSA9PT0gXCJoZWlnaHRcIiB8fCBwcm9wZXJ0eSA9PT0gXCJ3aWR0aFwiKSkge1xuICAgICAgLy8gaWYgd2UncmUgZGVhbGluZyB3aXRoIHdpZHRoL2hlaWdodCB0aGF0J3MgaW5zaWRlIGEgY29udGFpbmVyIHdpdGggcGFkZGluZyBhbmQvb3IgaXQncyBhIGZsZXhib3gvZ3JpZCBjb250YWluZXIsIHdlIG11c3QgYXBwbHkgaXQgdG8gdGhlIHRhcmdldCBpdHNlbGYgcmF0aGVyIHRoYW4gdGhlIF90ZW1wRGl2IGluIG9yZGVyIHRvIGVuc3VyZSBjb21wbGV0ZSBhY2N1cmFjeSwgZmFjdG9yaW5nIGluIHRoZSBwYXJlbnQncyBwYWRkaW5nLlxuICAgICAgdmFyIHYgPSB0YXJnZXQuc3R5bGVbcHJvcGVydHldO1xuICAgICAgdGFyZ2V0LnN0eWxlW3Byb3BlcnR5XSA9IGFtb3VudCArIHVuaXQ7XG4gICAgICBweCA9IHRhcmdldFttZWFzdXJlUHJvcGVydHldO1xuICAgICAgdiA/IHRhcmdldC5zdHlsZVtwcm9wZXJ0eV0gPSB2IDogX3JlbW92ZVByb3BlcnR5KHRhcmdldCwgcHJvcGVydHkpO1xuICAgIH0gZWxzZSB7XG4gICAgICAodG9QZXJjZW50IHx8IGN1clVuaXQgPT09IFwiJVwiKSAmJiAhX25vblN0YW5kYXJkTGF5b3V0c1tfZ2V0Q29tcHV0ZWRQcm9wZXJ0eShwYXJlbnQsIFwiZGlzcGxheVwiKV0gJiYgKHN0eWxlLnBvc2l0aW9uID0gX2dldENvbXB1dGVkUHJvcGVydHkodGFyZ2V0LCBcInBvc2l0aW9uXCIpKTtcbiAgICAgIHBhcmVudCA9PT0gdGFyZ2V0ICYmIChzdHlsZS5wb3NpdGlvbiA9IFwic3RhdGljXCIpOyAvLyBsaWtlIGZvciBib3JkZXJSYWRpdXMsIGlmIGl0J3MgYSAlIHdlIG11c3QgaGF2ZSBpdCByZWxhdGl2ZSB0byB0aGUgdGFyZ2V0IGl0c2VsZiBidXQgdGhhdCBtYXkgbm90IGhhdmUgcG9zaXRpb246IHJlbGF0aXZlIG9yIHBvc2l0aW9uOiBhYnNvbHV0ZSBpbiB3aGljaCBjYXNlIGl0J2QgZ28gdXAgdGhlIGNoYWluIHVudGlsIGl0IGZpbmRzIGl0cyBvZmZzZXRQYXJlbnQgKGJhZCkuIHBvc2l0aW9uOiBzdGF0aWMgcHJvdGVjdHMgYWdhaW5zdCB0aGF0LlxuXG4gICAgICBwYXJlbnQuYXBwZW5kQ2hpbGQoX3RlbXBEaXYpO1xuICAgICAgcHggPSBfdGVtcERpdlttZWFzdXJlUHJvcGVydHldO1xuICAgICAgcGFyZW50LnJlbW92ZUNoaWxkKF90ZW1wRGl2KTtcbiAgICAgIHN0eWxlLnBvc2l0aW9uID0gXCJhYnNvbHV0ZVwiO1xuICAgIH1cblxuICAgIGlmIChob3Jpem9udGFsICYmIHRvUGVyY2VudCkge1xuICAgICAgY2FjaGUgPSBfZ2V0Q2FjaGUocGFyZW50KTtcbiAgICAgIGNhY2hlLnRpbWUgPSBfdGlja2VyLnRpbWU7XG4gICAgICBjYWNoZS53aWR0aCA9IHBhcmVudFttZWFzdXJlUHJvcGVydHldO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBfcm91bmQodG9QaXhlbHMgPyBweCAqIGN1clZhbHVlIC8gYW1vdW50IDogcHggJiYgY3VyVmFsdWUgPyBhbW91bnQgLyBweCAqIGN1clZhbHVlIDogMCk7XG59LFxuICAgIF9nZXQgPSBmdW5jdGlvbiBfZ2V0KHRhcmdldCwgcHJvcGVydHksIHVuaXQsIHVuY2FjaGUpIHtcbiAgdmFyIHZhbHVlO1xuICBfcGx1Z2luSW5pdHRlZCB8fCBfaW5pdENvcmUoKTtcblxuICBpZiAocHJvcGVydHkgaW4gX3Byb3BlcnR5QWxpYXNlcyAmJiBwcm9wZXJ0eSAhPT0gXCJ0cmFuc2Zvcm1cIikge1xuICAgIHByb3BlcnR5ID0gX3Byb3BlcnR5QWxpYXNlc1twcm9wZXJ0eV07XG5cbiAgICBpZiAofnByb3BlcnR5LmluZGV4T2YoXCIsXCIpKSB7XG4gICAgICBwcm9wZXJ0eSA9IHByb3BlcnR5LnNwbGl0KFwiLFwiKVswXTtcbiAgICB9XG4gIH1cblxuICBpZiAoX3RyYW5zZm9ybVByb3BzW3Byb3BlcnR5XSAmJiBwcm9wZXJ0eSAhPT0gXCJ0cmFuc2Zvcm1cIikge1xuICAgIHZhbHVlID0gX3BhcnNlVHJhbnNmb3JtKHRhcmdldCwgdW5jYWNoZSk7XG4gICAgdmFsdWUgPSBwcm9wZXJ0eSAhPT0gXCJ0cmFuc2Zvcm1PcmlnaW5cIiA/IHZhbHVlW3Byb3BlcnR5XSA6IHZhbHVlLnN2ZyA/IHZhbHVlLm9yaWdpbiA6IF9maXJzdFR3b09ubHkoX2dldENvbXB1dGVkUHJvcGVydHkodGFyZ2V0LCBfdHJhbnNmb3JtT3JpZ2luUHJvcCkpICsgXCIgXCIgKyB2YWx1ZS56T3JpZ2luICsgXCJweFwiO1xuICB9IGVsc2Uge1xuICAgIHZhbHVlID0gdGFyZ2V0LnN0eWxlW3Byb3BlcnR5XTtcblxuICAgIGlmICghdmFsdWUgfHwgdmFsdWUgPT09IFwiYXV0b1wiIHx8IHVuY2FjaGUgfHwgfih2YWx1ZSArIFwiXCIpLmluZGV4T2YoXCJjYWxjKFwiKSkge1xuICAgICAgdmFsdWUgPSBfc3BlY2lhbFByb3BzW3Byb3BlcnR5XSAmJiBfc3BlY2lhbFByb3BzW3Byb3BlcnR5XSh0YXJnZXQsIHByb3BlcnR5LCB1bml0KSB8fCBfZ2V0Q29tcHV0ZWRQcm9wZXJ0eSh0YXJnZXQsIHByb3BlcnR5KSB8fCBfZ2V0UHJvcGVydHkodGFyZ2V0LCBwcm9wZXJ0eSkgfHwgKHByb3BlcnR5ID09PSBcIm9wYWNpdHlcIiA/IDEgOiAwKTsgLy8gbm90ZTogc29tZSBicm93c2VycywgbGlrZSBGaXJlZm94LCBkb24ndCByZXBvcnQgYm9yZGVyUmFkaXVzIGNvcnJlY3RseSEgSW5zdGVhZCwgaXQgb25seSByZXBvcnRzIGV2ZXJ5IGNvcm5lciBsaWtlICBib3JkZXJUb3BMZWZ0UmFkaXVzXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHVuaXQgJiYgIX4odmFsdWUgKyBcIlwiKS50cmltKCkuaW5kZXhPZihcIiBcIikgPyBfY29udmVydFRvVW5pdCh0YXJnZXQsIHByb3BlcnR5LCB2YWx1ZSwgdW5pdCkgKyB1bml0IDogdmFsdWU7XG59LFxuICAgIF90d2VlbkNvbXBsZXhDU1NTdHJpbmcgPSBmdW5jdGlvbiBfdHdlZW5Db21wbGV4Q1NTU3RyaW5nKHRhcmdldCwgcHJvcCwgc3RhcnQsIGVuZCkge1xuICAvLyBub3RlOiB3ZSBjYWxsIF90d2VlbkNvbXBsZXhDU1NTdHJpbmcuY2FsbChwbHVnaW5JbnN0YW5jZS4uLikgdG8gZW5zdXJlIHRoYXQgaXQncyBzY29wZWQgcHJvcGVybHkuIFdlIG1heSBjYWxsIGl0IGZyb20gd2l0aGluIGEgcGx1Z2luIHRvbywgdGh1cyBcInRoaXNcIiB3b3VsZCByZWZlciB0byB0aGUgcGx1Z2luLlxuICBpZiAoIXN0YXJ0IHx8IHN0YXJ0ID09PSBcIm5vbmVcIikge1xuICAgIC8vIHNvbWUgYnJvd3NlcnMgbGlrZSBTYWZhcmkgYWN0dWFsbHkgUFJFRkVSIHRoZSBwcmVmaXhlZCBwcm9wZXJ0eSBhbmQgbWlzLXJlcG9ydCB0aGUgdW5wcmVmaXhlZCB2YWx1ZSBsaWtlIGNsaXBQYXRoIChCVUcpLiBJbiBvdGhlciB3b3JkcywgZXZlbiB0aG91Z2ggY2xpcFBhdGggZXhpc3RzIGluIHRoZSBzdHlsZSAoXCJjbGlwUGF0aFwiIGluIHRhcmdldC5zdHlsZSkgYW5kIGl0J3Mgc2V0IGluIHRoZSBDU1MgcHJvcGVybHkgKGFsb25nIHdpdGggLXdlYmtpdC1jbGlwLXBhdGgpLCBTYWZhcmkgcmVwb3J0cyBjbGlwUGF0aCBhcyBcIm5vbmVcIiB3aGVyZWFzIFdlYmtpdENsaXBQYXRoIHJlcG9ydHMgYWNjdXJhdGVseSBsaWtlIFwiZWxsaXBzZSgxMDAlIDAlIGF0IDUwJSAwJSlcIiwgc28gaW4gdGhpcyBjYXNlIHdlIG11c3QgU1dJVENIIHRvIHVzaW5nIHRoZSBwcmVmaXhlZCBwcm9wZXJ0eSBpbnN0ZWFkLiBTZWUgaHR0cHM6Ly9nc2FwLmNvbS9mb3J1bXMvdG9waWMvMTgzMTAtY2xpcHBhdGgtZG9lc250LXdvcmstb24taW9zL1xuICAgIHZhciBwID0gX2NoZWNrUHJvcFByZWZpeChwcm9wLCB0YXJnZXQsIDEpLFxuICAgICAgICBzID0gcCAmJiBfZ2V0Q29tcHV0ZWRQcm9wZXJ0eSh0YXJnZXQsIHAsIDEpO1xuXG4gICAgaWYgKHMgJiYgcyAhPT0gc3RhcnQpIHtcbiAgICAgIHByb3AgPSBwO1xuICAgICAgc3RhcnQgPSBzO1xuICAgIH0gZWxzZSBpZiAocHJvcCA9PT0gXCJib3JkZXJDb2xvclwiKSB7XG4gICAgICBzdGFydCA9IF9nZXRDb21wdXRlZFByb3BlcnR5KHRhcmdldCwgXCJib3JkZXJUb3BDb2xvclwiKTsgLy8gRmlyZWZveCBidWc6IGFsd2F5cyByZXBvcnRzIFwiYm9yZGVyQ29sb3JcIiBhcyBcIlwiLCBzbyB3ZSBtdXN0IGZhbGwgYmFjayB0byBib3JkZXJUb3BDb2xvci4gU2VlIGh0dHBzOi8vZ3NhcC5jb20vZm9ydW1zL3RvcGljLzI0NTgzLWhvdy10by1yZXR1cm4tY29sb3JzLXRoYXQtaS1oYWQtYWZ0ZXItcmV2ZXJzZS9cbiAgICB9XG4gIH1cblxuICB2YXIgcHQgPSBuZXcgUHJvcFR3ZWVuKHRoaXMuX3B0LCB0YXJnZXQuc3R5bGUsIHByb3AsIDAsIDEsIF9yZW5kZXJDb21wbGV4U3RyaW5nKSxcbiAgICAgIGluZGV4ID0gMCxcbiAgICAgIG1hdGNoSW5kZXggPSAwLFxuICAgICAgYSxcbiAgICAgIHJlc3VsdCxcbiAgICAgIHN0YXJ0VmFsdWVzLFxuICAgICAgc3RhcnROdW0sXG4gICAgICBjb2xvcixcbiAgICAgIHN0YXJ0VmFsdWUsXG4gICAgICBlbmRWYWx1ZSxcbiAgICAgIGVuZE51bSxcbiAgICAgIGNodW5rLFxuICAgICAgZW5kVW5pdCxcbiAgICAgIHN0YXJ0VW5pdCxcbiAgICAgIGVuZFZhbHVlcztcbiAgcHQuYiA9IHN0YXJ0O1xuICBwdC5lID0gZW5kO1xuICBzdGFydCArPSBcIlwiOyAvLyBlbnN1cmUgdmFsdWVzIGFyZSBzdHJpbmdzXG5cbiAgZW5kICs9IFwiXCI7XG5cbiAgaWYgKGVuZCA9PT0gXCJhdXRvXCIpIHtcbiAgICBzdGFydFZhbHVlID0gdGFyZ2V0LnN0eWxlW3Byb3BdO1xuICAgIHRhcmdldC5zdHlsZVtwcm9wXSA9IGVuZDtcbiAgICBlbmQgPSBfZ2V0Q29tcHV0ZWRQcm9wZXJ0eSh0YXJnZXQsIHByb3ApIHx8IGVuZDtcbiAgICBzdGFydFZhbHVlID8gdGFyZ2V0LnN0eWxlW3Byb3BdID0gc3RhcnRWYWx1ZSA6IF9yZW1vdmVQcm9wZXJ0eSh0YXJnZXQsIHByb3ApO1xuICB9XG5cbiAgYSA9IFtzdGFydCwgZW5kXTtcblxuICBfY29sb3JTdHJpbmdGaWx0ZXIoYSk7IC8vIHBhc3MgYW4gYXJyYXkgd2l0aCB0aGUgc3RhcnRpbmcgYW5kIGVuZGluZyB2YWx1ZXMgYW5kIGxldCB0aGUgZmlsdGVyIGRvIHdoYXRldmVyIGl0IG5lZWRzIHRvIHRoZSB2YWx1ZXMuIElmIGNvbG9ycyBhcmUgZm91bmQsIGl0IHJldHVybnMgdHJ1ZSBhbmQgdGhlbiB3ZSBtdXN0IG1hdGNoIHdoZXJlIHRoZSBjb2xvciBzaG93cyB1cCBvcmRlci13aXNlIGJlY2F1c2UgZm9yIHRoaW5ncyBsaWtlIGJveFNoYWRvdywgc29tZXRpbWVzIHRoZSBicm93c2VyIHByb3ZpZGVzIHRoZSBjb21wdXRlZCB2YWx1ZXMgd2l0aCB0aGUgY29sb3IgRklSU1QsIGJ1dCB0aGUgdXNlciBwcm92aWRlcyBpdCB3aXRoIHRoZSBjb2xvciBMQVNULCBzbyBmbGlwIHRoZW0gaWYgbmVjZXNzYXJ5LiBTYW1lIGZvciBkcm9wLXNoYWRvdygpLlxuXG5cbiAgc3RhcnQgPSBhWzBdO1xuICBlbmQgPSBhWzFdO1xuICBzdGFydFZhbHVlcyA9IHN0YXJ0Lm1hdGNoKF9udW1XaXRoVW5pdEV4cCkgfHwgW107XG4gIGVuZFZhbHVlcyA9IGVuZC5tYXRjaChfbnVtV2l0aFVuaXRFeHApIHx8IFtdO1xuXG4gIGlmIChlbmRWYWx1ZXMubGVuZ3RoKSB7XG4gICAgd2hpbGUgKHJlc3VsdCA9IF9udW1XaXRoVW5pdEV4cC5leGVjKGVuZCkpIHtcbiAgICAgIGVuZFZhbHVlID0gcmVzdWx0WzBdO1xuICAgICAgY2h1bmsgPSBlbmQuc3Vic3RyaW5nKGluZGV4LCByZXN1bHQuaW5kZXgpO1xuXG4gICAgICBpZiAoY29sb3IpIHtcbiAgICAgICAgY29sb3IgPSAoY29sb3IgKyAxKSAlIDU7XG4gICAgICB9IGVsc2UgaWYgKGNodW5rLnN1YnN0cigtNSkgPT09IFwicmdiYShcIiB8fCBjaHVuay5zdWJzdHIoLTUpID09PSBcImhzbGEoXCIpIHtcbiAgICAgICAgY29sb3IgPSAxO1xuICAgICAgfVxuXG4gICAgICBpZiAoZW5kVmFsdWUgIT09IChzdGFydFZhbHVlID0gc3RhcnRWYWx1ZXNbbWF0Y2hJbmRleCsrXSB8fCBcIlwiKSkge1xuICAgICAgICBzdGFydE51bSA9IHBhcnNlRmxvYXQoc3RhcnRWYWx1ZSkgfHwgMDtcbiAgICAgICAgc3RhcnRVbml0ID0gc3RhcnRWYWx1ZS5zdWJzdHIoKHN0YXJ0TnVtICsgXCJcIikubGVuZ3RoKTtcbiAgICAgICAgZW5kVmFsdWUuY2hhckF0KDEpID09PSBcIj1cIiAmJiAoZW5kVmFsdWUgPSBfcGFyc2VSZWxhdGl2ZShzdGFydE51bSwgZW5kVmFsdWUpICsgc3RhcnRVbml0KTtcbiAgICAgICAgZW5kTnVtID0gcGFyc2VGbG9hdChlbmRWYWx1ZSk7XG4gICAgICAgIGVuZFVuaXQgPSBlbmRWYWx1ZS5zdWJzdHIoKGVuZE51bSArIFwiXCIpLmxlbmd0aCk7XG4gICAgICAgIGluZGV4ID0gX251bVdpdGhVbml0RXhwLmxhc3RJbmRleCAtIGVuZFVuaXQubGVuZ3RoO1xuXG4gICAgICAgIGlmICghZW5kVW5pdCkge1xuICAgICAgICAgIC8vaWYgc29tZXRoaW5nIGxpa2UgXCJwZXJzcGVjdGl2ZTozMDBcIiBpcyBwYXNzZWQgaW4gYW5kIHdlIG11c3QgYWRkIGEgdW5pdCB0byB0aGUgZW5kXG4gICAgICAgICAgZW5kVW5pdCA9IGVuZFVuaXQgfHwgX2NvbmZpZy51bml0c1twcm9wXSB8fCBzdGFydFVuaXQ7XG5cbiAgICAgICAgICBpZiAoaW5kZXggPT09IGVuZC5sZW5ndGgpIHtcbiAgICAgICAgICAgIGVuZCArPSBlbmRVbml0O1xuICAgICAgICAgICAgcHQuZSArPSBlbmRVbml0O1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChzdGFydFVuaXQgIT09IGVuZFVuaXQpIHtcbiAgICAgICAgICBzdGFydE51bSA9IF9jb252ZXJ0VG9Vbml0KHRhcmdldCwgcHJvcCwgc3RhcnRWYWx1ZSwgZW5kVW5pdCkgfHwgMDtcbiAgICAgICAgfSAvLyB0aGVzZSBuZXN0ZWQgUHJvcFR3ZWVucyBhcmUgaGFuZGxlZCBpbiBhIHNwZWNpYWwgd2F5IC0gd2UnbGwgbmV2ZXIgYWN0dWFsbHkgY2FsbCBhIHJlbmRlciBvciBzZXR0ZXIgbWV0aG9kIG9uIHRoZW0uIFdlJ2xsIGp1c3QgbG9vcCB0aHJvdWdoIHRoZW0gaW4gdGhlIHBhcmVudCBjb21wbGV4IHN0cmluZyBQcm9wVHdlZW4ncyByZW5kZXIgbWV0aG9kLlxuXG5cbiAgICAgICAgcHQuX3B0ID0ge1xuICAgICAgICAgIF9uZXh0OiBwdC5fcHQsXG4gICAgICAgICAgcDogY2h1bmsgfHwgbWF0Y2hJbmRleCA9PT0gMSA/IGNodW5rIDogXCIsXCIsXG4gICAgICAgICAgLy9ub3RlOiBTVkcgc3BlYyBhbGxvd3Mgb21pc3Npb24gb2YgY29tbWEvc3BhY2Ugd2hlbiBhIG5lZ2F0aXZlIHNpZ24gaXMgd2VkZ2VkIGJldHdlZW4gdHdvIG51bWJlcnMsIGxpa2UgMi41LTUuMyBpbnN0ZWFkIG9mIDIuNSwtNS4zIGJ1dCB3aGVuIHR3ZWVuaW5nLCB0aGUgbmVnYXRpdmUgdmFsdWUgbWF5IHN3aXRjaCB0byBwb3NpdGl2ZSwgc28gd2UgaW5zZXJ0IHRoZSBjb21tYSBqdXN0IGluIGNhc2UuXG4gICAgICAgICAgczogc3RhcnROdW0sXG4gICAgICAgICAgYzogZW5kTnVtIC0gc3RhcnROdW0sXG4gICAgICAgICAgbTogY29sb3IgJiYgY29sb3IgPCA0IHx8IHByb3AgPT09IFwiekluZGV4XCIgPyBNYXRoLnJvdW5kIDogMFxuICAgICAgICB9O1xuICAgICAgfVxuICAgIH1cblxuICAgIHB0LmMgPSBpbmRleCA8IGVuZC5sZW5ndGggPyBlbmQuc3Vic3RyaW5nKGluZGV4LCBlbmQubGVuZ3RoKSA6IFwiXCI7IC8vd2UgdXNlIHRoZSBcImNcIiBvZiB0aGUgUHJvcFR3ZWVuIHRvIHN0b3JlIHRoZSBmaW5hbCBwYXJ0IG9mIHRoZSBzdHJpbmcgKGFmdGVyIHRoZSBsYXN0IG51bWJlcilcbiAgfSBlbHNlIHtcbiAgICBwdC5yID0gcHJvcCA9PT0gXCJkaXNwbGF5XCIgJiYgZW5kID09PSBcIm5vbmVcIiA/IF9yZW5kZXJOb25Ud2VlbmluZ1ZhbHVlT25seUF0RW5kIDogX3JlbmRlck5vblR3ZWVuaW5nVmFsdWU7XG4gIH1cblxuICBfcmVsRXhwLnRlc3QoZW5kKSAmJiAocHQuZSA9IDApOyAvL2lmIHRoZSBlbmQgc3RyaW5nIGNvbnRhaW5zIHJlbGF0aXZlIHZhbHVlcyBvciBkeW5hbWljIHJhbmRvbSguLi4pIHZhbHVlcywgZGVsZXRlIHRoZSBlbmQgaXQgc28gdGhhdCBvbiB0aGUgZmluYWwgcmVuZGVyIHdlIGRvbid0IGFjdHVhbGx5IHNldCBpdCB0byB0aGUgc3RyaW5nIHdpdGggKz0gb3IgLT0gY2hhcmFjdGVycyAoZm9yY2VzIGl0IHRvIHVzZSB0aGUgY2FsY3VsYXRlZCB2YWx1ZSkuXG5cbiAgdGhpcy5fcHQgPSBwdDsgLy9zdGFydCB0aGUgbGlua2VkIGxpc3Qgd2l0aCB0aGlzIG5ldyBQcm9wVHdlZW4uIFJlbWVtYmVyLCB3ZSBjYWxsIF90d2VlbkNvbXBsZXhDU1NTdHJpbmcuY2FsbChwbHVnaW5JbnN0YW5jZS4uLikgdG8gZW5zdXJlIHRoYXQgaXQncyBzY29wZWQgcHJvcGVybHkuIFdlIG1heSBjYWxsIGl0IGZyb20gd2l0aGluIGFub3RoZXIgcGx1Z2luIHRvbywgdGh1cyBcInRoaXNcIiB3b3VsZCByZWZlciB0byB0aGUgcGx1Z2luLlxuXG4gIHJldHVybiBwdDtcbn0sXG4gICAgX2tleXdvcmRUb1BlcmNlbnQgPSB7XG4gIHRvcDogXCIwJVwiLFxuICBib3R0b206IFwiMTAwJVwiLFxuICBsZWZ0OiBcIjAlXCIsXG4gIHJpZ2h0OiBcIjEwMCVcIixcbiAgY2VudGVyOiBcIjUwJVwiXG59LFxuICAgIF9jb252ZXJ0S2V5d29yZHNUb1BlcmNlbnRhZ2VzID0gZnVuY3Rpb24gX2NvbnZlcnRLZXl3b3Jkc1RvUGVyY2VudGFnZXModmFsdWUpIHtcbiAgdmFyIHNwbGl0ID0gdmFsdWUuc3BsaXQoXCIgXCIpLFxuICAgICAgeCA9IHNwbGl0WzBdLFxuICAgICAgeSA9IHNwbGl0WzFdIHx8IFwiNTAlXCI7XG5cbiAgaWYgKHggPT09IFwidG9wXCIgfHwgeCA9PT0gXCJib3R0b21cIiB8fCB5ID09PSBcImxlZnRcIiB8fCB5ID09PSBcInJpZ2h0XCIpIHtcbiAgICAvL3RoZSB1c2VyIHByb3ZpZGVkIHRoZW0gaW4gdGhlIHdyb25nIG9yZGVyLCBzbyBmbGlwIHRoZW1cbiAgICB2YWx1ZSA9IHg7XG4gICAgeCA9IHk7XG4gICAgeSA9IHZhbHVlO1xuICB9XG5cbiAgc3BsaXRbMF0gPSBfa2V5d29yZFRvUGVyY2VudFt4XSB8fCB4O1xuICBzcGxpdFsxXSA9IF9rZXl3b3JkVG9QZXJjZW50W3ldIHx8IHk7XG4gIHJldHVybiBzcGxpdC5qb2luKFwiIFwiKTtcbn0sXG4gICAgX3JlbmRlckNsZWFyUHJvcHMgPSBmdW5jdGlvbiBfcmVuZGVyQ2xlYXJQcm9wcyhyYXRpbywgZGF0YSkge1xuICBpZiAoZGF0YS50d2VlbiAmJiBkYXRhLnR3ZWVuLl90aW1lID09PSBkYXRhLnR3ZWVuLl9kdXIpIHtcbiAgICB2YXIgdGFyZ2V0ID0gZGF0YS50LFxuICAgICAgICBzdHlsZSA9IHRhcmdldC5zdHlsZSxcbiAgICAgICAgcHJvcHMgPSBkYXRhLnUsXG4gICAgICAgIGNhY2hlID0gdGFyZ2V0Ll9nc2FwLFxuICAgICAgICBwcm9wLFxuICAgICAgICBjbGVhclRyYW5zZm9ybXMsXG4gICAgICAgIGk7XG5cbiAgICBpZiAocHJvcHMgPT09IFwiYWxsXCIgfHwgcHJvcHMgPT09IHRydWUpIHtcbiAgICAgIHN0eWxlLmNzc1RleHQgPSBcIlwiO1xuICAgICAgY2xlYXJUcmFuc2Zvcm1zID0gMTtcbiAgICB9IGVsc2Uge1xuICAgICAgcHJvcHMgPSBwcm9wcy5zcGxpdChcIixcIik7XG4gICAgICBpID0gcHJvcHMubGVuZ3RoO1xuXG4gICAgICB3aGlsZSAoLS1pID4gLTEpIHtcbiAgICAgICAgcHJvcCA9IHByb3BzW2ldO1xuXG4gICAgICAgIGlmIChfdHJhbnNmb3JtUHJvcHNbcHJvcF0pIHtcbiAgICAgICAgICBjbGVhclRyYW5zZm9ybXMgPSAxO1xuICAgICAgICAgIHByb3AgPSBwcm9wID09PSBcInRyYW5zZm9ybU9yaWdpblwiID8gX3RyYW5zZm9ybU9yaWdpblByb3AgOiBfdHJhbnNmb3JtUHJvcDtcbiAgICAgICAgfVxuXG4gICAgICAgIF9yZW1vdmVQcm9wZXJ0eSh0YXJnZXQsIHByb3ApO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChjbGVhclRyYW5zZm9ybXMpIHtcbiAgICAgIF9yZW1vdmVQcm9wZXJ0eSh0YXJnZXQsIF90cmFuc2Zvcm1Qcm9wKTtcblxuICAgICAgaWYgKGNhY2hlKSB7XG4gICAgICAgIGNhY2hlLnN2ZyAmJiB0YXJnZXQucmVtb3ZlQXR0cmlidXRlKFwidHJhbnNmb3JtXCIpO1xuXG4gICAgICAgIF9wYXJzZVRyYW5zZm9ybSh0YXJnZXQsIDEpOyAvLyBmb3JjZSBhbGwgdGhlIGNhY2hlZCB2YWx1ZXMgYmFjayB0byBcIm5vcm1hbFwiL2lkZW50aXR5LCBvdGhlcndpc2UgaWYgdGhlcmUncyBhbm90aGVyIHR3ZWVuIHRoYXQncyBhbHJlYWR5IHNldCB0byByZW5kZXIgdHJhbnNmb3JtcyBvbiB0aGlzIGVsZW1lbnQsIGl0IGNvdWxkIGRpc3BsYXkgdGhlIHdyb25nIHZhbHVlcy5cblxuXG4gICAgICAgIGNhY2hlLnVuY2FjaGUgPSAxO1xuXG4gICAgICAgIF9yZW1vdmVJbmRlcGVuZGVudFRyYW5zZm9ybXMoc3R5bGUpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufSxcbiAgICAvLyBub3RlOiBzcGVjaWFsUHJvcHMgc2hvdWxkIHJldHVybiAxIGlmIChhbmQgb25seSBpZikgdGhleSBoYXZlIGEgbm9uLXplcm8gcHJpb3JpdHkuIEl0IGluZGljYXRlcyB3ZSBuZWVkIHRvIHNvcnQgdGhlIGxpbmtlZCBsaXN0LlxuX3NwZWNpYWxQcm9wcyA9IHtcbiAgY2xlYXJQcm9wczogZnVuY3Rpb24gY2xlYXJQcm9wcyhwbHVnaW4sIHRhcmdldCwgcHJvcGVydHksIGVuZFZhbHVlLCB0d2Vlbikge1xuICAgIGlmICh0d2Vlbi5kYXRhICE9PSBcImlzRnJvbVN0YXJ0XCIpIHtcbiAgICAgIHZhciBwdCA9IHBsdWdpbi5fcHQgPSBuZXcgUHJvcFR3ZWVuKHBsdWdpbi5fcHQsIHRhcmdldCwgcHJvcGVydHksIDAsIDAsIF9yZW5kZXJDbGVhclByb3BzKTtcbiAgICAgIHB0LnUgPSBlbmRWYWx1ZTtcbiAgICAgIHB0LnByID0gLTEwO1xuICAgICAgcHQudHdlZW4gPSB0d2VlbjtcblxuICAgICAgcGx1Z2luLl9wcm9wcy5wdXNoKHByb3BlcnR5KTtcblxuICAgICAgcmV0dXJuIDE7XG4gICAgfVxuICB9XG4gIC8qIGNsYXNzTmFtZSBmZWF0dXJlIChhYm91dCAwLjRrYiBnemlwcGVkKS5cbiAgLCBjbGFzc05hbWUocGx1Z2luLCB0YXJnZXQsIHByb3BlcnR5LCBlbmRWYWx1ZSwgdHdlZW4pIHtcbiAgXHRsZXQgX3JlbmRlckNsYXNzTmFtZSA9IChyYXRpbywgZGF0YSkgPT4ge1xuICBcdFx0XHRkYXRhLmNzcy5yZW5kZXIocmF0aW8sIGRhdGEuY3NzKTtcbiAgXHRcdFx0aWYgKCFyYXRpbyB8fCByYXRpbyA9PT0gMSkge1xuICBcdFx0XHRcdGxldCBpbmxpbmUgPSBkYXRhLnJtdixcbiAgXHRcdFx0XHRcdHRhcmdldCA9IGRhdGEudCxcbiAgXHRcdFx0XHRcdHA7XG4gIFx0XHRcdFx0dGFyZ2V0LnNldEF0dHJpYnV0ZShcImNsYXNzXCIsIHJhdGlvID8gZGF0YS5lIDogZGF0YS5iKTtcbiAgXHRcdFx0XHRmb3IgKHAgaW4gaW5saW5lKSB7XG4gIFx0XHRcdFx0XHRfcmVtb3ZlUHJvcGVydHkodGFyZ2V0LCBwKTtcbiAgXHRcdFx0XHR9XG4gIFx0XHRcdH1cbiAgXHRcdH0sXG4gIFx0XHRfZ2V0QWxsU3R5bGVzID0gKHRhcmdldCkgPT4ge1xuICBcdFx0XHRsZXQgc3R5bGVzID0ge30sXG4gIFx0XHRcdFx0Y29tcHV0ZWQgPSBnZXRDb21wdXRlZFN0eWxlKHRhcmdldCksXG4gIFx0XHRcdFx0cDtcbiAgXHRcdFx0Zm9yIChwIGluIGNvbXB1dGVkKSB7XG4gIFx0XHRcdFx0aWYgKGlzTmFOKHApICYmIHAgIT09IFwiY3NzVGV4dFwiICYmIHAgIT09IFwibGVuZ3RoXCIpIHtcbiAgXHRcdFx0XHRcdHN0eWxlc1twXSA9IGNvbXB1dGVkW3BdO1xuICBcdFx0XHRcdH1cbiAgXHRcdFx0fVxuICBcdFx0XHRfc2V0RGVmYXVsdHMoc3R5bGVzLCBfcGFyc2VUcmFuc2Zvcm0odGFyZ2V0LCAxKSk7XG4gIFx0XHRcdHJldHVybiBzdHlsZXM7XG4gIFx0XHR9LFxuICBcdFx0c3RhcnRDbGFzc0xpc3QgPSB0YXJnZXQuZ2V0QXR0cmlidXRlKFwiY2xhc3NcIiksXG4gIFx0XHRzdHlsZSA9IHRhcmdldC5zdHlsZSxcbiAgXHRcdGNzc1RleHQgPSBzdHlsZS5jc3NUZXh0LFxuICBcdFx0Y2FjaGUgPSB0YXJnZXQuX2dzYXAsXG4gIFx0XHRjbGFzc1BUID0gY2FjaGUuY2xhc3NQVCxcbiAgXHRcdGlubGluZVRvUmVtb3ZlQXRFbmQgPSB7fSxcbiAgXHRcdGRhdGEgPSB7dDp0YXJnZXQsIHBsdWdpbjpwbHVnaW4sIHJtdjppbmxpbmVUb1JlbW92ZUF0RW5kLCBiOnN0YXJ0Q2xhc3NMaXN0LCBlOihlbmRWYWx1ZS5jaGFyQXQoMSkgIT09IFwiPVwiKSA/IGVuZFZhbHVlIDogc3RhcnRDbGFzc0xpc3QucmVwbGFjZShuZXcgUmVnRXhwKFwiKD86XFxcXHN8XilcIiArIGVuZFZhbHVlLnN1YnN0cigyKSArIFwiKD8hW1xcXFx3LV0pXCIpLCBcIlwiKSArICgoZW5kVmFsdWUuY2hhckF0KDApID09PSBcIitcIikgPyBcIiBcIiArIGVuZFZhbHVlLnN1YnN0cigyKSA6IFwiXCIpfSxcbiAgXHRcdGNoYW5naW5nVmFycyA9IHt9LFxuICBcdFx0c3RhcnRWYXJzID0gX2dldEFsbFN0eWxlcyh0YXJnZXQpLFxuICBcdFx0dHJhbnNmb3JtUmVsYXRlZCA9IC8odHJhbnNmb3JtfHBlcnNwZWN0aXZlKS9pLFxuICBcdFx0ZW5kVmFycywgcDtcbiAgXHRpZiAoY2xhc3NQVCkge1xuICBcdFx0Y2xhc3NQVC5yKDEsIGNsYXNzUFQuZCk7XG4gIFx0XHRfcmVtb3ZlTGlua2VkTGlzdEl0ZW0oY2xhc3NQVC5kLnBsdWdpbiwgY2xhc3NQVCwgXCJfcHRcIik7XG4gIFx0fVxuICBcdHRhcmdldC5zZXRBdHRyaWJ1dGUoXCJjbGFzc1wiLCBkYXRhLmUpO1xuICBcdGVuZFZhcnMgPSBfZ2V0QWxsU3R5bGVzKHRhcmdldCwgdHJ1ZSk7XG4gIFx0dGFyZ2V0LnNldEF0dHJpYnV0ZShcImNsYXNzXCIsIHN0YXJ0Q2xhc3NMaXN0KTtcbiAgXHRmb3IgKHAgaW4gZW5kVmFycykge1xuICBcdFx0aWYgKGVuZFZhcnNbcF0gIT09IHN0YXJ0VmFyc1twXSAmJiAhdHJhbnNmb3JtUmVsYXRlZC50ZXN0KHApKSB7XG4gIFx0XHRcdGNoYW5naW5nVmFyc1twXSA9IGVuZFZhcnNbcF07XG4gIFx0XHRcdGlmICghc3R5bGVbcF0gJiYgc3R5bGVbcF0gIT09IFwiMFwiKSB7XG4gIFx0XHRcdFx0aW5saW5lVG9SZW1vdmVBdEVuZFtwXSA9IDE7XG4gIFx0XHRcdH1cbiAgXHRcdH1cbiAgXHR9XG4gIFx0Y2FjaGUuY2xhc3NQVCA9IHBsdWdpbi5fcHQgPSBuZXcgUHJvcFR3ZWVuKHBsdWdpbi5fcHQsIHRhcmdldCwgXCJjbGFzc05hbWVcIiwgMCwgMCwgX3JlbmRlckNsYXNzTmFtZSwgZGF0YSwgMCwgLTExKTtcbiAgXHRpZiAoc3R5bGUuY3NzVGV4dCAhPT0gY3NzVGV4dCkgeyAvL29ubHkgYXBwbHkgaWYgdGhpbmdzIGNoYW5nZS4gT3RoZXJ3aXNlLCBpbiBjYXNlcyBsaWtlIGEgYmFja2dyb3VuZC1pbWFnZSB0aGF0J3MgcHVsbGVkIGR5bmFtaWNhbGx5LCBpdCBjb3VsZCBjYXVzZSBhIHJlZnJlc2guIFNlZSBodHRwczovL2dzYXAuY29tL2ZvcnVtcy90b3BpYy8yMDM2OC1wb3NzaWJsZS1nc2FwLWJ1Zy1zd2l0Y2hpbmctY2xhc3NuYW1lcy1pbi1jaHJvbWUvLlxuICBcdFx0c3R5bGUuY3NzVGV4dCA9IGNzc1RleHQ7IC8vd2UgcmVjb3JkZWQgY3NzVGV4dCBiZWZvcmUgd2Ugc3dhcHBlZCBjbGFzc2VzIGFuZCByYW4gX2dldEFsbFN0eWxlcygpIGJlY2F1c2UgaW4gY2FzZXMgd2hlbiBhIGNsYXNzTmFtZSB0d2VlbiBpcyBvdmVyd3JpdHRlbiwgd2UgcmVtb3ZlIGFsbCB0aGUgcmVsYXRlZCB0d2VlbmluZyBwcm9wZXJ0aWVzIGZyb20gdGhhdCBjbGFzcyBjaGFuZ2UgKG90aGVyd2lzZSBjbGFzcy1zcGVjaWZpYyBzdHVmZiBjYW4ndCBvdmVycmlkZSBwcm9wZXJ0aWVzIHdlJ3ZlIGRpcmVjdGx5IHNldCBvbiB0aGUgdGFyZ2V0J3Mgc3R5bGUgb2JqZWN0IGR1ZSB0byBzcGVjaWZpY2l0eSkuXG4gIFx0fVxuICBcdF9wYXJzZVRyYW5zZm9ybSh0YXJnZXQsIHRydWUpOyAvL3RvIGNsZWFyIHRoZSBjYWNoaW5nIG9mIHRyYW5zZm9ybXNcbiAgXHRkYXRhLmNzcyA9IG5ldyBnc2FwLnBsdWdpbnMuY3NzKCk7XG4gIFx0ZGF0YS5jc3MuaW5pdCh0YXJnZXQsIGNoYW5naW5nVmFycywgdHdlZW4pO1xuICBcdHBsdWdpbi5fcHJvcHMucHVzaCguLi5kYXRhLmNzcy5fcHJvcHMpO1xuICBcdHJldHVybiAxO1xuICB9XG4gICovXG5cbn0sXG5cbi8qXG4gKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogVFJBTlNGT1JNU1xuICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqL1xuX2lkZW50aXR5MkRNYXRyaXggPSBbMSwgMCwgMCwgMSwgMCwgMF0sXG4gICAgX3JvdGF0aW9uYWxQcm9wZXJ0aWVzID0ge30sXG4gICAgX2lzTnVsbFRyYW5zZm9ybSA9IGZ1bmN0aW9uIF9pc051bGxUcmFuc2Zvcm0odmFsdWUpIHtcbiAgcmV0dXJuIHZhbHVlID09PSBcIm1hdHJpeCgxLCAwLCAwLCAxLCAwLCAwKVwiIHx8IHZhbHVlID09PSBcIm5vbmVcIiB8fCAhdmFsdWU7XG59LFxuICAgIF9nZXRDb21wdXRlZFRyYW5zZm9ybU1hdHJpeEFzQXJyYXkgPSBmdW5jdGlvbiBfZ2V0Q29tcHV0ZWRUcmFuc2Zvcm1NYXRyaXhBc0FycmF5KHRhcmdldCkge1xuICB2YXIgbWF0cml4U3RyaW5nID0gX2dldENvbXB1dGVkUHJvcGVydHkodGFyZ2V0LCBfdHJhbnNmb3JtUHJvcCk7XG5cbiAgcmV0dXJuIF9pc051bGxUcmFuc2Zvcm0obWF0cml4U3RyaW5nKSA/IF9pZGVudGl0eTJETWF0cml4IDogbWF0cml4U3RyaW5nLnN1YnN0cig3KS5tYXRjaChfbnVtRXhwKS5tYXAoX3JvdW5kKTtcbn0sXG4gICAgX2dldE1hdHJpeCA9IGZ1bmN0aW9uIF9nZXRNYXRyaXgodGFyZ2V0LCBmb3JjZTJEKSB7XG4gIHZhciBjYWNoZSA9IHRhcmdldC5fZ3NhcCB8fCBfZ2V0Q2FjaGUodGFyZ2V0KSxcbiAgICAgIHN0eWxlID0gdGFyZ2V0LnN0eWxlLFxuICAgICAgbWF0cml4ID0gX2dldENvbXB1dGVkVHJhbnNmb3JtTWF0cml4QXNBcnJheSh0YXJnZXQpLFxuICAgICAgcGFyZW50LFxuICAgICAgbmV4dFNpYmxpbmcsXG4gICAgICB0ZW1wLFxuICAgICAgYWRkZWRUb0RPTTtcblxuICBpZiAoY2FjaGUuc3ZnICYmIHRhcmdldC5nZXRBdHRyaWJ1dGUoXCJ0cmFuc2Zvcm1cIikpIHtcbiAgICB0ZW1wID0gdGFyZ2V0LnRyYW5zZm9ybS5iYXNlVmFsLmNvbnNvbGlkYXRlKCkubWF0cml4OyAvL2Vuc3VyZXMgdGhhdCBldmVuIGNvbXBsZXggdmFsdWVzIGxpa2UgXCJ0cmFuc2xhdGUoNTAsNjApIHJvdGF0ZSgxMzUsMCwwKVwiIGFyZSBwYXJzZWQgYmVjYXVzZSBpdCBtYXNoZXMgaXQgaW50byBhIG1hdHJpeC5cblxuICAgIG1hdHJpeCA9IFt0ZW1wLmEsIHRlbXAuYiwgdGVtcC5jLCB0ZW1wLmQsIHRlbXAuZSwgdGVtcC5mXTtcbiAgICByZXR1cm4gbWF0cml4LmpvaW4oXCIsXCIpID09PSBcIjEsMCwwLDEsMCwwXCIgPyBfaWRlbnRpdHkyRE1hdHJpeCA6IG1hdHJpeDtcbiAgfSBlbHNlIGlmIChtYXRyaXggPT09IF9pZGVudGl0eTJETWF0cml4ICYmICF0YXJnZXQub2Zmc2V0UGFyZW50ICYmIHRhcmdldCAhPT0gX2RvY0VsZW1lbnQgJiYgIWNhY2hlLnN2Zykge1xuICAgIC8vbm90ZTogaWYgb2Zmc2V0UGFyZW50IGlzIG51bGwsIHRoYXQgbWVhbnMgdGhlIGVsZW1lbnQgaXNuJ3QgaW4gdGhlIG5vcm1hbCBkb2N1bWVudCBmbG93LCBsaWtlIGlmIGl0IGhhcyBkaXNwbGF5Om5vbmUgb3Igb25lIG9mIGl0cyBhbmNlc3RvcnMgaGFzIGRpc3BsYXk6bm9uZSkuIEZpcmVmb3ggcmV0dXJucyBudWxsIGZvciBnZXRDb21wdXRlZFN0eWxlKCkgaWYgdGhlIGVsZW1lbnQgaXMgaW4gYW4gaWZyYW1lIHRoYXQgaGFzIGRpc3BsYXk6bm9uZS4gaHR0cHM6Ly9idWd6aWxsYS5tb3ppbGxhLm9yZy9zaG93X2J1Zy5jZ2k/aWQ9NTQ4Mzk3XG4gICAgLy9icm93c2VycyBkb24ndCByZXBvcnQgdHJhbnNmb3JtcyBhY2N1cmF0ZWx5IHVubGVzcyB0aGUgZWxlbWVudCBpcyBpbiB0aGUgRE9NIGFuZCBoYXMgYSBkaXNwbGF5IHZhbHVlIHRoYXQncyBub3QgXCJub25lXCIuIEZpcmVmb3ggYW5kIE1pY3Jvc29mdCBicm93c2VycyBoYXZlIGEgcGFydGlhbCBidWcgd2hlcmUgdGhleSdsbCByZXBvcnQgdHJhbnNmb3JtcyBldmVuIGlmIGRpc3BsYXk6bm9uZSBCVVQgbm90IGFueSBwZXJjZW50YWdlLWJhc2VkIHZhbHVlcyBsaWtlIHRyYW5zbGF0ZSgtNTAlLCA4cHgpIHdpbGwgYmUgcmVwb3J0ZWQgYXMgaWYgaXQncyB0cmFuc2xhdGUoMCwgOHB4KS5cbiAgICB0ZW1wID0gc3R5bGUuZGlzcGxheTtcbiAgICBzdHlsZS5kaXNwbGF5ID0gXCJibG9ja1wiO1xuICAgIHBhcmVudCA9IHRhcmdldC5wYXJlbnROb2RlO1xuXG4gICAgaWYgKCFwYXJlbnQgfHwgIXRhcmdldC5vZmZzZXRQYXJlbnQpIHtcbiAgICAgIC8vIG5vdGU6IGluIDMuMy4wIHdlIHN3aXRjaGVkIHRhcmdldC5vZmZzZXRQYXJlbnQgdG8gX2RvYy5ib2R5LmNvbnRhaW5zKHRhcmdldCkgdG8gYXZvaWQgW3NvbWV0aW1lcyB1bm5lY2Vzc2FyeV0gTXV0YXRpb25PYnNlcnZlciBjYWxscyBidXQgdGhhdCB3YXNuJ3QgYWRlcXVhdGUgYmVjYXVzZSB0aGVyZSBhcmUgZWRnZSBjYXNlcyB3aGVyZSBuZXN0ZWQgcG9zaXRpb246IGZpeGVkIGVsZW1lbnRzIG5lZWQgdG8gZ2V0IHJlcGFyZW50ZWQgdG8gYWNjdXJhdGVseSBzZW5zZSB0cmFuc2Zvcm1zLiBTZWUgaHR0cHM6Ly9naXRodWIuY29tL2dyZWVuc29jay9HU0FQL2lzc3Vlcy8zODggYW5kIGh0dHBzOi8vZ2l0aHViLmNvbS9ncmVlbnNvY2svR1NBUC9pc3N1ZXMvMzc1XG4gICAgICBhZGRlZFRvRE9NID0gMTsgLy9mbGFnXG5cbiAgICAgIG5leHRTaWJsaW5nID0gdGFyZ2V0Lm5leHRFbGVtZW50U2libGluZztcblxuICAgICAgX2RvY0VsZW1lbnQuYXBwZW5kQ2hpbGQodGFyZ2V0KTsgLy93ZSBtdXN0IGFkZCBpdCB0byB0aGUgRE9NIGluIG9yZGVyIHRvIGdldCB2YWx1ZXMgcHJvcGVybHlcblxuICAgIH1cblxuICAgIG1hdHJpeCA9IF9nZXRDb21wdXRlZFRyYW5zZm9ybU1hdHJpeEFzQXJyYXkodGFyZ2V0KTtcbiAgICB0ZW1wID8gc3R5bGUuZGlzcGxheSA9IHRlbXAgOiBfcmVtb3ZlUHJvcGVydHkodGFyZ2V0LCBcImRpc3BsYXlcIik7XG5cbiAgICBpZiAoYWRkZWRUb0RPTSkge1xuICAgICAgbmV4dFNpYmxpbmcgPyBwYXJlbnQuaW5zZXJ0QmVmb3JlKHRhcmdldCwgbmV4dFNpYmxpbmcpIDogcGFyZW50ID8gcGFyZW50LmFwcGVuZENoaWxkKHRhcmdldCkgOiBfZG9jRWxlbWVudC5yZW1vdmVDaGlsZCh0YXJnZXQpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBmb3JjZTJEICYmIG1hdHJpeC5sZW5ndGggPiA2ID8gW21hdHJpeFswXSwgbWF0cml4WzFdLCBtYXRyaXhbNF0sIG1hdHJpeFs1XSwgbWF0cml4WzEyXSwgbWF0cml4WzEzXV0gOiBtYXRyaXg7XG59LFxuICAgIF9hcHBseVNWR09yaWdpbiA9IGZ1bmN0aW9uIF9hcHBseVNWR09yaWdpbih0YXJnZXQsIG9yaWdpbiwgb3JpZ2luSXNBYnNvbHV0ZSwgc21vb3RoLCBtYXRyaXhBcnJheSwgcGx1Z2luVG9BZGRQcm9wVHdlZW5zVG8pIHtcbiAgdmFyIGNhY2hlID0gdGFyZ2V0Ll9nc2FwLFxuICAgICAgbWF0cml4ID0gbWF0cml4QXJyYXkgfHwgX2dldE1hdHJpeCh0YXJnZXQsIHRydWUpLFxuICAgICAgeE9yaWdpbk9sZCA9IGNhY2hlLnhPcmlnaW4gfHwgMCxcbiAgICAgIHlPcmlnaW5PbGQgPSBjYWNoZS55T3JpZ2luIHx8IDAsXG4gICAgICB4T2Zmc2V0T2xkID0gY2FjaGUueE9mZnNldCB8fCAwLFxuICAgICAgeU9mZnNldE9sZCA9IGNhY2hlLnlPZmZzZXQgfHwgMCxcbiAgICAgIGEgPSBtYXRyaXhbMF0sXG4gICAgICBiID0gbWF0cml4WzFdLFxuICAgICAgYyA9IG1hdHJpeFsyXSxcbiAgICAgIGQgPSBtYXRyaXhbM10sXG4gICAgICB0eCA9IG1hdHJpeFs0XSxcbiAgICAgIHR5ID0gbWF0cml4WzVdLFxuICAgICAgb3JpZ2luU3BsaXQgPSBvcmlnaW4uc3BsaXQoXCIgXCIpLFxuICAgICAgeE9yaWdpbiA9IHBhcnNlRmxvYXQob3JpZ2luU3BsaXRbMF0pIHx8IDAsXG4gICAgICB5T3JpZ2luID0gcGFyc2VGbG9hdChvcmlnaW5TcGxpdFsxXSkgfHwgMCxcbiAgICAgIGJvdW5kcyxcbiAgICAgIGRldGVybWluYW50LFxuICAgICAgeCxcbiAgICAgIHk7XG5cbiAgaWYgKCFvcmlnaW5Jc0Fic29sdXRlKSB7XG4gICAgYm91bmRzID0gX2dldEJCb3godGFyZ2V0KTtcbiAgICB4T3JpZ2luID0gYm91bmRzLnggKyAofm9yaWdpblNwbGl0WzBdLmluZGV4T2YoXCIlXCIpID8geE9yaWdpbiAvIDEwMCAqIGJvdW5kcy53aWR0aCA6IHhPcmlnaW4pO1xuICAgIHlPcmlnaW4gPSBib3VuZHMueSArICh+KG9yaWdpblNwbGl0WzFdIHx8IG9yaWdpblNwbGl0WzBdKS5pbmRleE9mKFwiJVwiKSA/IHlPcmlnaW4gLyAxMDAgKiBib3VuZHMuaGVpZ2h0IDogeU9yaWdpbik7IC8vIGlmICghKFwieE9yaWdpblwiIGluIGNhY2hlKSAmJiAoeE9yaWdpbiB8fCB5T3JpZ2luKSkgeyAvLyBhZGRlZCBpbiAzLjEyLjMsIHJldmVydGVkIGluIDMuMTIuNDsgcmVxdWlyZXMgbW9yZSBleHBsb3JhdGlvblxuICAgIC8vIFx0eE9yaWdpbiAtPSBib3VuZHMueDtcbiAgICAvLyBcdHlPcmlnaW4gLT0gYm91bmRzLnk7XG4gICAgLy8gfVxuICB9IGVsc2UgaWYgKG1hdHJpeCAhPT0gX2lkZW50aXR5MkRNYXRyaXggJiYgKGRldGVybWluYW50ID0gYSAqIGQgLSBiICogYykpIHtcbiAgICAvL2lmIGl0J3MgemVybyAobGlrZSBpZiBzY2FsZVggYW5kIHNjYWxlWSBhcmUgemVybyksIHNraXAgaXQgdG8gYXZvaWQgZXJyb3JzIHdpdGggZGl2aWRpbmcgYnkgemVyby5cbiAgICB4ID0geE9yaWdpbiAqIChkIC8gZGV0ZXJtaW5hbnQpICsgeU9yaWdpbiAqICgtYyAvIGRldGVybWluYW50KSArIChjICogdHkgLSBkICogdHgpIC8gZGV0ZXJtaW5hbnQ7XG4gICAgeSA9IHhPcmlnaW4gKiAoLWIgLyBkZXRlcm1pbmFudCkgKyB5T3JpZ2luICogKGEgLyBkZXRlcm1pbmFudCkgLSAoYSAqIHR5IC0gYiAqIHR4KSAvIGRldGVybWluYW50O1xuICAgIHhPcmlnaW4gPSB4O1xuICAgIHlPcmlnaW4gPSB5OyAvLyB0aGVvcnk6IHdlIG9ubHkgaGFkIHRvIGRvIHRoaXMgZm9yIHNtb290aGluZyBhbmQgaXQgYXNzdW1lcyB0aGF0IHRoZSBwcmV2aW91cyBvbmUgd2FzIG5vdCBvcmlnaW5Jc0Fic29sdXRlLlxuICB9XG5cbiAgaWYgKHNtb290aCB8fCBzbW9vdGggIT09IGZhbHNlICYmIGNhY2hlLnNtb290aCkge1xuICAgIHR4ID0geE9yaWdpbiAtIHhPcmlnaW5PbGQ7XG4gICAgdHkgPSB5T3JpZ2luIC0geU9yaWdpbk9sZDtcbiAgICBjYWNoZS54T2Zmc2V0ID0geE9mZnNldE9sZCArICh0eCAqIGEgKyB0eSAqIGMpIC0gdHg7XG4gICAgY2FjaGUueU9mZnNldCA9IHlPZmZzZXRPbGQgKyAodHggKiBiICsgdHkgKiBkKSAtIHR5O1xuICB9IGVsc2Uge1xuICAgIGNhY2hlLnhPZmZzZXQgPSBjYWNoZS55T2Zmc2V0ID0gMDtcbiAgfVxuXG4gIGNhY2hlLnhPcmlnaW4gPSB4T3JpZ2luO1xuICBjYWNoZS55T3JpZ2luID0geU9yaWdpbjtcbiAgY2FjaGUuc21vb3RoID0gISFzbW9vdGg7XG4gIGNhY2hlLm9yaWdpbiA9IG9yaWdpbjtcbiAgY2FjaGUub3JpZ2luSXNBYnNvbHV0ZSA9ICEhb3JpZ2luSXNBYnNvbHV0ZTtcbiAgdGFyZ2V0LnN0eWxlW190cmFuc2Zvcm1PcmlnaW5Qcm9wXSA9IFwiMHB4IDBweFwiOyAvL290aGVyd2lzZSwgaWYgc29tZW9uZSBzZXRzICBhbiBvcmlnaW4gdmlhIENTUywgaXQgd2lsbCBsaWtlbHkgaW50ZXJmZXJlIHdpdGggdGhlIFNWRyB0cmFuc2Zvcm0gYXR0cmlidXRlIG9uZXMgKGJlY2F1c2UgcmVtZW1iZXIsIHdlJ3JlIGJha2luZyB0aGUgb3JpZ2luIGludG8gdGhlIG1hdHJpeCgpIHZhbHVlKS5cblxuICBpZiAocGx1Z2luVG9BZGRQcm9wVHdlZW5zVG8pIHtcbiAgICBfYWRkTm9uVHdlZW5pbmdQVChwbHVnaW5Ub0FkZFByb3BUd2VlbnNUbywgY2FjaGUsIFwieE9yaWdpblwiLCB4T3JpZ2luT2xkLCB4T3JpZ2luKTtcblxuICAgIF9hZGROb25Ud2VlbmluZ1BUKHBsdWdpblRvQWRkUHJvcFR3ZWVuc1RvLCBjYWNoZSwgXCJ5T3JpZ2luXCIsIHlPcmlnaW5PbGQsIHlPcmlnaW4pO1xuXG4gICAgX2FkZE5vblR3ZWVuaW5nUFQocGx1Z2luVG9BZGRQcm9wVHdlZW5zVG8sIGNhY2hlLCBcInhPZmZzZXRcIiwgeE9mZnNldE9sZCwgY2FjaGUueE9mZnNldCk7XG5cbiAgICBfYWRkTm9uVHdlZW5pbmdQVChwbHVnaW5Ub0FkZFByb3BUd2VlbnNUbywgY2FjaGUsIFwieU9mZnNldFwiLCB5T2Zmc2V0T2xkLCBjYWNoZS55T2Zmc2V0KTtcbiAgfVxuXG4gIHRhcmdldC5zZXRBdHRyaWJ1dGUoXCJkYXRhLXN2Zy1vcmlnaW5cIiwgeE9yaWdpbiArIFwiIFwiICsgeU9yaWdpbik7XG59LFxuICAgIF9wYXJzZVRyYW5zZm9ybSA9IGZ1bmN0aW9uIF9wYXJzZVRyYW5zZm9ybSh0YXJnZXQsIHVuY2FjaGUpIHtcbiAgdmFyIGNhY2hlID0gdGFyZ2V0Ll9nc2FwIHx8IG5ldyBHU0NhY2hlKHRhcmdldCk7XG5cbiAgaWYgKFwieFwiIGluIGNhY2hlICYmICF1bmNhY2hlICYmICFjYWNoZS51bmNhY2hlKSB7XG4gICAgcmV0dXJuIGNhY2hlO1xuICB9XG5cbiAgdmFyIHN0eWxlID0gdGFyZ2V0LnN0eWxlLFxuICAgICAgaW52ZXJ0ZWRTY2FsZVggPSBjYWNoZS5zY2FsZVggPCAwLFxuICAgICAgcHggPSBcInB4XCIsXG4gICAgICBkZWcgPSBcImRlZ1wiLFxuICAgICAgY3MgPSBnZXRDb21wdXRlZFN0eWxlKHRhcmdldCksXG4gICAgICBvcmlnaW4gPSBfZ2V0Q29tcHV0ZWRQcm9wZXJ0eSh0YXJnZXQsIF90cmFuc2Zvcm1PcmlnaW5Qcm9wKSB8fCBcIjBcIixcbiAgICAgIHgsXG4gICAgICB5LFxuICAgICAgeixcbiAgICAgIHNjYWxlWCxcbiAgICAgIHNjYWxlWSxcbiAgICAgIHJvdGF0aW9uLFxuICAgICAgcm90YXRpb25YLFxuICAgICAgcm90YXRpb25ZLFxuICAgICAgc2tld1gsXG4gICAgICBza2V3WSxcbiAgICAgIHBlcnNwZWN0aXZlLFxuICAgICAgeE9yaWdpbixcbiAgICAgIHlPcmlnaW4sXG4gICAgICBtYXRyaXgsXG4gICAgICBhbmdsZSxcbiAgICAgIGNvcyxcbiAgICAgIHNpbixcbiAgICAgIGEsXG4gICAgICBiLFxuICAgICAgYyxcbiAgICAgIGQsXG4gICAgICBhMTIsXG4gICAgICBhMjIsXG4gICAgICB0MSxcbiAgICAgIHQyLFxuICAgICAgdDMsXG4gICAgICBhMTMsXG4gICAgICBhMjMsXG4gICAgICBhMzMsXG4gICAgICBhNDIsXG4gICAgICBhNDMsXG4gICAgICBhMzI7XG4gIHggPSB5ID0geiA9IHJvdGF0aW9uID0gcm90YXRpb25YID0gcm90YXRpb25ZID0gc2tld1ggPSBza2V3WSA9IHBlcnNwZWN0aXZlID0gMDtcbiAgc2NhbGVYID0gc2NhbGVZID0gMTtcbiAgY2FjaGUuc3ZnID0gISEodGFyZ2V0LmdldENUTSAmJiBfaXNTVkcodGFyZ2V0KSk7XG5cbiAgaWYgKGNzLnRyYW5zbGF0ZSkge1xuICAgIC8vIGFjY29tbW9kYXRlIGluZGVwZW5kZW50IHRyYW5zZm9ybXMgYnkgY29tYmluaW5nIHRoZW0gaW50byBub3JtYWwgb25lcy5cbiAgICBpZiAoY3MudHJhbnNsYXRlICE9PSBcIm5vbmVcIiB8fCBjcy5zY2FsZSAhPT0gXCJub25lXCIgfHwgY3Mucm90YXRlICE9PSBcIm5vbmVcIikge1xuICAgICAgc3R5bGVbX3RyYW5zZm9ybVByb3BdID0gKGNzLnRyYW5zbGF0ZSAhPT0gXCJub25lXCIgPyBcInRyYW5zbGF0ZTNkKFwiICsgKGNzLnRyYW5zbGF0ZSArIFwiIDAgMFwiKS5zcGxpdChcIiBcIikuc2xpY2UoMCwgMykuam9pbihcIiwgXCIpICsgXCIpIFwiIDogXCJcIikgKyAoY3Mucm90YXRlICE9PSBcIm5vbmVcIiA/IFwicm90YXRlKFwiICsgY3Mucm90YXRlICsgXCIpIFwiIDogXCJcIikgKyAoY3Muc2NhbGUgIT09IFwibm9uZVwiID8gXCJzY2FsZShcIiArIGNzLnNjYWxlLnNwbGl0KFwiIFwiKS5qb2luKFwiLFwiKSArIFwiKSBcIiA6IFwiXCIpICsgKGNzW190cmFuc2Zvcm1Qcm9wXSAhPT0gXCJub25lXCIgPyBjc1tfdHJhbnNmb3JtUHJvcF0gOiBcIlwiKTtcbiAgICB9XG5cbiAgICBzdHlsZS5zY2FsZSA9IHN0eWxlLnJvdGF0ZSA9IHN0eWxlLnRyYW5zbGF0ZSA9IFwibm9uZVwiO1xuICB9XG5cbiAgbWF0cml4ID0gX2dldE1hdHJpeCh0YXJnZXQsIGNhY2hlLnN2Zyk7XG5cbiAgaWYgKGNhY2hlLnN2Zykge1xuICAgIGlmIChjYWNoZS51bmNhY2hlKSB7XG4gICAgICAvLyBpZiBjYWNoZS51bmNhY2hlIGlzIHRydWUgKGFuZCBtYXliZSBpZiBvcmlnaW4gaXMgMCwwKSwgd2UgbmVlZCB0byBzZXQgZWxlbWVudC5zdHlsZS50cmFuc2Zvcm1PcmlnaW4gPSAoY2FjaGUueE9yaWdpbiAtIGJib3gueCkgKyBcInB4IFwiICsgKGNhY2hlLnlPcmlnaW4gLSBiYm94LnkpICsgXCJweFwiLiBQcmV2aW91c2x5IHdlIGxldCB0aGUgZGF0YS1zdmctb3JpZ2luIHN0YXkgaW5zdGVhZCwgYnV0IHdoZW4gaW50cm9kdWNpbmcgcmV2ZXJ0KCksIGl0IGNvbXBsaWNhdGVkIHRoaW5ncy5cbiAgICAgIHQyID0gdGFyZ2V0LmdldEJCb3goKTtcbiAgICAgIG9yaWdpbiA9IGNhY2hlLnhPcmlnaW4gLSB0Mi54ICsgXCJweCBcIiArIChjYWNoZS55T3JpZ2luIC0gdDIueSkgKyBcInB4XCI7XG4gICAgICB0MSA9IFwiXCI7XG4gICAgfSBlbHNlIHtcbiAgICAgIHQxID0gIXVuY2FjaGUgJiYgdGFyZ2V0LmdldEF0dHJpYnV0ZShcImRhdGEtc3ZnLW9yaWdpblwiKTsgLy8gIFJlbWVtYmVyLCB0byB3b3JrIGFyb3VuZCBicm93c2VyIGluY29uc2lzdGVuY2llcyB3ZSBhbHdheXMgZm9yY2UgU1ZHIGVsZW1lbnRzJyB0cmFuc2Zvcm1PcmlnaW4gdG8gMCwwIGFuZCBvZmZzZXQgdGhlIHRyYW5zbGF0aW9uIGFjY29yZGluZ2x5LlxuICAgIH1cblxuICAgIF9hcHBseVNWR09yaWdpbih0YXJnZXQsIHQxIHx8IG9yaWdpbiwgISF0MSB8fCBjYWNoZS5vcmlnaW5Jc0Fic29sdXRlLCBjYWNoZS5zbW9vdGggIT09IGZhbHNlLCBtYXRyaXgpO1xuICB9XG5cbiAgeE9yaWdpbiA9IGNhY2hlLnhPcmlnaW4gfHwgMDtcbiAgeU9yaWdpbiA9IGNhY2hlLnlPcmlnaW4gfHwgMDtcblxuICBpZiAobWF0cml4ICE9PSBfaWRlbnRpdHkyRE1hdHJpeCkge1xuICAgIGEgPSBtYXRyaXhbMF07IC8vYTExXG5cbiAgICBiID0gbWF0cml4WzFdOyAvL2EyMVxuXG4gICAgYyA9IG1hdHJpeFsyXTsgLy9hMzFcblxuICAgIGQgPSBtYXRyaXhbM107IC8vYTQxXG5cbiAgICB4ID0gYTEyID0gbWF0cml4WzRdO1xuICAgIHkgPSBhMjIgPSBtYXRyaXhbNV07IC8vMkQgbWF0cml4XG5cbiAgICBpZiAobWF0cml4Lmxlbmd0aCA9PT0gNikge1xuICAgICAgc2NhbGVYID0gTWF0aC5zcXJ0KGEgKiBhICsgYiAqIGIpO1xuICAgICAgc2NhbGVZID0gTWF0aC5zcXJ0KGQgKiBkICsgYyAqIGMpO1xuICAgICAgcm90YXRpb24gPSBhIHx8IGIgPyBfYXRhbjIoYiwgYSkgKiBfUkFEMkRFRyA6IDA7IC8vbm90ZTogaWYgc2NhbGVYIGlzIDAsIHdlIGNhbm5vdCBhY2N1cmF0ZWx5IG1lYXN1cmUgcm90YXRpb24uIFNhbWUgZm9yIHNrZXdYIHdpdGggYSBzY2FsZVkgb2YgMC4gVGhlcmVmb3JlLCB3ZSBkZWZhdWx0IHRvIHRoZSBwcmV2aW91c2x5IHJlY29yZGVkIHZhbHVlIChvciB6ZXJvIGlmIHRoYXQgZG9lc24ndCBleGlzdCkuXG5cbiAgICAgIHNrZXdYID0gYyB8fCBkID8gX2F0YW4yKGMsIGQpICogX1JBRDJERUcgKyByb3RhdGlvbiA6IDA7XG4gICAgICBza2V3WCAmJiAoc2NhbGVZICo9IE1hdGguYWJzKE1hdGguY29zKHNrZXdYICogX0RFRzJSQUQpKSk7XG5cbiAgICAgIGlmIChjYWNoZS5zdmcpIHtcbiAgICAgICAgeCAtPSB4T3JpZ2luIC0gKHhPcmlnaW4gKiBhICsgeU9yaWdpbiAqIGMpO1xuICAgICAgICB5IC09IHlPcmlnaW4gLSAoeE9yaWdpbiAqIGIgKyB5T3JpZ2luICogZCk7XG4gICAgICB9IC8vM0QgbWF0cml4XG5cbiAgICB9IGVsc2Uge1xuICAgICAgYTMyID0gbWF0cml4WzZdO1xuICAgICAgYTQyID0gbWF0cml4WzddO1xuICAgICAgYTEzID0gbWF0cml4WzhdO1xuICAgICAgYTIzID0gbWF0cml4WzldO1xuICAgICAgYTMzID0gbWF0cml4WzEwXTtcbiAgICAgIGE0MyA9IG1hdHJpeFsxMV07XG4gICAgICB4ID0gbWF0cml4WzEyXTtcbiAgICAgIHkgPSBtYXRyaXhbMTNdO1xuICAgICAgeiA9IG1hdHJpeFsxNF07XG4gICAgICBhbmdsZSA9IF9hdGFuMihhMzIsIGEzMyk7XG4gICAgICByb3RhdGlvblggPSBhbmdsZSAqIF9SQUQyREVHOyAvL3JvdGF0aW9uWFxuXG4gICAgICBpZiAoYW5nbGUpIHtcbiAgICAgICAgY29zID0gTWF0aC5jb3MoLWFuZ2xlKTtcbiAgICAgICAgc2luID0gTWF0aC5zaW4oLWFuZ2xlKTtcbiAgICAgICAgdDEgPSBhMTIgKiBjb3MgKyBhMTMgKiBzaW47XG4gICAgICAgIHQyID0gYTIyICogY29zICsgYTIzICogc2luO1xuICAgICAgICB0MyA9IGEzMiAqIGNvcyArIGEzMyAqIHNpbjtcbiAgICAgICAgYTEzID0gYTEyICogLXNpbiArIGExMyAqIGNvcztcbiAgICAgICAgYTIzID0gYTIyICogLXNpbiArIGEyMyAqIGNvcztcbiAgICAgICAgYTMzID0gYTMyICogLXNpbiArIGEzMyAqIGNvcztcbiAgICAgICAgYTQzID0gYTQyICogLXNpbiArIGE0MyAqIGNvcztcbiAgICAgICAgYTEyID0gdDE7XG4gICAgICAgIGEyMiA9IHQyO1xuICAgICAgICBhMzIgPSB0MztcbiAgICAgIH0gLy9yb3RhdGlvbllcblxuXG4gICAgICBhbmdsZSA9IF9hdGFuMigtYywgYTMzKTtcbiAgICAgIHJvdGF0aW9uWSA9IGFuZ2xlICogX1JBRDJERUc7XG5cbiAgICAgIGlmIChhbmdsZSkge1xuICAgICAgICBjb3MgPSBNYXRoLmNvcygtYW5nbGUpO1xuICAgICAgICBzaW4gPSBNYXRoLnNpbigtYW5nbGUpO1xuICAgICAgICB0MSA9IGEgKiBjb3MgLSBhMTMgKiBzaW47XG4gICAgICAgIHQyID0gYiAqIGNvcyAtIGEyMyAqIHNpbjtcbiAgICAgICAgdDMgPSBjICogY29zIC0gYTMzICogc2luO1xuICAgICAgICBhNDMgPSBkICogc2luICsgYTQzICogY29zO1xuICAgICAgICBhID0gdDE7XG4gICAgICAgIGIgPSB0MjtcbiAgICAgICAgYyA9IHQzO1xuICAgICAgfSAvL3JvdGF0aW9uWlxuXG5cbiAgICAgIGFuZ2xlID0gX2F0YW4yKGIsIGEpO1xuICAgICAgcm90YXRpb24gPSBhbmdsZSAqIF9SQUQyREVHO1xuXG4gICAgICBpZiAoYW5nbGUpIHtcbiAgICAgICAgY29zID0gTWF0aC5jb3MoYW5nbGUpO1xuICAgICAgICBzaW4gPSBNYXRoLnNpbihhbmdsZSk7XG4gICAgICAgIHQxID0gYSAqIGNvcyArIGIgKiBzaW47XG4gICAgICAgIHQyID0gYTEyICogY29zICsgYTIyICogc2luO1xuICAgICAgICBiID0gYiAqIGNvcyAtIGEgKiBzaW47XG4gICAgICAgIGEyMiA9IGEyMiAqIGNvcyAtIGExMiAqIHNpbjtcbiAgICAgICAgYSA9IHQxO1xuICAgICAgICBhMTIgPSB0MjtcbiAgICAgIH1cblxuICAgICAgaWYgKHJvdGF0aW9uWCAmJiBNYXRoLmFicyhyb3RhdGlvblgpICsgTWF0aC5hYnMocm90YXRpb24pID4gMzU5LjkpIHtcbiAgICAgICAgLy93aGVuIHJvdGF0aW9uWSBpcyBzZXQsIGl0IHdpbGwgb2Z0ZW4gYmUgcGFyc2VkIGFzIDE4MCBkZWdyZWVzIGRpZmZlcmVudCB0aGFuIGl0IHNob3VsZCBiZSwgYW5kIHJvdGF0aW9uWCBhbmQgcm90YXRpb24gYm90aCBiZWluZyAxODAgKGl0IGxvb2tzIHRoZSBzYW1lKSwgc28gd2UgYWRqdXN0IGZvciB0aGF0IGhlcmUuXG4gICAgICAgIHJvdGF0aW9uWCA9IHJvdGF0aW9uID0gMDtcbiAgICAgICAgcm90YXRpb25ZID0gMTgwIC0gcm90YXRpb25ZO1xuICAgICAgfVxuXG4gICAgICBzY2FsZVggPSBfcm91bmQoTWF0aC5zcXJ0KGEgKiBhICsgYiAqIGIgKyBjICogYykpO1xuICAgICAgc2NhbGVZID0gX3JvdW5kKE1hdGguc3FydChhMjIgKiBhMjIgKyBhMzIgKiBhMzIpKTtcbiAgICAgIGFuZ2xlID0gX2F0YW4yKGExMiwgYTIyKTtcbiAgICAgIHNrZXdYID0gTWF0aC5hYnMoYW5nbGUpID4gMC4wMDAyID8gYW5nbGUgKiBfUkFEMkRFRyA6IDA7XG4gICAgICBwZXJzcGVjdGl2ZSA9IGE0MyA/IDEgLyAoYTQzIDwgMCA/IC1hNDMgOiBhNDMpIDogMDtcbiAgICB9XG5cbiAgICBpZiAoY2FjaGUuc3ZnKSB7XG4gICAgICAvL3NlbnNlIGlmIHRoZXJlIGFyZSBDU1MgdHJhbnNmb3JtcyBhcHBsaWVkIG9uIGFuIFNWRyBlbGVtZW50IGluIHdoaWNoIGNhc2Ugd2UgbXVzdCBvdmVyd3JpdGUgdGhlbSB3aGVuIHJlbmRlcmluZy4gVGhlIHRyYW5zZm9ybSBhdHRyaWJ1dGUgaXMgbW9yZSByZWxpYWJsZSBjcm9zcy1icm93c2VyLCBidXQgd2UgY2FuJ3QganVzdCByZW1vdmUgdGhlIENTUyBvbmVzIGJlY2F1c2UgdGhleSBtYXkgYmUgYXBwbGllZCBpbiBhIENTUyBydWxlIHNvbWV3aGVyZSAobm90IGp1c3QgaW5saW5lKS5cbiAgICAgIHQxID0gdGFyZ2V0LmdldEF0dHJpYnV0ZShcInRyYW5zZm9ybVwiKTtcbiAgICAgIGNhY2hlLmZvcmNlQ1NTID0gdGFyZ2V0LnNldEF0dHJpYnV0ZShcInRyYW5zZm9ybVwiLCBcIlwiKSB8fCAhX2lzTnVsbFRyYW5zZm9ybShfZ2V0Q29tcHV0ZWRQcm9wZXJ0eSh0YXJnZXQsIF90cmFuc2Zvcm1Qcm9wKSk7XG4gICAgICB0MSAmJiB0YXJnZXQuc2V0QXR0cmlidXRlKFwidHJhbnNmb3JtXCIsIHQxKTtcbiAgICB9XG4gIH1cblxuICBpZiAoTWF0aC5hYnMoc2tld1gpID4gOTAgJiYgTWF0aC5hYnMoc2tld1gpIDwgMjcwKSB7XG4gICAgaWYgKGludmVydGVkU2NhbGVYKSB7XG4gICAgICBzY2FsZVggKj0gLTE7XG4gICAgICBza2V3WCArPSByb3RhdGlvbiA8PSAwID8gMTgwIDogLTE4MDtcbiAgICAgIHJvdGF0aW9uICs9IHJvdGF0aW9uIDw9IDAgPyAxODAgOiAtMTgwO1xuICAgIH0gZWxzZSB7XG4gICAgICBzY2FsZVkgKj0gLTE7XG4gICAgICBza2V3WCArPSBza2V3WCA8PSAwID8gMTgwIDogLTE4MDtcbiAgICB9XG4gIH1cblxuICB1bmNhY2hlID0gdW5jYWNoZSB8fCBjYWNoZS51bmNhY2hlO1xuICBjYWNoZS54ID0geCAtICgoY2FjaGUueFBlcmNlbnQgPSB4ICYmICghdW5jYWNoZSAmJiBjYWNoZS54UGVyY2VudCB8fCAoTWF0aC5yb3VuZCh0YXJnZXQub2Zmc2V0V2lkdGggLyAyKSA9PT0gTWF0aC5yb3VuZCgteCkgPyAtNTAgOiAwKSkpID8gdGFyZ2V0Lm9mZnNldFdpZHRoICogY2FjaGUueFBlcmNlbnQgLyAxMDAgOiAwKSArIHB4O1xuICBjYWNoZS55ID0geSAtICgoY2FjaGUueVBlcmNlbnQgPSB5ICYmICghdW5jYWNoZSAmJiBjYWNoZS55UGVyY2VudCB8fCAoTWF0aC5yb3VuZCh0YXJnZXQub2Zmc2V0SGVpZ2h0IC8gMikgPT09IE1hdGgucm91bmQoLXkpID8gLTUwIDogMCkpKSA/IHRhcmdldC5vZmZzZXRIZWlnaHQgKiBjYWNoZS55UGVyY2VudCAvIDEwMCA6IDApICsgcHg7XG4gIGNhY2hlLnogPSB6ICsgcHg7XG4gIGNhY2hlLnNjYWxlWCA9IF9yb3VuZChzY2FsZVgpO1xuICBjYWNoZS5zY2FsZVkgPSBfcm91bmQoc2NhbGVZKTtcbiAgY2FjaGUucm90YXRpb24gPSBfcm91bmQocm90YXRpb24pICsgZGVnO1xuICBjYWNoZS5yb3RhdGlvblggPSBfcm91bmQocm90YXRpb25YKSArIGRlZztcbiAgY2FjaGUucm90YXRpb25ZID0gX3JvdW5kKHJvdGF0aW9uWSkgKyBkZWc7XG4gIGNhY2hlLnNrZXdYID0gc2tld1ggKyBkZWc7XG4gIGNhY2hlLnNrZXdZID0gc2tld1kgKyBkZWc7XG4gIGNhY2hlLnRyYW5zZm9ybVBlcnNwZWN0aXZlID0gcGVyc3BlY3RpdmUgKyBweDtcblxuICBpZiAoY2FjaGUuek9yaWdpbiA9IHBhcnNlRmxvYXQob3JpZ2luLnNwbGl0KFwiIFwiKVsyXSkgfHwgIXVuY2FjaGUgJiYgY2FjaGUuek9yaWdpbiB8fCAwKSB7XG4gICAgc3R5bGVbX3RyYW5zZm9ybU9yaWdpblByb3BdID0gX2ZpcnN0VHdvT25seShvcmlnaW4pO1xuICB9XG5cbiAgY2FjaGUueE9mZnNldCA9IGNhY2hlLnlPZmZzZXQgPSAwO1xuICBjYWNoZS5mb3JjZTNEID0gX2NvbmZpZy5mb3JjZTNEO1xuICBjYWNoZS5yZW5kZXJUcmFuc2Zvcm0gPSBjYWNoZS5zdmcgPyBfcmVuZGVyU1ZHVHJhbnNmb3JtcyA6IF9zdXBwb3J0czNEID8gX3JlbmRlckNTU1RyYW5zZm9ybXMgOiBfcmVuZGVyTm9uM0RUcmFuc2Zvcm1zO1xuICBjYWNoZS51bmNhY2hlID0gMDtcbiAgcmV0dXJuIGNhY2hlO1xufSxcbiAgICBfZmlyc3RUd29Pbmx5ID0gZnVuY3Rpb24gX2ZpcnN0VHdvT25seSh2YWx1ZSkge1xuICByZXR1cm4gKHZhbHVlID0gdmFsdWUuc3BsaXQoXCIgXCIpKVswXSArIFwiIFwiICsgdmFsdWVbMV07XG59LFxuICAgIC8vZm9yIGhhbmRsaW5nIHRyYW5zZm9ybU9yaWdpbiB2YWx1ZXMsIHN0cmlwcGluZyBvdXQgdGhlIDNyZCBkaW1lbnNpb25cbl9hZGRQeFRyYW5zbGF0ZSA9IGZ1bmN0aW9uIF9hZGRQeFRyYW5zbGF0ZSh0YXJnZXQsIHN0YXJ0LCB2YWx1ZSkge1xuICB2YXIgdW5pdCA9IGdldFVuaXQoc3RhcnQpO1xuICByZXR1cm4gX3JvdW5kKHBhcnNlRmxvYXQoc3RhcnQpICsgcGFyc2VGbG9hdChfY29udmVydFRvVW5pdCh0YXJnZXQsIFwieFwiLCB2YWx1ZSArIFwicHhcIiwgdW5pdCkpKSArIHVuaXQ7XG59LFxuICAgIF9yZW5kZXJOb24zRFRyYW5zZm9ybXMgPSBmdW5jdGlvbiBfcmVuZGVyTm9uM0RUcmFuc2Zvcm1zKHJhdGlvLCBjYWNoZSkge1xuICBjYWNoZS56ID0gXCIwcHhcIjtcbiAgY2FjaGUucm90YXRpb25ZID0gY2FjaGUucm90YXRpb25YID0gXCIwZGVnXCI7XG4gIGNhY2hlLmZvcmNlM0QgPSAwO1xuXG4gIF9yZW5kZXJDU1NUcmFuc2Zvcm1zKHJhdGlvLCBjYWNoZSk7XG59LFxuICAgIF96ZXJvRGVnID0gXCIwZGVnXCIsXG4gICAgX3plcm9QeCA9IFwiMHB4XCIsXG4gICAgX2VuZFBhcmVudGhlc2lzID0gXCIpIFwiLFxuICAgIF9yZW5kZXJDU1NUcmFuc2Zvcm1zID0gZnVuY3Rpb24gX3JlbmRlckNTU1RyYW5zZm9ybXMocmF0aW8sIGNhY2hlKSB7XG4gIHZhciBfcmVmID0gY2FjaGUgfHwgdGhpcyxcbiAgICAgIHhQZXJjZW50ID0gX3JlZi54UGVyY2VudCxcbiAgICAgIHlQZXJjZW50ID0gX3JlZi55UGVyY2VudCxcbiAgICAgIHggPSBfcmVmLngsXG4gICAgICB5ID0gX3JlZi55LFxuICAgICAgeiA9IF9yZWYueixcbiAgICAgIHJvdGF0aW9uID0gX3JlZi5yb3RhdGlvbixcbiAgICAgIHJvdGF0aW9uWSA9IF9yZWYucm90YXRpb25ZLFxuICAgICAgcm90YXRpb25YID0gX3JlZi5yb3RhdGlvblgsXG4gICAgICBza2V3WCA9IF9yZWYuc2tld1gsXG4gICAgICBza2V3WSA9IF9yZWYuc2tld1ksXG4gICAgICBzY2FsZVggPSBfcmVmLnNjYWxlWCxcbiAgICAgIHNjYWxlWSA9IF9yZWYuc2NhbGVZLFxuICAgICAgdHJhbnNmb3JtUGVyc3BlY3RpdmUgPSBfcmVmLnRyYW5zZm9ybVBlcnNwZWN0aXZlLFxuICAgICAgZm9yY2UzRCA9IF9yZWYuZm9yY2UzRCxcbiAgICAgIHRhcmdldCA9IF9yZWYudGFyZ2V0LFxuICAgICAgek9yaWdpbiA9IF9yZWYuek9yaWdpbixcbiAgICAgIHRyYW5zZm9ybXMgPSBcIlwiLFxuICAgICAgdXNlM0QgPSBmb3JjZTNEID09PSBcImF1dG9cIiAmJiByYXRpbyAmJiByYXRpbyAhPT0gMSB8fCBmb3JjZTNEID09PSB0cnVlOyAvLyBTYWZhcmkgaGFzIGEgYnVnIHRoYXQgY2F1c2VzIGl0IG5vdCB0byByZW5kZXIgM0QgdHJhbnNmb3JtLW9yaWdpbiB2YWx1ZXMgcHJvcGVybHksIHNvIHdlIGZvcmNlIHRoZSB6IG9yaWdpbiB0byAwLCByZWNvcmQgaXQgaW4gdGhlIGNhY2hlLCBhbmQgdGhlbiBkbyB0aGUgbWF0aCBoZXJlIHRvIG9mZnNldCB0aGUgdHJhbnNsYXRlIHZhbHVlcyBhY2NvcmRpbmdseSAoYmFzaWNhbGx5IGRvIHRoZSAzRCB0cmFuc2Zvcm0tb3JpZ2luIHBhcnQgbWFudWFsbHkpXG5cblxuICBpZiAoek9yaWdpbiAmJiAocm90YXRpb25YICE9PSBfemVyb0RlZyB8fCByb3RhdGlvblkgIT09IF96ZXJvRGVnKSkge1xuICAgIHZhciBhbmdsZSA9IHBhcnNlRmxvYXQocm90YXRpb25ZKSAqIF9ERUcyUkFELFxuICAgICAgICBhMTMgPSBNYXRoLnNpbihhbmdsZSksXG4gICAgICAgIGEzMyA9IE1hdGguY29zKGFuZ2xlKSxcbiAgICAgICAgY29zO1xuXG4gICAgYW5nbGUgPSBwYXJzZUZsb2F0KHJvdGF0aW9uWCkgKiBfREVHMlJBRDtcbiAgICBjb3MgPSBNYXRoLmNvcyhhbmdsZSk7XG4gICAgeCA9IF9hZGRQeFRyYW5zbGF0ZSh0YXJnZXQsIHgsIGExMyAqIGNvcyAqIC16T3JpZ2luKTtcbiAgICB5ID0gX2FkZFB4VHJhbnNsYXRlKHRhcmdldCwgeSwgLU1hdGguc2luKGFuZ2xlKSAqIC16T3JpZ2luKTtcbiAgICB6ID0gX2FkZFB4VHJhbnNsYXRlKHRhcmdldCwgeiwgYTMzICogY29zICogLXpPcmlnaW4gKyB6T3JpZ2luKTtcbiAgfVxuXG4gIGlmICh0cmFuc2Zvcm1QZXJzcGVjdGl2ZSAhPT0gX3plcm9QeCkge1xuICAgIHRyYW5zZm9ybXMgKz0gXCJwZXJzcGVjdGl2ZShcIiArIHRyYW5zZm9ybVBlcnNwZWN0aXZlICsgX2VuZFBhcmVudGhlc2lzO1xuICB9XG5cbiAgaWYgKHhQZXJjZW50IHx8IHlQZXJjZW50KSB7XG4gICAgdHJhbnNmb3JtcyArPSBcInRyYW5zbGF0ZShcIiArIHhQZXJjZW50ICsgXCIlLCBcIiArIHlQZXJjZW50ICsgXCIlKSBcIjtcbiAgfVxuXG4gIGlmICh1c2UzRCB8fCB4ICE9PSBfemVyb1B4IHx8IHkgIT09IF96ZXJvUHggfHwgeiAhPT0gX3plcm9QeCkge1xuICAgIHRyYW5zZm9ybXMgKz0geiAhPT0gX3plcm9QeCB8fCB1c2UzRCA/IFwidHJhbnNsYXRlM2QoXCIgKyB4ICsgXCIsIFwiICsgeSArIFwiLCBcIiArIHogKyBcIikgXCIgOiBcInRyYW5zbGF0ZShcIiArIHggKyBcIiwgXCIgKyB5ICsgX2VuZFBhcmVudGhlc2lzO1xuICB9XG5cbiAgaWYgKHJvdGF0aW9uICE9PSBfemVyb0RlZykge1xuICAgIHRyYW5zZm9ybXMgKz0gXCJyb3RhdGUoXCIgKyByb3RhdGlvbiArIF9lbmRQYXJlbnRoZXNpcztcbiAgfVxuXG4gIGlmIChyb3RhdGlvblkgIT09IF96ZXJvRGVnKSB7XG4gICAgdHJhbnNmb3JtcyArPSBcInJvdGF0ZVkoXCIgKyByb3RhdGlvblkgKyBfZW5kUGFyZW50aGVzaXM7XG4gIH1cblxuICBpZiAocm90YXRpb25YICE9PSBfemVyb0RlZykge1xuICAgIHRyYW5zZm9ybXMgKz0gXCJyb3RhdGVYKFwiICsgcm90YXRpb25YICsgX2VuZFBhcmVudGhlc2lzO1xuICB9XG5cbiAgaWYgKHNrZXdYICE9PSBfemVyb0RlZyB8fCBza2V3WSAhPT0gX3plcm9EZWcpIHtcbiAgICB0cmFuc2Zvcm1zICs9IFwic2tldyhcIiArIHNrZXdYICsgXCIsIFwiICsgc2tld1kgKyBfZW5kUGFyZW50aGVzaXM7XG4gIH1cblxuICBpZiAoc2NhbGVYICE9PSAxIHx8IHNjYWxlWSAhPT0gMSkge1xuICAgIHRyYW5zZm9ybXMgKz0gXCJzY2FsZShcIiArIHNjYWxlWCArIFwiLCBcIiArIHNjYWxlWSArIF9lbmRQYXJlbnRoZXNpcztcbiAgfVxuXG4gIHRhcmdldC5zdHlsZVtfdHJhbnNmb3JtUHJvcF0gPSB0cmFuc2Zvcm1zIHx8IFwidHJhbnNsYXRlKDAsIDApXCI7XG59LFxuICAgIF9yZW5kZXJTVkdUcmFuc2Zvcm1zID0gZnVuY3Rpb24gX3JlbmRlclNWR1RyYW5zZm9ybXMocmF0aW8sIGNhY2hlKSB7XG4gIHZhciBfcmVmMiA9IGNhY2hlIHx8IHRoaXMsXG4gICAgICB4UGVyY2VudCA9IF9yZWYyLnhQZXJjZW50LFxuICAgICAgeVBlcmNlbnQgPSBfcmVmMi55UGVyY2VudCxcbiAgICAgIHggPSBfcmVmMi54LFxuICAgICAgeSA9IF9yZWYyLnksXG4gICAgICByb3RhdGlvbiA9IF9yZWYyLnJvdGF0aW9uLFxuICAgICAgc2tld1ggPSBfcmVmMi5za2V3WCxcbiAgICAgIHNrZXdZID0gX3JlZjIuc2tld1ksXG4gICAgICBzY2FsZVggPSBfcmVmMi5zY2FsZVgsXG4gICAgICBzY2FsZVkgPSBfcmVmMi5zY2FsZVksXG4gICAgICB0YXJnZXQgPSBfcmVmMi50YXJnZXQsXG4gICAgICB4T3JpZ2luID0gX3JlZjIueE9yaWdpbixcbiAgICAgIHlPcmlnaW4gPSBfcmVmMi55T3JpZ2luLFxuICAgICAgeE9mZnNldCA9IF9yZWYyLnhPZmZzZXQsXG4gICAgICB5T2Zmc2V0ID0gX3JlZjIueU9mZnNldCxcbiAgICAgIGZvcmNlQ1NTID0gX3JlZjIuZm9yY2VDU1MsXG4gICAgICB0eCA9IHBhcnNlRmxvYXQoeCksXG4gICAgICB0eSA9IHBhcnNlRmxvYXQoeSksXG4gICAgICBhMTEsXG4gICAgICBhMjEsXG4gICAgICBhMTIsXG4gICAgICBhMjIsXG4gICAgICB0ZW1wO1xuXG4gIHJvdGF0aW9uID0gcGFyc2VGbG9hdChyb3RhdGlvbik7XG4gIHNrZXdYID0gcGFyc2VGbG9hdChza2V3WCk7XG4gIHNrZXdZID0gcGFyc2VGbG9hdChza2V3WSk7XG5cbiAgaWYgKHNrZXdZKSB7XG4gICAgLy9mb3IgcGVyZm9ybWFuY2UgcmVhc29ucywgd2UgY29tYmluZSBhbGwgc2tld2luZyBpbnRvIHRoZSBza2V3WCBhbmQgcm90YXRpb24gdmFsdWVzLiBSZW1lbWJlciwgYSBza2V3WSBvZiAxMCBkZWdyZWVzIGxvb2tzIHRoZSBzYW1lIGFzIGEgcm90YXRpb24gb2YgMTAgZGVncmVlcyBwbHVzIGEgc2tld1ggb2YgMTAgZGVncmVlcy5cbiAgICBza2V3WSA9IHBhcnNlRmxvYXQoc2tld1kpO1xuICAgIHNrZXdYICs9IHNrZXdZO1xuICAgIHJvdGF0aW9uICs9IHNrZXdZO1xuICB9XG5cbiAgaWYgKHJvdGF0aW9uIHx8IHNrZXdYKSB7XG4gICAgcm90YXRpb24gKj0gX0RFRzJSQUQ7XG4gICAgc2tld1ggKj0gX0RFRzJSQUQ7XG4gICAgYTExID0gTWF0aC5jb3Mocm90YXRpb24pICogc2NhbGVYO1xuICAgIGEyMSA9IE1hdGguc2luKHJvdGF0aW9uKSAqIHNjYWxlWDtcbiAgICBhMTIgPSBNYXRoLnNpbihyb3RhdGlvbiAtIHNrZXdYKSAqIC1zY2FsZVk7XG4gICAgYTIyID0gTWF0aC5jb3Mocm90YXRpb24gLSBza2V3WCkgKiBzY2FsZVk7XG5cbiAgICBpZiAoc2tld1gpIHtcbiAgICAgIHNrZXdZICo9IF9ERUcyUkFEO1xuICAgICAgdGVtcCA9IE1hdGgudGFuKHNrZXdYIC0gc2tld1kpO1xuICAgICAgdGVtcCA9IE1hdGguc3FydCgxICsgdGVtcCAqIHRlbXApO1xuICAgICAgYTEyICo9IHRlbXA7XG4gICAgICBhMjIgKj0gdGVtcDtcblxuICAgICAgaWYgKHNrZXdZKSB7XG4gICAgICAgIHRlbXAgPSBNYXRoLnRhbihza2V3WSk7XG4gICAgICAgIHRlbXAgPSBNYXRoLnNxcnQoMSArIHRlbXAgKiB0ZW1wKTtcbiAgICAgICAgYTExICo9IHRlbXA7XG4gICAgICAgIGEyMSAqPSB0ZW1wO1xuICAgICAgfVxuICAgIH1cblxuICAgIGExMSA9IF9yb3VuZChhMTEpO1xuICAgIGEyMSA9IF9yb3VuZChhMjEpO1xuICAgIGExMiA9IF9yb3VuZChhMTIpO1xuICAgIGEyMiA9IF9yb3VuZChhMjIpO1xuICB9IGVsc2Uge1xuICAgIGExMSA9IHNjYWxlWDtcbiAgICBhMjIgPSBzY2FsZVk7XG4gICAgYTIxID0gYTEyID0gMDtcbiAgfVxuXG4gIGlmICh0eCAmJiAhfih4ICsgXCJcIikuaW5kZXhPZihcInB4XCIpIHx8IHR5ICYmICF+KHkgKyBcIlwiKS5pbmRleE9mKFwicHhcIikpIHtcbiAgICB0eCA9IF9jb252ZXJ0VG9Vbml0KHRhcmdldCwgXCJ4XCIsIHgsIFwicHhcIik7XG4gICAgdHkgPSBfY29udmVydFRvVW5pdCh0YXJnZXQsIFwieVwiLCB5LCBcInB4XCIpO1xuICB9XG5cbiAgaWYgKHhPcmlnaW4gfHwgeU9yaWdpbiB8fCB4T2Zmc2V0IHx8IHlPZmZzZXQpIHtcbiAgICB0eCA9IF9yb3VuZCh0eCArIHhPcmlnaW4gLSAoeE9yaWdpbiAqIGExMSArIHlPcmlnaW4gKiBhMTIpICsgeE9mZnNldCk7XG4gICAgdHkgPSBfcm91bmQodHkgKyB5T3JpZ2luIC0gKHhPcmlnaW4gKiBhMjEgKyB5T3JpZ2luICogYTIyKSArIHlPZmZzZXQpO1xuICB9XG5cbiAgaWYgKHhQZXJjZW50IHx8IHlQZXJjZW50KSB7XG4gICAgLy9UaGUgU1ZHIHNwZWMgZG9lc24ndCBzdXBwb3J0IHBlcmNlbnRhZ2UtYmFzZWQgdHJhbnNsYXRpb24gaW4gdGhlIFwidHJhbnNmb3JtXCIgYXR0cmlidXRlLCBzbyB3ZSBtZXJnZSBpdCBpbnRvIHRoZSB0cmFuc2xhdGlvbiB0byBzaW11bGF0ZSBpdC5cbiAgICB0ZW1wID0gdGFyZ2V0LmdldEJCb3goKTtcbiAgICB0eCA9IF9yb3VuZCh0eCArIHhQZXJjZW50IC8gMTAwICogdGVtcC53aWR0aCk7XG4gICAgdHkgPSBfcm91bmQodHkgKyB5UGVyY2VudCAvIDEwMCAqIHRlbXAuaGVpZ2h0KTtcbiAgfVxuXG4gIHRlbXAgPSBcIm1hdHJpeChcIiArIGExMSArIFwiLFwiICsgYTIxICsgXCIsXCIgKyBhMTIgKyBcIixcIiArIGEyMiArIFwiLFwiICsgdHggKyBcIixcIiArIHR5ICsgXCIpXCI7XG4gIHRhcmdldC5zZXRBdHRyaWJ1dGUoXCJ0cmFuc2Zvcm1cIiwgdGVtcCk7XG4gIGZvcmNlQ1NTICYmICh0YXJnZXQuc3R5bGVbX3RyYW5zZm9ybVByb3BdID0gdGVtcCk7IC8vc29tZSBicm93c2VycyBwcmlvcml0aXplIENTUyB0cmFuc2Zvcm1zIG92ZXIgdGhlIHRyYW5zZm9ybSBhdHRyaWJ1dGUuIFdoZW4gd2Ugc2Vuc2UgdGhhdCB0aGUgdXNlciBoYXMgQ1NTIHRyYW5zZm9ybXMgYXBwbGllZCwgd2UgbXVzdCBvdmVyd3JpdGUgdGhlbSB0aGlzIHdheSAob3RoZXJ3aXNlIHNvbWUgYnJvd3NlciBzaW1wbHkgd29uJ3QgcmVuZGVyIHRoZSB0cmFuc2Zvcm0gYXR0cmlidXRlIGNoYW5nZXMhKVxufSxcbiAgICBfYWRkUm90YXRpb25hbFByb3BUd2VlbiA9IGZ1bmN0aW9uIF9hZGRSb3RhdGlvbmFsUHJvcFR3ZWVuKHBsdWdpbiwgdGFyZ2V0LCBwcm9wZXJ0eSwgc3RhcnROdW0sIGVuZFZhbHVlKSB7XG4gIHZhciBjYXAgPSAzNjAsXG4gICAgICBpc1N0cmluZyA9IF9pc1N0cmluZyhlbmRWYWx1ZSksXG4gICAgICBlbmROdW0gPSBwYXJzZUZsb2F0KGVuZFZhbHVlKSAqIChpc1N0cmluZyAmJiB+ZW5kVmFsdWUuaW5kZXhPZihcInJhZFwiKSA/IF9SQUQyREVHIDogMSksXG4gICAgICBjaGFuZ2UgPSBlbmROdW0gLSBzdGFydE51bSxcbiAgICAgIGZpbmFsVmFsdWUgPSBzdGFydE51bSArIGNoYW5nZSArIFwiZGVnXCIsXG4gICAgICBkaXJlY3Rpb24sXG4gICAgICBwdDtcblxuICBpZiAoaXNTdHJpbmcpIHtcbiAgICBkaXJlY3Rpb24gPSBlbmRWYWx1ZS5zcGxpdChcIl9cIilbMV07XG5cbiAgICBpZiAoZGlyZWN0aW9uID09PSBcInNob3J0XCIpIHtcbiAgICAgIGNoYW5nZSAlPSBjYXA7XG5cbiAgICAgIGlmIChjaGFuZ2UgIT09IGNoYW5nZSAlIChjYXAgLyAyKSkge1xuICAgICAgICBjaGFuZ2UgKz0gY2hhbmdlIDwgMCA/IGNhcCA6IC1jYXA7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGRpcmVjdGlvbiA9PT0gXCJjd1wiICYmIGNoYW5nZSA8IDApIHtcbiAgICAgIGNoYW5nZSA9IChjaGFuZ2UgKyBjYXAgKiBfYmlnTnVtKSAlIGNhcCAtIH5+KGNoYW5nZSAvIGNhcCkgKiBjYXA7XG4gICAgfSBlbHNlIGlmIChkaXJlY3Rpb24gPT09IFwiY2N3XCIgJiYgY2hhbmdlID4gMCkge1xuICAgICAgY2hhbmdlID0gKGNoYW5nZSAtIGNhcCAqIF9iaWdOdW0pICUgY2FwIC0gfn4oY2hhbmdlIC8gY2FwKSAqIGNhcDtcbiAgICB9XG4gIH1cblxuICBwbHVnaW4uX3B0ID0gcHQgPSBuZXcgUHJvcFR3ZWVuKHBsdWdpbi5fcHQsIHRhcmdldCwgcHJvcGVydHksIHN0YXJ0TnVtLCBjaGFuZ2UsIF9yZW5kZXJQcm9wV2l0aEVuZCk7XG4gIHB0LmUgPSBmaW5hbFZhbHVlO1xuICBwdC51ID0gXCJkZWdcIjtcblxuICBwbHVnaW4uX3Byb3BzLnB1c2gocHJvcGVydHkpO1xuXG4gIHJldHVybiBwdDtcbn0sXG4gICAgX2Fzc2lnbiA9IGZ1bmN0aW9uIF9hc3NpZ24odGFyZ2V0LCBzb3VyY2UpIHtcbiAgLy8gSW50ZXJuZXQgRXhwbG9yZXIgZG9lc24ndCBoYXZlIE9iamVjdC5hc3NpZ24oKSwgc28gd2UgcmVjcmVhdGUgaXQgaGVyZS5cbiAgZm9yICh2YXIgcCBpbiBzb3VyY2UpIHtcbiAgICB0YXJnZXRbcF0gPSBzb3VyY2VbcF07XG4gIH1cblxuICByZXR1cm4gdGFyZ2V0O1xufSxcbiAgICBfYWRkUmF3VHJhbnNmb3JtUFRzID0gZnVuY3Rpb24gX2FkZFJhd1RyYW5zZm9ybVBUcyhwbHVnaW4sIHRyYW5zZm9ybXMsIHRhcmdldCkge1xuICAvL2ZvciBoYW5kbGluZyBjYXNlcyB3aGVyZSBzb21lb25lIHBhc3NlcyBpbiBhIHdob2xlIHRyYW5zZm9ybSBzdHJpbmcsIGxpa2UgdHJhbnNmb3JtOiBcInNjYWxlKDIsIDMpIHJvdGF0ZSgyMGRlZykgdHJhbnNsYXRlWSgzMGVtKVwiXG4gIHZhciBzdGFydENhY2hlID0gX2Fzc2lnbih7fSwgdGFyZ2V0Ll9nc2FwKSxcbiAgICAgIGV4Y2x1ZGUgPSBcInBlcnNwZWN0aXZlLGZvcmNlM0QsdHJhbnNmb3JtT3JpZ2luLHN2Z09yaWdpblwiLFxuICAgICAgc3R5bGUgPSB0YXJnZXQuc3R5bGUsXG4gICAgICBlbmRDYWNoZSxcbiAgICAgIHAsXG4gICAgICBzdGFydFZhbHVlLFxuICAgICAgZW5kVmFsdWUsXG4gICAgICBzdGFydE51bSxcbiAgICAgIGVuZE51bSxcbiAgICAgIHN0YXJ0VW5pdCxcbiAgICAgIGVuZFVuaXQ7XG5cbiAgaWYgKHN0YXJ0Q2FjaGUuc3ZnKSB7XG4gICAgc3RhcnRWYWx1ZSA9IHRhcmdldC5nZXRBdHRyaWJ1dGUoXCJ0cmFuc2Zvcm1cIik7XG4gICAgdGFyZ2V0LnNldEF0dHJpYnV0ZShcInRyYW5zZm9ybVwiLCBcIlwiKTtcbiAgICBzdHlsZVtfdHJhbnNmb3JtUHJvcF0gPSB0cmFuc2Zvcm1zO1xuICAgIGVuZENhY2hlID0gX3BhcnNlVHJhbnNmb3JtKHRhcmdldCwgMSk7XG5cbiAgICBfcmVtb3ZlUHJvcGVydHkodGFyZ2V0LCBfdHJhbnNmb3JtUHJvcCk7XG5cbiAgICB0YXJnZXQuc2V0QXR0cmlidXRlKFwidHJhbnNmb3JtXCIsIHN0YXJ0VmFsdWUpO1xuICB9IGVsc2Uge1xuICAgIHN0YXJ0VmFsdWUgPSBnZXRDb21wdXRlZFN0eWxlKHRhcmdldClbX3RyYW5zZm9ybVByb3BdO1xuICAgIHN0eWxlW190cmFuc2Zvcm1Qcm9wXSA9IHRyYW5zZm9ybXM7XG4gICAgZW5kQ2FjaGUgPSBfcGFyc2VUcmFuc2Zvcm0odGFyZ2V0LCAxKTtcbiAgICBzdHlsZVtfdHJhbnNmb3JtUHJvcF0gPSBzdGFydFZhbHVlO1xuICB9XG5cbiAgZm9yIChwIGluIF90cmFuc2Zvcm1Qcm9wcykge1xuICAgIHN0YXJ0VmFsdWUgPSBzdGFydENhY2hlW3BdO1xuICAgIGVuZFZhbHVlID0gZW5kQ2FjaGVbcF07XG5cbiAgICBpZiAoc3RhcnRWYWx1ZSAhPT0gZW5kVmFsdWUgJiYgZXhjbHVkZS5pbmRleE9mKHApIDwgMCkge1xuICAgICAgLy90d2VlbmluZyB0byBubyBwZXJzcGVjdGl2ZSBnaXZlcyB2ZXJ5IHVuaW50dWl0aXZlIHJlc3VsdHMgLSBqdXN0IGtlZXAgdGhlIHNhbWUgcGVyc3BlY3RpdmUgaW4gdGhhdCBjYXNlLlxuICAgICAgc3RhcnRVbml0ID0gZ2V0VW5pdChzdGFydFZhbHVlKTtcbiAgICAgIGVuZFVuaXQgPSBnZXRVbml0KGVuZFZhbHVlKTtcbiAgICAgIHN0YXJ0TnVtID0gc3RhcnRVbml0ICE9PSBlbmRVbml0ID8gX2NvbnZlcnRUb1VuaXQodGFyZ2V0LCBwLCBzdGFydFZhbHVlLCBlbmRVbml0KSA6IHBhcnNlRmxvYXQoc3RhcnRWYWx1ZSk7XG4gICAgICBlbmROdW0gPSBwYXJzZUZsb2F0KGVuZFZhbHVlKTtcbiAgICAgIHBsdWdpbi5fcHQgPSBuZXcgUHJvcFR3ZWVuKHBsdWdpbi5fcHQsIGVuZENhY2hlLCBwLCBzdGFydE51bSwgZW5kTnVtIC0gc3RhcnROdW0sIF9yZW5kZXJDU1NQcm9wKTtcbiAgICAgIHBsdWdpbi5fcHQudSA9IGVuZFVuaXQgfHwgMDtcblxuICAgICAgcGx1Z2luLl9wcm9wcy5wdXNoKHApO1xuICAgIH1cbiAgfVxuXG4gIF9hc3NpZ24oZW5kQ2FjaGUsIHN0YXJ0Q2FjaGUpO1xufTsgLy8gaGFuZGxlIHNwbGl0dGluZyBhcGFydCBwYWRkaW5nLCBtYXJnaW4sIGJvcmRlcldpZHRoLCBhbmQgYm9yZGVyUmFkaXVzIGludG8gdGhlaXIgNCBjb21wb25lbnRzLiBGaXJlZm94LCBmb3IgZXhhbXBsZSwgd29uJ3QgcmVwb3J0IGJvcmRlclJhZGl1cyBjb3JyZWN0bHkgLSBpdCB3aWxsIG9ubHkgZG8gYm9yZGVyVG9wTGVmdFJhZGl1cyBhbmQgdGhlIG90aGVyIGNvcm5lcnMuIFdlIGFsc28gd2FudCB0byBoYW5kbGUgcGFkZGluZ1RvcCwgbWFyZ2luTGVmdCwgYm9yZGVyUmlnaHRXaWR0aCwgZXRjLlxuXG5cbl9mb3JFYWNoTmFtZShcInBhZGRpbmcsbWFyZ2luLFdpZHRoLFJhZGl1c1wiLCBmdW5jdGlvbiAobmFtZSwgaW5kZXgpIHtcbiAgdmFyIHQgPSBcIlRvcFwiLFxuICAgICAgciA9IFwiUmlnaHRcIixcbiAgICAgIGIgPSBcIkJvdHRvbVwiLFxuICAgICAgbCA9IFwiTGVmdFwiLFxuICAgICAgcHJvcHMgPSAoaW5kZXggPCAzID8gW3QsIHIsIGIsIGxdIDogW3QgKyBsLCB0ICsgciwgYiArIHIsIGIgKyBsXSkubWFwKGZ1bmN0aW9uIChzaWRlKSB7XG4gICAgcmV0dXJuIGluZGV4IDwgMiA/IG5hbWUgKyBzaWRlIDogXCJib3JkZXJcIiArIHNpZGUgKyBuYW1lO1xuICB9KTtcblxuICBfc3BlY2lhbFByb3BzW2luZGV4ID4gMSA/IFwiYm9yZGVyXCIgKyBuYW1lIDogbmFtZV0gPSBmdW5jdGlvbiAocGx1Z2luLCB0YXJnZXQsIHByb3BlcnR5LCBlbmRWYWx1ZSwgdHdlZW4pIHtcbiAgICB2YXIgYSwgdmFycztcblxuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoIDwgNCkge1xuICAgICAgLy8gZ2V0dGVyLCBwYXNzZWQgdGFyZ2V0LCBwcm9wZXJ0eSwgYW5kIHVuaXQgKGZyb20gX2dldCgpKVxuICAgICAgYSA9IHByb3BzLm1hcChmdW5jdGlvbiAocHJvcCkge1xuICAgICAgICByZXR1cm4gX2dldChwbHVnaW4sIHByb3AsIHByb3BlcnR5KTtcbiAgICAgIH0pO1xuICAgICAgdmFycyA9IGEuam9pbihcIiBcIik7XG4gICAgICByZXR1cm4gdmFycy5zcGxpdChhWzBdKS5sZW5ndGggPT09IDUgPyBhWzBdIDogdmFycztcbiAgICB9XG5cbiAgICBhID0gKGVuZFZhbHVlICsgXCJcIikuc3BsaXQoXCIgXCIpO1xuICAgIHZhcnMgPSB7fTtcbiAgICBwcm9wcy5mb3JFYWNoKGZ1bmN0aW9uIChwcm9wLCBpKSB7XG4gICAgICByZXR1cm4gdmFyc1twcm9wXSA9IGFbaV0gPSBhW2ldIHx8IGFbKGkgLSAxKSAvIDIgfCAwXTtcbiAgICB9KTtcbiAgICBwbHVnaW4uaW5pdCh0YXJnZXQsIHZhcnMsIHR3ZWVuKTtcbiAgfTtcbn0pO1xuXG5leHBvcnQgdmFyIENTU1BsdWdpbiA9IHtcbiAgbmFtZTogXCJjc3NcIixcbiAgcmVnaXN0ZXI6IF9pbml0Q29yZSxcbiAgdGFyZ2V0VGVzdDogZnVuY3Rpb24gdGFyZ2V0VGVzdCh0YXJnZXQpIHtcbiAgICByZXR1cm4gdGFyZ2V0LnN0eWxlICYmIHRhcmdldC5ub2RlVHlwZTtcbiAgfSxcbiAgaW5pdDogZnVuY3Rpb24gaW5pdCh0YXJnZXQsIHZhcnMsIHR3ZWVuLCBpbmRleCwgdGFyZ2V0cykge1xuICAgIHZhciBwcm9wcyA9IHRoaXMuX3Byb3BzLFxuICAgICAgICBzdHlsZSA9IHRhcmdldC5zdHlsZSxcbiAgICAgICAgc3RhcnRBdCA9IHR3ZWVuLnZhcnMuc3RhcnRBdCxcbiAgICAgICAgc3RhcnRWYWx1ZSxcbiAgICAgICAgZW5kVmFsdWUsXG4gICAgICAgIGVuZE51bSxcbiAgICAgICAgc3RhcnROdW0sXG4gICAgICAgIHR5cGUsXG4gICAgICAgIHNwZWNpYWxQcm9wLFxuICAgICAgICBwLFxuICAgICAgICBzdGFydFVuaXQsXG4gICAgICAgIGVuZFVuaXQsXG4gICAgICAgIHJlbGF0aXZlLFxuICAgICAgICBpc1RyYW5zZm9ybVJlbGF0ZWQsXG4gICAgICAgIHRyYW5zZm9ybVByb3BUd2VlbixcbiAgICAgICAgY2FjaGUsXG4gICAgICAgIHNtb290aCxcbiAgICAgICAgaGFzUHJpb3JpdHksXG4gICAgICAgIGlubGluZVByb3BzO1xuICAgIF9wbHVnaW5Jbml0dGVkIHx8IF9pbml0Q29yZSgpOyAvLyB3ZSBtYXkgY2FsbCBpbml0KCkgbXVsdGlwbGUgdGltZXMgb24gdGhlIHNhbWUgcGx1Z2luIGluc3RhbmNlLCBsaWtlIHdoZW4gYWRkaW5nIHNwZWNpYWwgcHJvcGVydGllcywgc28gbWFrZSBzdXJlIHdlIGRvbid0IG92ZXJ3cml0ZSB0aGUgcmV2ZXJ0IGRhdGEgb3IgaW5saW5lUHJvcHNcblxuICAgIHRoaXMuc3R5bGVzID0gdGhpcy5zdHlsZXMgfHwgX2dldFN0eWxlU2F2ZXIodGFyZ2V0KTtcbiAgICBpbmxpbmVQcm9wcyA9IHRoaXMuc3R5bGVzLnByb3BzO1xuICAgIHRoaXMudHdlZW4gPSB0d2VlbjtcblxuICAgIGZvciAocCBpbiB2YXJzKSB7XG4gICAgICBpZiAocCA9PT0gXCJhdXRvUm91bmRcIikge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgZW5kVmFsdWUgPSB2YXJzW3BdO1xuXG4gICAgICBpZiAoX3BsdWdpbnNbcF0gJiYgX2NoZWNrUGx1Z2luKHAsIHZhcnMsIHR3ZWVuLCBpbmRleCwgdGFyZ2V0LCB0YXJnZXRzKSkge1xuICAgICAgICAvLyBwbHVnaW5zXG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICB0eXBlID0gdHlwZW9mIGVuZFZhbHVlO1xuICAgICAgc3BlY2lhbFByb3AgPSBfc3BlY2lhbFByb3BzW3BdO1xuXG4gICAgICBpZiAodHlwZSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgIGVuZFZhbHVlID0gZW5kVmFsdWUuY2FsbCh0d2VlbiwgaW5kZXgsIHRhcmdldCwgdGFyZ2V0cyk7XG4gICAgICAgIHR5cGUgPSB0eXBlb2YgZW5kVmFsdWU7XG4gICAgICB9XG5cbiAgICAgIGlmICh0eXBlID09PSBcInN0cmluZ1wiICYmIH5lbmRWYWx1ZS5pbmRleE9mKFwicmFuZG9tKFwiKSkge1xuICAgICAgICBlbmRWYWx1ZSA9IF9yZXBsYWNlUmFuZG9tKGVuZFZhbHVlKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHNwZWNpYWxQcm9wKSB7XG4gICAgICAgIHNwZWNpYWxQcm9wKHRoaXMsIHRhcmdldCwgcCwgZW5kVmFsdWUsIHR3ZWVuKSAmJiAoaGFzUHJpb3JpdHkgPSAxKTtcbiAgICAgIH0gZWxzZSBpZiAocC5zdWJzdHIoMCwgMikgPT09IFwiLS1cIikge1xuICAgICAgICAvL0NTUyB2YXJpYWJsZVxuICAgICAgICBzdGFydFZhbHVlID0gKGdldENvbXB1dGVkU3R5bGUodGFyZ2V0KS5nZXRQcm9wZXJ0eVZhbHVlKHApICsgXCJcIikudHJpbSgpO1xuICAgICAgICBlbmRWYWx1ZSArPSBcIlwiO1xuICAgICAgICBfY29sb3JFeHAubGFzdEluZGV4ID0gMDtcblxuICAgICAgICBpZiAoIV9jb2xvckV4cC50ZXN0KHN0YXJ0VmFsdWUpKSB7XG4gICAgICAgICAgLy8gY29sb3JzIGRvbid0IGhhdmUgdW5pdHNcbiAgICAgICAgICBzdGFydFVuaXQgPSBnZXRVbml0KHN0YXJ0VmFsdWUpO1xuICAgICAgICAgIGVuZFVuaXQgPSBnZXRVbml0KGVuZFZhbHVlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGVuZFVuaXQgPyBzdGFydFVuaXQgIT09IGVuZFVuaXQgJiYgKHN0YXJ0VmFsdWUgPSBfY29udmVydFRvVW5pdCh0YXJnZXQsIHAsIHN0YXJ0VmFsdWUsIGVuZFVuaXQpICsgZW5kVW5pdCkgOiBzdGFydFVuaXQgJiYgKGVuZFZhbHVlICs9IHN0YXJ0VW5pdCk7XG4gICAgICAgIHRoaXMuYWRkKHN0eWxlLCBcInNldFByb3BlcnR5XCIsIHN0YXJ0VmFsdWUsIGVuZFZhbHVlLCBpbmRleCwgdGFyZ2V0cywgMCwgMCwgcCk7XG4gICAgICAgIHByb3BzLnB1c2gocCk7XG4gICAgICAgIGlubGluZVByb3BzLnB1c2gocCwgMCwgc3R5bGVbcF0pO1xuICAgICAgfSBlbHNlIGlmICh0eXBlICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgIGlmIChzdGFydEF0ICYmIHAgaW4gc3RhcnRBdCkge1xuICAgICAgICAgIC8vIGluIGNhc2Ugc29tZW9uZSBoYXJkLWNvZGVzIGEgY29tcGxleCB2YWx1ZSBhcyB0aGUgc3RhcnQsIGxpa2UgdG9wOiBcImNhbGMoMnZoIC8gMilcIi4gV2l0aG91dCB0aGlzLCBpdCdkIHVzZSB0aGUgY29tcHV0ZWQgdmFsdWUgKGFsd2F5cyBpbiBweClcbiAgICAgICAgICBzdGFydFZhbHVlID0gdHlwZW9mIHN0YXJ0QXRbcF0gPT09IFwiZnVuY3Rpb25cIiA/IHN0YXJ0QXRbcF0uY2FsbCh0d2VlbiwgaW5kZXgsIHRhcmdldCwgdGFyZ2V0cykgOiBzdGFydEF0W3BdO1xuICAgICAgICAgIF9pc1N0cmluZyhzdGFydFZhbHVlKSAmJiB+c3RhcnRWYWx1ZS5pbmRleE9mKFwicmFuZG9tKFwiKSAmJiAoc3RhcnRWYWx1ZSA9IF9yZXBsYWNlUmFuZG9tKHN0YXJ0VmFsdWUpKTtcbiAgICAgICAgICBnZXRVbml0KHN0YXJ0VmFsdWUgKyBcIlwiKSB8fCBzdGFydFZhbHVlID09PSBcImF1dG9cIiB8fCAoc3RhcnRWYWx1ZSArPSBfY29uZmlnLnVuaXRzW3BdIHx8IGdldFVuaXQoX2dldCh0YXJnZXQsIHApKSB8fCBcIlwiKTsgLy8gZm9yIGNhc2VzIHdoZW4gc29tZW9uZSBwYXNzZXMgaW4gYSB1bml0bGVzcyB2YWx1ZSBsaWtlIHt4OiAxMDB9OyBpZiB3ZSB0cnkgc2V0dGluZyB0cmFuc2xhdGUoMTAwLCAwcHgpIGl0IHdvbid0IHdvcmsuXG5cbiAgICAgICAgICAoc3RhcnRWYWx1ZSArIFwiXCIpLmNoYXJBdCgxKSA9PT0gXCI9XCIgJiYgKHN0YXJ0VmFsdWUgPSBfZ2V0KHRhcmdldCwgcCkpOyAvLyBjYW4ndCB3b3JrIHdpdGggcmVsYXRpdmUgdmFsdWVzXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgc3RhcnRWYWx1ZSA9IF9nZXQodGFyZ2V0LCBwKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHN0YXJ0TnVtID0gcGFyc2VGbG9hdChzdGFydFZhbHVlKTtcbiAgICAgICAgcmVsYXRpdmUgPSB0eXBlID09PSBcInN0cmluZ1wiICYmIGVuZFZhbHVlLmNoYXJBdCgxKSA9PT0gXCI9XCIgJiYgZW5kVmFsdWUuc3Vic3RyKDAsIDIpO1xuICAgICAgICByZWxhdGl2ZSAmJiAoZW5kVmFsdWUgPSBlbmRWYWx1ZS5zdWJzdHIoMikpO1xuICAgICAgICBlbmROdW0gPSBwYXJzZUZsb2F0KGVuZFZhbHVlKTtcblxuICAgICAgICBpZiAocCBpbiBfcHJvcGVydHlBbGlhc2VzKSB7XG4gICAgICAgICAgaWYgKHAgPT09IFwiYXV0b0FscGhhXCIpIHtcbiAgICAgICAgICAgIC8vc3BlY2lhbCBjYXNlIHdoZXJlIHdlIGNvbnRyb2wgdGhlIHZpc2liaWxpdHkgYWxvbmcgd2l0aCBvcGFjaXR5LiBXZSBzdGlsbCBhbGxvdyB0aGUgb3BhY2l0eSB2YWx1ZSB0byBwYXNzIHRocm91Z2ggYW5kIGdldCB0d2VlbmVkLlxuICAgICAgICAgICAgaWYgKHN0YXJ0TnVtID09PSAxICYmIF9nZXQodGFyZ2V0LCBcInZpc2liaWxpdHlcIikgPT09IFwiaGlkZGVuXCIgJiYgZW5kTnVtKSB7XG4gICAgICAgICAgICAgIC8vaWYgdmlzaWJpbGl0eSBpcyBpbml0aWFsbHkgc2V0IHRvIFwiaGlkZGVuXCIsIHdlIHNob3VsZCBpbnRlcnByZXQgdGhhdCBhcyBpbnRlbnQgdG8gbWFrZSBvcGFjaXR5IDAgKGEgY29udmVuaWVuY2UpXG4gICAgICAgICAgICAgIHN0YXJ0TnVtID0gMDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaW5saW5lUHJvcHMucHVzaChcInZpc2liaWxpdHlcIiwgMCwgc3R5bGUudmlzaWJpbGl0eSk7XG5cbiAgICAgICAgICAgIF9hZGROb25Ud2VlbmluZ1BUKHRoaXMsIHN0eWxlLCBcInZpc2liaWxpdHlcIiwgc3RhcnROdW0gPyBcImluaGVyaXRcIiA6IFwiaGlkZGVuXCIsIGVuZE51bSA/IFwiaW5oZXJpdFwiIDogXCJoaWRkZW5cIiwgIWVuZE51bSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHAgIT09IFwic2NhbGVcIiAmJiBwICE9PSBcInRyYW5zZm9ybVwiKSB7XG4gICAgICAgICAgICBwID0gX3Byb3BlcnR5QWxpYXNlc1twXTtcbiAgICAgICAgICAgIH5wLmluZGV4T2YoXCIsXCIpICYmIChwID0gcC5zcGxpdChcIixcIilbMF0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlzVHJhbnNmb3JtUmVsYXRlZCA9IHAgaW4gX3RyYW5zZm9ybVByb3BzOyAvLy0tLSBUUkFOU0ZPUk0tUkVMQVRFRCAtLS1cblxuICAgICAgICBpZiAoaXNUcmFuc2Zvcm1SZWxhdGVkKSB7XG4gICAgICAgICAgdGhpcy5zdHlsZXMuc2F2ZShwKTtcblxuICAgICAgICAgIGlmICghdHJhbnNmb3JtUHJvcFR3ZWVuKSB7XG4gICAgICAgICAgICBjYWNoZSA9IHRhcmdldC5fZ3NhcDtcbiAgICAgICAgICAgIGNhY2hlLnJlbmRlclRyYW5zZm9ybSAmJiAhdmFycy5wYXJzZVRyYW5zZm9ybSB8fCBfcGFyc2VUcmFuc2Zvcm0odGFyZ2V0LCB2YXJzLnBhcnNlVHJhbnNmb3JtKTsgLy8gaWYsIGZvciBleGFtcGxlLCBnc2FwLnNldCguLi4ge3RyYW5zZm9ybTpcInRyYW5zbGF0ZVgoNTB2dylcIn0pLCB0aGUgX2dldCgpIGNhbGwgZG9lc24ndCBwYXJzZSB0aGUgdHJhbnNmb3JtLCB0aHVzIGNhY2hlLnJlbmRlclRyYW5zZm9ybSB3b24ndCBiZSBzZXQgeWV0IHNvIGZvcmNlIHRoZSBwYXJzaW5nIG9mIHRoZSB0cmFuc2Zvcm0gaGVyZS5cblxuICAgICAgICAgICAgc21vb3RoID0gdmFycy5zbW9vdGhPcmlnaW4gIT09IGZhbHNlICYmIGNhY2hlLnNtb290aDtcbiAgICAgICAgICAgIHRyYW5zZm9ybVByb3BUd2VlbiA9IHRoaXMuX3B0ID0gbmV3IFByb3BUd2Vlbih0aGlzLl9wdCwgc3R5bGUsIF90cmFuc2Zvcm1Qcm9wLCAwLCAxLCBjYWNoZS5yZW5kZXJUcmFuc2Zvcm0sIGNhY2hlLCAwLCAtMSk7IC8vdGhlIGZpcnN0IHRpbWUgdGhyb3VnaCwgY3JlYXRlIHRoZSByZW5kZXJpbmcgUHJvcFR3ZWVuIHNvIHRoYXQgaXQgcnVucyBMQVNUIChpbiB0aGUgbGlua2VkIGxpc3QsIHdlIGtlZXAgYWRkaW5nIHRvIHRoZSBiZWdpbm5pbmcpXG5cbiAgICAgICAgICAgIHRyYW5zZm9ybVByb3BUd2Vlbi5kZXAgPSAxOyAvL2ZsYWcgaXQgYXMgZGVwZW5kZW50IHNvIHRoYXQgaWYgdGhpbmdzIGdldCBraWxsZWQvb3ZlcndyaXR0ZW4gYW5kIHRoaXMgaXMgdGhlIG9ubHkgUHJvcFR3ZWVuIGxlZnQsIHdlIGNhbiBzYWZlbHkga2lsbCB0aGUgd2hvbGUgdHdlZW4uXG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHAgPT09IFwic2NhbGVcIikge1xuICAgICAgICAgICAgdGhpcy5fcHQgPSBuZXcgUHJvcFR3ZWVuKHRoaXMuX3B0LCBjYWNoZSwgXCJzY2FsZVlcIiwgY2FjaGUuc2NhbGVZLCAocmVsYXRpdmUgPyBfcGFyc2VSZWxhdGl2ZShjYWNoZS5zY2FsZVksIHJlbGF0aXZlICsgZW5kTnVtKSA6IGVuZE51bSkgLSBjYWNoZS5zY2FsZVkgfHwgMCwgX3JlbmRlckNTU1Byb3ApO1xuICAgICAgICAgICAgdGhpcy5fcHQudSA9IDA7XG4gICAgICAgICAgICBwcm9wcy5wdXNoKFwic2NhbGVZXCIsIHApO1xuICAgICAgICAgICAgcCArPSBcIlhcIjtcbiAgICAgICAgICB9IGVsc2UgaWYgKHAgPT09IFwidHJhbnNmb3JtT3JpZ2luXCIpIHtcbiAgICAgICAgICAgIGlubGluZVByb3BzLnB1c2goX3RyYW5zZm9ybU9yaWdpblByb3AsIDAsIHN0eWxlW190cmFuc2Zvcm1PcmlnaW5Qcm9wXSk7XG4gICAgICAgICAgICBlbmRWYWx1ZSA9IF9jb252ZXJ0S2V5d29yZHNUb1BlcmNlbnRhZ2VzKGVuZFZhbHVlKTsgLy9pbiBjYXNlIHNvbWV0aGluZyBsaWtlIFwibGVmdCB0b3BcIiBvciBcImJvdHRvbSByaWdodFwiIGlzIHBhc3NlZCBpbi4gQ29udmVydCB0byBwZXJjZW50YWdlcy5cblxuICAgICAgICAgICAgaWYgKGNhY2hlLnN2Zykge1xuICAgICAgICAgICAgICBfYXBwbHlTVkdPcmlnaW4odGFyZ2V0LCBlbmRWYWx1ZSwgMCwgc21vb3RoLCAwLCB0aGlzKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGVuZFVuaXQgPSBwYXJzZUZsb2F0KGVuZFZhbHVlLnNwbGl0KFwiIFwiKVsyXSkgfHwgMDsgLy9oYW5kbGUgdGhlIHpPcmlnaW4gc2VwYXJhdGVseSFcblxuICAgICAgICAgICAgICBlbmRVbml0ICE9PSBjYWNoZS56T3JpZ2luICYmIF9hZGROb25Ud2VlbmluZ1BUKHRoaXMsIGNhY2hlLCBcInpPcmlnaW5cIiwgY2FjaGUuek9yaWdpbiwgZW5kVW5pdCk7XG5cbiAgICAgICAgICAgICAgX2FkZE5vblR3ZWVuaW5nUFQodGhpcywgc3R5bGUsIHAsIF9maXJzdFR3b09ubHkoc3RhcnRWYWx1ZSksIF9maXJzdFR3b09ubHkoZW5kVmFsdWUpKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfSBlbHNlIGlmIChwID09PSBcInN2Z09yaWdpblwiKSB7XG4gICAgICAgICAgICBfYXBwbHlTVkdPcmlnaW4odGFyZ2V0LCBlbmRWYWx1ZSwgMSwgc21vb3RoLCAwLCB0aGlzKTtcblxuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfSBlbHNlIGlmIChwIGluIF9yb3RhdGlvbmFsUHJvcGVydGllcykge1xuICAgICAgICAgICAgX2FkZFJvdGF0aW9uYWxQcm9wVHdlZW4odGhpcywgY2FjaGUsIHAsIHN0YXJ0TnVtLCByZWxhdGl2ZSA/IF9wYXJzZVJlbGF0aXZlKHN0YXJ0TnVtLCByZWxhdGl2ZSArIGVuZFZhbHVlKSA6IGVuZFZhbHVlKTtcblxuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfSBlbHNlIGlmIChwID09PSBcInNtb290aE9yaWdpblwiKSB7XG4gICAgICAgICAgICBfYWRkTm9uVHdlZW5pbmdQVCh0aGlzLCBjYWNoZSwgXCJzbW9vdGhcIiwgY2FjaGUuc21vb3RoLCBlbmRWYWx1ZSk7XG5cbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgIH0gZWxzZSBpZiAocCA9PT0gXCJmb3JjZTNEXCIpIHtcbiAgICAgICAgICAgIGNhY2hlW3BdID0gZW5kVmFsdWU7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9IGVsc2UgaWYgKHAgPT09IFwidHJhbnNmb3JtXCIpIHtcbiAgICAgICAgICAgIF9hZGRSYXdUcmFuc2Zvcm1QVHModGhpcywgZW5kVmFsdWUsIHRhcmdldCk7XG5cbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmICghKHAgaW4gc3R5bGUpKSB7XG4gICAgICAgICAgcCA9IF9jaGVja1Byb3BQcmVmaXgocCkgfHwgcDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpc1RyYW5zZm9ybVJlbGF0ZWQgfHwgKGVuZE51bSB8fCBlbmROdW0gPT09IDApICYmIChzdGFydE51bSB8fCBzdGFydE51bSA9PT0gMCkgJiYgIV9jb21wbGV4RXhwLnRlc3QoZW5kVmFsdWUpICYmIHAgaW4gc3R5bGUpIHtcbiAgICAgICAgICBzdGFydFVuaXQgPSAoc3RhcnRWYWx1ZSArIFwiXCIpLnN1YnN0cigoc3RhcnROdW0gKyBcIlwiKS5sZW5ndGgpO1xuICAgICAgICAgIGVuZE51bSB8fCAoZW5kTnVtID0gMCk7IC8vIHByb3RlY3QgYWdhaW5zdCBOYU5cblxuICAgICAgICAgIGVuZFVuaXQgPSBnZXRVbml0KGVuZFZhbHVlKSB8fCAocCBpbiBfY29uZmlnLnVuaXRzID8gX2NvbmZpZy51bml0c1twXSA6IHN0YXJ0VW5pdCk7XG4gICAgICAgICAgc3RhcnRVbml0ICE9PSBlbmRVbml0ICYmIChzdGFydE51bSA9IF9jb252ZXJ0VG9Vbml0KHRhcmdldCwgcCwgc3RhcnRWYWx1ZSwgZW5kVW5pdCkpO1xuICAgICAgICAgIHRoaXMuX3B0ID0gbmV3IFByb3BUd2Vlbih0aGlzLl9wdCwgaXNUcmFuc2Zvcm1SZWxhdGVkID8gY2FjaGUgOiBzdHlsZSwgcCwgc3RhcnROdW0sIChyZWxhdGl2ZSA/IF9wYXJzZVJlbGF0aXZlKHN0YXJ0TnVtLCByZWxhdGl2ZSArIGVuZE51bSkgOiBlbmROdW0pIC0gc3RhcnROdW0sICFpc1RyYW5zZm9ybVJlbGF0ZWQgJiYgKGVuZFVuaXQgPT09IFwicHhcIiB8fCBwID09PSBcInpJbmRleFwiKSAmJiB2YXJzLmF1dG9Sb3VuZCAhPT0gZmFsc2UgPyBfcmVuZGVyUm91bmRlZENTU1Byb3AgOiBfcmVuZGVyQ1NTUHJvcCk7XG4gICAgICAgICAgdGhpcy5fcHQudSA9IGVuZFVuaXQgfHwgMDtcblxuICAgICAgICAgIGlmIChzdGFydFVuaXQgIT09IGVuZFVuaXQgJiYgZW5kVW5pdCAhPT0gXCIlXCIpIHtcbiAgICAgICAgICAgIC8vd2hlbiB0aGUgdHdlZW4gZ29lcyBhbGwgdGhlIHdheSBiYWNrIHRvIHRoZSBiZWdpbm5pbmcsIHdlIG5lZWQgdG8gcmV2ZXJ0IGl0IHRvIHRoZSBPTEQvT1JJR0lOQUwgdmFsdWUgKHdpdGggdGhvc2UgdW5pdHMpLiBXZSByZWNvcmQgdGhhdCBhcyBhIFwiYlwiIChiZWdpbm5pbmcpIHByb3BlcnR5IGFuZCBwb2ludCB0byBhIHJlbmRlciBtZXRob2QgdGhhdCBoYW5kbGVzIHRoYXQuIChwZXJmb3JtYW5jZSBvcHRpbWl6YXRpb24pXG4gICAgICAgICAgICB0aGlzLl9wdC5iID0gc3RhcnRWYWx1ZTtcbiAgICAgICAgICAgIHRoaXMuX3B0LnIgPSBfcmVuZGVyQ1NTUHJvcFdpdGhCZWdpbm5pbmc7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKCEocCBpbiBzdHlsZSkpIHtcbiAgICAgICAgICBpZiAocCBpbiB0YXJnZXQpIHtcbiAgICAgICAgICAgIC8vbWF5YmUgaXQncyBub3QgYSBzdHlsZSAtIGl0IGNvdWxkIGJlIGEgcHJvcGVydHkgYWRkZWQgZGlyZWN0bHkgdG8gYW4gZWxlbWVudCBpbiB3aGljaCBjYXNlIHdlJ2xsIHRyeSB0byBhbmltYXRlIHRoYXQuXG4gICAgICAgICAgICB0aGlzLmFkZCh0YXJnZXQsIHAsIHN0YXJ0VmFsdWUgfHwgdGFyZ2V0W3BdLCByZWxhdGl2ZSA/IHJlbGF0aXZlICsgZW5kVmFsdWUgOiBlbmRWYWx1ZSwgaW5kZXgsIHRhcmdldHMpO1xuICAgICAgICAgIH0gZWxzZSBpZiAocCAhPT0gXCJwYXJzZVRyYW5zZm9ybVwiKSB7XG4gICAgICAgICAgICBfbWlzc2luZ1BsdWdpbihwLCBlbmRWYWx1ZSk7XG5cbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBfdHdlZW5Db21wbGV4Q1NTU3RyaW5nLmNhbGwodGhpcywgdGFyZ2V0LCBwLCBzdGFydFZhbHVlLCByZWxhdGl2ZSA/IHJlbGF0aXZlICsgZW5kVmFsdWUgOiBlbmRWYWx1ZSk7XG4gICAgICAgIH1cblxuICAgICAgICBpc1RyYW5zZm9ybVJlbGF0ZWQgfHwgKHAgaW4gc3R5bGUgPyBpbmxpbmVQcm9wcy5wdXNoKHAsIDAsIHN0eWxlW3BdKSA6IGlubGluZVByb3BzLnB1c2gocCwgMSwgc3RhcnRWYWx1ZSB8fCB0YXJnZXRbcF0pKTtcbiAgICAgICAgcHJvcHMucHVzaChwKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBoYXNQcmlvcml0eSAmJiBfc29ydFByb3BUd2VlbnNCeVByaW9yaXR5KHRoaXMpO1xuICB9LFxuICByZW5kZXI6IGZ1bmN0aW9uIHJlbmRlcihyYXRpbywgZGF0YSkge1xuICAgIGlmIChkYXRhLnR3ZWVuLl90aW1lIHx8ICFfcmV2ZXJ0aW5nKCkpIHtcbiAgICAgIHZhciBwdCA9IGRhdGEuX3B0O1xuXG4gICAgICB3aGlsZSAocHQpIHtcbiAgICAgICAgcHQucihyYXRpbywgcHQuZCk7XG4gICAgICAgIHB0ID0gcHQuX25leHQ7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGRhdGEuc3R5bGVzLnJldmVydCgpO1xuICAgIH1cbiAgfSxcbiAgZ2V0OiBfZ2V0LFxuICBhbGlhc2VzOiBfcHJvcGVydHlBbGlhc2VzLFxuICBnZXRTZXR0ZXI6IGZ1bmN0aW9uIGdldFNldHRlcih0YXJnZXQsIHByb3BlcnR5LCBwbHVnaW4pIHtcbiAgICAvL3JldHVybnMgYSBzZXR0ZXIgZnVuY3Rpb24gdGhhdCBhY2NlcHRzIHRhcmdldCwgcHJvcGVydHksIHZhbHVlIGFuZCBhcHBsaWVzIGl0IGFjY29yZGluZ2x5LiBSZW1lbWJlciwgcHJvcGVydGllcyBsaWtlIFwieFwiIGFyZW4ndCBhcyBzaW1wbGUgYXMgdGFyZ2V0LnN0eWxlLnByb3BlcnR5ID0gdmFsdWUgYmVjYXVzZSB0aGV5J3ZlIGdvdCB0byBiZSBhcHBsaWVkIHRvIGEgcHJveHkgb2JqZWN0IGFuZCB0aGVuIG1lcmdlZCBpbnRvIGEgdHJhbnNmb3JtIHN0cmluZyBpbiBhIHJlbmRlcmVyLlxuICAgIHZhciBwID0gX3Byb3BlcnR5QWxpYXNlc1twcm9wZXJ0eV07XG4gICAgcCAmJiBwLmluZGV4T2YoXCIsXCIpIDwgMCAmJiAocHJvcGVydHkgPSBwKTtcbiAgICByZXR1cm4gcHJvcGVydHkgaW4gX3RyYW5zZm9ybVByb3BzICYmIHByb3BlcnR5ICE9PSBfdHJhbnNmb3JtT3JpZ2luUHJvcCAmJiAodGFyZ2V0Ll9nc2FwLnggfHwgX2dldCh0YXJnZXQsIFwieFwiKSkgPyBwbHVnaW4gJiYgX3JlY2VudFNldHRlclBsdWdpbiA9PT0gcGx1Z2luID8gcHJvcGVydHkgPT09IFwic2NhbGVcIiA/IF9zZXR0ZXJTY2FsZSA6IF9zZXR0ZXJUcmFuc2Zvcm0gOiAoX3JlY2VudFNldHRlclBsdWdpbiA9IHBsdWdpbiB8fCB7fSkgJiYgKHByb3BlcnR5ID09PSBcInNjYWxlXCIgPyBfc2V0dGVyU2NhbGVXaXRoUmVuZGVyIDogX3NldHRlclRyYW5zZm9ybVdpdGhSZW5kZXIpIDogdGFyZ2V0LnN0eWxlICYmICFfaXNVbmRlZmluZWQodGFyZ2V0LnN0eWxlW3Byb3BlcnR5XSkgPyBfc2V0dGVyQ1NTU3R5bGUgOiB+cHJvcGVydHkuaW5kZXhPZihcIi1cIikgPyBfc2V0dGVyQ1NTUHJvcCA6IF9nZXRTZXR0ZXIodGFyZ2V0LCBwcm9wZXJ0eSk7XG4gIH0sXG4gIGNvcmU6IHtcbiAgICBfcmVtb3ZlUHJvcGVydHk6IF9yZW1vdmVQcm9wZXJ0eSxcbiAgICBfZ2V0TWF0cml4OiBfZ2V0TWF0cml4XG4gIH1cbn07XG5nc2FwLnV0aWxzLmNoZWNrUHJlZml4ID0gX2NoZWNrUHJvcFByZWZpeDtcbmdzYXAuY29yZS5nZXRTdHlsZVNhdmVyID0gX2dldFN0eWxlU2F2ZXI7XG5cbihmdW5jdGlvbiAocG9zaXRpb25BbmRTY2FsZSwgcm90YXRpb24sIG90aGVycywgYWxpYXNlcykge1xuICB2YXIgYWxsID0gX2ZvckVhY2hOYW1lKHBvc2l0aW9uQW5kU2NhbGUgKyBcIixcIiArIHJvdGF0aW9uICsgXCIsXCIgKyBvdGhlcnMsIGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgX3RyYW5zZm9ybVByb3BzW25hbWVdID0gMTtcbiAgfSk7XG5cbiAgX2ZvckVhY2hOYW1lKHJvdGF0aW9uLCBmdW5jdGlvbiAobmFtZSkge1xuICAgIF9jb25maWcudW5pdHNbbmFtZV0gPSBcImRlZ1wiO1xuICAgIF9yb3RhdGlvbmFsUHJvcGVydGllc1tuYW1lXSA9IDE7XG4gIH0pO1xuXG4gIF9wcm9wZXJ0eUFsaWFzZXNbYWxsWzEzXV0gPSBwb3NpdGlvbkFuZFNjYWxlICsgXCIsXCIgKyByb3RhdGlvbjtcblxuICBfZm9yRWFjaE5hbWUoYWxpYXNlcywgZnVuY3Rpb24gKG5hbWUpIHtcbiAgICB2YXIgc3BsaXQgPSBuYW1lLnNwbGl0KFwiOlwiKTtcbiAgICBfcHJvcGVydHlBbGlhc2VzW3NwbGl0WzFdXSA9IGFsbFtzcGxpdFswXV07XG4gIH0pO1xufSkoXCJ4LHkseixzY2FsZSxzY2FsZVgsc2NhbGVZLHhQZXJjZW50LHlQZXJjZW50XCIsIFwicm90YXRpb24scm90YXRpb25YLHJvdGF0aW9uWSxza2V3WCxza2V3WVwiLCBcInRyYW5zZm9ybSx0cmFuc2Zvcm1PcmlnaW4sc3ZnT3JpZ2luLGZvcmNlM0Qsc21vb3RoT3JpZ2luLHRyYW5zZm9ybVBlcnNwZWN0aXZlXCIsIFwiMDp0cmFuc2xhdGVYLDE6dHJhbnNsYXRlWSwyOnRyYW5zbGF0ZVosODpyb3RhdGUsODpyb3RhdGlvblosODpyb3RhdGVaLDk6cm90YXRlWCwxMDpyb3RhdGVZXCIpO1xuXG5fZm9yRWFjaE5hbWUoXCJ4LHkseix0b3AscmlnaHQsYm90dG9tLGxlZnQsd2lkdGgsaGVpZ2h0LGZvbnRTaXplLHBhZGRpbmcsbWFyZ2luLHBlcnNwZWN0aXZlXCIsIGZ1bmN0aW9uIChuYW1lKSB7XG4gIF9jb25maWcudW5pdHNbbmFtZV0gPSBcInB4XCI7XG59KTtcblxuZ3NhcC5yZWdpc3RlclBsdWdpbihDU1NQbHVnaW4pO1xuZXhwb3J0IHsgQ1NTUGx1Z2luIGFzIGRlZmF1bHQsIF9nZXRCQm94LCBfY3JlYXRlRWxlbWVudCwgX2NoZWNrUHJvcFByZWZpeCBhcyBjaGVja1ByZWZpeCB9OyIsImltcG9ydCB7IGdzYXAsIFBvd2VyMCwgUG93ZXIxLCBQb3dlcjIsIFBvd2VyMywgUG93ZXI0LCBMaW5lYXIsIFF1YWQsIEN1YmljLCBRdWFydCwgUXVpbnQsIFN0cm9uZywgRWxhc3RpYywgQmFjaywgU3RlcHBlZEVhc2UsIEJvdW5jZSwgU2luZSwgRXhwbywgQ2lyYywgVHdlZW5MaXRlLCBUaW1lbGluZUxpdGUsIFRpbWVsaW5lTWF4IH0gZnJvbSBcIi4vZ3NhcC1jb3JlLmpzXCI7XG5pbXBvcnQgeyBDU1NQbHVnaW4gfSBmcm9tIFwiLi9DU1NQbHVnaW4uanNcIjtcbnZhciBnc2FwV2l0aENTUyA9IGdzYXAucmVnaXN0ZXJQbHVnaW4oQ1NTUGx1Z2luKSB8fCBnc2FwLFxuICAgIC8vIHRvIHByb3RlY3QgZnJvbSB0cmVlIHNoYWtpbmdcblR3ZWVuTWF4V2l0aENTUyA9IGdzYXBXaXRoQ1NTLmNvcmUuVHdlZW47XG5leHBvcnQgeyBnc2FwV2l0aENTUyBhcyBnc2FwLCBnc2FwV2l0aENTUyBhcyBkZWZhdWx0LCBDU1NQbHVnaW4sIFR3ZWVuTWF4V2l0aENTUyBhcyBUd2Vlbk1heCwgVHdlZW5MaXRlLCBUaW1lbGluZU1heCwgVGltZWxpbmVMaXRlLCBQb3dlcjAsIFBvd2VyMSwgUG93ZXIyLCBQb3dlcjMsIFBvd2VyNCwgTGluZWFyLCBRdWFkLCBDdWJpYywgUXVhcnQsIFF1aW50LCBTdHJvbmcsIEVsYXN0aWMsIEJhY2ssIFN0ZXBwZWRFYXNlLCBCb3VuY2UsIFNpbmUsIEV4cG8sIENpcmMgfTsiLCJmdW5jdGlvbiBfZGVmaW5lUHJvcGVydGllcyh0YXJnZXQsIHByb3BzKSB7IGZvciAodmFyIGkgPSAwOyBpIDwgcHJvcHMubGVuZ3RoOyBpKyspIHsgdmFyIGRlc2NyaXB0b3IgPSBwcm9wc1tpXTsgZGVzY3JpcHRvci5lbnVtZXJhYmxlID0gZGVzY3JpcHRvci5lbnVtZXJhYmxlIHx8IGZhbHNlOyBkZXNjcmlwdG9yLmNvbmZpZ3VyYWJsZSA9IHRydWU7IGlmIChcInZhbHVlXCIgaW4gZGVzY3JpcHRvcikgZGVzY3JpcHRvci53cml0YWJsZSA9IHRydWU7IE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIGRlc2NyaXB0b3Iua2V5LCBkZXNjcmlwdG9yKTsgfSB9XG5cbmZ1bmN0aW9uIF9jcmVhdGVDbGFzcyhDb25zdHJ1Y3RvciwgcHJvdG9Qcm9wcywgc3RhdGljUHJvcHMpIHsgaWYgKHByb3RvUHJvcHMpIF9kZWZpbmVQcm9wZXJ0aWVzKENvbnN0cnVjdG9yLnByb3RvdHlwZSwgcHJvdG9Qcm9wcyk7IGlmIChzdGF0aWNQcm9wcykgX2RlZmluZVByb3BlcnRpZXMoQ29uc3RydWN0b3IsIHN0YXRpY1Byb3BzKTsgcmV0dXJuIENvbnN0cnVjdG9yOyB9XG5cbi8qIVxuICogT2JzZXJ2ZXIgMy4xMi41XG4gKiBodHRwczovL2dzYXAuY29tXG4gKlxuICogQGxpY2Vuc2UgQ29weXJpZ2h0IDIwMDgtMjAyNCwgR3JlZW5Tb2NrLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogU3ViamVjdCB0byB0aGUgdGVybXMgYXQgaHR0cHM6Ly9nc2FwLmNvbS9zdGFuZGFyZC1saWNlbnNlIG9yIGZvclxuICogQ2x1YiBHU0FQIG1lbWJlcnMsIHRoZSBhZ3JlZW1lbnQgaXNzdWVkIHdpdGggdGhhdCBtZW1iZXJzaGlwLlxuICogQGF1dGhvcjogSmFjayBEb3lsZSwgamFja0BncmVlbnNvY2suY29tXG4qL1xuXG4vKiBlc2xpbnQtZGlzYWJsZSAqL1xudmFyIGdzYXAsXG4gICAgX2NvcmVJbml0dGVkLFxuICAgIF9jbGFtcCxcbiAgICBfd2luLFxuICAgIF9kb2MsXG4gICAgX2RvY0VsLFxuICAgIF9ib2R5LFxuICAgIF9pc1RvdWNoLFxuICAgIF9wb2ludGVyVHlwZSxcbiAgICBTY3JvbGxUcmlnZ2VyLFxuICAgIF9yb290LFxuICAgIF9ub3JtYWxpemVyLFxuICAgIF9ldmVudFR5cGVzLFxuICAgIF9jb250ZXh0LFxuICAgIF9nZXRHU0FQID0gZnVuY3Rpb24gX2dldEdTQVAoKSB7XG4gIHJldHVybiBnc2FwIHx8IHR5cGVvZiB3aW5kb3cgIT09IFwidW5kZWZpbmVkXCIgJiYgKGdzYXAgPSB3aW5kb3cuZ3NhcCkgJiYgZ3NhcC5yZWdpc3RlclBsdWdpbiAmJiBnc2FwO1xufSxcbiAgICBfc3RhcnR1cCA9IDEsXG4gICAgX29ic2VydmVycyA9IFtdLFxuICAgIF9zY3JvbGxlcnMgPSBbXSxcbiAgICBfcHJveGllcyA9IFtdLFxuICAgIF9nZXRUaW1lID0gRGF0ZS5ub3csXG4gICAgX2JyaWRnZSA9IGZ1bmN0aW9uIF9icmlkZ2UobmFtZSwgdmFsdWUpIHtcbiAgcmV0dXJuIHZhbHVlO1xufSxcbiAgICBfaW50ZWdyYXRlID0gZnVuY3Rpb24gX2ludGVncmF0ZSgpIHtcbiAgdmFyIGNvcmUgPSBTY3JvbGxUcmlnZ2VyLmNvcmUsXG4gICAgICBkYXRhID0gY29yZS5icmlkZ2UgfHwge30sXG4gICAgICBzY3JvbGxlcnMgPSBjb3JlLl9zY3JvbGxlcnMsXG4gICAgICBwcm94aWVzID0gY29yZS5fcHJveGllcztcbiAgc2Nyb2xsZXJzLnB1c2guYXBwbHkoc2Nyb2xsZXJzLCBfc2Nyb2xsZXJzKTtcbiAgcHJveGllcy5wdXNoLmFwcGx5KHByb3hpZXMsIF9wcm94aWVzKTtcbiAgX3Njcm9sbGVycyA9IHNjcm9sbGVycztcbiAgX3Byb3hpZXMgPSBwcm94aWVzO1xuXG4gIF9icmlkZ2UgPSBmdW5jdGlvbiBfYnJpZGdlKG5hbWUsIHZhbHVlKSB7XG4gICAgcmV0dXJuIGRhdGFbbmFtZV0odmFsdWUpO1xuICB9O1xufSxcbiAgICBfZ2V0UHJveHlQcm9wID0gZnVuY3Rpb24gX2dldFByb3h5UHJvcChlbGVtZW50LCBwcm9wZXJ0eSkge1xuICByZXR1cm4gfl9wcm94aWVzLmluZGV4T2YoZWxlbWVudCkgJiYgX3Byb3hpZXNbX3Byb3hpZXMuaW5kZXhPZihlbGVtZW50KSArIDFdW3Byb3BlcnR5XTtcbn0sXG4gICAgX2lzVmlld3BvcnQgPSBmdW5jdGlvbiBfaXNWaWV3cG9ydChlbCkge1xuICByZXR1cm4gISF+X3Jvb3QuaW5kZXhPZihlbCk7XG59LFxuICAgIF9hZGRMaXN0ZW5lciA9IGZ1bmN0aW9uIF9hZGRMaXN0ZW5lcihlbGVtZW50LCB0eXBlLCBmdW5jLCBwYXNzaXZlLCBjYXB0dXJlKSB7XG4gIHJldHVybiBlbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIodHlwZSwgZnVuYywge1xuICAgIHBhc3NpdmU6IHBhc3NpdmUgIT09IGZhbHNlLFxuICAgIGNhcHR1cmU6ICEhY2FwdHVyZVxuICB9KTtcbn0sXG4gICAgX3JlbW92ZUxpc3RlbmVyID0gZnVuY3Rpb24gX3JlbW92ZUxpc3RlbmVyKGVsZW1lbnQsIHR5cGUsIGZ1bmMsIGNhcHR1cmUpIHtcbiAgcmV0dXJuIGVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcih0eXBlLCBmdW5jLCAhIWNhcHR1cmUpO1xufSxcbiAgICBfc2Nyb2xsTGVmdCA9IFwic2Nyb2xsTGVmdFwiLFxuICAgIF9zY3JvbGxUb3AgPSBcInNjcm9sbFRvcFwiLFxuICAgIF9vblNjcm9sbCA9IGZ1bmN0aW9uIF9vblNjcm9sbCgpIHtcbiAgcmV0dXJuIF9ub3JtYWxpemVyICYmIF9ub3JtYWxpemVyLmlzUHJlc3NlZCB8fCBfc2Nyb2xsZXJzLmNhY2hlKys7XG59LFxuICAgIF9zY3JvbGxDYWNoZUZ1bmMgPSBmdW5jdGlvbiBfc2Nyb2xsQ2FjaGVGdW5jKGYsIGRvTm90Q2FjaGUpIHtcbiAgdmFyIGNhY2hpbmdGdW5jID0gZnVuY3Rpb24gY2FjaGluZ0Z1bmModmFsdWUpIHtcbiAgICAvLyBzaW5jZSByZWFkaW5nIHRoZSBzY3JvbGxUb3Avc2Nyb2xsTGVmdC9wYWdlT2Zmc2V0WS9wYWdlT2Zmc2V0WCBjYW4gdHJpZ2dlciBhIGxheW91dCwgdGhpcyBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gY2FjaGUgdGhlIHZhbHVlIHNvIGl0IG9ubHkgZ2V0cyByZWFkIGZyZXNoIGFmdGVyIGEgXCJzY3JvbGxcIiBldmVudCBmaXJlcyAob3Igd2hpbGUgd2UncmUgcmVmcmVzaGluZyBiZWNhdXNlIHRoYXQgY2FuIGxlbmd0aGVuIHRoZSBwYWdlIGFuZCBhbHRlciB0aGUgc2Nyb2xsIHBvc2l0aW9uKS4gd2hlbiBcInNvZnRcIiBpcyB0cnVlLCB0aGF0IG1lYW5zIGRvbid0IGFjdHVhbGx5IHNldCB0aGUgc2Nyb2xsLCBidXQgY2FjaGUgdGhlIG5ldyB2YWx1ZSBpbnN0ZWFkICh1c2VmdWwgaW4gU2Nyb2xsU21vb3RoZXIpXG4gICAgaWYgKHZhbHVlIHx8IHZhbHVlID09PSAwKSB7XG4gICAgICBfc3RhcnR1cCAmJiAoX3dpbi5oaXN0b3J5LnNjcm9sbFJlc3RvcmF0aW9uID0gXCJtYW51YWxcIik7IC8vIG90aGVyd2lzZSB0aGUgbmV3IHBvc2l0aW9uIHdpbGwgZ2V0IG92ZXJ3cml0dGVuIGJ5IHRoZSBicm93c2VyIG9ubG9hZC5cblxuICAgICAgdmFyIGlzTm9ybWFsaXppbmcgPSBfbm9ybWFsaXplciAmJiBfbm9ybWFsaXplci5pc1ByZXNzZWQ7XG4gICAgICB2YWx1ZSA9IGNhY2hpbmdGdW5jLnYgPSBNYXRoLnJvdW5kKHZhbHVlKSB8fCAoX25vcm1hbGl6ZXIgJiYgX25vcm1hbGl6ZXIuaU9TID8gMSA6IDApOyAvL1RPRE86IGlPUyBCdWc6IGlmIHlvdSBhbGxvdyBpdCB0byBnbyB0byAwLCBTYWZhcmkgY2FuIHN0YXJ0IHRvIHJlcG9ydCBzdXBlciBzdHJhbmdlICh3aWxkbHkgaW5hY2N1cmF0ZSkgdG91Y2ggcG9zaXRpb25zIVxuXG4gICAgICBmKHZhbHVlKTtcbiAgICAgIGNhY2hpbmdGdW5jLmNhY2hlSUQgPSBfc2Nyb2xsZXJzLmNhY2hlO1xuICAgICAgaXNOb3JtYWxpemluZyAmJiBfYnJpZGdlKFwic3NcIiwgdmFsdWUpOyAvLyBzZXQgc2Nyb2xsIChub3RpZnkgU2Nyb2xsVHJpZ2dlciBzbyBpdCBjYW4gZGlzcGF0Y2ggYSBcInNjcm9sbFN0YXJ0XCIgZXZlbnQgaWYgbmVjZXNzYXJ5XG4gICAgfSBlbHNlIGlmIChkb05vdENhY2hlIHx8IF9zY3JvbGxlcnMuY2FjaGUgIT09IGNhY2hpbmdGdW5jLmNhY2hlSUQgfHwgX2JyaWRnZShcInJlZlwiKSkge1xuICAgICAgY2FjaGluZ0Z1bmMuY2FjaGVJRCA9IF9zY3JvbGxlcnMuY2FjaGU7XG4gICAgICBjYWNoaW5nRnVuYy52ID0gZigpO1xuICAgIH1cblxuICAgIHJldHVybiBjYWNoaW5nRnVuYy52ICsgY2FjaGluZ0Z1bmMub2Zmc2V0O1xuICB9O1xuXG4gIGNhY2hpbmdGdW5jLm9mZnNldCA9IDA7XG4gIHJldHVybiBmICYmIGNhY2hpbmdGdW5jO1xufSxcbiAgICBfaG9yaXpvbnRhbCA9IHtcbiAgczogX3Njcm9sbExlZnQsXG4gIHA6IFwibGVmdFwiLFxuICBwMjogXCJMZWZ0XCIsXG4gIG9zOiBcInJpZ2h0XCIsXG4gIG9zMjogXCJSaWdodFwiLFxuICBkOiBcIndpZHRoXCIsXG4gIGQyOiBcIldpZHRoXCIsXG4gIGE6IFwieFwiLFxuICBzYzogX3Njcm9sbENhY2hlRnVuYyhmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gYXJndW1lbnRzLmxlbmd0aCA/IF93aW4uc2Nyb2xsVG8odmFsdWUsIF92ZXJ0aWNhbC5zYygpKSA6IF93aW4ucGFnZVhPZmZzZXQgfHwgX2RvY1tfc2Nyb2xsTGVmdF0gfHwgX2RvY0VsW19zY3JvbGxMZWZ0XSB8fCBfYm9keVtfc2Nyb2xsTGVmdF0gfHwgMDtcbiAgfSlcbn0sXG4gICAgX3ZlcnRpY2FsID0ge1xuICBzOiBfc2Nyb2xsVG9wLFxuICBwOiBcInRvcFwiLFxuICBwMjogXCJUb3BcIixcbiAgb3M6IFwiYm90dG9tXCIsXG4gIG9zMjogXCJCb3R0b21cIixcbiAgZDogXCJoZWlnaHRcIixcbiAgZDI6IFwiSGVpZ2h0XCIsXG4gIGE6IFwieVwiLFxuICBvcDogX2hvcml6b250YWwsXG4gIHNjOiBfc2Nyb2xsQ2FjaGVGdW5jKGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHJldHVybiBhcmd1bWVudHMubGVuZ3RoID8gX3dpbi5zY3JvbGxUbyhfaG9yaXpvbnRhbC5zYygpLCB2YWx1ZSkgOiBfd2luLnBhZ2VZT2Zmc2V0IHx8IF9kb2NbX3Njcm9sbFRvcF0gfHwgX2RvY0VsW19zY3JvbGxUb3BdIHx8IF9ib2R5W19zY3JvbGxUb3BdIHx8IDA7XG4gIH0pXG59LFxuICAgIF9nZXRUYXJnZXQgPSBmdW5jdGlvbiBfZ2V0VGFyZ2V0KHQsIHNlbGYpIHtcbiAgcmV0dXJuIChzZWxmICYmIHNlbGYuX2N0eCAmJiBzZWxmLl9jdHguc2VsZWN0b3IgfHwgZ3NhcC51dGlscy50b0FycmF5KSh0KVswXSB8fCAodHlwZW9mIHQgPT09IFwic3RyaW5nXCIgJiYgZ3NhcC5jb25maWcoKS5udWxsVGFyZ2V0V2FybiAhPT0gZmFsc2UgPyBjb25zb2xlLndhcm4oXCJFbGVtZW50IG5vdCBmb3VuZDpcIiwgdCkgOiBudWxsKTtcbn0sXG4gICAgX2dldFNjcm9sbEZ1bmMgPSBmdW5jdGlvbiBfZ2V0U2Nyb2xsRnVuYyhlbGVtZW50LCBfcmVmKSB7XG4gIHZhciBzID0gX3JlZi5zLFxuICAgICAgc2MgPSBfcmVmLnNjO1xuICAvLyB3ZSBzdG9yZSB0aGUgc2Nyb2xsZXIgZnVuY3Rpb25zIGluIGFuIGFsdGVybmF0aW5nIHNlcXVlbmNlZCBBcnJheSBsaWtlIFtlbGVtZW50LCB2ZXJ0aWNhbFNjcm9sbEZ1bmMsIGhvcml6b250YWxTY3JvbGxGdW5jLCAuLi5dIHNvIHRoYXQgd2UgY2FuIG1pbmltaXplIG1lbW9yeSwgbWF4aW1pemUgcGVyZm9ybWFuY2UsIGFuZCB3ZSBhbHNvIHJlY29yZCB0aGUgbGFzdCBwb3NpdGlvbiBhcyBhIFwiLnJlY1wiIHByb3BlcnR5IGluIG9yZGVyIHRvIHJldmVydCB0byB0aGF0IGFmdGVyIHJlZnJlc2hpbmcgdG8gZW5zdXJlIHRoaW5ncyBkb24ndCBzaGlmdCBhcm91bmQuXG4gIF9pc1ZpZXdwb3J0KGVsZW1lbnQpICYmIChlbGVtZW50ID0gX2RvYy5zY3JvbGxpbmdFbGVtZW50IHx8IF9kb2NFbCk7XG5cbiAgdmFyIGkgPSBfc2Nyb2xsZXJzLmluZGV4T2YoZWxlbWVudCksXG4gICAgICBvZmZzZXQgPSBzYyA9PT0gX3ZlcnRpY2FsLnNjID8gMSA6IDI7XG5cbiAgIX5pICYmIChpID0gX3Njcm9sbGVycy5wdXNoKGVsZW1lbnQpIC0gMSk7XG4gIF9zY3JvbGxlcnNbaSArIG9mZnNldF0gfHwgX2FkZExpc3RlbmVyKGVsZW1lbnQsIFwic2Nyb2xsXCIsIF9vblNjcm9sbCk7IC8vIGNsZWFyIHRoZSBjYWNoZSB3aGVuIGEgc2Nyb2xsIG9jY3Vyc1xuXG4gIHZhciBwcmV2ID0gX3Njcm9sbGVyc1tpICsgb2Zmc2V0XSxcbiAgICAgIGZ1bmMgPSBwcmV2IHx8IChfc2Nyb2xsZXJzW2kgKyBvZmZzZXRdID0gX3Njcm9sbENhY2hlRnVuYyhfZ2V0UHJveHlQcm9wKGVsZW1lbnQsIHMpLCB0cnVlKSB8fCAoX2lzVmlld3BvcnQoZWxlbWVudCkgPyBzYyA6IF9zY3JvbGxDYWNoZUZ1bmMoZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgcmV0dXJuIGFyZ3VtZW50cy5sZW5ndGggPyBlbGVtZW50W3NdID0gdmFsdWUgOiBlbGVtZW50W3NdO1xuICB9KSkpO1xuICBmdW5jLnRhcmdldCA9IGVsZW1lbnQ7XG4gIHByZXYgfHwgKGZ1bmMuc21vb3RoID0gZ3NhcC5nZXRQcm9wZXJ0eShlbGVtZW50LCBcInNjcm9sbEJlaGF2aW9yXCIpID09PSBcInNtb290aFwiKTsgLy8gb25seSBzZXQgaXQgdGhlIGZpcnN0IHRpbWUgKGRvbid0IHJlc2V0IGV2ZXJ5IHRpbWUgYSBzY3JvbGxGdW5jIGlzIHJlcXVlc3RlZCBiZWNhdXNlIHBlcmhhcHMgaXQgaGFwcGVucyBkdXJpbmcgYSByZWZyZXNoKCkgd2hlbiBpdCdzIGRpc2FibGVkIGluIFNjcm9sbFRyaWdnZXIuXG5cbiAgcmV0dXJuIGZ1bmM7XG59LFxuICAgIF9nZXRWZWxvY2l0eVByb3AgPSBmdW5jdGlvbiBfZ2V0VmVsb2NpdHlQcm9wKHZhbHVlLCBtaW5UaW1lUmVmcmVzaCwgdXNlRGVsdGEpIHtcbiAgdmFyIHYxID0gdmFsdWUsXG4gICAgICB2MiA9IHZhbHVlLFxuICAgICAgdDEgPSBfZ2V0VGltZSgpLFxuICAgICAgdDIgPSB0MSxcbiAgICAgIG1pbiA9IG1pblRpbWVSZWZyZXNoIHx8IDUwLFxuICAgICAgZHJvcFRvWmVyb1RpbWUgPSBNYXRoLm1heCg1MDAsIG1pbiAqIDMpLFxuICAgICAgdXBkYXRlID0gZnVuY3Rpb24gdXBkYXRlKHZhbHVlLCBmb3JjZSkge1xuICAgIHZhciB0ID0gX2dldFRpbWUoKTtcblxuICAgIGlmIChmb3JjZSB8fCB0IC0gdDEgPiBtaW4pIHtcbiAgICAgIHYyID0gdjE7XG4gICAgICB2MSA9IHZhbHVlO1xuICAgICAgdDIgPSB0MTtcbiAgICAgIHQxID0gdDtcbiAgICB9IGVsc2UgaWYgKHVzZURlbHRhKSB7XG4gICAgICB2MSArPSB2YWx1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gbm90IHRvdGFsbHkgbmVjZXNzYXJ5LCBidXQgbWFrZXMgaXQgYSBiaXQgbW9yZSBhY2N1cmF0ZSBieSBhZGp1c3RpbmcgdGhlIHYxIHZhbHVlIGFjY29yZGluZyB0byB0aGUgbmV3IHNsb3BlLiBUaGlzIHdheSB3ZSdyZSBub3QganVzdCBpZ25vcmluZyB0aGUgaW5jb21pbmcgZGF0YS4gUmVtb3ZpbmcgZm9yIG5vdyBiZWNhdXNlIGl0IGRvZXNuJ3Qgc2VlbSB0byBtYWtlIG11Y2ggcHJhY3RpY2FsIGRpZmZlcmVuY2UgYW5kIGl0J3MgcHJvYmFibHkgbm90IHdvcnRoIHRoZSBrYi5cbiAgICAgIHYxID0gdjIgKyAodmFsdWUgLSB2MikgLyAodCAtIHQyKSAqICh0MSAtIHQyKTtcbiAgICB9XG4gIH0sXG4gICAgICByZXNldCA9IGZ1bmN0aW9uIHJlc2V0KCkge1xuICAgIHYyID0gdjEgPSB1c2VEZWx0YSA/IDAgOiB2MTtcbiAgICB0MiA9IHQxID0gMDtcbiAgfSxcbiAgICAgIGdldFZlbG9jaXR5ID0gZnVuY3Rpb24gZ2V0VmVsb2NpdHkobGF0ZXN0VmFsdWUpIHtcbiAgICB2YXIgdE9sZCA9IHQyLFxuICAgICAgICB2T2xkID0gdjIsXG4gICAgICAgIHQgPSBfZ2V0VGltZSgpO1xuXG4gICAgKGxhdGVzdFZhbHVlIHx8IGxhdGVzdFZhbHVlID09PSAwKSAmJiBsYXRlc3RWYWx1ZSAhPT0gdjEgJiYgdXBkYXRlKGxhdGVzdFZhbHVlKTtcbiAgICByZXR1cm4gdDEgPT09IHQyIHx8IHQgLSB0MiA+IGRyb3BUb1plcm9UaW1lID8gMCA6ICh2MSArICh1c2VEZWx0YSA/IHZPbGQgOiAtdk9sZCkpIC8gKCh1c2VEZWx0YSA/IHQgOiB0MSkgLSB0T2xkKSAqIDEwMDA7XG4gIH07XG5cbiAgcmV0dXJuIHtcbiAgICB1cGRhdGU6IHVwZGF0ZSxcbiAgICByZXNldDogcmVzZXQsXG4gICAgZ2V0VmVsb2NpdHk6IGdldFZlbG9jaXR5XG4gIH07XG59LFxuICAgIF9nZXRFdmVudCA9IGZ1bmN0aW9uIF9nZXRFdmVudChlLCBwcmV2ZW50RGVmYXVsdCkge1xuICBwcmV2ZW50RGVmYXVsdCAmJiAhZS5fZ3NhcEFsbG93ICYmIGUucHJldmVudERlZmF1bHQoKTtcbiAgcmV0dXJuIGUuY2hhbmdlZFRvdWNoZXMgPyBlLmNoYW5nZWRUb3VjaGVzWzBdIDogZTtcbn0sXG4gICAgX2dldEFic29sdXRlTWF4ID0gZnVuY3Rpb24gX2dldEFic29sdXRlTWF4KGEpIHtcbiAgdmFyIG1heCA9IE1hdGgubWF4LmFwcGx5KE1hdGgsIGEpLFxuICAgICAgbWluID0gTWF0aC5taW4uYXBwbHkoTWF0aCwgYSk7XG4gIHJldHVybiBNYXRoLmFicyhtYXgpID49IE1hdGguYWJzKG1pbikgPyBtYXggOiBtaW47XG59LFxuICAgIF9zZXRTY3JvbGxUcmlnZ2VyID0gZnVuY3Rpb24gX3NldFNjcm9sbFRyaWdnZXIoKSB7XG4gIFNjcm9sbFRyaWdnZXIgPSBnc2FwLmNvcmUuZ2xvYmFscygpLlNjcm9sbFRyaWdnZXI7XG4gIFNjcm9sbFRyaWdnZXIgJiYgU2Nyb2xsVHJpZ2dlci5jb3JlICYmIF9pbnRlZ3JhdGUoKTtcbn0sXG4gICAgX2luaXRDb3JlID0gZnVuY3Rpb24gX2luaXRDb3JlKGNvcmUpIHtcbiAgZ3NhcCA9IGNvcmUgfHwgX2dldEdTQVAoKTtcblxuICBpZiAoIV9jb3JlSW5pdHRlZCAmJiBnc2FwICYmIHR5cGVvZiBkb2N1bWVudCAhPT0gXCJ1bmRlZmluZWRcIiAmJiBkb2N1bWVudC5ib2R5KSB7XG4gICAgX3dpbiA9IHdpbmRvdztcbiAgICBfZG9jID0gZG9jdW1lbnQ7XG4gICAgX2RvY0VsID0gX2RvYy5kb2N1bWVudEVsZW1lbnQ7XG4gICAgX2JvZHkgPSBfZG9jLmJvZHk7XG4gICAgX3Jvb3QgPSBbX3dpbiwgX2RvYywgX2RvY0VsLCBfYm9keV07XG4gICAgX2NsYW1wID0gZ3NhcC51dGlscy5jbGFtcDtcblxuICAgIF9jb250ZXh0ID0gZ3NhcC5jb3JlLmNvbnRleHQgfHwgZnVuY3Rpb24gKCkge307XG5cbiAgICBfcG9pbnRlclR5cGUgPSBcIm9ucG9pbnRlcmVudGVyXCIgaW4gX2JvZHkgPyBcInBvaW50ZXJcIiA6IFwibW91c2VcIjsgLy8gaXNUb3VjaCBpcyAwIGlmIG5vIHRvdWNoLCAxIGlmIE9OTFkgdG91Y2gsIGFuZCAyIGlmIGl0IGNhbiBhY2NvbW1vZGF0ZSB0b3VjaCBidXQgYWxzbyBvdGhlciB0eXBlcyBsaWtlIG1vdXNlL3BvaW50ZXIuXG5cbiAgICBfaXNUb3VjaCA9IE9ic2VydmVyLmlzVG91Y2ggPSBfd2luLm1hdGNoTWVkaWEgJiYgX3dpbi5tYXRjaE1lZGlhKFwiKGhvdmVyOiBub25lKSwgKHBvaW50ZXI6IGNvYXJzZSlcIikubWF0Y2hlcyA/IDEgOiBcIm9udG91Y2hzdGFydFwiIGluIF93aW4gfHwgbmF2aWdhdG9yLm1heFRvdWNoUG9pbnRzID4gMCB8fCBuYXZpZ2F0b3IubXNNYXhUb3VjaFBvaW50cyA+IDAgPyAyIDogMDtcbiAgICBfZXZlbnRUeXBlcyA9IE9ic2VydmVyLmV2ZW50VHlwZXMgPSAoXCJvbnRvdWNoc3RhcnRcIiBpbiBfZG9jRWwgPyBcInRvdWNoc3RhcnQsdG91Y2htb3ZlLHRvdWNoY2FuY2VsLHRvdWNoZW5kXCIgOiAhKFwib25wb2ludGVyZG93blwiIGluIF9kb2NFbCkgPyBcIm1vdXNlZG93bixtb3VzZW1vdmUsbW91c2V1cCxtb3VzZXVwXCIgOiBcInBvaW50ZXJkb3duLHBvaW50ZXJtb3ZlLHBvaW50ZXJjYW5jZWwscG9pbnRlcnVwXCIpLnNwbGl0KFwiLFwiKTtcbiAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBfc3RhcnR1cCA9IDA7XG4gICAgfSwgNTAwKTtcblxuICAgIF9zZXRTY3JvbGxUcmlnZ2VyKCk7XG5cbiAgICBfY29yZUluaXR0ZWQgPSAxO1xuICB9XG5cbiAgcmV0dXJuIF9jb3JlSW5pdHRlZDtcbn07XG5cbl9ob3Jpem9udGFsLm9wID0gX3ZlcnRpY2FsO1xuX3Njcm9sbGVycy5jYWNoZSA9IDA7XG5leHBvcnQgdmFyIE9ic2VydmVyID0gLyojX19QVVJFX18qL2Z1bmN0aW9uICgpIHtcbiAgZnVuY3Rpb24gT2JzZXJ2ZXIodmFycykge1xuICAgIHRoaXMuaW5pdCh2YXJzKTtcbiAgfVxuXG4gIHZhciBfcHJvdG8gPSBPYnNlcnZlci5wcm90b3R5cGU7XG5cbiAgX3Byb3RvLmluaXQgPSBmdW5jdGlvbiBpbml0KHZhcnMpIHtcbiAgICBfY29yZUluaXR0ZWQgfHwgX2luaXRDb3JlKGdzYXApIHx8IGNvbnNvbGUud2FybihcIlBsZWFzZSBnc2FwLnJlZ2lzdGVyUGx1Z2luKE9ic2VydmVyKVwiKTtcbiAgICBTY3JvbGxUcmlnZ2VyIHx8IF9zZXRTY3JvbGxUcmlnZ2VyKCk7XG4gICAgdmFyIHRvbGVyYW5jZSA9IHZhcnMudG9sZXJhbmNlLFxuICAgICAgICBkcmFnTWluaW11bSA9IHZhcnMuZHJhZ01pbmltdW0sXG4gICAgICAgIHR5cGUgPSB2YXJzLnR5cGUsXG4gICAgICAgIHRhcmdldCA9IHZhcnMudGFyZ2V0LFxuICAgICAgICBsaW5lSGVpZ2h0ID0gdmFycy5saW5lSGVpZ2h0LFxuICAgICAgICBkZWJvdW5jZSA9IHZhcnMuZGVib3VuY2UsXG4gICAgICAgIHByZXZlbnREZWZhdWx0ID0gdmFycy5wcmV2ZW50RGVmYXVsdCxcbiAgICAgICAgb25TdG9wID0gdmFycy5vblN0b3AsXG4gICAgICAgIG9uU3RvcERlbGF5ID0gdmFycy5vblN0b3BEZWxheSxcbiAgICAgICAgaWdub3JlID0gdmFycy5pZ25vcmUsXG4gICAgICAgIHdoZWVsU3BlZWQgPSB2YXJzLndoZWVsU3BlZWQsXG4gICAgICAgIGV2ZW50ID0gdmFycy5ldmVudCxcbiAgICAgICAgb25EcmFnU3RhcnQgPSB2YXJzLm9uRHJhZ1N0YXJ0LFxuICAgICAgICBvbkRyYWdFbmQgPSB2YXJzLm9uRHJhZ0VuZCxcbiAgICAgICAgb25EcmFnID0gdmFycy5vbkRyYWcsXG4gICAgICAgIG9uUHJlc3MgPSB2YXJzLm9uUHJlc3MsXG4gICAgICAgIG9uUmVsZWFzZSA9IHZhcnMub25SZWxlYXNlLFxuICAgICAgICBvblJpZ2h0ID0gdmFycy5vblJpZ2h0LFxuICAgICAgICBvbkxlZnQgPSB2YXJzLm9uTGVmdCxcbiAgICAgICAgb25VcCA9IHZhcnMub25VcCxcbiAgICAgICAgb25Eb3duID0gdmFycy5vbkRvd24sXG4gICAgICAgIG9uQ2hhbmdlWCA9IHZhcnMub25DaGFuZ2VYLFxuICAgICAgICBvbkNoYW5nZVkgPSB2YXJzLm9uQ2hhbmdlWSxcbiAgICAgICAgb25DaGFuZ2UgPSB2YXJzLm9uQ2hhbmdlLFxuICAgICAgICBvblRvZ2dsZVggPSB2YXJzLm9uVG9nZ2xlWCxcbiAgICAgICAgb25Ub2dnbGVZID0gdmFycy5vblRvZ2dsZVksXG4gICAgICAgIG9uSG92ZXIgPSB2YXJzLm9uSG92ZXIsXG4gICAgICAgIG9uSG92ZXJFbmQgPSB2YXJzLm9uSG92ZXJFbmQsXG4gICAgICAgIG9uTW92ZSA9IHZhcnMub25Nb3ZlLFxuICAgICAgICBpZ25vcmVDaGVjayA9IHZhcnMuaWdub3JlQ2hlY2ssXG4gICAgICAgIGlzTm9ybWFsaXplciA9IHZhcnMuaXNOb3JtYWxpemVyLFxuICAgICAgICBvbkdlc3R1cmVTdGFydCA9IHZhcnMub25HZXN0dXJlU3RhcnQsXG4gICAgICAgIG9uR2VzdHVyZUVuZCA9IHZhcnMub25HZXN0dXJlRW5kLFxuICAgICAgICBvbldoZWVsID0gdmFycy5vbldoZWVsLFxuICAgICAgICBvbkVuYWJsZSA9IHZhcnMub25FbmFibGUsXG4gICAgICAgIG9uRGlzYWJsZSA9IHZhcnMub25EaXNhYmxlLFxuICAgICAgICBvbkNsaWNrID0gdmFycy5vbkNsaWNrLFxuICAgICAgICBzY3JvbGxTcGVlZCA9IHZhcnMuc2Nyb2xsU3BlZWQsXG4gICAgICAgIGNhcHR1cmUgPSB2YXJzLmNhcHR1cmUsXG4gICAgICAgIGFsbG93Q2xpY2tzID0gdmFycy5hbGxvd0NsaWNrcyxcbiAgICAgICAgbG9ja0F4aXMgPSB2YXJzLmxvY2tBeGlzLFxuICAgICAgICBvbkxvY2tBeGlzID0gdmFycy5vbkxvY2tBeGlzO1xuICAgIHRoaXMudGFyZ2V0ID0gdGFyZ2V0ID0gX2dldFRhcmdldCh0YXJnZXQpIHx8IF9kb2NFbDtcbiAgICB0aGlzLnZhcnMgPSB2YXJzO1xuICAgIGlnbm9yZSAmJiAoaWdub3JlID0gZ3NhcC51dGlscy50b0FycmF5KGlnbm9yZSkpO1xuICAgIHRvbGVyYW5jZSA9IHRvbGVyYW5jZSB8fCAxZS05O1xuICAgIGRyYWdNaW5pbXVtID0gZHJhZ01pbmltdW0gfHwgMDtcbiAgICB3aGVlbFNwZWVkID0gd2hlZWxTcGVlZCB8fCAxO1xuICAgIHNjcm9sbFNwZWVkID0gc2Nyb2xsU3BlZWQgfHwgMTtcbiAgICB0eXBlID0gdHlwZSB8fCBcIndoZWVsLHRvdWNoLHBvaW50ZXJcIjtcbiAgICBkZWJvdW5jZSA9IGRlYm91bmNlICE9PSBmYWxzZTtcbiAgICBsaW5lSGVpZ2h0IHx8IChsaW5lSGVpZ2h0ID0gcGFyc2VGbG9hdChfd2luLmdldENvbXB1dGVkU3R5bGUoX2JvZHkpLmxpbmVIZWlnaHQpIHx8IDIyKTsgLy8gbm90ZTogYnJvd3NlciBtYXkgcmVwb3J0IFwibm9ybWFsXCIsIHNvIGRlZmF1bHQgdG8gMjIuXG5cbiAgICB2YXIgaWQsXG4gICAgICAgIG9uU3RvcERlbGF5ZWRDYWxsLFxuICAgICAgICBkcmFnZ2VkLFxuICAgICAgICBtb3ZlZCxcbiAgICAgICAgd2hlZWxlZCxcbiAgICAgICAgbG9ja2VkLFxuICAgICAgICBheGlzLFxuICAgICAgICBzZWxmID0gdGhpcyxcbiAgICAgICAgcHJldkRlbHRhWCA9IDAsXG4gICAgICAgIHByZXZEZWx0YVkgPSAwLFxuICAgICAgICBwYXNzaXZlID0gdmFycy5wYXNzaXZlIHx8ICFwcmV2ZW50RGVmYXVsdCxcbiAgICAgICAgc2Nyb2xsRnVuY1ggPSBfZ2V0U2Nyb2xsRnVuYyh0YXJnZXQsIF9ob3Jpem9udGFsKSxcbiAgICAgICAgc2Nyb2xsRnVuY1kgPSBfZ2V0U2Nyb2xsRnVuYyh0YXJnZXQsIF92ZXJ0aWNhbCksXG4gICAgICAgIHNjcm9sbFggPSBzY3JvbGxGdW5jWCgpLFxuICAgICAgICBzY3JvbGxZID0gc2Nyb2xsRnVuY1koKSxcbiAgICAgICAgbGltaXRUb1RvdWNoID0gfnR5cGUuaW5kZXhPZihcInRvdWNoXCIpICYmICF+dHlwZS5pbmRleE9mKFwicG9pbnRlclwiKSAmJiBfZXZlbnRUeXBlc1swXSA9PT0gXCJwb2ludGVyZG93blwiLFxuICAgICAgICAvLyBmb3IgZGV2aWNlcyB0aGF0IGFjY29tbW9kYXRlIG1vdXNlIGV2ZW50cyBhbmQgdG91Y2ggZXZlbnRzLCB3ZSBuZWVkIHRvIGRpc3Rpbmd1aXNoLlxuICAgIGlzVmlld3BvcnQgPSBfaXNWaWV3cG9ydCh0YXJnZXQpLFxuICAgICAgICBvd25lckRvYyA9IHRhcmdldC5vd25lckRvY3VtZW50IHx8IF9kb2MsXG4gICAgICAgIGRlbHRhWCA9IFswLCAwLCAwXSxcbiAgICAgICAgLy8gd2hlZWwsIHNjcm9sbCwgcG9pbnRlci90b3VjaFxuICAgIGRlbHRhWSA9IFswLCAwLCAwXSxcbiAgICAgICAgb25DbGlja1RpbWUgPSAwLFxuICAgICAgICBjbGlja0NhcHR1cmUgPSBmdW5jdGlvbiBjbGlja0NhcHR1cmUoKSB7XG4gICAgICByZXR1cm4gb25DbGlja1RpbWUgPSBfZ2V0VGltZSgpO1xuICAgIH0sXG4gICAgICAgIF9pZ25vcmVDaGVjayA9IGZ1bmN0aW9uIF9pZ25vcmVDaGVjayhlLCBpc1BvaW50ZXJPclRvdWNoKSB7XG4gICAgICByZXR1cm4gKHNlbGYuZXZlbnQgPSBlKSAmJiBpZ25vcmUgJiYgfmlnbm9yZS5pbmRleE9mKGUudGFyZ2V0KSB8fCBpc1BvaW50ZXJPclRvdWNoICYmIGxpbWl0VG9Ub3VjaCAmJiBlLnBvaW50ZXJUeXBlICE9PSBcInRvdWNoXCIgfHwgaWdub3JlQ2hlY2sgJiYgaWdub3JlQ2hlY2soZSwgaXNQb2ludGVyT3JUb3VjaCk7XG4gICAgfSxcbiAgICAgICAgb25TdG9wRnVuYyA9IGZ1bmN0aW9uIG9uU3RvcEZ1bmMoKSB7XG4gICAgICBzZWxmLl92eC5yZXNldCgpO1xuXG4gICAgICBzZWxmLl92eS5yZXNldCgpO1xuXG4gICAgICBvblN0b3BEZWxheWVkQ2FsbC5wYXVzZSgpO1xuICAgICAgb25TdG9wICYmIG9uU3RvcChzZWxmKTtcbiAgICB9LFxuICAgICAgICB1cGRhdGUgPSBmdW5jdGlvbiB1cGRhdGUoKSB7XG4gICAgICB2YXIgZHggPSBzZWxmLmRlbHRhWCA9IF9nZXRBYnNvbHV0ZU1heChkZWx0YVgpLFxuICAgICAgICAgIGR5ID0gc2VsZi5kZWx0YVkgPSBfZ2V0QWJzb2x1dGVNYXgoZGVsdGFZKSxcbiAgICAgICAgICBjaGFuZ2VkWCA9IE1hdGguYWJzKGR4KSA+PSB0b2xlcmFuY2UsXG4gICAgICAgICAgY2hhbmdlZFkgPSBNYXRoLmFicyhkeSkgPj0gdG9sZXJhbmNlO1xuXG4gICAgICBvbkNoYW5nZSAmJiAoY2hhbmdlZFggfHwgY2hhbmdlZFkpICYmIG9uQ2hhbmdlKHNlbGYsIGR4LCBkeSwgZGVsdGFYLCBkZWx0YVkpOyAvLyBpbiBTY3JvbGxUcmlnZ2VyLm5vcm1hbGl6ZVNjcm9sbCgpLCB3ZSBuZWVkIHRvIGtub3cgaWYgaXQgd2FzIHRvdWNoL3BvaW50ZXIgc28gd2UgbmVlZCBhY2Nlc3MgdG8gdGhlIGRlbHRhWC9kZWx0YVkgQXJyYXlzIGJlZm9yZSB3ZSBjbGVhciB0aGVtIG91dC5cblxuICAgICAgaWYgKGNoYW5nZWRYKSB7XG4gICAgICAgIG9uUmlnaHQgJiYgc2VsZi5kZWx0YVggPiAwICYmIG9uUmlnaHQoc2VsZik7XG4gICAgICAgIG9uTGVmdCAmJiBzZWxmLmRlbHRhWCA8IDAgJiYgb25MZWZ0KHNlbGYpO1xuICAgICAgICBvbkNoYW5nZVggJiYgb25DaGFuZ2VYKHNlbGYpO1xuICAgICAgICBvblRvZ2dsZVggJiYgc2VsZi5kZWx0YVggPCAwICE9PSBwcmV2RGVsdGFYIDwgMCAmJiBvblRvZ2dsZVgoc2VsZik7XG4gICAgICAgIHByZXZEZWx0YVggPSBzZWxmLmRlbHRhWDtcbiAgICAgICAgZGVsdGFYWzBdID0gZGVsdGFYWzFdID0gZGVsdGFYWzJdID0gMDtcbiAgICAgIH1cblxuICAgICAgaWYgKGNoYW5nZWRZKSB7XG4gICAgICAgIG9uRG93biAmJiBzZWxmLmRlbHRhWSA+IDAgJiYgb25Eb3duKHNlbGYpO1xuICAgICAgICBvblVwICYmIHNlbGYuZGVsdGFZIDwgMCAmJiBvblVwKHNlbGYpO1xuICAgICAgICBvbkNoYW5nZVkgJiYgb25DaGFuZ2VZKHNlbGYpO1xuICAgICAgICBvblRvZ2dsZVkgJiYgc2VsZi5kZWx0YVkgPCAwICE9PSBwcmV2RGVsdGFZIDwgMCAmJiBvblRvZ2dsZVkoc2VsZik7XG4gICAgICAgIHByZXZEZWx0YVkgPSBzZWxmLmRlbHRhWTtcbiAgICAgICAgZGVsdGFZWzBdID0gZGVsdGFZWzFdID0gZGVsdGFZWzJdID0gMDtcbiAgICAgIH1cblxuICAgICAgaWYgKG1vdmVkIHx8IGRyYWdnZWQpIHtcbiAgICAgICAgb25Nb3ZlICYmIG9uTW92ZShzZWxmKTtcblxuICAgICAgICBpZiAoZHJhZ2dlZCkge1xuICAgICAgICAgIG9uRHJhZyhzZWxmKTtcbiAgICAgICAgICBkcmFnZ2VkID0gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICBtb3ZlZCA9IGZhbHNlO1xuICAgICAgfVxuXG4gICAgICBsb2NrZWQgJiYgIShsb2NrZWQgPSBmYWxzZSkgJiYgb25Mb2NrQXhpcyAmJiBvbkxvY2tBeGlzKHNlbGYpO1xuXG4gICAgICBpZiAod2hlZWxlZCkge1xuICAgICAgICBvbldoZWVsKHNlbGYpO1xuICAgICAgICB3aGVlbGVkID0gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIGlkID0gMDtcbiAgICB9LFxuICAgICAgICBvbkRlbHRhID0gZnVuY3Rpb24gb25EZWx0YSh4LCB5LCBpbmRleCkge1xuICAgICAgZGVsdGFYW2luZGV4XSArPSB4O1xuICAgICAgZGVsdGFZW2luZGV4XSArPSB5O1xuXG4gICAgICBzZWxmLl92eC51cGRhdGUoeCk7XG5cbiAgICAgIHNlbGYuX3Z5LnVwZGF0ZSh5KTtcblxuICAgICAgZGVib3VuY2UgPyBpZCB8fCAoaWQgPSByZXF1ZXN0QW5pbWF0aW9uRnJhbWUodXBkYXRlKSkgOiB1cGRhdGUoKTtcbiAgICB9LFxuICAgICAgICBvblRvdWNoT3JQb2ludGVyRGVsdGEgPSBmdW5jdGlvbiBvblRvdWNoT3JQb2ludGVyRGVsdGEoeCwgeSkge1xuICAgICAgaWYgKGxvY2tBeGlzICYmICFheGlzKSB7XG4gICAgICAgIHNlbGYuYXhpcyA9IGF4aXMgPSBNYXRoLmFicyh4KSA+IE1hdGguYWJzKHkpID8gXCJ4XCIgOiBcInlcIjtcbiAgICAgICAgbG9ja2VkID0gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKGF4aXMgIT09IFwieVwiKSB7XG4gICAgICAgIGRlbHRhWFsyXSArPSB4O1xuXG4gICAgICAgIHNlbGYuX3Z4LnVwZGF0ZSh4LCB0cnVlKTsgLy8gdXBkYXRlIHRoZSB2ZWxvY2l0eSBhcyBmcmVxdWVudGx5IGFzIHBvc3NpYmxlIGluc3RlYWQgb2YgaW4gdGhlIGRlYm91bmNlZCBmdW5jdGlvbiBzbyB0aGF0IHZlcnkgcXVpY2sgdG91Y2gtc2Nyb2xscyAoZmxpY2tzKSBmZWVsIG5hdHVyYWwuIElmIGl0J3MgdGhlIG1vdXNlL3RvdWNoL3BvaW50ZXIsIGZvcmNlIGl0IHNvIHRoYXQgd2UgZ2V0IHNuYXBweS9hY2N1cmF0ZSBtb21lbnR1bSBzY3JvbGwuXG5cbiAgICAgIH1cblxuICAgICAgaWYgKGF4aXMgIT09IFwieFwiKSB7XG4gICAgICAgIGRlbHRhWVsyXSArPSB5O1xuXG4gICAgICAgIHNlbGYuX3Z5LnVwZGF0ZSh5LCB0cnVlKTtcbiAgICAgIH1cblxuICAgICAgZGVib3VuY2UgPyBpZCB8fCAoaWQgPSByZXF1ZXN0QW5pbWF0aW9uRnJhbWUodXBkYXRlKSkgOiB1cGRhdGUoKTtcbiAgICB9LFxuICAgICAgICBfb25EcmFnID0gZnVuY3Rpb24gX29uRHJhZyhlKSB7XG4gICAgICBpZiAoX2lnbm9yZUNoZWNrKGUsIDEpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgZSA9IF9nZXRFdmVudChlLCBwcmV2ZW50RGVmYXVsdCk7XG4gICAgICB2YXIgeCA9IGUuY2xpZW50WCxcbiAgICAgICAgICB5ID0gZS5jbGllbnRZLFxuICAgICAgICAgIGR4ID0geCAtIHNlbGYueCxcbiAgICAgICAgICBkeSA9IHkgLSBzZWxmLnksXG4gICAgICAgICAgaXNEcmFnZ2luZyA9IHNlbGYuaXNEcmFnZ2luZztcbiAgICAgIHNlbGYueCA9IHg7XG4gICAgICBzZWxmLnkgPSB5O1xuXG4gICAgICBpZiAoaXNEcmFnZ2luZyB8fCBNYXRoLmFicyhzZWxmLnN0YXJ0WCAtIHgpID49IGRyYWdNaW5pbXVtIHx8IE1hdGguYWJzKHNlbGYuc3RhcnRZIC0geSkgPj0gZHJhZ01pbmltdW0pIHtcbiAgICAgICAgb25EcmFnICYmIChkcmFnZ2VkID0gdHJ1ZSk7XG4gICAgICAgIGlzRHJhZ2dpbmcgfHwgKHNlbGYuaXNEcmFnZ2luZyA9IHRydWUpO1xuICAgICAgICBvblRvdWNoT3JQb2ludGVyRGVsdGEoZHgsIGR5KTtcbiAgICAgICAgaXNEcmFnZ2luZyB8fCBvbkRyYWdTdGFydCAmJiBvbkRyYWdTdGFydChzZWxmKTtcbiAgICAgIH1cbiAgICB9LFxuICAgICAgICBfb25QcmVzcyA9IHNlbGYub25QcmVzcyA9IGZ1bmN0aW9uIChlKSB7XG4gICAgICBpZiAoX2lnbm9yZUNoZWNrKGUsIDEpIHx8IGUgJiYgZS5idXR0b24pIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBzZWxmLmF4aXMgPSBheGlzID0gbnVsbDtcbiAgICAgIG9uU3RvcERlbGF5ZWRDYWxsLnBhdXNlKCk7XG4gICAgICBzZWxmLmlzUHJlc3NlZCA9IHRydWU7XG4gICAgICBlID0gX2dldEV2ZW50KGUpOyAvLyBub3RlOiBtYXkgbmVlZCB0byBwcmV2ZW50RGVmYXVsdCg/KSBXb24ndCBzaWRlLXNjcm9sbCBvbiBpT1MgU2FmYXJpIGlmIHdlIGRvLCB0aG91Z2guXG5cbiAgICAgIHByZXZEZWx0YVggPSBwcmV2RGVsdGFZID0gMDtcbiAgICAgIHNlbGYuc3RhcnRYID0gc2VsZi54ID0gZS5jbGllbnRYO1xuICAgICAgc2VsZi5zdGFydFkgPSBzZWxmLnkgPSBlLmNsaWVudFk7XG5cbiAgICAgIHNlbGYuX3Z4LnJlc2V0KCk7IC8vIG90aGVyd2lzZSB0aGUgdDIgbWF5IGJlIHN0YWxlIGlmIHRoZSB1c2VyIHRvdWNoZXMgYW5kIGZsaWNrcyBzdXBlciBmYXN0IGFuZCByZWxlYXNlcyBpbiBsZXNzIHRoYW4gMiByZXF1ZXN0QW5pbWF0aW9uRnJhbWUgdGlja3MsIGNhdXNpbmcgdmVsb2NpdHkgdG8gYmUgMC5cblxuXG4gICAgICBzZWxmLl92eS5yZXNldCgpO1xuXG4gICAgICBfYWRkTGlzdGVuZXIoaXNOb3JtYWxpemVyID8gdGFyZ2V0IDogb3duZXJEb2MsIF9ldmVudFR5cGVzWzFdLCBfb25EcmFnLCBwYXNzaXZlLCB0cnVlKTtcblxuICAgICAgc2VsZi5kZWx0YVggPSBzZWxmLmRlbHRhWSA9IDA7XG4gICAgICBvblByZXNzICYmIG9uUHJlc3Moc2VsZik7XG4gICAgfSxcbiAgICAgICAgX29uUmVsZWFzZSA9IHNlbGYub25SZWxlYXNlID0gZnVuY3Rpb24gKGUpIHtcbiAgICAgIGlmIChfaWdub3JlQ2hlY2soZSwgMSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBfcmVtb3ZlTGlzdGVuZXIoaXNOb3JtYWxpemVyID8gdGFyZ2V0IDogb3duZXJEb2MsIF9ldmVudFR5cGVzWzFdLCBfb25EcmFnLCB0cnVlKTtcblxuICAgICAgdmFyIGlzVHJhY2tpbmdEcmFnID0gIWlzTmFOKHNlbGYueSAtIHNlbGYuc3RhcnRZKSxcbiAgICAgICAgICB3YXNEcmFnZ2luZyA9IHNlbGYuaXNEcmFnZ2luZyxcbiAgICAgICAgICBpc0RyYWdOb3RDbGljayA9IHdhc0RyYWdnaW5nICYmIChNYXRoLmFicyhzZWxmLnggLSBzZWxmLnN0YXJ0WCkgPiAzIHx8IE1hdGguYWJzKHNlbGYueSAtIHNlbGYuc3RhcnRZKSA+IDMpLFxuICAgICAgICAgIC8vIHNvbWUgdG91Y2ggZGV2aWNlcyBuZWVkIHNvbWUgd2lnZ2xlIHJvb20gaW4gdGVybXMgb2Ygc2Vuc2luZyBjbGlja3MgLSB0aGUgZmluZ2VyIG1heSBtb3ZlIGEgZmV3IHBpeGVscy5cbiAgICAgIGV2ZW50RGF0YSA9IF9nZXRFdmVudChlKTtcblxuICAgICAgaWYgKCFpc0RyYWdOb3RDbGljayAmJiBpc1RyYWNraW5nRHJhZykge1xuICAgICAgICBzZWxmLl92eC5yZXNldCgpO1xuXG4gICAgICAgIHNlbGYuX3Z5LnJlc2V0KCk7IC8vaWYgKHByZXZlbnREZWZhdWx0ICYmIGFsbG93Q2xpY2tzICYmIHNlbGYuaXNQcmVzc2VkKSB7IC8vIGNoZWNrIGlzUHJlc3NlZCBiZWNhdXNlIGluIGEgcmFyZSBlZGdlIGNhc2UsIHRoZSBpbnB1dE9ic2VydmVyIGluIFNjcm9sbFRyaWdnZXIgbWF5IHN0b3BQcm9wYWdhdGlvbigpIG9uIHRoZSBwcmVzcy9kcmFnLCBzbyB0aGUgb25SZWxlYXNlIG1heSBnZXQgZmlyZWQgd2l0aG91dCB0aGUgb25QcmVzcy9vbkRyYWcgZXZlciBnZXR0aW5nIGNhbGxlZCwgdGh1cyBpdCBjb3VsZCB0cmlnZ2VyIGEgY2xpY2sgdG8gb2NjdXIgb24gYSBsaW5rIGFmdGVyIHNjcm9sbC1kcmFnZ2luZyBpdC5cblxuXG4gICAgICAgIGlmIChwcmV2ZW50RGVmYXVsdCAmJiBhbGxvd0NsaWNrcykge1xuICAgICAgICAgIGdzYXAuZGVsYXllZENhbGwoMC4wOCwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgLy8gc29tZSBicm93c2VycyAobGlrZSBGaXJlZm94KSB3b24ndCB0cnVzdCBzY3JpcHQtZ2VuZXJhdGVkIGNsaWNrcywgc28gaWYgdGhlIHVzZXIgdHJpZXMgdG8gY2xpY2sgb24gYSB2aWRlbyB0byBwbGF5IGl0LCBmb3IgZXhhbXBsZSwgaXQgc2ltcGx5IHdvbid0IHdvcmsuIFNpbmNlIGEgcmVndWxhciBcImNsaWNrXCIgZXZlbnQgd2lsbCBtb3N0IGxpa2VseSBiZSBnZW5lcmF0ZWQgYW55d2F5IChvbmUgdGhhdCBoYXMgaXRzIGlzVHJ1c3RlZCBmbGFnIHNldCB0byB0cnVlKSwgd2UgbXVzdCBzbGlnaHRseSBkZWxheSBvdXIgc2NyaXB0LWdlbmVyYXRlZCBjbGljayBzbyB0aGF0IHRoZSBcInJlYWxcIi90cnVzdGVkIG9uZSBpcyBwcmlvcml0aXplZC4gUmVtZW1iZXIsIHdoZW4gdGhlcmUgYXJlIGR1cGxpY2F0ZSBldmVudHMgaW4gcXVpY2sgc3VjY2Vzc2lvbiwgd2Ugc3VwcHJlc3MgYWxsIGJ1dCB0aGUgZmlyc3Qgb25lLiBTb21lIGJyb3dzZXJzIGRvbid0IGV2ZW4gdHJpZ2dlciB0aGUgXCJyZWFsXCIgb25lIGF0IGFsbCwgc28gb3VyIHN5bnRoZXRpYyBvbmUgaXMgYSBzYWZldHkgdmFsdmUgdGhhdCBlbnN1cmVzIHRoYXQgbm8gbWF0dGVyIHdoYXQsIGEgY2xpY2sgZXZlbnQgZG9lcyBnZXQgZGlzcGF0Y2hlZC5cbiAgICAgICAgICAgIGlmIChfZ2V0VGltZSgpIC0gb25DbGlja1RpbWUgPiAzMDAgJiYgIWUuZGVmYXVsdFByZXZlbnRlZCkge1xuICAgICAgICAgICAgICBpZiAoZS50YXJnZXQuY2xpY2spIHtcbiAgICAgICAgICAgICAgICAvL3NvbWUgYnJvd3NlcnMgKGxpa2UgbW9iaWxlIFNhZmFyaSkgZG9uJ3QgcHJvcGVybHkgdHJpZ2dlciB0aGUgY2xpY2sgZXZlbnRcbiAgICAgICAgICAgICAgICBlLnRhcmdldC5jbGljaygpO1xuICAgICAgICAgICAgICB9IGVsc2UgaWYgKG93bmVyRG9jLmNyZWF0ZUV2ZW50KSB7XG4gICAgICAgICAgICAgICAgdmFyIHN5bnRoZXRpY0V2ZW50ID0gb3duZXJEb2MuY3JlYXRlRXZlbnQoXCJNb3VzZUV2ZW50c1wiKTtcbiAgICAgICAgICAgICAgICBzeW50aGV0aWNFdmVudC5pbml0TW91c2VFdmVudChcImNsaWNrXCIsIHRydWUsIHRydWUsIF93aW4sIDEsIGV2ZW50RGF0YS5zY3JlZW5YLCBldmVudERhdGEuc2NyZWVuWSwgZXZlbnREYXRhLmNsaWVudFgsIGV2ZW50RGF0YS5jbGllbnRZLCBmYWxzZSwgZmFsc2UsIGZhbHNlLCBmYWxzZSwgMCwgbnVsbCk7XG4gICAgICAgICAgICAgICAgZS50YXJnZXQuZGlzcGF0Y2hFdmVudChzeW50aGV0aWNFdmVudCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBzZWxmLmlzRHJhZ2dpbmcgPSBzZWxmLmlzR2VzdHVyaW5nID0gc2VsZi5pc1ByZXNzZWQgPSBmYWxzZTtcbiAgICAgIG9uU3RvcCAmJiB3YXNEcmFnZ2luZyAmJiAhaXNOb3JtYWxpemVyICYmIG9uU3RvcERlbGF5ZWRDYWxsLnJlc3RhcnQodHJ1ZSk7XG4gICAgICBvbkRyYWdFbmQgJiYgd2FzRHJhZ2dpbmcgJiYgb25EcmFnRW5kKHNlbGYpO1xuICAgICAgb25SZWxlYXNlICYmIG9uUmVsZWFzZShzZWxmLCBpc0RyYWdOb3RDbGljayk7XG4gICAgfSxcbiAgICAgICAgX29uR2VzdHVyZVN0YXJ0ID0gZnVuY3Rpb24gX29uR2VzdHVyZVN0YXJ0KGUpIHtcbiAgICAgIHJldHVybiBlLnRvdWNoZXMgJiYgZS50b3VjaGVzLmxlbmd0aCA+IDEgJiYgKHNlbGYuaXNHZXN0dXJpbmcgPSB0cnVlKSAmJiBvbkdlc3R1cmVTdGFydChlLCBzZWxmLmlzRHJhZ2dpbmcpO1xuICAgIH0sXG4gICAgICAgIF9vbkdlc3R1cmVFbmQgPSBmdW5jdGlvbiBfb25HZXN0dXJlRW5kKCkge1xuICAgICAgcmV0dXJuIChzZWxmLmlzR2VzdHVyaW5nID0gZmFsc2UpIHx8IG9uR2VzdHVyZUVuZChzZWxmKTtcbiAgICB9LFxuICAgICAgICBvblNjcm9sbCA9IGZ1bmN0aW9uIG9uU2Nyb2xsKGUpIHtcbiAgICAgIGlmIChfaWdub3JlQ2hlY2soZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB2YXIgeCA9IHNjcm9sbEZ1bmNYKCksXG4gICAgICAgICAgeSA9IHNjcm9sbEZ1bmNZKCk7XG4gICAgICBvbkRlbHRhKCh4IC0gc2Nyb2xsWCkgKiBzY3JvbGxTcGVlZCwgKHkgLSBzY3JvbGxZKSAqIHNjcm9sbFNwZWVkLCAxKTtcbiAgICAgIHNjcm9sbFggPSB4O1xuICAgICAgc2Nyb2xsWSA9IHk7XG4gICAgICBvblN0b3AgJiYgb25TdG9wRGVsYXllZENhbGwucmVzdGFydCh0cnVlKTtcbiAgICB9LFxuICAgICAgICBfb25XaGVlbCA9IGZ1bmN0aW9uIF9vbldoZWVsKGUpIHtcbiAgICAgIGlmIChfaWdub3JlQ2hlY2soZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBlID0gX2dldEV2ZW50KGUsIHByZXZlbnREZWZhdWx0KTtcbiAgICAgIG9uV2hlZWwgJiYgKHdoZWVsZWQgPSB0cnVlKTtcbiAgICAgIHZhciBtdWx0aXBsaWVyID0gKGUuZGVsdGFNb2RlID09PSAxID8gbGluZUhlaWdodCA6IGUuZGVsdGFNb2RlID09PSAyID8gX3dpbi5pbm5lckhlaWdodCA6IDEpICogd2hlZWxTcGVlZDtcbiAgICAgIG9uRGVsdGEoZS5kZWx0YVggKiBtdWx0aXBsaWVyLCBlLmRlbHRhWSAqIG11bHRpcGxpZXIsIDApO1xuICAgICAgb25TdG9wICYmICFpc05vcm1hbGl6ZXIgJiYgb25TdG9wRGVsYXllZENhbGwucmVzdGFydCh0cnVlKTtcbiAgICB9LFxuICAgICAgICBfb25Nb3ZlID0gZnVuY3Rpb24gX29uTW92ZShlKSB7XG4gICAgICBpZiAoX2lnbm9yZUNoZWNrKGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIHggPSBlLmNsaWVudFgsXG4gICAgICAgICAgeSA9IGUuY2xpZW50WSxcbiAgICAgICAgICBkeCA9IHggLSBzZWxmLngsXG4gICAgICAgICAgZHkgPSB5IC0gc2VsZi55O1xuICAgICAgc2VsZi54ID0geDtcbiAgICAgIHNlbGYueSA9IHk7XG4gICAgICBtb3ZlZCA9IHRydWU7XG4gICAgICBvblN0b3AgJiYgb25TdG9wRGVsYXllZENhbGwucmVzdGFydCh0cnVlKTtcbiAgICAgIChkeCB8fCBkeSkgJiYgb25Ub3VjaE9yUG9pbnRlckRlbHRhKGR4LCBkeSk7XG4gICAgfSxcbiAgICAgICAgX29uSG92ZXIgPSBmdW5jdGlvbiBfb25Ib3ZlcihlKSB7XG4gICAgICBzZWxmLmV2ZW50ID0gZTtcbiAgICAgIG9uSG92ZXIoc2VsZik7XG4gICAgfSxcbiAgICAgICAgX29uSG92ZXJFbmQgPSBmdW5jdGlvbiBfb25Ib3ZlckVuZChlKSB7XG4gICAgICBzZWxmLmV2ZW50ID0gZTtcbiAgICAgIG9uSG92ZXJFbmQoc2VsZik7XG4gICAgfSxcbiAgICAgICAgX29uQ2xpY2sgPSBmdW5jdGlvbiBfb25DbGljayhlKSB7XG4gICAgICByZXR1cm4gX2lnbm9yZUNoZWNrKGUpIHx8IF9nZXRFdmVudChlLCBwcmV2ZW50RGVmYXVsdCkgJiYgb25DbGljayhzZWxmKTtcbiAgICB9O1xuXG4gICAgb25TdG9wRGVsYXllZENhbGwgPSBzZWxmLl9kYyA9IGdzYXAuZGVsYXllZENhbGwob25TdG9wRGVsYXkgfHwgMC4yNSwgb25TdG9wRnVuYykucGF1c2UoKTtcbiAgICBzZWxmLmRlbHRhWCA9IHNlbGYuZGVsdGFZID0gMDtcbiAgICBzZWxmLl92eCA9IF9nZXRWZWxvY2l0eVByb3AoMCwgNTAsIHRydWUpO1xuICAgIHNlbGYuX3Z5ID0gX2dldFZlbG9jaXR5UHJvcCgwLCA1MCwgdHJ1ZSk7XG4gICAgc2VsZi5zY3JvbGxYID0gc2Nyb2xsRnVuY1g7XG4gICAgc2VsZi5zY3JvbGxZID0gc2Nyb2xsRnVuY1k7XG4gICAgc2VsZi5pc0RyYWdnaW5nID0gc2VsZi5pc0dlc3R1cmluZyA9IHNlbGYuaXNQcmVzc2VkID0gZmFsc2U7XG5cbiAgICBfY29udGV4dCh0aGlzKTtcblxuICAgIHNlbGYuZW5hYmxlID0gZnVuY3Rpb24gKGUpIHtcbiAgICAgIGlmICghc2VsZi5pc0VuYWJsZWQpIHtcbiAgICAgICAgX2FkZExpc3RlbmVyKGlzVmlld3BvcnQgPyBvd25lckRvYyA6IHRhcmdldCwgXCJzY3JvbGxcIiwgX29uU2Nyb2xsKTtcblxuICAgICAgICB0eXBlLmluZGV4T2YoXCJzY3JvbGxcIikgPj0gMCAmJiBfYWRkTGlzdGVuZXIoaXNWaWV3cG9ydCA/IG93bmVyRG9jIDogdGFyZ2V0LCBcInNjcm9sbFwiLCBvblNjcm9sbCwgcGFzc2l2ZSwgY2FwdHVyZSk7XG4gICAgICAgIHR5cGUuaW5kZXhPZihcIndoZWVsXCIpID49IDAgJiYgX2FkZExpc3RlbmVyKHRhcmdldCwgXCJ3aGVlbFwiLCBfb25XaGVlbCwgcGFzc2l2ZSwgY2FwdHVyZSk7XG5cbiAgICAgICAgaWYgKHR5cGUuaW5kZXhPZihcInRvdWNoXCIpID49IDAgJiYgX2lzVG91Y2ggfHwgdHlwZS5pbmRleE9mKFwicG9pbnRlclwiKSA+PSAwKSB7XG4gICAgICAgICAgX2FkZExpc3RlbmVyKHRhcmdldCwgX2V2ZW50VHlwZXNbMF0sIF9vblByZXNzLCBwYXNzaXZlLCBjYXB0dXJlKTtcblxuICAgICAgICAgIF9hZGRMaXN0ZW5lcihvd25lckRvYywgX2V2ZW50VHlwZXNbMl0sIF9vblJlbGVhc2UpO1xuXG4gICAgICAgICAgX2FkZExpc3RlbmVyKG93bmVyRG9jLCBfZXZlbnRUeXBlc1szXSwgX29uUmVsZWFzZSk7XG5cbiAgICAgICAgICBhbGxvd0NsaWNrcyAmJiBfYWRkTGlzdGVuZXIodGFyZ2V0LCBcImNsaWNrXCIsIGNsaWNrQ2FwdHVyZSwgdHJ1ZSwgdHJ1ZSk7XG4gICAgICAgICAgb25DbGljayAmJiBfYWRkTGlzdGVuZXIodGFyZ2V0LCBcImNsaWNrXCIsIF9vbkNsaWNrKTtcbiAgICAgICAgICBvbkdlc3R1cmVTdGFydCAmJiBfYWRkTGlzdGVuZXIob3duZXJEb2MsIFwiZ2VzdHVyZXN0YXJ0XCIsIF9vbkdlc3R1cmVTdGFydCk7XG4gICAgICAgICAgb25HZXN0dXJlRW5kICYmIF9hZGRMaXN0ZW5lcihvd25lckRvYywgXCJnZXN0dXJlZW5kXCIsIF9vbkdlc3R1cmVFbmQpO1xuICAgICAgICAgIG9uSG92ZXIgJiYgX2FkZExpc3RlbmVyKHRhcmdldCwgX3BvaW50ZXJUeXBlICsgXCJlbnRlclwiLCBfb25Ib3Zlcik7XG4gICAgICAgICAgb25Ib3ZlckVuZCAmJiBfYWRkTGlzdGVuZXIodGFyZ2V0LCBfcG9pbnRlclR5cGUgKyBcImxlYXZlXCIsIF9vbkhvdmVyRW5kKTtcbiAgICAgICAgICBvbk1vdmUgJiYgX2FkZExpc3RlbmVyKHRhcmdldCwgX3BvaW50ZXJUeXBlICsgXCJtb3ZlXCIsIF9vbk1vdmUpO1xuICAgICAgICB9XG5cbiAgICAgICAgc2VsZi5pc0VuYWJsZWQgPSB0cnVlO1xuICAgICAgICBlICYmIGUudHlwZSAmJiBfb25QcmVzcyhlKTtcbiAgICAgICAgb25FbmFibGUgJiYgb25FbmFibGUoc2VsZik7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBzZWxmO1xuICAgIH07XG5cbiAgICBzZWxmLmRpc2FibGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICBpZiAoc2VsZi5pc0VuYWJsZWQpIHtcbiAgICAgICAgLy8gb25seSByZW1vdmUgdGhlIF9vblNjcm9sbCBsaXN0ZW5lciBpZiB0aGVyZSBhcmVuJ3QgYW55IG90aGVycyB0aGF0IHJlbHkgb24gdGhlIGZ1bmN0aW9uYWxpdHkuXG4gICAgICAgIF9vYnNlcnZlcnMuZmlsdGVyKGZ1bmN0aW9uIChvKSB7XG4gICAgICAgICAgcmV0dXJuIG8gIT09IHNlbGYgJiYgX2lzVmlld3BvcnQoby50YXJnZXQpO1xuICAgICAgICB9KS5sZW5ndGggfHwgX3JlbW92ZUxpc3RlbmVyKGlzVmlld3BvcnQgPyBvd25lckRvYyA6IHRhcmdldCwgXCJzY3JvbGxcIiwgX29uU2Nyb2xsKTtcblxuICAgICAgICBpZiAoc2VsZi5pc1ByZXNzZWQpIHtcbiAgICAgICAgICBzZWxmLl92eC5yZXNldCgpO1xuXG4gICAgICAgICAgc2VsZi5fdnkucmVzZXQoKTtcblxuICAgICAgICAgIF9yZW1vdmVMaXN0ZW5lcihpc05vcm1hbGl6ZXIgPyB0YXJnZXQgOiBvd25lckRvYywgX2V2ZW50VHlwZXNbMV0sIF9vbkRyYWcsIHRydWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgX3JlbW92ZUxpc3RlbmVyKGlzVmlld3BvcnQgPyBvd25lckRvYyA6IHRhcmdldCwgXCJzY3JvbGxcIiwgb25TY3JvbGwsIGNhcHR1cmUpO1xuXG4gICAgICAgIF9yZW1vdmVMaXN0ZW5lcih0YXJnZXQsIFwid2hlZWxcIiwgX29uV2hlZWwsIGNhcHR1cmUpO1xuXG4gICAgICAgIF9yZW1vdmVMaXN0ZW5lcih0YXJnZXQsIF9ldmVudFR5cGVzWzBdLCBfb25QcmVzcywgY2FwdHVyZSk7XG5cbiAgICAgICAgX3JlbW92ZUxpc3RlbmVyKG93bmVyRG9jLCBfZXZlbnRUeXBlc1syXSwgX29uUmVsZWFzZSk7XG5cbiAgICAgICAgX3JlbW92ZUxpc3RlbmVyKG93bmVyRG9jLCBfZXZlbnRUeXBlc1szXSwgX29uUmVsZWFzZSk7XG5cbiAgICAgICAgX3JlbW92ZUxpc3RlbmVyKHRhcmdldCwgXCJjbGlja1wiLCBjbGlja0NhcHR1cmUsIHRydWUpO1xuXG4gICAgICAgIF9yZW1vdmVMaXN0ZW5lcih0YXJnZXQsIFwiY2xpY2tcIiwgX29uQ2xpY2spO1xuXG4gICAgICAgIF9yZW1vdmVMaXN0ZW5lcihvd25lckRvYywgXCJnZXN0dXJlc3RhcnRcIiwgX29uR2VzdHVyZVN0YXJ0KTtcblxuICAgICAgICBfcmVtb3ZlTGlzdGVuZXIob3duZXJEb2MsIFwiZ2VzdHVyZWVuZFwiLCBfb25HZXN0dXJlRW5kKTtcblxuICAgICAgICBfcmVtb3ZlTGlzdGVuZXIodGFyZ2V0LCBfcG9pbnRlclR5cGUgKyBcImVudGVyXCIsIF9vbkhvdmVyKTtcblxuICAgICAgICBfcmVtb3ZlTGlzdGVuZXIodGFyZ2V0LCBfcG9pbnRlclR5cGUgKyBcImxlYXZlXCIsIF9vbkhvdmVyRW5kKTtcblxuICAgICAgICBfcmVtb3ZlTGlzdGVuZXIodGFyZ2V0LCBfcG9pbnRlclR5cGUgKyBcIm1vdmVcIiwgX29uTW92ZSk7XG5cbiAgICAgICAgc2VsZi5pc0VuYWJsZWQgPSBzZWxmLmlzUHJlc3NlZCA9IHNlbGYuaXNEcmFnZ2luZyA9IGZhbHNlO1xuICAgICAgICBvbkRpc2FibGUgJiYgb25EaXNhYmxlKHNlbGYpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBzZWxmLmtpbGwgPSBzZWxmLnJldmVydCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIHNlbGYuZGlzYWJsZSgpO1xuXG4gICAgICB2YXIgaSA9IF9vYnNlcnZlcnMuaW5kZXhPZihzZWxmKTtcblxuICAgICAgaSA+PSAwICYmIF9vYnNlcnZlcnMuc3BsaWNlKGksIDEpO1xuICAgICAgX25vcm1hbGl6ZXIgPT09IHNlbGYgJiYgKF9ub3JtYWxpemVyID0gMCk7XG4gICAgfTtcblxuICAgIF9vYnNlcnZlcnMucHVzaChzZWxmKTtcblxuICAgIGlzTm9ybWFsaXplciAmJiBfaXNWaWV3cG9ydCh0YXJnZXQpICYmIChfbm9ybWFsaXplciA9IHNlbGYpO1xuICAgIHNlbGYuZW5hYmxlKGV2ZW50KTtcbiAgfTtcblxuICBfY3JlYXRlQ2xhc3MoT2JzZXJ2ZXIsIFt7XG4gICAga2V5OiBcInZlbG9jaXR5WFwiLFxuICAgIGdldDogZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgcmV0dXJuIHRoaXMuX3Z4LmdldFZlbG9jaXR5KCk7XG4gICAgfVxuICB9LCB7XG4gICAga2V5OiBcInZlbG9jaXR5WVwiLFxuICAgIGdldDogZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgcmV0dXJuIHRoaXMuX3Z5LmdldFZlbG9jaXR5KCk7XG4gICAgfVxuICB9XSk7XG5cbiAgcmV0dXJuIE9ic2VydmVyO1xufSgpO1xuT2JzZXJ2ZXIudmVyc2lvbiA9IFwiMy4xMi41XCI7XG5cbk9ic2VydmVyLmNyZWF0ZSA9IGZ1bmN0aW9uICh2YXJzKSB7XG4gIHJldHVybiBuZXcgT2JzZXJ2ZXIodmFycyk7XG59O1xuXG5PYnNlcnZlci5yZWdpc3RlciA9IF9pbml0Q29yZTtcblxuT2JzZXJ2ZXIuZ2V0QWxsID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gX29ic2VydmVycy5zbGljZSgpO1xufTtcblxuT2JzZXJ2ZXIuZ2V0QnlJZCA9IGZ1bmN0aW9uIChpZCkge1xuICByZXR1cm4gX29ic2VydmVycy5maWx0ZXIoZnVuY3Rpb24gKG8pIHtcbiAgICByZXR1cm4gby52YXJzLmlkID09PSBpZDtcbiAgfSlbMF07XG59O1xuXG5fZ2V0R1NBUCgpICYmIGdzYXAucmVnaXN0ZXJQbHVnaW4oT2JzZXJ2ZXIpO1xuZXhwb3J0IHsgT2JzZXJ2ZXIgYXMgZGVmYXVsdCwgX2lzVmlld3BvcnQsIF9zY3JvbGxlcnMsIF9nZXRTY3JvbGxGdW5jLCBfZ2V0UHJveHlQcm9wLCBfcHJveGllcywgX2dldFZlbG9jaXR5UHJvcCwgX3ZlcnRpY2FsLCBfaG9yaXpvbnRhbCwgX2dldFRhcmdldCB9OyIsIi8qIVxuICogU2Nyb2xsVHJpZ2dlciAzLjEyLjVcbiAqIGh0dHBzOi8vZ3NhcC5jb21cbiAqXG4gKiBAbGljZW5zZSBDb3B5cmlnaHQgMjAwOC0yMDI0LCBHcmVlblNvY2suIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhdCBodHRwczovL2dzYXAuY29tL3N0YW5kYXJkLWxpY2Vuc2Ugb3IgZm9yXG4gKiBDbHViIEdTQVAgbWVtYmVycywgdGhlIGFncmVlbWVudCBpc3N1ZWQgd2l0aCB0aGF0IG1lbWJlcnNoaXAuXG4gKiBAYXV0aG9yOiBKYWNrIERveWxlLCBqYWNrQGdyZWVuc29jay5jb21cbiovXG5cbi8qIGVzbGludC1kaXNhYmxlICovXG5pbXBvcnQgeyBPYnNlcnZlciwgX2dldFRhcmdldCwgX3ZlcnRpY2FsLCBfaG9yaXpvbnRhbCwgX3Njcm9sbGVycywgX3Byb3hpZXMsIF9nZXRTY3JvbGxGdW5jLCBfZ2V0UHJveHlQcm9wLCBfZ2V0VmVsb2NpdHlQcm9wIH0gZnJvbSBcIi4vT2JzZXJ2ZXIuanNcIjtcblxudmFyIGdzYXAsXG4gICAgX2NvcmVJbml0dGVkLFxuICAgIF93aW4sXG4gICAgX2RvYyxcbiAgICBfZG9jRWwsXG4gICAgX2JvZHksXG4gICAgX3Jvb3QsXG4gICAgX3Jlc2l6ZURlbGF5LFxuICAgIF90b0FycmF5LFxuICAgIF9jbGFtcCxcbiAgICBfdGltZTIsXG4gICAgX3N5bmNJbnRlcnZhbCxcbiAgICBfcmVmcmVzaGluZyxcbiAgICBfcG9pbnRlcklzRG93bixcbiAgICBfdHJhbnNmb3JtUHJvcCxcbiAgICBfaSxcbiAgICBfcHJldldpZHRoLFxuICAgIF9wcmV2SGVpZ2h0LFxuICAgIF9hdXRvUmVmcmVzaCxcbiAgICBfc29ydCxcbiAgICBfc3VwcHJlc3NPdmVyd3JpdGVzLFxuICAgIF9pZ25vcmVSZXNpemUsXG4gICAgX25vcm1hbGl6ZXIsXG4gICAgX2lnbm9yZU1vYmlsZVJlc2l6ZSxcbiAgICBfYmFzZVNjcmVlbkhlaWdodCxcbiAgICBfYmFzZVNjcmVlbldpZHRoLFxuICAgIF9maXhJT1NCdWcsXG4gICAgX2NvbnRleHQsXG4gICAgX3Njcm9sbFJlc3RvcmF0aW9uLFxuICAgIF9kaXYxMDB2aCxcbiAgICBfMTAwdmgsXG4gICAgX2lzUmV2ZXJ0ZWQsXG4gICAgX2NsYW1waW5nTWF4LFxuICAgIF9saW1pdENhbGxiYWNrcyxcbiAgICAvLyBpZiB0cnVlLCB3ZSdsbCBvbmx5IHRyaWdnZXIgY2FsbGJhY2tzIGlmIHRoZSBhY3RpdmUgc3RhdGUgdG9nZ2xlcywgc28gaWYgeW91IHNjcm9sbCBpbW1lZGlhdGVseSBwYXN0IGJvdGggdGhlIHN0YXJ0IGFuZCBlbmQgcG9zaXRpb25zIG9mIGEgU2Nyb2xsVHJpZ2dlciAodGh1cyBpbmFjdGl2ZSB0byBpbmFjdGl2ZSksIG5laXRoZXIgaXRzIG9uRW50ZXIgbm9yIG9uTGVhdmUgd2lsbCBiZSBjYWxsZWQuIFRoaXMgaXMgdXNlZnVsIGR1cmluZyBzdGFydHVwLlxuX3N0YXJ0dXAgPSAxLFxuICAgIF9nZXRUaW1lID0gRGF0ZS5ub3csXG4gICAgX3RpbWUxID0gX2dldFRpbWUoKSxcbiAgICBfbGFzdFNjcm9sbFRpbWUgPSAwLFxuICAgIF9lbmFibGVkID0gMCxcbiAgICBfcGFyc2VDbGFtcCA9IGZ1bmN0aW9uIF9wYXJzZUNsYW1wKHZhbHVlLCB0eXBlLCBzZWxmKSB7XG4gIHZhciBjbGFtcCA9IF9pc1N0cmluZyh2YWx1ZSkgJiYgKHZhbHVlLnN1YnN0cigwLCA2KSA9PT0gXCJjbGFtcChcIiB8fCB2YWx1ZS5pbmRleE9mKFwibWF4XCIpID4gLTEpO1xuICBzZWxmW1wiX1wiICsgdHlwZSArIFwiQ2xhbXBcIl0gPSBjbGFtcDtcbiAgcmV0dXJuIGNsYW1wID8gdmFsdWUuc3Vic3RyKDYsIHZhbHVlLmxlbmd0aCAtIDcpIDogdmFsdWU7XG59LFxuICAgIF9rZWVwQ2xhbXAgPSBmdW5jdGlvbiBfa2VlcENsYW1wKHZhbHVlLCBjbGFtcCkge1xuICByZXR1cm4gY2xhbXAgJiYgKCFfaXNTdHJpbmcodmFsdWUpIHx8IHZhbHVlLnN1YnN0cigwLCA2KSAhPT0gXCJjbGFtcChcIikgPyBcImNsYW1wKFwiICsgdmFsdWUgKyBcIilcIiA6IHZhbHVlO1xufSxcbiAgICBfcmFmQnVnRml4ID0gZnVuY3Rpb24gX3JhZkJ1Z0ZpeCgpIHtcbiAgcmV0dXJuIF9lbmFibGVkICYmIHJlcXVlc3RBbmltYXRpb25GcmFtZShfcmFmQnVnRml4KTtcbn0sXG4gICAgLy8gaW4gc29tZSBicm93c2VycyAobGlrZSBGaXJlZm94KSwgc2NyZWVuIHJlcGFpbnRzIHdlcmVuJ3QgY29uc2lzdGVudCB1bmxlc3Mgd2UgaGFkIFNPTUVUSElORyBxdWV1ZWQgdXAgaW4gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCkhIFNvIHRoaXMganVzdCBjcmVhdGVzIGEgc3VwZXIgc2ltcGxlIGxvb3AgdG8ga2VlcCBpdCBhbGl2ZSBhbmQgc21vb3RoIG91dCByZXBhaW50cy5cbl9wb2ludGVyRG93bkhhbmRsZXIgPSBmdW5jdGlvbiBfcG9pbnRlckRvd25IYW5kbGVyKCkge1xuICByZXR1cm4gX3BvaW50ZXJJc0Rvd24gPSAxO1xufSxcbiAgICBfcG9pbnRlclVwSGFuZGxlciA9IGZ1bmN0aW9uIF9wb2ludGVyVXBIYW5kbGVyKCkge1xuICByZXR1cm4gX3BvaW50ZXJJc0Rvd24gPSAwO1xufSxcbiAgICBfcGFzc1Rocm91Z2ggPSBmdW5jdGlvbiBfcGFzc1Rocm91Z2godikge1xuICByZXR1cm4gdjtcbn0sXG4gICAgX3JvdW5kID0gZnVuY3Rpb24gX3JvdW5kKHZhbHVlKSB7XG4gIHJldHVybiBNYXRoLnJvdW5kKHZhbHVlICogMTAwMDAwKSAvIDEwMDAwMCB8fCAwO1xufSxcbiAgICBfd2luZG93RXhpc3RzID0gZnVuY3Rpb24gX3dpbmRvd0V4aXN0cygpIHtcbiAgcmV0dXJuIHR5cGVvZiB3aW5kb3cgIT09IFwidW5kZWZpbmVkXCI7XG59LFxuICAgIF9nZXRHU0FQID0gZnVuY3Rpb24gX2dldEdTQVAoKSB7XG4gIHJldHVybiBnc2FwIHx8IF93aW5kb3dFeGlzdHMoKSAmJiAoZ3NhcCA9IHdpbmRvdy5nc2FwKSAmJiBnc2FwLnJlZ2lzdGVyUGx1Z2luICYmIGdzYXA7XG59LFxuICAgIF9pc1ZpZXdwb3J0ID0gZnVuY3Rpb24gX2lzVmlld3BvcnQoZSkge1xuICByZXR1cm4gISF+X3Jvb3QuaW5kZXhPZihlKTtcbn0sXG4gICAgX2dldFZpZXdwb3J0RGltZW5zaW9uID0gZnVuY3Rpb24gX2dldFZpZXdwb3J0RGltZW5zaW9uKGRpbWVuc2lvblByb3BlcnR5KSB7XG4gIHJldHVybiAoZGltZW5zaW9uUHJvcGVydHkgPT09IFwiSGVpZ2h0XCIgPyBfMTAwdmggOiBfd2luW1wiaW5uZXJcIiArIGRpbWVuc2lvblByb3BlcnR5XSkgfHwgX2RvY0VsW1wiY2xpZW50XCIgKyBkaW1lbnNpb25Qcm9wZXJ0eV0gfHwgX2JvZHlbXCJjbGllbnRcIiArIGRpbWVuc2lvblByb3BlcnR5XTtcbn0sXG4gICAgX2dldEJvdW5kc0Z1bmMgPSBmdW5jdGlvbiBfZ2V0Qm91bmRzRnVuYyhlbGVtZW50KSB7XG4gIHJldHVybiBfZ2V0UHJveHlQcm9wKGVsZW1lbnQsIFwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0XCIpIHx8IChfaXNWaWV3cG9ydChlbGVtZW50KSA/IGZ1bmN0aW9uICgpIHtcbiAgICBfd2luT2Zmc2V0cy53aWR0aCA9IF93aW4uaW5uZXJXaWR0aDtcbiAgICBfd2luT2Zmc2V0cy5oZWlnaHQgPSBfMTAwdmg7XG4gICAgcmV0dXJuIF93aW5PZmZzZXRzO1xuICB9IDogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBfZ2V0Qm91bmRzKGVsZW1lbnQpO1xuICB9KTtcbn0sXG4gICAgX2dldFNpemVGdW5jID0gZnVuY3Rpb24gX2dldFNpemVGdW5jKHNjcm9sbGVyLCBpc1ZpZXdwb3J0LCBfcmVmKSB7XG4gIHZhciBkID0gX3JlZi5kLFxuICAgICAgZDIgPSBfcmVmLmQyLFxuICAgICAgYSA9IF9yZWYuYTtcbiAgcmV0dXJuIChhID0gX2dldFByb3h5UHJvcChzY3JvbGxlciwgXCJnZXRCb3VuZGluZ0NsaWVudFJlY3RcIikpID8gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBhKClbZF07XG4gIH0gOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIChpc1ZpZXdwb3J0ID8gX2dldFZpZXdwb3J0RGltZW5zaW9uKGQyKSA6IHNjcm9sbGVyW1wiY2xpZW50XCIgKyBkMl0pIHx8IDA7XG4gIH07XG59LFxuICAgIF9nZXRPZmZzZXRzRnVuYyA9IGZ1bmN0aW9uIF9nZXRPZmZzZXRzRnVuYyhlbGVtZW50LCBpc1ZpZXdwb3J0KSB7XG4gIHJldHVybiAhaXNWaWV3cG9ydCB8fCB+X3Byb3hpZXMuaW5kZXhPZihlbGVtZW50KSA/IF9nZXRCb3VuZHNGdW5jKGVsZW1lbnQpIDogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBfd2luT2Zmc2V0cztcbiAgfTtcbn0sXG4gICAgX21heFNjcm9sbCA9IGZ1bmN0aW9uIF9tYXhTY3JvbGwoZWxlbWVudCwgX3JlZjIpIHtcbiAgdmFyIHMgPSBfcmVmMi5zLFxuICAgICAgZDIgPSBfcmVmMi5kMixcbiAgICAgIGQgPSBfcmVmMi5kLFxuICAgICAgYSA9IF9yZWYyLmE7XG4gIHJldHVybiBNYXRoLm1heCgwLCAocyA9IFwic2Nyb2xsXCIgKyBkMikgJiYgKGEgPSBfZ2V0UHJveHlQcm9wKGVsZW1lbnQsIHMpKSA/IGEoKSAtIF9nZXRCb3VuZHNGdW5jKGVsZW1lbnQpKClbZF0gOiBfaXNWaWV3cG9ydChlbGVtZW50KSA/IChfZG9jRWxbc10gfHwgX2JvZHlbc10pIC0gX2dldFZpZXdwb3J0RGltZW5zaW9uKGQyKSA6IGVsZW1lbnRbc10gLSBlbGVtZW50W1wib2Zmc2V0XCIgKyBkMl0pO1xufSxcbiAgICBfaXRlcmF0ZUF1dG9SZWZyZXNoID0gZnVuY3Rpb24gX2l0ZXJhdGVBdXRvUmVmcmVzaChmdW5jLCBldmVudHMpIHtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBfYXV0b1JlZnJlc2gubGVuZ3RoOyBpICs9IDMpIHtcbiAgICAoIWV2ZW50cyB8fCB+ZXZlbnRzLmluZGV4T2YoX2F1dG9SZWZyZXNoW2kgKyAxXSkpICYmIGZ1bmMoX2F1dG9SZWZyZXNoW2ldLCBfYXV0b1JlZnJlc2hbaSArIDFdLCBfYXV0b1JlZnJlc2hbaSArIDJdKTtcbiAgfVxufSxcbiAgICBfaXNTdHJpbmcgPSBmdW5jdGlvbiBfaXNTdHJpbmcodmFsdWUpIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIjtcbn0sXG4gICAgX2lzRnVuY3Rpb24gPSBmdW5jdGlvbiBfaXNGdW5jdGlvbih2YWx1ZSkge1xuICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSBcImZ1bmN0aW9uXCI7XG59LFxuICAgIF9pc051bWJlciA9IGZ1bmN0aW9uIF9pc051bWJlcih2YWx1ZSkge1xuICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSBcIm51bWJlclwiO1xufSxcbiAgICBfaXNPYmplY3QgPSBmdW5jdGlvbiBfaXNPYmplY3QodmFsdWUpIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIjtcbn0sXG4gICAgX2VuZEFuaW1hdGlvbiA9IGZ1bmN0aW9uIF9lbmRBbmltYXRpb24oYW5pbWF0aW9uLCByZXZlcnNlZCwgcGF1c2UpIHtcbiAgcmV0dXJuIGFuaW1hdGlvbiAmJiBhbmltYXRpb24ucHJvZ3Jlc3MocmV2ZXJzZWQgPyAwIDogMSkgJiYgcGF1c2UgJiYgYW5pbWF0aW9uLnBhdXNlKCk7XG59LFxuICAgIF9jYWxsYmFjayA9IGZ1bmN0aW9uIF9jYWxsYmFjayhzZWxmLCBmdW5jKSB7XG4gIGlmIChzZWxmLmVuYWJsZWQpIHtcbiAgICB2YXIgcmVzdWx0ID0gc2VsZi5fY3R4ID8gc2VsZi5fY3R4LmFkZChmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gZnVuYyhzZWxmKTtcbiAgICB9KSA6IGZ1bmMoc2VsZik7XG4gICAgcmVzdWx0ICYmIHJlc3VsdC50b3RhbFRpbWUgJiYgKHNlbGYuY2FsbGJhY2tBbmltYXRpb24gPSByZXN1bHQpO1xuICB9XG59LFxuICAgIF9hYnMgPSBNYXRoLmFicyxcbiAgICBfbGVmdCA9IFwibGVmdFwiLFxuICAgIF90b3AgPSBcInRvcFwiLFxuICAgIF9yaWdodCA9IFwicmlnaHRcIixcbiAgICBfYm90dG9tID0gXCJib3R0b21cIixcbiAgICBfd2lkdGggPSBcIndpZHRoXCIsXG4gICAgX2hlaWdodCA9IFwiaGVpZ2h0XCIsXG4gICAgX1JpZ2h0ID0gXCJSaWdodFwiLFxuICAgIF9MZWZ0ID0gXCJMZWZ0XCIsXG4gICAgX1RvcCA9IFwiVG9wXCIsXG4gICAgX0JvdHRvbSA9IFwiQm90dG9tXCIsXG4gICAgX3BhZGRpbmcgPSBcInBhZGRpbmdcIixcbiAgICBfbWFyZ2luID0gXCJtYXJnaW5cIixcbiAgICBfV2lkdGggPSBcIldpZHRoXCIsXG4gICAgX0hlaWdodCA9IFwiSGVpZ2h0XCIsXG4gICAgX3B4ID0gXCJweFwiLFxuICAgIF9nZXRDb21wdXRlZFN0eWxlID0gZnVuY3Rpb24gX2dldENvbXB1dGVkU3R5bGUoZWxlbWVudCkge1xuICByZXR1cm4gX3dpbi5nZXRDb21wdXRlZFN0eWxlKGVsZW1lbnQpO1xufSxcbiAgICBfbWFrZVBvc2l0aW9uYWJsZSA9IGZ1bmN0aW9uIF9tYWtlUG9zaXRpb25hYmxlKGVsZW1lbnQpIHtcbiAgLy8gaWYgdGhlIGVsZW1lbnQgYWxyZWFkeSBoYXMgcG9zaXRpb246IGFic29sdXRlIG9yIGZpeGVkLCBsZWF2ZSB0aGF0LCBvdGhlcndpc2UgbWFrZSBpdCBwb3NpdGlvbjogcmVsYXRpdmVcbiAgdmFyIHBvc2l0aW9uID0gX2dldENvbXB1dGVkU3R5bGUoZWxlbWVudCkucG9zaXRpb247XG5cbiAgZWxlbWVudC5zdHlsZS5wb3NpdGlvbiA9IHBvc2l0aW9uID09PSBcImFic29sdXRlXCIgfHwgcG9zaXRpb24gPT09IFwiZml4ZWRcIiA/IHBvc2l0aW9uIDogXCJyZWxhdGl2ZVwiO1xufSxcbiAgICBfc2V0RGVmYXVsdHMgPSBmdW5jdGlvbiBfc2V0RGVmYXVsdHMob2JqLCBkZWZhdWx0cykge1xuICBmb3IgKHZhciBwIGluIGRlZmF1bHRzKSB7XG4gICAgcCBpbiBvYmogfHwgKG9ialtwXSA9IGRlZmF1bHRzW3BdKTtcbiAgfVxuXG4gIHJldHVybiBvYmo7XG59LFxuICAgIF9nZXRCb3VuZHMgPSBmdW5jdGlvbiBfZ2V0Qm91bmRzKGVsZW1lbnQsIHdpdGhvdXRUcmFuc2Zvcm1zKSB7XG4gIHZhciB0d2VlbiA9IHdpdGhvdXRUcmFuc2Zvcm1zICYmIF9nZXRDb21wdXRlZFN0eWxlKGVsZW1lbnQpW190cmFuc2Zvcm1Qcm9wXSAhPT0gXCJtYXRyaXgoMSwgMCwgMCwgMSwgMCwgMClcIiAmJiBnc2FwLnRvKGVsZW1lbnQsIHtcbiAgICB4OiAwLFxuICAgIHk6IDAsXG4gICAgeFBlcmNlbnQ6IDAsXG4gICAgeVBlcmNlbnQ6IDAsXG4gICAgcm90YXRpb246IDAsXG4gICAgcm90YXRpb25YOiAwLFxuICAgIHJvdGF0aW9uWTogMCxcbiAgICBzY2FsZTogMSxcbiAgICBza2V3WDogMCxcbiAgICBza2V3WTogMFxuICB9KS5wcm9ncmVzcygxKSxcbiAgICAgIGJvdW5kcyA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gIHR3ZWVuICYmIHR3ZWVuLnByb2dyZXNzKDApLmtpbGwoKTtcbiAgcmV0dXJuIGJvdW5kcztcbn0sXG4gICAgX2dldFNpemUgPSBmdW5jdGlvbiBfZ2V0U2l6ZShlbGVtZW50LCBfcmVmMykge1xuICB2YXIgZDIgPSBfcmVmMy5kMjtcbiAgcmV0dXJuIGVsZW1lbnRbXCJvZmZzZXRcIiArIGQyXSB8fCBlbGVtZW50W1wiY2xpZW50XCIgKyBkMl0gfHwgMDtcbn0sXG4gICAgX2dldExhYmVsUmF0aW9BcnJheSA9IGZ1bmN0aW9uIF9nZXRMYWJlbFJhdGlvQXJyYXkodGltZWxpbmUpIHtcbiAgdmFyIGEgPSBbXSxcbiAgICAgIGxhYmVscyA9IHRpbWVsaW5lLmxhYmVscyxcbiAgICAgIGR1cmF0aW9uID0gdGltZWxpbmUuZHVyYXRpb24oKSxcbiAgICAgIHA7XG5cbiAgZm9yIChwIGluIGxhYmVscykge1xuICAgIGEucHVzaChsYWJlbHNbcF0gLyBkdXJhdGlvbik7XG4gIH1cblxuICByZXR1cm4gYTtcbn0sXG4gICAgX2dldENsb3Nlc3RMYWJlbCA9IGZ1bmN0aW9uIF9nZXRDbG9zZXN0TGFiZWwoYW5pbWF0aW9uKSB7XG4gIHJldHVybiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gZ3NhcC51dGlscy5zbmFwKF9nZXRMYWJlbFJhdGlvQXJyYXkoYW5pbWF0aW9uKSwgdmFsdWUpO1xuICB9O1xufSxcbiAgICBfc25hcERpcmVjdGlvbmFsID0gZnVuY3Rpb24gX3NuYXBEaXJlY3Rpb25hbChzbmFwSW5jcmVtZW50T3JBcnJheSkge1xuICB2YXIgc25hcCA9IGdzYXAudXRpbHMuc25hcChzbmFwSW5jcmVtZW50T3JBcnJheSksXG4gICAgICBhID0gQXJyYXkuaXNBcnJheShzbmFwSW5jcmVtZW50T3JBcnJheSkgJiYgc25hcEluY3JlbWVudE9yQXJyYXkuc2xpY2UoMCkuc29ydChmdW5jdGlvbiAoYSwgYikge1xuICAgIHJldHVybiBhIC0gYjtcbiAgfSk7XG4gIHJldHVybiBhID8gZnVuY3Rpb24gKHZhbHVlLCBkaXJlY3Rpb24sIHRocmVzaG9sZCkge1xuICAgIGlmICh0aHJlc2hvbGQgPT09IHZvaWQgMCkge1xuICAgICAgdGhyZXNob2xkID0gMWUtMztcbiAgICB9XG5cbiAgICB2YXIgaTtcblxuICAgIGlmICghZGlyZWN0aW9uKSB7XG4gICAgICByZXR1cm4gc25hcCh2YWx1ZSk7XG4gICAgfVxuXG4gICAgaWYgKGRpcmVjdGlvbiA+IDApIHtcbiAgICAgIHZhbHVlIC09IHRocmVzaG9sZDsgLy8gdG8gYXZvaWQgcm91bmRpbmcgZXJyb3JzLiBJZiB3ZSdyZSB0b28gc3RyaWN0LCBpdCBtaWdodCBzbmFwIGZvcndhcmQsIHRoZW4gaW1tZWRpYXRlbHkgYWdhaW4sIGFuZCBhZ2Fpbi5cblxuICAgICAgZm9yIChpID0gMDsgaSA8IGEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaWYgKGFbaV0gPj0gdmFsdWUpIHtcbiAgICAgICAgICByZXR1cm4gYVtpXTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gYVtpIC0gMV07XG4gICAgfSBlbHNlIHtcbiAgICAgIGkgPSBhLmxlbmd0aDtcbiAgICAgIHZhbHVlICs9IHRocmVzaG9sZDtcblxuICAgICAgd2hpbGUgKGktLSkge1xuICAgICAgICBpZiAoYVtpXSA8PSB2YWx1ZSkge1xuICAgICAgICAgIHJldHVybiBhW2ldO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGFbMF07XG4gIH0gOiBmdW5jdGlvbiAodmFsdWUsIGRpcmVjdGlvbiwgdGhyZXNob2xkKSB7XG4gICAgaWYgKHRocmVzaG9sZCA9PT0gdm9pZCAwKSB7XG4gICAgICB0aHJlc2hvbGQgPSAxZS0zO1xuICAgIH1cblxuICAgIHZhciBzbmFwcGVkID0gc25hcCh2YWx1ZSk7XG4gICAgcmV0dXJuICFkaXJlY3Rpb24gfHwgTWF0aC5hYnMoc25hcHBlZCAtIHZhbHVlKSA8IHRocmVzaG9sZCB8fCBzbmFwcGVkIC0gdmFsdWUgPCAwID09PSBkaXJlY3Rpb24gPCAwID8gc25hcHBlZCA6IHNuYXAoZGlyZWN0aW9uIDwgMCA/IHZhbHVlIC0gc25hcEluY3JlbWVudE9yQXJyYXkgOiB2YWx1ZSArIHNuYXBJbmNyZW1lbnRPckFycmF5KTtcbiAgfTtcbn0sXG4gICAgX2dldExhYmVsQXREaXJlY3Rpb24gPSBmdW5jdGlvbiBfZ2V0TGFiZWxBdERpcmVjdGlvbih0aW1lbGluZSkge1xuICByZXR1cm4gZnVuY3Rpb24gKHZhbHVlLCBzdCkge1xuICAgIHJldHVybiBfc25hcERpcmVjdGlvbmFsKF9nZXRMYWJlbFJhdGlvQXJyYXkodGltZWxpbmUpKSh2YWx1ZSwgc3QuZGlyZWN0aW9uKTtcbiAgfTtcbn0sXG4gICAgX211bHRpTGlzdGVuZXIgPSBmdW5jdGlvbiBfbXVsdGlMaXN0ZW5lcihmdW5jLCBlbGVtZW50LCB0eXBlcywgY2FsbGJhY2spIHtcbiAgcmV0dXJuIHR5cGVzLnNwbGl0KFwiLFwiKS5mb3JFYWNoKGZ1bmN0aW9uICh0eXBlKSB7XG4gICAgcmV0dXJuIGZ1bmMoZWxlbWVudCwgdHlwZSwgY2FsbGJhY2spO1xuICB9KTtcbn0sXG4gICAgX2FkZExpc3RlbmVyID0gZnVuY3Rpb24gX2FkZExpc3RlbmVyKGVsZW1lbnQsIHR5cGUsIGZ1bmMsIG5vblBhc3NpdmUsIGNhcHR1cmUpIHtcbiAgcmV0dXJuIGVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcih0eXBlLCBmdW5jLCB7XG4gICAgcGFzc2l2ZTogIW5vblBhc3NpdmUsXG4gICAgY2FwdHVyZTogISFjYXB0dXJlXG4gIH0pO1xufSxcbiAgICBfcmVtb3ZlTGlzdGVuZXIgPSBmdW5jdGlvbiBfcmVtb3ZlTGlzdGVuZXIoZWxlbWVudCwgdHlwZSwgZnVuYywgY2FwdHVyZSkge1xuICByZXR1cm4gZWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKHR5cGUsIGZ1bmMsICEhY2FwdHVyZSk7XG59LFxuICAgIF93aGVlbExpc3RlbmVyID0gZnVuY3Rpb24gX3doZWVsTGlzdGVuZXIoZnVuYywgZWwsIHNjcm9sbEZ1bmMpIHtcbiAgc2Nyb2xsRnVuYyA9IHNjcm9sbEZ1bmMgJiYgc2Nyb2xsRnVuYy53aGVlbEhhbmRsZXI7XG5cbiAgaWYgKHNjcm9sbEZ1bmMpIHtcbiAgICBmdW5jKGVsLCBcIndoZWVsXCIsIHNjcm9sbEZ1bmMpO1xuICAgIGZ1bmMoZWwsIFwidG91Y2htb3ZlXCIsIHNjcm9sbEZ1bmMpO1xuICB9XG59LFxuICAgIF9tYXJrZXJEZWZhdWx0cyA9IHtcbiAgc3RhcnRDb2xvcjogXCJncmVlblwiLFxuICBlbmRDb2xvcjogXCJyZWRcIixcbiAgaW5kZW50OiAwLFxuICBmb250U2l6ZTogXCIxNnB4XCIsXG4gIGZvbnRXZWlnaHQ6IFwibm9ybWFsXCJcbn0sXG4gICAgX2RlZmF1bHRzID0ge1xuICB0b2dnbGVBY3Rpb25zOiBcInBsYXlcIixcbiAgYW50aWNpcGF0ZVBpbjogMFxufSxcbiAgICBfa2V5d29yZHMgPSB7XG4gIHRvcDogMCxcbiAgbGVmdDogMCxcbiAgY2VudGVyOiAwLjUsXG4gIGJvdHRvbTogMSxcbiAgcmlnaHQ6IDFcbn0sXG4gICAgX29mZnNldFRvUHggPSBmdW5jdGlvbiBfb2Zmc2V0VG9QeCh2YWx1ZSwgc2l6ZSkge1xuICBpZiAoX2lzU3RyaW5nKHZhbHVlKSkge1xuICAgIHZhciBlcUluZGV4ID0gdmFsdWUuaW5kZXhPZihcIj1cIiksXG4gICAgICAgIHJlbGF0aXZlID0gfmVxSW5kZXggPyArKHZhbHVlLmNoYXJBdChlcUluZGV4IC0gMSkgKyAxKSAqIHBhcnNlRmxvYXQodmFsdWUuc3Vic3RyKGVxSW5kZXggKyAxKSkgOiAwO1xuXG4gICAgaWYgKH5lcUluZGV4KSB7XG4gICAgICB2YWx1ZS5pbmRleE9mKFwiJVwiKSA+IGVxSW5kZXggJiYgKHJlbGF0aXZlICo9IHNpemUgLyAxMDApO1xuICAgICAgdmFsdWUgPSB2YWx1ZS5zdWJzdHIoMCwgZXFJbmRleCAtIDEpO1xuICAgIH1cblxuICAgIHZhbHVlID0gcmVsYXRpdmUgKyAodmFsdWUgaW4gX2tleXdvcmRzID8gX2tleXdvcmRzW3ZhbHVlXSAqIHNpemUgOiB+dmFsdWUuaW5kZXhPZihcIiVcIikgPyBwYXJzZUZsb2F0KHZhbHVlKSAqIHNpemUgLyAxMDAgOiBwYXJzZUZsb2F0KHZhbHVlKSB8fCAwKTtcbiAgfVxuXG4gIHJldHVybiB2YWx1ZTtcbn0sXG4gICAgX2NyZWF0ZU1hcmtlciA9IGZ1bmN0aW9uIF9jcmVhdGVNYXJrZXIodHlwZSwgbmFtZSwgY29udGFpbmVyLCBkaXJlY3Rpb24sIF9yZWY0LCBvZmZzZXQsIG1hdGNoV2lkdGhFbCwgY29udGFpbmVyQW5pbWF0aW9uKSB7XG4gIHZhciBzdGFydENvbG9yID0gX3JlZjQuc3RhcnRDb2xvcixcbiAgICAgIGVuZENvbG9yID0gX3JlZjQuZW5kQ29sb3IsXG4gICAgICBmb250U2l6ZSA9IF9yZWY0LmZvbnRTaXplLFxuICAgICAgaW5kZW50ID0gX3JlZjQuaW5kZW50LFxuICAgICAgZm9udFdlaWdodCA9IF9yZWY0LmZvbnRXZWlnaHQ7XG5cbiAgdmFyIGUgPSBfZG9jLmNyZWF0ZUVsZW1lbnQoXCJkaXZcIiksXG4gICAgICB1c2VGaXhlZFBvc2l0aW9uID0gX2lzVmlld3BvcnQoY29udGFpbmVyKSB8fCBfZ2V0UHJveHlQcm9wKGNvbnRhaW5lciwgXCJwaW5UeXBlXCIpID09PSBcImZpeGVkXCIsXG4gICAgICBpc1Njcm9sbGVyID0gdHlwZS5pbmRleE9mKFwic2Nyb2xsZXJcIikgIT09IC0xLFxuICAgICAgcGFyZW50ID0gdXNlRml4ZWRQb3NpdGlvbiA/IF9ib2R5IDogY29udGFpbmVyLFxuICAgICAgaXNTdGFydCA9IHR5cGUuaW5kZXhPZihcInN0YXJ0XCIpICE9PSAtMSxcbiAgICAgIGNvbG9yID0gaXNTdGFydCA/IHN0YXJ0Q29sb3IgOiBlbmRDb2xvcixcbiAgICAgIGNzcyA9IFwiYm9yZGVyLWNvbG9yOlwiICsgY29sb3IgKyBcIjtmb250LXNpemU6XCIgKyBmb250U2l6ZSArIFwiO2NvbG9yOlwiICsgY29sb3IgKyBcIjtmb250LXdlaWdodDpcIiArIGZvbnRXZWlnaHQgKyBcIjtwb2ludGVyLWV2ZW50czpub25lO3doaXRlLXNwYWNlOm5vd3JhcDtmb250LWZhbWlseTpzYW5zLXNlcmlmLEFyaWFsO3otaW5kZXg6MTAwMDtwYWRkaW5nOjRweCA4cHg7Ym9yZGVyLXdpZHRoOjA7Ym9yZGVyLXN0eWxlOnNvbGlkO1wiO1xuXG4gIGNzcyArPSBcInBvc2l0aW9uOlwiICsgKChpc1Njcm9sbGVyIHx8IGNvbnRhaW5lckFuaW1hdGlvbikgJiYgdXNlRml4ZWRQb3NpdGlvbiA/IFwiZml4ZWQ7XCIgOiBcImFic29sdXRlO1wiKTtcbiAgKGlzU2Nyb2xsZXIgfHwgY29udGFpbmVyQW5pbWF0aW9uIHx8ICF1c2VGaXhlZFBvc2l0aW9uKSAmJiAoY3NzICs9IChkaXJlY3Rpb24gPT09IF92ZXJ0aWNhbCA/IF9yaWdodCA6IF9ib3R0b20pICsgXCI6XCIgKyAob2Zmc2V0ICsgcGFyc2VGbG9hdChpbmRlbnQpKSArIFwicHg7XCIpO1xuICBtYXRjaFdpZHRoRWwgJiYgKGNzcyArPSBcImJveC1zaXppbmc6Ym9yZGVyLWJveDt0ZXh0LWFsaWduOmxlZnQ7d2lkdGg6XCIgKyBtYXRjaFdpZHRoRWwub2Zmc2V0V2lkdGggKyBcInB4O1wiKTtcbiAgZS5faXNTdGFydCA9IGlzU3RhcnQ7XG4gIGUuc2V0QXR0cmlidXRlKFwiY2xhc3NcIiwgXCJnc2FwLW1hcmtlci1cIiArIHR5cGUgKyAobmFtZSA/IFwiIG1hcmtlci1cIiArIG5hbWUgOiBcIlwiKSk7XG4gIGUuc3R5bGUuY3NzVGV4dCA9IGNzcztcbiAgZS5pbm5lclRleHQgPSBuYW1lIHx8IG5hbWUgPT09IDAgPyB0eXBlICsgXCItXCIgKyBuYW1lIDogdHlwZTtcbiAgcGFyZW50LmNoaWxkcmVuWzBdID8gcGFyZW50Lmluc2VydEJlZm9yZShlLCBwYXJlbnQuY2hpbGRyZW5bMF0pIDogcGFyZW50LmFwcGVuZENoaWxkKGUpO1xuICBlLl9vZmZzZXQgPSBlW1wib2Zmc2V0XCIgKyBkaXJlY3Rpb24ub3AuZDJdO1xuXG4gIF9wb3NpdGlvbk1hcmtlcihlLCAwLCBkaXJlY3Rpb24sIGlzU3RhcnQpO1xuXG4gIHJldHVybiBlO1xufSxcbiAgICBfcG9zaXRpb25NYXJrZXIgPSBmdW5jdGlvbiBfcG9zaXRpb25NYXJrZXIobWFya2VyLCBzdGFydCwgZGlyZWN0aW9uLCBmbGlwcGVkKSB7XG4gIHZhciB2YXJzID0ge1xuICAgIGRpc3BsYXk6IFwiYmxvY2tcIlxuICB9LFxuICAgICAgc2lkZSA9IGRpcmVjdGlvbltmbGlwcGVkID8gXCJvczJcIiA6IFwicDJcIl0sXG4gICAgICBvcHBvc2l0ZVNpZGUgPSBkaXJlY3Rpb25bZmxpcHBlZCA/IFwicDJcIiA6IFwib3MyXCJdO1xuICBtYXJrZXIuX2lzRmxpcHBlZCA9IGZsaXBwZWQ7XG4gIHZhcnNbZGlyZWN0aW9uLmEgKyBcIlBlcmNlbnRcIl0gPSBmbGlwcGVkID8gLTEwMCA6IDA7XG4gIHZhcnNbZGlyZWN0aW9uLmFdID0gZmxpcHBlZCA/IFwiMXB4XCIgOiAwO1xuICB2YXJzW1wiYm9yZGVyXCIgKyBzaWRlICsgX1dpZHRoXSA9IDE7XG4gIHZhcnNbXCJib3JkZXJcIiArIG9wcG9zaXRlU2lkZSArIF9XaWR0aF0gPSAwO1xuICB2YXJzW2RpcmVjdGlvbi5wXSA9IHN0YXJ0ICsgXCJweFwiO1xuICBnc2FwLnNldChtYXJrZXIsIHZhcnMpO1xufSxcbiAgICBfdHJpZ2dlcnMgPSBbXSxcbiAgICBfaWRzID0ge30sXG4gICAgX3JhZklELFxuICAgIF9zeW5jID0gZnVuY3Rpb24gX3N5bmMoKSB7XG4gIHJldHVybiBfZ2V0VGltZSgpIC0gX2xhc3RTY3JvbGxUaW1lID4gMzQgJiYgKF9yYWZJRCB8fCAoX3JhZklEID0gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKF91cGRhdGVBbGwpKSk7XG59LFxuICAgIF9vblNjcm9sbCA9IGZ1bmN0aW9uIF9vblNjcm9sbCgpIHtcbiAgLy8gcHJldmlvdXNseSwgd2UgdHJpZWQgdG8gb3B0aW1pemUgcGVyZm9ybWFuY2UgYnkgYmF0Y2hpbmcvZGVmZXJyaW5nIHRvIHRoZSBuZXh0IHJlcXVlc3RBbmltYXRpb25GcmFtZSgpLCBidXQgZGlzY292ZXJlZCB0aGF0IFNhZmFyaSBoYXMgYSBmZXcgYnVncyB0aGF0IG1ha2UgdGhpcyB1bndvcmthYmxlIChlc3BlY2lhbGx5IG9uIGlPUykuIFNlZSBodHRwczovL2NvZGVwZW4uaW8vR3JlZW5Tb2NrL3Blbi8xNmM0MzViMTJlZjA5YzM4MTI1MjA0ODE4ZTdiNDVmYz9lZGl0b3JzPTAwMTAgYW5kIGh0dHBzOi8vY29kZXBlbi5pby9HcmVlblNvY2svcGVuL0pqT3hZcFEvM2RkNjVjY2VjNWE2MGYxZDg2MmMzNTVkODRkMTQ1NjI/ZWRpdG9ycz0wMDEwIGFuZCBodHRwczovL2NvZGVwZW4uaW8vR3JlZW5Tb2NrL3Blbi9FeGJyUE5hLzA4N2NlZjE5N2RjMzU0NDVhMDk1MWU4OTM1YzQxNTAzP2VkaXRvcnM9MDAxMFxuICBpZiAoIV9ub3JtYWxpemVyIHx8ICFfbm9ybWFsaXplci5pc1ByZXNzZWQgfHwgX25vcm1hbGl6ZXIuc3RhcnRYID4gX2JvZHkuY2xpZW50V2lkdGgpIHtcbiAgICAvLyBpZiB0aGUgdXNlciBpcyBkcmFnZ2luZyB0aGUgc2Nyb2xsYmFyLCBhbGxvdyBpdC5cbiAgICBfc2Nyb2xsZXJzLmNhY2hlKys7XG5cbiAgICBpZiAoX25vcm1hbGl6ZXIpIHtcbiAgICAgIF9yYWZJRCB8fCAoX3JhZklEID0gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKF91cGRhdGVBbGwpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgX3VwZGF0ZUFsbCgpOyAvLyBTYWZhcmkgaW4gcGFydGljdWxhciAob24gZGVza3RvcCkgTkVFRFMgdGhlIGltbWVkaWF0ZSB1cGRhdGUgcmF0aGVyIHRoYW4gd2FpdGluZyBmb3IgYSByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKSB3aGVyZWFzIGlPUyBzZWVtcyB0byBiZW5lZml0IGZyb20gd2FpdGluZyBmb3IgdGhlIHJlcXVlc3RBbmltYXRpb25GcmFtZSgpIHRpY2ssIGF0IGxlYXN0IHdoZW4gbm9ybWFsaXppbmcuIFNlZSBodHRwczovL2NvZGVwZW4uaW8vR3JlZW5Tb2NrL3Blbi9xQllvenFPP2VkaXRvcnM9MDExMFxuXG4gICAgfVxuXG4gICAgX2xhc3RTY3JvbGxUaW1lIHx8IF9kaXNwYXRjaChcInNjcm9sbFN0YXJ0XCIpO1xuICAgIF9sYXN0U2Nyb2xsVGltZSA9IF9nZXRUaW1lKCk7XG4gIH1cbn0sXG4gICAgX3NldEJhc2VEaW1lbnNpb25zID0gZnVuY3Rpb24gX3NldEJhc2VEaW1lbnNpb25zKCkge1xuICBfYmFzZVNjcmVlbldpZHRoID0gX3dpbi5pbm5lcldpZHRoO1xuICBfYmFzZVNjcmVlbkhlaWdodCA9IF93aW4uaW5uZXJIZWlnaHQ7XG59LFxuICAgIF9vblJlc2l6ZSA9IGZ1bmN0aW9uIF9vblJlc2l6ZSgpIHtcbiAgX3Njcm9sbGVycy5jYWNoZSsrO1xuICAhX3JlZnJlc2hpbmcgJiYgIV9pZ25vcmVSZXNpemUgJiYgIV9kb2MuZnVsbHNjcmVlbkVsZW1lbnQgJiYgIV9kb2Mud2Via2l0RnVsbHNjcmVlbkVsZW1lbnQgJiYgKCFfaWdub3JlTW9iaWxlUmVzaXplIHx8IF9iYXNlU2NyZWVuV2lkdGggIT09IF93aW4uaW5uZXJXaWR0aCB8fCBNYXRoLmFicyhfd2luLmlubmVySGVpZ2h0IC0gX2Jhc2VTY3JlZW5IZWlnaHQpID4gX3dpbi5pbm5lckhlaWdodCAqIDAuMjUpICYmIF9yZXNpemVEZWxheS5yZXN0YXJ0KHRydWUpO1xufSxcbiAgICAvLyBpZ25vcmUgcmVzaXplcyB0cmlnZ2VyZWQgYnkgcmVmcmVzaCgpXG5fbGlzdGVuZXJzID0ge30sXG4gICAgX2VtcHR5QXJyYXkgPSBbXSxcbiAgICBfc29mdFJlZnJlc2ggPSBmdW5jdGlvbiBfc29mdFJlZnJlc2goKSB7XG4gIHJldHVybiBfcmVtb3ZlTGlzdGVuZXIoU2Nyb2xsVHJpZ2dlciwgXCJzY3JvbGxFbmRcIiwgX3NvZnRSZWZyZXNoKSB8fCBfcmVmcmVzaEFsbCh0cnVlKTtcbn0sXG4gICAgX2Rpc3BhdGNoID0gZnVuY3Rpb24gX2Rpc3BhdGNoKHR5cGUpIHtcbiAgcmV0dXJuIF9saXN0ZW5lcnNbdHlwZV0gJiYgX2xpc3RlbmVyc1t0eXBlXS5tYXAoZnVuY3Rpb24gKGYpIHtcbiAgICByZXR1cm4gZigpO1xuICB9KSB8fCBfZW1wdHlBcnJheTtcbn0sXG4gICAgX3NhdmVkU3R5bGVzID0gW10sXG4gICAgLy8gd2hlbiBTY3JvbGxUcmlnZ2VyLnNhdmVTdHlsZXMoKSBpcyBjYWxsZWQsIHRoZSBpbmxpbmUgc3R5bGVzIGFyZSByZWNvcmRlZCBpbiB0aGlzIEFycmF5IGluIGEgc2VxdWVudGlhbCBmb3JtYXQgbGlrZSBbZWxlbWVudCwgY3NzVGV4dCwgZ3NDYWNoZSwgbWVkaWFdLiBUaGlzIGtlZXBzIGl0IHZlcnkgbWVtb3J5LWVmZmljaWVudCBhbmQgZmFzdCB0byBpdGVyYXRlIHRocm91Z2guXG5fcmV2ZXJ0UmVjb3JkZWQgPSBmdW5jdGlvbiBfcmV2ZXJ0UmVjb3JkZWQobWVkaWEpIHtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBfc2F2ZWRTdHlsZXMubGVuZ3RoOyBpICs9IDUpIHtcbiAgICBpZiAoIW1lZGlhIHx8IF9zYXZlZFN0eWxlc1tpICsgNF0gJiYgX3NhdmVkU3R5bGVzW2kgKyA0XS5xdWVyeSA9PT0gbWVkaWEpIHtcbiAgICAgIF9zYXZlZFN0eWxlc1tpXS5zdHlsZS5jc3NUZXh0ID0gX3NhdmVkU3R5bGVzW2kgKyAxXTtcbiAgICAgIF9zYXZlZFN0eWxlc1tpXS5nZXRCQm94ICYmIF9zYXZlZFN0eWxlc1tpXS5zZXRBdHRyaWJ1dGUoXCJ0cmFuc2Zvcm1cIiwgX3NhdmVkU3R5bGVzW2kgKyAyXSB8fCBcIlwiKTtcbiAgICAgIF9zYXZlZFN0eWxlc1tpICsgM10udW5jYWNoZSA9IDE7XG4gICAgfVxuICB9XG59LFxuICAgIF9yZXZlcnRBbGwgPSBmdW5jdGlvbiBfcmV2ZXJ0QWxsKGtpbGwsIG1lZGlhKSB7XG4gIHZhciB0cmlnZ2VyO1xuXG4gIGZvciAoX2kgPSAwOyBfaSA8IF90cmlnZ2Vycy5sZW5ndGg7IF9pKyspIHtcbiAgICB0cmlnZ2VyID0gX3RyaWdnZXJzW19pXTtcblxuICAgIGlmICh0cmlnZ2VyICYmICghbWVkaWEgfHwgdHJpZ2dlci5fY3R4ID09PSBtZWRpYSkpIHtcbiAgICAgIGlmIChraWxsKSB7XG4gICAgICAgIHRyaWdnZXIua2lsbCgxKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRyaWdnZXIucmV2ZXJ0KHRydWUsIHRydWUpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIF9pc1JldmVydGVkID0gdHJ1ZTtcbiAgbWVkaWEgJiYgX3JldmVydFJlY29yZGVkKG1lZGlhKTtcbiAgbWVkaWEgfHwgX2Rpc3BhdGNoKFwicmV2ZXJ0XCIpO1xufSxcbiAgICBfY2xlYXJTY3JvbGxNZW1vcnkgPSBmdW5jdGlvbiBfY2xlYXJTY3JvbGxNZW1vcnkoc2Nyb2xsUmVzdG9yYXRpb24sIGZvcmNlKSB7XG4gIC8vIHplcm8tb3V0IGFsbCB0aGUgcmVjb3JkZWQgc2Nyb2xsIHBvc2l0aW9ucy4gRG9uJ3QgdXNlIF90cmlnZ2VycyBiZWNhdXNlIGlmLCBmb3IgZXhhbXBsZSwgLm1hdGNoTWVkaWEoKSBpcyB1c2VkIHRvIGNyZWF0ZSBzb21lIFNjcm9sbFRyaWdnZXJzIGFuZCB0aGVuIHRoZSB1c2VyIHJlc2l6ZXMgYW5kIGl0IHJlbW92ZXMgQUxMIFNjcm9sbFRyaWdnZXJzLCBhbmQgdGhlbiBnbyBiYWNrIHRvIGEgc2l6ZSB3aGVyZSB0aGVyZSBhcmUgU2Nyb2xsVHJpZ2dlcnMsIGl0IHdvdWxkIGhhdmUga2VwdCB0aGUgcG9zaXRpb24ocykgc2F2ZWQgZnJvbSB0aGUgaW5pdGlhbCBzdGF0ZS5cbiAgX3Njcm9sbGVycy5jYWNoZSsrO1xuICAoZm9yY2UgfHwgIV9yZWZyZXNoaW5nQWxsKSAmJiBfc2Nyb2xsZXJzLmZvckVhY2goZnVuY3Rpb24gKG9iaikge1xuICAgIHJldHVybiBfaXNGdW5jdGlvbihvYmopICYmIG9iai5jYWNoZUlEKysgJiYgKG9iai5yZWMgPSAwKTtcbiAgfSk7XG4gIF9pc1N0cmluZyhzY3JvbGxSZXN0b3JhdGlvbikgJiYgKF93aW4uaGlzdG9yeS5zY3JvbGxSZXN0b3JhdGlvbiA9IF9zY3JvbGxSZXN0b3JhdGlvbiA9IHNjcm9sbFJlc3RvcmF0aW9uKTtcbn0sXG4gICAgX3JlZnJlc2hpbmdBbGwsXG4gICAgX3JlZnJlc2hJRCA9IDAsXG4gICAgX3F1ZXVlUmVmcmVzaElELFxuICAgIF9xdWV1ZVJlZnJlc2hBbGwgPSBmdW5jdGlvbiBfcXVldWVSZWZyZXNoQWxsKCkge1xuICAvLyB3ZSBkb24ndCB3YW50IHRvIGNhbGwgX3JlZnJlc2hBbGwoKSBldmVyeSB0aW1lIHdlIGNyZWF0ZSBhIG5ldyBTY3JvbGxUcmlnZ2VyIChmb3IgcGVyZm9ybWFuY2UgcmVhc29ucykgLSBpdCdzIGJldHRlciB0byBiYXRjaCB0aGVtLiBTb21lIGZyYW1ld29ya3MgZHluYW1pY2FsbHkgbG9hZCBjb250ZW50IGFuZCB3ZSBjYW4ndCByZWx5IG9uIHRoZSB3aW5kb3cncyBcImxvYWRcIiBvciBcIkRPTUNvbnRlbnRMb2FkZWRcIiBldmVudHMgdG8gdHJpZ2dlciBpdC5cbiAgaWYgKF9xdWV1ZVJlZnJlc2hJRCAhPT0gX3JlZnJlc2hJRCkge1xuICAgIHZhciBpZCA9IF9xdWV1ZVJlZnJlc2hJRCA9IF9yZWZyZXNoSUQ7XG4gICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBpZCA9PT0gX3JlZnJlc2hJRCAmJiBfcmVmcmVzaEFsbCh0cnVlKTtcbiAgICB9KTtcbiAgfVxufSxcbiAgICBfcmVmcmVzaDEwMHZoID0gZnVuY3Rpb24gX3JlZnJlc2gxMDB2aCgpIHtcbiAgX2JvZHkuYXBwZW5kQ2hpbGQoX2RpdjEwMHZoKTtcblxuICBfMTAwdmggPSAhX25vcm1hbGl6ZXIgJiYgX2RpdjEwMHZoLm9mZnNldEhlaWdodCB8fCBfd2luLmlubmVySGVpZ2h0O1xuXG4gIF9ib2R5LnJlbW92ZUNoaWxkKF9kaXYxMDB2aCk7XG59LFxuICAgIF9oaWRlQWxsTWFya2VycyA9IGZ1bmN0aW9uIF9oaWRlQWxsTWFya2VycyhoaWRlKSB7XG4gIHJldHVybiBfdG9BcnJheShcIi5nc2FwLW1hcmtlci1zdGFydCwgLmdzYXAtbWFya2VyLWVuZCwgLmdzYXAtbWFya2VyLXNjcm9sbGVyLXN0YXJ0LCAuZ3NhcC1tYXJrZXItc2Nyb2xsZXItZW5kXCIpLmZvckVhY2goZnVuY3Rpb24gKGVsKSB7XG4gICAgcmV0dXJuIGVsLnN0eWxlLmRpc3BsYXkgPSBoaWRlID8gXCJub25lXCIgOiBcImJsb2NrXCI7XG4gIH0pO1xufSxcbiAgICBfcmVmcmVzaEFsbCA9IGZ1bmN0aW9uIF9yZWZyZXNoQWxsKGZvcmNlLCBza2lwUmV2ZXJ0KSB7XG4gIGlmIChfbGFzdFNjcm9sbFRpbWUgJiYgIWZvcmNlICYmICFfaXNSZXZlcnRlZCkge1xuICAgIF9hZGRMaXN0ZW5lcihTY3JvbGxUcmlnZ2VyLCBcInNjcm9sbEVuZFwiLCBfc29mdFJlZnJlc2gpO1xuXG4gICAgcmV0dXJuO1xuICB9XG5cbiAgX3JlZnJlc2gxMDB2aCgpO1xuXG4gIF9yZWZyZXNoaW5nQWxsID0gU2Nyb2xsVHJpZ2dlci5pc1JlZnJlc2hpbmcgPSB0cnVlO1xuXG4gIF9zY3JvbGxlcnMuZm9yRWFjaChmdW5jdGlvbiAob2JqKSB7XG4gICAgcmV0dXJuIF9pc0Z1bmN0aW9uKG9iaikgJiYgKytvYmouY2FjaGVJRCAmJiAob2JqLnJlYyA9IG9iaigpKTtcbiAgfSk7IC8vIGZvcmNlIHRoZSBjbGVhcmluZyBvZiB0aGUgY2FjaGUgYmVjYXVzZSBzb21lIGJyb3dzZXJzIHRha2UgYSBsaXR0bGUgd2hpbGUgdG8gZGlzcGF0Y2ggdGhlIFwic2Nyb2xsXCIgZXZlbnQgYW5kIHRoZSB1c2VyIG1heSBoYXZlIGNoYW5nZWQgdGhlIHNjcm9sbCBwb3NpdGlvbiBhbmQgdGhlbiBjYWxsZWQgU2Nyb2xsVHJpZ2dlci5yZWZyZXNoKCkgcmlnaHQgYXdheVxuXG5cbiAgdmFyIHJlZnJlc2hJbml0cyA9IF9kaXNwYXRjaChcInJlZnJlc2hJbml0XCIpO1xuXG4gIF9zb3J0ICYmIFNjcm9sbFRyaWdnZXIuc29ydCgpO1xuICBza2lwUmV2ZXJ0IHx8IF9yZXZlcnRBbGwoKTtcblxuICBfc2Nyb2xsZXJzLmZvckVhY2goZnVuY3Rpb24gKG9iaikge1xuICAgIGlmIChfaXNGdW5jdGlvbihvYmopKSB7XG4gICAgICBvYmouc21vb3RoICYmIChvYmoudGFyZ2V0LnN0eWxlLnNjcm9sbEJlaGF2aW9yID0gXCJhdXRvXCIpOyAvLyBzbW9vdGggc2Nyb2xsaW5nIGludGVyZmVyZXNcblxuICAgICAgb2JqKDApO1xuICAgIH1cbiAgfSk7XG5cbiAgX3RyaWdnZXJzLnNsaWNlKDApLmZvckVhY2goZnVuY3Rpb24gKHQpIHtcbiAgICByZXR1cm4gdC5yZWZyZXNoKCk7XG4gIH0pOyAvLyBkb24ndCBsb29wIHdpdGggX2kgYmVjYXVzZSBkdXJpbmcgYSByZWZyZXNoKCkgc29tZW9uZSBjb3VsZCBjYWxsIFNjcm9sbFRyaWdnZXIudXBkYXRlKCkgd2hpY2ggd291bGQgaXRlcmF0ZSB0aHJvdWdoIF9pIHJlc3VsdGluZyBpbiBhIHNraXAuXG5cblxuICBfaXNSZXZlcnRlZCA9IGZhbHNlO1xuXG4gIF90cmlnZ2Vycy5mb3JFYWNoKGZ1bmN0aW9uICh0KSB7XG4gICAgLy8gbmVzdGVkIHBpbnMgKHBpbm5lZENvbnRhaW5lcikgd2l0aCBwaW5TcGFjaW5nIG1heSBleHBhbmQgdGhlIGNvbnRhaW5lciwgc28gd2UgbXVzdCBhY2NvbW1vZGF0ZSB0aGF0IGhlcmUuXG4gICAgaWYgKHQuX3N1YlBpbk9mZnNldCAmJiB0LnBpbikge1xuICAgICAgdmFyIHByb3AgPSB0LnZhcnMuaG9yaXpvbnRhbCA/IFwib2Zmc2V0V2lkdGhcIiA6IFwib2Zmc2V0SGVpZ2h0XCIsXG4gICAgICAgICAgb3JpZ2luYWwgPSB0LnBpbltwcm9wXTtcbiAgICAgIHQucmV2ZXJ0KHRydWUsIDEpO1xuICAgICAgdC5hZGp1c3RQaW5TcGFjaW5nKHQucGluW3Byb3BdIC0gb3JpZ2luYWwpO1xuICAgICAgdC5yZWZyZXNoKCk7XG4gICAgfVxuICB9KTtcblxuICBfY2xhbXBpbmdNYXggPSAxOyAvLyBwaW5TcGFjaW5nIG1pZ2h0IGJlIHByb3BwaW5nIGEgcGFnZSBvcGVuLCB0aHVzIHdoZW4gd2UgLnNldFBvc2l0aW9ucygpIHRvIGNsYW1wIGEgU2Nyb2xsVHJpZ2dlcidzIGVuZCB3ZSBzaG91bGQgbGVhdmUgdGhlIHBpblNwYWNpbmcgYWxvbmUuIFRoYXQncyB3aGF0IHRoaXMgZmxhZyBpcyBmb3IuXG5cbiAgX2hpZGVBbGxNYXJrZXJzKHRydWUpO1xuXG4gIF90cmlnZ2Vycy5mb3JFYWNoKGZ1bmN0aW9uICh0KSB7XG4gICAgLy8gdGhlIHNjcm9sbGVyJ3MgbWF4IHNjcm9sbCBwb3NpdGlvbiBtYXkgY2hhbmdlIGFmdGVyIGFsbCB0aGUgU2Nyb2xsVHJpZ2dlcnMgcmVmcmVzaGVkIChsaWtlIHBpbm5pbmcgY291bGQgcHVzaCBpdCBkb3duKSwgc28gd2UgbmVlZCB0byBsb29wIGJhY2sgYW5kIGNvcnJlY3QgYW55IHdpdGggZW5kOiBcIm1heFwiLiBTYW1lIGZvciBhbnl0aGluZyB3aXRoIGEgY2xhbXBlZCBlbmRcbiAgICB2YXIgbWF4ID0gX21heFNjcm9sbCh0LnNjcm9sbGVyLCB0Ll9kaXIpLFxuICAgICAgICBlbmRDbGFtcCA9IHQudmFycy5lbmQgPT09IFwibWF4XCIgfHwgdC5fZW5kQ2xhbXAgJiYgdC5lbmQgPiBtYXgsXG4gICAgICAgIHN0YXJ0Q2xhbXAgPSB0Ll9zdGFydENsYW1wICYmIHQuc3RhcnQgPj0gbWF4O1xuXG4gICAgKGVuZENsYW1wIHx8IHN0YXJ0Q2xhbXApICYmIHQuc2V0UG9zaXRpb25zKHN0YXJ0Q2xhbXAgPyBtYXggLSAxIDogdC5zdGFydCwgZW5kQ2xhbXAgPyBNYXRoLm1heChzdGFydENsYW1wID8gbWF4IDogdC5zdGFydCArIDEsIG1heCkgOiB0LmVuZCwgdHJ1ZSk7XG4gIH0pO1xuXG4gIF9oaWRlQWxsTWFya2VycyhmYWxzZSk7XG5cbiAgX2NsYW1waW5nTWF4ID0gMDtcbiAgcmVmcmVzaEluaXRzLmZvckVhY2goZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgIHJldHVybiByZXN1bHQgJiYgcmVzdWx0LnJlbmRlciAmJiByZXN1bHQucmVuZGVyKC0xKTtcbiAgfSk7IC8vIGlmIHRoZSBvblJlZnJlc2hJbml0KCkgcmV0dXJucyBhbiBhbmltYXRpb24gKHR5cGljYWxseSBhIGdzYXAuc2V0KCkpLCByZXZlcnQgaXQuIFRoaXMgbWFrZXMgaXQgZWFzeSB0byBwdXQgdGhpbmdzIGluIGEgY2VydGFpbiBzcG90IGJlZm9yZSByZWZyZXNoaW5nIGZvciBtZWFzdXJlbWVudCBwdXJwb3NlcywgYW5kIHRoZW4gcHV0IHRoaW5ncyBiYWNrLlxuXG4gIF9zY3JvbGxlcnMuZm9yRWFjaChmdW5jdGlvbiAob2JqKSB7XG4gICAgaWYgKF9pc0Z1bmN0aW9uKG9iaikpIHtcbiAgICAgIG9iai5zbW9vdGggJiYgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIG9iai50YXJnZXQuc3R5bGUuc2Nyb2xsQmVoYXZpb3IgPSBcInNtb290aFwiO1xuICAgICAgfSk7XG4gICAgICBvYmoucmVjICYmIG9iaihvYmoucmVjKTtcbiAgICB9XG4gIH0pO1xuXG4gIF9jbGVhclNjcm9sbE1lbW9yeShfc2Nyb2xsUmVzdG9yYXRpb24sIDEpO1xuXG4gIF9yZXNpemVEZWxheS5wYXVzZSgpO1xuXG4gIF9yZWZyZXNoSUQrKztcbiAgX3JlZnJlc2hpbmdBbGwgPSAyO1xuXG4gIF91cGRhdGVBbGwoMik7XG5cbiAgX3RyaWdnZXJzLmZvckVhY2goZnVuY3Rpb24gKHQpIHtcbiAgICByZXR1cm4gX2lzRnVuY3Rpb24odC52YXJzLm9uUmVmcmVzaCkgJiYgdC52YXJzLm9uUmVmcmVzaCh0KTtcbiAgfSk7XG5cbiAgX3JlZnJlc2hpbmdBbGwgPSBTY3JvbGxUcmlnZ2VyLmlzUmVmcmVzaGluZyA9IGZhbHNlO1xuXG4gIF9kaXNwYXRjaChcInJlZnJlc2hcIik7XG59LFxuICAgIF9sYXN0U2Nyb2xsID0gMCxcbiAgICBfZGlyZWN0aW9uID0gMSxcbiAgICBfcHJpbWFyeSxcbiAgICBfdXBkYXRlQWxsID0gZnVuY3Rpb24gX3VwZGF0ZUFsbChmb3JjZSkge1xuICBpZiAoZm9yY2UgPT09IDIgfHwgIV9yZWZyZXNoaW5nQWxsICYmICFfaXNSZXZlcnRlZCkge1xuICAgIC8vIF9pc1JldmVydGVkIGNvdWxkIGJlIHRydWUgaWYsIGZvciBleGFtcGxlLCBhIG1hdGNoTWVkaWEoKSBpcyBpbiB0aGUgcHJvY2VzcyBvZiBleGVjdXRpbmcuIFdlIGRvbid0IHdhbnQgdG8gdXBkYXRlIGR1cmluZyB0aGUgdGltZSBldmVyeXRoaW5nIGlzIHJldmVydGVkLlxuICAgIFNjcm9sbFRyaWdnZXIuaXNVcGRhdGluZyA9IHRydWU7XG4gICAgX3ByaW1hcnkgJiYgX3ByaW1hcnkudXBkYXRlKDApOyAvLyBTY3JvbGxTbW9vdGhlciB1c2VzIHJlZnJlc2hQcmlvcml0eSAtOTk5OSB0byBiZWNvbWUgdGhlIHByaW1hcnkgdGhhdCBnZXRzIHVwZGF0ZWQgYmVmb3JlIGFsbCBvdGhlcnMgYmVjYXVzZSBpdCBhZmZlY3RzIHRoZSBzY3JvbGwgcG9zaXRpb24uXG5cbiAgICB2YXIgbCA9IF90cmlnZ2Vycy5sZW5ndGgsXG4gICAgICAgIHRpbWUgPSBfZ2V0VGltZSgpLFxuICAgICAgICByZWNvcmRWZWxvY2l0eSA9IHRpbWUgLSBfdGltZTEgPj0gNTAsXG4gICAgICAgIHNjcm9sbCA9IGwgJiYgX3RyaWdnZXJzWzBdLnNjcm9sbCgpO1xuXG4gICAgX2RpcmVjdGlvbiA9IF9sYXN0U2Nyb2xsID4gc2Nyb2xsID8gLTEgOiAxO1xuICAgIF9yZWZyZXNoaW5nQWxsIHx8IChfbGFzdFNjcm9sbCA9IHNjcm9sbCk7XG5cbiAgICBpZiAocmVjb3JkVmVsb2NpdHkpIHtcbiAgICAgIGlmIChfbGFzdFNjcm9sbFRpbWUgJiYgIV9wb2ludGVySXNEb3duICYmIHRpbWUgLSBfbGFzdFNjcm9sbFRpbWUgPiAyMDApIHtcbiAgICAgICAgX2xhc3RTY3JvbGxUaW1lID0gMDtcblxuICAgICAgICBfZGlzcGF0Y2goXCJzY3JvbGxFbmRcIik7XG4gICAgICB9XG5cbiAgICAgIF90aW1lMiA9IF90aW1lMTtcbiAgICAgIF90aW1lMSA9IHRpbWU7XG4gICAgfVxuXG4gICAgaWYgKF9kaXJlY3Rpb24gPCAwKSB7XG4gICAgICBfaSA9IGw7XG5cbiAgICAgIHdoaWxlIChfaS0tID4gMCkge1xuICAgICAgICBfdHJpZ2dlcnNbX2ldICYmIF90cmlnZ2Vyc1tfaV0udXBkYXRlKDAsIHJlY29yZFZlbG9jaXR5KTtcbiAgICAgIH1cblxuICAgICAgX2RpcmVjdGlvbiA9IDE7XG4gICAgfSBlbHNlIHtcbiAgICAgIGZvciAoX2kgPSAwOyBfaSA8IGw7IF9pKyspIHtcbiAgICAgICAgX3RyaWdnZXJzW19pXSAmJiBfdHJpZ2dlcnNbX2ldLnVwZGF0ZSgwLCByZWNvcmRWZWxvY2l0eSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgU2Nyb2xsVHJpZ2dlci5pc1VwZGF0aW5nID0gZmFsc2U7XG4gIH1cblxuICBfcmFmSUQgPSAwO1xufSxcbiAgICBfcHJvcE5hbWVzVG9Db3B5ID0gW19sZWZ0LCBfdG9wLCBfYm90dG9tLCBfcmlnaHQsIF9tYXJnaW4gKyBfQm90dG9tLCBfbWFyZ2luICsgX1JpZ2h0LCBfbWFyZ2luICsgX1RvcCwgX21hcmdpbiArIF9MZWZ0LCBcImRpc3BsYXlcIiwgXCJmbGV4U2hyaW5rXCIsIFwiZmxvYXRcIiwgXCJ6SW5kZXhcIiwgXCJncmlkQ29sdW1uU3RhcnRcIiwgXCJncmlkQ29sdW1uRW5kXCIsIFwiZ3JpZFJvd1N0YXJ0XCIsIFwiZ3JpZFJvd0VuZFwiLCBcImdyaWRBcmVhXCIsIFwianVzdGlmeVNlbGZcIiwgXCJhbGlnblNlbGZcIiwgXCJwbGFjZVNlbGZcIiwgXCJvcmRlclwiXSxcbiAgICBfc3RhdGVQcm9wcyA9IF9wcm9wTmFtZXNUb0NvcHkuY29uY2F0KFtfd2lkdGgsIF9oZWlnaHQsIFwiYm94U2l6aW5nXCIsIFwibWF4XCIgKyBfV2lkdGgsIFwibWF4XCIgKyBfSGVpZ2h0LCBcInBvc2l0aW9uXCIsIF9tYXJnaW4sIF9wYWRkaW5nLCBfcGFkZGluZyArIF9Ub3AsIF9wYWRkaW5nICsgX1JpZ2h0LCBfcGFkZGluZyArIF9Cb3R0b20sIF9wYWRkaW5nICsgX0xlZnRdKSxcbiAgICBfc3dhcFBpbk91dCA9IGZ1bmN0aW9uIF9zd2FwUGluT3V0KHBpbiwgc3BhY2VyLCBzdGF0ZSkge1xuICBfc2V0U3RhdGUoc3RhdGUpO1xuXG4gIHZhciBjYWNoZSA9IHBpbi5fZ3NhcDtcblxuICBpZiAoY2FjaGUuc3BhY2VySXNOYXRpdmUpIHtcbiAgICBfc2V0U3RhdGUoY2FjaGUuc3BhY2VyU3RhdGUpO1xuICB9IGVsc2UgaWYgKHBpbi5fZ3NhcC5zd2FwcGVkSW4pIHtcbiAgICB2YXIgcGFyZW50ID0gc3BhY2VyLnBhcmVudE5vZGU7XG5cbiAgICBpZiAocGFyZW50KSB7XG4gICAgICBwYXJlbnQuaW5zZXJ0QmVmb3JlKHBpbiwgc3BhY2VyKTtcbiAgICAgIHBhcmVudC5yZW1vdmVDaGlsZChzcGFjZXIpO1xuICAgIH1cbiAgfVxuXG4gIHBpbi5fZ3NhcC5zd2FwcGVkSW4gPSBmYWxzZTtcbn0sXG4gICAgX3N3YXBQaW5JbiA9IGZ1bmN0aW9uIF9zd2FwUGluSW4ocGluLCBzcGFjZXIsIGNzLCBzcGFjZXJTdGF0ZSkge1xuICBpZiAoIXBpbi5fZ3NhcC5zd2FwcGVkSW4pIHtcbiAgICB2YXIgaSA9IF9wcm9wTmFtZXNUb0NvcHkubGVuZ3RoLFxuICAgICAgICBzcGFjZXJTdHlsZSA9IHNwYWNlci5zdHlsZSxcbiAgICAgICAgcGluU3R5bGUgPSBwaW4uc3R5bGUsXG4gICAgICAgIHA7XG5cbiAgICB3aGlsZSAoaS0tKSB7XG4gICAgICBwID0gX3Byb3BOYW1lc1RvQ29weVtpXTtcbiAgICAgIHNwYWNlclN0eWxlW3BdID0gY3NbcF07XG4gICAgfVxuXG4gICAgc3BhY2VyU3R5bGUucG9zaXRpb24gPSBjcy5wb3NpdGlvbiA9PT0gXCJhYnNvbHV0ZVwiID8gXCJhYnNvbHV0ZVwiIDogXCJyZWxhdGl2ZVwiO1xuICAgIGNzLmRpc3BsYXkgPT09IFwiaW5saW5lXCIgJiYgKHNwYWNlclN0eWxlLmRpc3BsYXkgPSBcImlubGluZS1ibG9ja1wiKTtcbiAgICBwaW5TdHlsZVtfYm90dG9tXSA9IHBpblN0eWxlW19yaWdodF0gPSBcImF1dG9cIjtcbiAgICBzcGFjZXJTdHlsZS5mbGV4QmFzaXMgPSBjcy5mbGV4QmFzaXMgfHwgXCJhdXRvXCI7XG4gICAgc3BhY2VyU3R5bGUub3ZlcmZsb3cgPSBcInZpc2libGVcIjtcbiAgICBzcGFjZXJTdHlsZS5ib3hTaXppbmcgPSBcImJvcmRlci1ib3hcIjtcbiAgICBzcGFjZXJTdHlsZVtfd2lkdGhdID0gX2dldFNpemUocGluLCBfaG9yaXpvbnRhbCkgKyBfcHg7XG4gICAgc3BhY2VyU3R5bGVbX2hlaWdodF0gPSBfZ2V0U2l6ZShwaW4sIF92ZXJ0aWNhbCkgKyBfcHg7XG4gICAgc3BhY2VyU3R5bGVbX3BhZGRpbmddID0gcGluU3R5bGVbX21hcmdpbl0gPSBwaW5TdHlsZVtfdG9wXSA9IHBpblN0eWxlW19sZWZ0XSA9IFwiMFwiO1xuXG4gICAgX3NldFN0YXRlKHNwYWNlclN0YXRlKTtcblxuICAgIHBpblN0eWxlW193aWR0aF0gPSBwaW5TdHlsZVtcIm1heFwiICsgX1dpZHRoXSA9IGNzW193aWR0aF07XG4gICAgcGluU3R5bGVbX2hlaWdodF0gPSBwaW5TdHlsZVtcIm1heFwiICsgX0hlaWdodF0gPSBjc1tfaGVpZ2h0XTtcbiAgICBwaW5TdHlsZVtfcGFkZGluZ10gPSBjc1tfcGFkZGluZ107XG5cbiAgICBpZiAocGluLnBhcmVudE5vZGUgIT09IHNwYWNlcikge1xuICAgICAgcGluLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKHNwYWNlciwgcGluKTtcbiAgICAgIHNwYWNlci5hcHBlbmRDaGlsZChwaW4pO1xuICAgIH1cblxuICAgIHBpbi5fZ3NhcC5zd2FwcGVkSW4gPSB0cnVlO1xuICB9XG59LFxuICAgIF9jYXBzRXhwID0gLyhbQS1aXSkvZyxcbiAgICBfc2V0U3RhdGUgPSBmdW5jdGlvbiBfc2V0U3RhdGUoc3RhdGUpIHtcbiAgaWYgKHN0YXRlKSB7XG4gICAgdmFyIHN0eWxlID0gc3RhdGUudC5zdHlsZSxcbiAgICAgICAgbCA9IHN0YXRlLmxlbmd0aCxcbiAgICAgICAgaSA9IDAsXG4gICAgICAgIHAsXG4gICAgICAgIHZhbHVlO1xuICAgIChzdGF0ZS50Ll9nc2FwIHx8IGdzYXAuY29yZS5nZXRDYWNoZShzdGF0ZS50KSkudW5jYWNoZSA9IDE7IC8vIG90aGVyd2lzZSB0cmFuc2Zvcm1zIG1heSBiZSBvZmZcblxuICAgIGZvciAoOyBpIDwgbDsgaSArPSAyKSB7XG4gICAgICB2YWx1ZSA9IHN0YXRlW2kgKyAxXTtcbiAgICAgIHAgPSBzdGF0ZVtpXTtcblxuICAgICAgaWYgKHZhbHVlKSB7XG4gICAgICAgIHN0eWxlW3BdID0gdmFsdWU7XG4gICAgICB9IGVsc2UgaWYgKHN0eWxlW3BdKSB7XG4gICAgICAgIHN0eWxlLnJlbW92ZVByb3BlcnR5KHAucmVwbGFjZShfY2Fwc0V4cCwgXCItJDFcIikudG9Mb3dlckNhc2UoKSk7XG4gICAgICB9XG4gICAgfVxuICB9XG59LFxuICAgIF9nZXRTdGF0ZSA9IGZ1bmN0aW9uIF9nZXRTdGF0ZShlbGVtZW50KSB7XG4gIC8vIHJldHVybnMgYW4gQXJyYXkgd2l0aCBhbHRlcm5hdGluZyB2YWx1ZXMgbGlrZSBbcHJvcGVydHksIHZhbHVlLCBwcm9wZXJ0eSwgdmFsdWVdIGFuZCBhIFwidFwiIHByb3BlcnR5IHBvaW50aW5nIHRvIHRoZSB0YXJnZXQgKGVsZW1lbnQpLiBNYWtlcyBpdCBmYXN0IGFuZCBjaGVhcC5cbiAgdmFyIGwgPSBfc3RhdGVQcm9wcy5sZW5ndGgsXG4gICAgICBzdHlsZSA9IGVsZW1lbnQuc3R5bGUsXG4gICAgICBzdGF0ZSA9IFtdLFxuICAgICAgaSA9IDA7XG5cbiAgZm9yICg7IGkgPCBsOyBpKyspIHtcbiAgICBzdGF0ZS5wdXNoKF9zdGF0ZVByb3BzW2ldLCBzdHlsZVtfc3RhdGVQcm9wc1tpXV0pO1xuICB9XG5cbiAgc3RhdGUudCA9IGVsZW1lbnQ7XG4gIHJldHVybiBzdGF0ZTtcbn0sXG4gICAgX2NvcHlTdGF0ZSA9IGZ1bmN0aW9uIF9jb3B5U3RhdGUoc3RhdGUsIG92ZXJyaWRlLCBvbWl0T2Zmc2V0cykge1xuICB2YXIgcmVzdWx0ID0gW10sXG4gICAgICBsID0gc3RhdGUubGVuZ3RoLFxuICAgICAgaSA9IG9taXRPZmZzZXRzID8gOCA6IDAsXG4gICAgICAvLyBza2lwIHRvcCwgbGVmdCwgcmlnaHQsIGJvdHRvbSBpZiBvbWl0T2Zmc2V0cyBpcyB0cnVlXG4gIHA7XG5cbiAgZm9yICg7IGkgPCBsOyBpICs9IDIpIHtcbiAgICBwID0gc3RhdGVbaV07XG4gICAgcmVzdWx0LnB1c2gocCwgcCBpbiBvdmVycmlkZSA/IG92ZXJyaWRlW3BdIDogc3RhdGVbaSArIDFdKTtcbiAgfVxuXG4gIHJlc3VsdC50ID0gc3RhdGUudDtcbiAgcmV0dXJuIHJlc3VsdDtcbn0sXG4gICAgX3dpbk9mZnNldHMgPSB7XG4gIGxlZnQ6IDAsXG4gIHRvcDogMFxufSxcbiAgICAvLyAvLyBwb3RlbnRpYWwgZnV0dXJlIGZlYXR1cmUgKD8pIEFsbG93IHVzZXJzIHRvIGNhbGN1bGF0ZSB3aGVyZSBhIHRyaWdnZXIgaGl0cyAoc2Nyb2xsIHBvc2l0aW9uKSBsaWtlIGdldFNjcm9sbFBvc2l0aW9uKFwiI2lkXCIsIFwidG9wIGJvdHRvbVwiKVxuLy8gX2dldFNjcm9sbFBvc2l0aW9uID0gKHRyaWdnZXIsIHBvc2l0aW9uLCB7c2Nyb2xsZXIsIGNvbnRhaW5lckFuaW1hdGlvbiwgaG9yaXpvbnRhbH0pID0+IHtcbi8vIFx0c2Nyb2xsZXIgPSBfZ2V0VGFyZ2V0KHNjcm9sbGVyIHx8IF93aW4pO1xuLy8gXHRsZXQgZGlyZWN0aW9uID0gaG9yaXpvbnRhbCA/IF9ob3Jpem9udGFsIDogX3ZlcnRpY2FsLFxuLy8gXHRcdGlzVmlld3BvcnQgPSBfaXNWaWV3cG9ydChzY3JvbGxlcik7XG4vLyBcdF9nZXRTaXplRnVuYyhzY3JvbGxlciwgaXNWaWV3cG9ydCwgZGlyZWN0aW9uKTtcbi8vIFx0cmV0dXJuIF9wYXJzZVBvc2l0aW9uKHBvc2l0aW9uLCBfZ2V0VGFyZ2V0KHRyaWdnZXIpLCBfZ2V0U2l6ZUZ1bmMoc2Nyb2xsZXIsIGlzVmlld3BvcnQsIGRpcmVjdGlvbikoKSwgZGlyZWN0aW9uLCBfZ2V0U2Nyb2xsRnVuYyhzY3JvbGxlciwgZGlyZWN0aW9uKSgpLCAwLCAwLCAwLCBfZ2V0T2Zmc2V0c0Z1bmMoc2Nyb2xsZXIsIGlzVmlld3BvcnQpKCksIGlzVmlld3BvcnQgPyAwIDogcGFyc2VGbG9hdChfZ2V0Q29tcHV0ZWRTdHlsZShzY3JvbGxlcilbXCJib3JkZXJcIiArIGRpcmVjdGlvbi5wMiArIF9XaWR0aF0pIHx8IDAsIDAsIGNvbnRhaW5lckFuaW1hdGlvbiA/IGNvbnRhaW5lckFuaW1hdGlvbi5kdXJhdGlvbigpIDogX21heFNjcm9sbChzY3JvbGxlciksIGNvbnRhaW5lckFuaW1hdGlvbik7XG4vLyB9LFxuX3BhcnNlUG9zaXRpb24gPSBmdW5jdGlvbiBfcGFyc2VQb3NpdGlvbih2YWx1ZSwgdHJpZ2dlciwgc2Nyb2xsZXJTaXplLCBkaXJlY3Rpb24sIHNjcm9sbCwgbWFya2VyLCBtYXJrZXJTY3JvbGxlciwgc2VsZiwgc2Nyb2xsZXJCb3VuZHMsIGJvcmRlcldpZHRoLCB1c2VGaXhlZFBvc2l0aW9uLCBzY3JvbGxlck1heCwgY29udGFpbmVyQW5pbWF0aW9uLCBjbGFtcFplcm9Qcm9wKSB7XG4gIF9pc0Z1bmN0aW9uKHZhbHVlKSAmJiAodmFsdWUgPSB2YWx1ZShzZWxmKSk7XG5cbiAgaWYgKF9pc1N0cmluZyh2YWx1ZSkgJiYgdmFsdWUuc3Vic3RyKDAsIDMpID09PSBcIm1heFwiKSB7XG4gICAgdmFsdWUgPSBzY3JvbGxlck1heCArICh2YWx1ZS5jaGFyQXQoNCkgPT09IFwiPVwiID8gX29mZnNldFRvUHgoXCIwXCIgKyB2YWx1ZS5zdWJzdHIoMyksIHNjcm9sbGVyU2l6ZSkgOiAwKTtcbiAgfVxuXG4gIHZhciB0aW1lID0gY29udGFpbmVyQW5pbWF0aW9uID8gY29udGFpbmVyQW5pbWF0aW9uLnRpbWUoKSA6IDAsXG4gICAgICBwMSxcbiAgICAgIHAyLFxuICAgICAgZWxlbWVudDtcbiAgY29udGFpbmVyQW5pbWF0aW9uICYmIGNvbnRhaW5lckFuaW1hdGlvbi5zZWVrKDApO1xuICBpc05hTih2YWx1ZSkgfHwgKHZhbHVlID0gK3ZhbHVlKTsgLy8gY29udmVydCBhIHN0cmluZyBudW1iZXIgbGlrZSBcIjQ1XCIgdG8gYW4gYWN0dWFsIG51bWJlclxuXG4gIGlmICghX2lzTnVtYmVyKHZhbHVlKSkge1xuICAgIF9pc0Z1bmN0aW9uKHRyaWdnZXIpICYmICh0cmlnZ2VyID0gdHJpZ2dlcihzZWxmKSk7XG4gICAgdmFyIG9mZnNldHMgPSAodmFsdWUgfHwgXCIwXCIpLnNwbGl0KFwiIFwiKSxcbiAgICAgICAgYm91bmRzLFxuICAgICAgICBsb2NhbE9mZnNldCxcbiAgICAgICAgZ2xvYmFsT2Zmc2V0LFxuICAgICAgICBkaXNwbGF5O1xuICAgIGVsZW1lbnQgPSBfZ2V0VGFyZ2V0KHRyaWdnZXIsIHNlbGYpIHx8IF9ib2R5O1xuICAgIGJvdW5kcyA9IF9nZXRCb3VuZHMoZWxlbWVudCkgfHwge307XG5cbiAgICBpZiAoKCFib3VuZHMgfHwgIWJvdW5kcy5sZWZ0ICYmICFib3VuZHMudG9wKSAmJiBfZ2V0Q29tcHV0ZWRTdHlsZShlbGVtZW50KS5kaXNwbGF5ID09PSBcIm5vbmVcIikge1xuICAgICAgLy8gaWYgZGlzcGxheSBpcyBcIm5vbmVcIiwgaXQgd29uJ3QgcmVwb3J0IGdldEJvdW5kaW5nQ2xpZW50UmVjdCgpIHByb3Blcmx5XG4gICAgICBkaXNwbGF5ID0gZWxlbWVudC5zdHlsZS5kaXNwbGF5O1xuICAgICAgZWxlbWVudC5zdHlsZS5kaXNwbGF5ID0gXCJibG9ja1wiO1xuICAgICAgYm91bmRzID0gX2dldEJvdW5kcyhlbGVtZW50KTtcbiAgICAgIGRpc3BsYXkgPyBlbGVtZW50LnN0eWxlLmRpc3BsYXkgPSBkaXNwbGF5IDogZWxlbWVudC5zdHlsZS5yZW1vdmVQcm9wZXJ0eShcImRpc3BsYXlcIik7XG4gICAgfVxuXG4gICAgbG9jYWxPZmZzZXQgPSBfb2Zmc2V0VG9QeChvZmZzZXRzWzBdLCBib3VuZHNbZGlyZWN0aW9uLmRdKTtcbiAgICBnbG9iYWxPZmZzZXQgPSBfb2Zmc2V0VG9QeChvZmZzZXRzWzFdIHx8IFwiMFwiLCBzY3JvbGxlclNpemUpO1xuICAgIHZhbHVlID0gYm91bmRzW2RpcmVjdGlvbi5wXSAtIHNjcm9sbGVyQm91bmRzW2RpcmVjdGlvbi5wXSAtIGJvcmRlcldpZHRoICsgbG9jYWxPZmZzZXQgKyBzY3JvbGwgLSBnbG9iYWxPZmZzZXQ7XG4gICAgbWFya2VyU2Nyb2xsZXIgJiYgX3Bvc2l0aW9uTWFya2VyKG1hcmtlclNjcm9sbGVyLCBnbG9iYWxPZmZzZXQsIGRpcmVjdGlvbiwgc2Nyb2xsZXJTaXplIC0gZ2xvYmFsT2Zmc2V0IDwgMjAgfHwgbWFya2VyU2Nyb2xsZXIuX2lzU3RhcnQgJiYgZ2xvYmFsT2Zmc2V0ID4gMjApO1xuICAgIHNjcm9sbGVyU2l6ZSAtPSBzY3JvbGxlclNpemUgLSBnbG9iYWxPZmZzZXQ7IC8vIGFkanVzdCBmb3IgdGhlIG1hcmtlclxuICB9IGVsc2Uge1xuICAgIGNvbnRhaW5lckFuaW1hdGlvbiAmJiAodmFsdWUgPSBnc2FwLnV0aWxzLm1hcFJhbmdlKGNvbnRhaW5lckFuaW1hdGlvbi5zY3JvbGxUcmlnZ2VyLnN0YXJ0LCBjb250YWluZXJBbmltYXRpb24uc2Nyb2xsVHJpZ2dlci5lbmQsIDAsIHNjcm9sbGVyTWF4LCB2YWx1ZSkpO1xuICAgIG1hcmtlclNjcm9sbGVyICYmIF9wb3NpdGlvbk1hcmtlcihtYXJrZXJTY3JvbGxlciwgc2Nyb2xsZXJTaXplLCBkaXJlY3Rpb24sIHRydWUpO1xuICB9XG5cbiAgaWYgKGNsYW1wWmVyb1Byb3ApIHtcbiAgICBzZWxmW2NsYW1wWmVyb1Byb3BdID0gdmFsdWUgfHwgLTAuMDAxO1xuICAgIHZhbHVlIDwgMCAmJiAodmFsdWUgPSAwKTtcbiAgfVxuXG4gIGlmIChtYXJrZXIpIHtcbiAgICB2YXIgcG9zaXRpb24gPSB2YWx1ZSArIHNjcm9sbGVyU2l6ZSxcbiAgICAgICAgaXNTdGFydCA9IG1hcmtlci5faXNTdGFydDtcbiAgICBwMSA9IFwic2Nyb2xsXCIgKyBkaXJlY3Rpb24uZDI7XG5cbiAgICBfcG9zaXRpb25NYXJrZXIobWFya2VyLCBwb3NpdGlvbiwgZGlyZWN0aW9uLCBpc1N0YXJ0ICYmIHBvc2l0aW9uID4gMjAgfHwgIWlzU3RhcnQgJiYgKHVzZUZpeGVkUG9zaXRpb24gPyBNYXRoLm1heChfYm9keVtwMV0sIF9kb2NFbFtwMV0pIDogbWFya2VyLnBhcmVudE5vZGVbcDFdKSA8PSBwb3NpdGlvbiArIDEpO1xuXG4gICAgaWYgKHVzZUZpeGVkUG9zaXRpb24pIHtcbiAgICAgIHNjcm9sbGVyQm91bmRzID0gX2dldEJvdW5kcyhtYXJrZXJTY3JvbGxlcik7XG4gICAgICB1c2VGaXhlZFBvc2l0aW9uICYmIChtYXJrZXIuc3R5bGVbZGlyZWN0aW9uLm9wLnBdID0gc2Nyb2xsZXJCb3VuZHNbZGlyZWN0aW9uLm9wLnBdIC0gZGlyZWN0aW9uLm9wLm0gLSBtYXJrZXIuX29mZnNldCArIF9weCk7XG4gICAgfVxuICB9XG5cbiAgaWYgKGNvbnRhaW5lckFuaW1hdGlvbiAmJiBlbGVtZW50KSB7XG4gICAgcDEgPSBfZ2V0Qm91bmRzKGVsZW1lbnQpO1xuICAgIGNvbnRhaW5lckFuaW1hdGlvbi5zZWVrKHNjcm9sbGVyTWF4KTtcbiAgICBwMiA9IF9nZXRCb3VuZHMoZWxlbWVudCk7XG4gICAgY29udGFpbmVyQW5pbWF0aW9uLl9jYVNjcm9sbERpc3QgPSBwMVtkaXJlY3Rpb24ucF0gLSBwMltkaXJlY3Rpb24ucF07XG4gICAgdmFsdWUgPSB2YWx1ZSAvIGNvbnRhaW5lckFuaW1hdGlvbi5fY2FTY3JvbGxEaXN0ICogc2Nyb2xsZXJNYXg7XG4gIH1cblxuICBjb250YWluZXJBbmltYXRpb24gJiYgY29udGFpbmVyQW5pbWF0aW9uLnNlZWsodGltZSk7XG4gIHJldHVybiBjb250YWluZXJBbmltYXRpb24gPyB2YWx1ZSA6IE1hdGgucm91bmQodmFsdWUpO1xufSxcbiAgICBfcHJlZml4RXhwID0gLyh3ZWJraXR8bW96fGxlbmd0aHxjc3NUZXh0fGluc2V0KS9pLFxuICAgIF9yZXBhcmVudCA9IGZ1bmN0aW9uIF9yZXBhcmVudChlbGVtZW50LCBwYXJlbnQsIHRvcCwgbGVmdCkge1xuICBpZiAoZWxlbWVudC5wYXJlbnROb2RlICE9PSBwYXJlbnQpIHtcbiAgICB2YXIgc3R5bGUgPSBlbGVtZW50LnN0eWxlLFxuICAgICAgICBwLFxuICAgICAgICBjcztcblxuICAgIGlmIChwYXJlbnQgPT09IF9ib2R5KSB7XG4gICAgICBlbGVtZW50Ll9zdE9yaWcgPSBzdHlsZS5jc3NUZXh0OyAvLyByZWNvcmQgb3JpZ2luYWwgaW5saW5lIHN0eWxlcyBzbyB3ZSBjYW4gcmV2ZXJ0IHRoZW0gbGF0ZXJcblxuICAgICAgY3MgPSBfZ2V0Q29tcHV0ZWRTdHlsZShlbGVtZW50KTtcblxuICAgICAgZm9yIChwIGluIGNzKSB7XG4gICAgICAgIC8vIG11c3QgY29weSBhbGwgcmVsZXZhbnQgc3R5bGVzIHRvIGVuc3VyZSB0aGF0IG5vdGhpbmcgY2hhbmdlcyB2aXN1YWxseSB3aGVuIHdlIHJlcGFyZW50IHRvIHRoZSA8Ym9keT4uIFNraXAgdGhlIHZlbmRvciBwcmVmaXhlZCBvbmVzLlxuICAgICAgICBpZiAoIStwICYmICFfcHJlZml4RXhwLnRlc3QocCkgJiYgY3NbcF0gJiYgdHlwZW9mIHN0eWxlW3BdID09PSBcInN0cmluZ1wiICYmIHAgIT09IFwiMFwiKSB7XG4gICAgICAgICAgc3R5bGVbcF0gPSBjc1twXTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBzdHlsZS50b3AgPSB0b3A7XG4gICAgICBzdHlsZS5sZWZ0ID0gbGVmdDtcbiAgICB9IGVsc2Uge1xuICAgICAgc3R5bGUuY3NzVGV4dCA9IGVsZW1lbnQuX3N0T3JpZztcbiAgICB9XG5cbiAgICBnc2FwLmNvcmUuZ2V0Q2FjaGUoZWxlbWVudCkudW5jYWNoZSA9IDE7XG4gICAgcGFyZW50LmFwcGVuZENoaWxkKGVsZW1lbnQpO1xuICB9XG59LFxuICAgIF9pbnRlcnJ1cHRpb25UcmFja2VyID0gZnVuY3Rpb24gX2ludGVycnVwdGlvblRyYWNrZXIoZ2V0VmFsdWVGdW5jLCBpbml0aWFsVmFsdWUsIG9uSW50ZXJydXB0KSB7XG4gIHZhciBsYXN0MSA9IGluaXRpYWxWYWx1ZSxcbiAgICAgIGxhc3QyID0gbGFzdDE7XG4gIHJldHVybiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICB2YXIgY3VycmVudCA9IE1hdGgucm91bmQoZ2V0VmFsdWVGdW5jKCkpOyAvLyByb3VuZCBiZWNhdXNlIGluIHNvbWUgW3ZlcnkgdW5jb21tb25dIFdpbmRvd3MgZW52aXJvbm1lbnRzLCBzY3JvbGwgY2FuIGdldCByZXBvcnRlZCB3aXRoIGRlY2ltYWxzIGV2ZW4gdGhvdWdoIGl0IHdhcyBzZXQgd2l0aG91dC5cblxuICAgIGlmIChjdXJyZW50ICE9PSBsYXN0MSAmJiBjdXJyZW50ICE9PSBsYXN0MiAmJiBNYXRoLmFicyhjdXJyZW50IC0gbGFzdDEpID4gMyAmJiBNYXRoLmFicyhjdXJyZW50IC0gbGFzdDIpID4gMykge1xuICAgICAgLy8gaWYgdGhlIHVzZXIgc2Nyb2xscywga2lsbCB0aGUgdHdlZW4uIGlPUyBTYWZhcmkgaW50ZXJtaXR0ZW50bHkgbWlzcmVwb3J0cyB0aGUgc2Nyb2xsIHBvc2l0aW9uLCBpdCBtYXkgYmUgdGhlIG1vc3QgcmVjZW50bHktc2V0IG9uZSBvciB0aGUgb25lIGJlZm9yZSB0aGF0ISBXaGVuIFNhZmFyaSBpcyB6b29tZWQgKENNRC0rKSwgaXQgb2Z0ZW4gbWlzcmVwb3J0cyBhcyAxIHBpeGVsIG9mZiB0b28hIFNvIGlmIHdlIHNldCB0aGUgc2Nyb2xsIHBvc2l0aW9uIHRvIDEyNSwgZm9yIGV4YW1wbGUsIGl0J2xsIGFjdHVhbGx5IHJlcG9ydCBpdCBhcyAxMjQuXG4gICAgICB2YWx1ZSA9IGN1cnJlbnQ7XG4gICAgICBvbkludGVycnVwdCAmJiBvbkludGVycnVwdCgpO1xuICAgIH1cblxuICAgIGxhc3QyID0gbGFzdDE7XG4gICAgbGFzdDEgPSB2YWx1ZTtcbiAgICByZXR1cm4gdmFsdWU7XG4gIH07XG59LFxuICAgIF9zaGlmdE1hcmtlciA9IGZ1bmN0aW9uIF9zaGlmdE1hcmtlcihtYXJrZXIsIGRpcmVjdGlvbiwgdmFsdWUpIHtcbiAgdmFyIHZhcnMgPSB7fTtcbiAgdmFyc1tkaXJlY3Rpb24ucF0gPSBcIis9XCIgKyB2YWx1ZTtcbiAgZ3NhcC5zZXQobWFya2VyLCB2YXJzKTtcbn0sXG4gICAgLy8gX21lcmdlQW5pbWF0aW9ucyA9IGFuaW1hdGlvbnMgPT4ge1xuLy8gXHRsZXQgdGwgPSBnc2FwLnRpbWVsaW5lKHtzbW9vdGhDaGlsZFRpbWluZzogdHJ1ZX0pLnN0YXJ0VGltZShNYXRoLm1pbiguLi5hbmltYXRpb25zLm1hcChhID0+IGEuZ2xvYmFsVGltZSgwKSkpKTtcbi8vIFx0YW5pbWF0aW9ucy5mb3JFYWNoKGEgPT4ge2xldCB0aW1lID0gYS50b3RhbFRpbWUoKTsgdGwuYWRkKGEpOyBhLnRvdGFsVGltZSh0aW1lKTsgfSk7XG4vLyBcdHRsLnNtb290aENoaWxkVGltaW5nID0gZmFsc2U7XG4vLyBcdHJldHVybiB0bDtcbi8vIH0sXG4vLyByZXR1cm5zIGEgZnVuY3Rpb24gdGhhdCBjYW4gYmUgdXNlZCB0byB0d2VlbiB0aGUgc2Nyb2xsIHBvc2l0aW9uIGluIHRoZSBkaXJlY3Rpb24gcHJvdmlkZWQsIGFuZCB3aGVuIGRvaW5nIHNvIGl0J2xsIGFkZCBhIC50d2VlbiBwcm9wZXJ0eSB0byB0aGUgRlVOQ1RJT04gaXRzZWxmLCBhbmQgcmVtb3ZlIGl0IHdoZW4gdGhlIHR3ZWVuIGNvbXBsZXRlcyBvciBnZXRzIGtpbGxlZC4gVGhpcyBnaXZlcyB1cyBhIHdheSB0byBoYXZlIG11bHRpcGxlIFNjcm9sbFRyaWdnZXJzIHVzZSBhIGNlbnRyYWwgZnVuY3Rpb24gZm9yIGFueSBnaXZlbiBzY3JvbGxlciBhbmQgc2VlIGlmIHRoZXJlJ3MgYSBzY3JvbGwgdHdlZW4gcnVubmluZyAod2hpY2ggd291bGQgYWZmZWN0IGlmL2hvdyB0aGluZ3MgZ2V0IHVwZGF0ZWQpXG5fZ2V0VHdlZW5DcmVhdG9yID0gZnVuY3Rpb24gX2dldFR3ZWVuQ3JlYXRvcihzY3JvbGxlciwgZGlyZWN0aW9uKSB7XG4gIHZhciBnZXRTY3JvbGwgPSBfZ2V0U2Nyb2xsRnVuYyhzY3JvbGxlciwgZGlyZWN0aW9uKSxcbiAgICAgIHByb3AgPSBcIl9zY3JvbGxcIiArIGRpcmVjdGlvbi5wMixcbiAgICAgIC8vIGFkZCBhIHR3ZWVuYWJsZSBwcm9wZXJ0eSB0byB0aGUgc2Nyb2xsZXIgdGhhdCdzIGEgZ2V0dGVyL3NldHRlciBmdW5jdGlvbiwgbGlrZSBfc2Nyb2xsVG9wIG9yIF9zY3JvbGxMZWZ0LiBUaGlzIHdheSwgaWYgc29tZW9uZSBkb2VzIGdzYXAua2lsbFR3ZWVuc09mKHNjcm9sbGVyKSBpdCdsbCBraWxsIHRoZSBzY3JvbGwgdHdlZW4uXG4gIGdldFR3ZWVuID0gZnVuY3Rpb24gZ2V0VHdlZW4oc2Nyb2xsVG8sIHZhcnMsIGluaXRpYWxWYWx1ZSwgY2hhbmdlMSwgY2hhbmdlMikge1xuICAgIHZhciB0d2VlbiA9IGdldFR3ZWVuLnR3ZWVuLFxuICAgICAgICBvbkNvbXBsZXRlID0gdmFycy5vbkNvbXBsZXRlLFxuICAgICAgICBtb2RpZmllcnMgPSB7fTtcbiAgICBpbml0aWFsVmFsdWUgPSBpbml0aWFsVmFsdWUgfHwgZ2V0U2Nyb2xsKCk7XG5cbiAgICB2YXIgY2hlY2tGb3JJbnRlcnJ1cHRpb24gPSBfaW50ZXJydXB0aW9uVHJhY2tlcihnZXRTY3JvbGwsIGluaXRpYWxWYWx1ZSwgZnVuY3Rpb24gKCkge1xuICAgICAgdHdlZW4ua2lsbCgpO1xuICAgICAgZ2V0VHdlZW4udHdlZW4gPSAwO1xuICAgIH0pO1xuXG4gICAgY2hhbmdlMiA9IGNoYW5nZTEgJiYgY2hhbmdlMiB8fCAwOyAvLyBpZiBjaGFuZ2UxIGlzIDAsIHdlIHNldCB0aGF0IHRvIHRoZSBkaWZmZXJlbmNlIGFuZCBpZ25vcmUgY2hhbmdlMi4gT3RoZXJ3aXNlLCB0aGVyZSB3b3VsZCBiZSBhIGNvbXBvdW5kIGVmZmVjdC5cblxuICAgIGNoYW5nZTEgPSBjaGFuZ2UxIHx8IHNjcm9sbFRvIC0gaW5pdGlhbFZhbHVlO1xuICAgIHR3ZWVuICYmIHR3ZWVuLmtpbGwoKTtcbiAgICB2YXJzW3Byb3BdID0gc2Nyb2xsVG87XG4gICAgdmFycy5pbmhlcml0ID0gZmFsc2U7XG4gICAgdmFycy5tb2RpZmllcnMgPSBtb2RpZmllcnM7XG5cbiAgICBtb2RpZmllcnNbcHJvcF0gPSBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gY2hlY2tGb3JJbnRlcnJ1cHRpb24oaW5pdGlhbFZhbHVlICsgY2hhbmdlMSAqIHR3ZWVuLnJhdGlvICsgY2hhbmdlMiAqIHR3ZWVuLnJhdGlvICogdHdlZW4ucmF0aW8pO1xuICAgIH07XG5cbiAgICB2YXJzLm9uVXBkYXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgX3Njcm9sbGVycy5jYWNoZSsrO1xuICAgICAgZ2V0VHdlZW4udHdlZW4gJiYgX3VwZGF0ZUFsbCgpOyAvLyBpZiBpdCB3YXMgaW50ZXJydXB0ZWQva2lsbGVkLCBsaWtlIGluIGEgY29udGV4dC5yZXZlcnQoKSwgZG9uJ3QgZm9yY2UgYW4gdXBkYXRlQWxsKClcbiAgICB9O1xuXG4gICAgdmFycy5vbkNvbXBsZXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgZ2V0VHdlZW4udHdlZW4gPSAwO1xuICAgICAgb25Db21wbGV0ZSAmJiBvbkNvbXBsZXRlLmNhbGwodHdlZW4pO1xuICAgIH07XG5cbiAgICB0d2VlbiA9IGdldFR3ZWVuLnR3ZWVuID0gZ3NhcC50byhzY3JvbGxlciwgdmFycyk7XG4gICAgcmV0dXJuIHR3ZWVuO1xuICB9O1xuXG4gIHNjcm9sbGVyW3Byb3BdID0gZ2V0U2Nyb2xsO1xuXG4gIGdldFNjcm9sbC53aGVlbEhhbmRsZXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIGdldFR3ZWVuLnR3ZWVuICYmIGdldFR3ZWVuLnR3ZWVuLmtpbGwoKSAmJiAoZ2V0VHdlZW4udHdlZW4gPSAwKTtcbiAgfTtcblxuICBfYWRkTGlzdGVuZXIoc2Nyb2xsZXIsIFwid2hlZWxcIiwgZ2V0U2Nyb2xsLndoZWVsSGFuZGxlcik7IC8vIFdpbmRvd3MgbWFjaGluZXMgaGFuZGxlIG1vdXNld2hlZWwgc2Nyb2xsaW5nIGluIGNodW5rcyAobGlrZSBcIjMgbGluZXMgcGVyIHNjcm9sbFwiKSBtZWFuaW5nIHRoZSB0eXBpY2FsIHN0cmF0ZWd5IGZvciBjYW5jZWxsaW5nIHRoZSBzY3JvbGwgaXNuJ3QgYXMgc2Vuc2l0aXZlLiBJdCdzIG11Y2ggbW9yZSBsaWtlbHkgdG8gbWF0Y2ggb25lIG9mIHRoZSBwcmV2aW91cyAyIHNjcm9sbCBldmVudCBwb3NpdGlvbnMuIFNvIHdlIGtpbGwgYW55IHNuYXBwaW5nIGFzIHNvb24gYXMgdGhlcmUncyBhIHdoZWVsIGV2ZW50LlxuXG5cbiAgU2Nyb2xsVHJpZ2dlci5pc1RvdWNoICYmIF9hZGRMaXN0ZW5lcihzY3JvbGxlciwgXCJ0b3VjaG1vdmVcIiwgZ2V0U2Nyb2xsLndoZWVsSGFuZGxlcik7XG4gIHJldHVybiBnZXRUd2Vlbjtcbn07XG5cbmV4cG9ydCB2YXIgU2Nyb2xsVHJpZ2dlciA9IC8qI19fUFVSRV9fKi9mdW5jdGlvbiAoKSB7XG4gIGZ1bmN0aW9uIFNjcm9sbFRyaWdnZXIodmFycywgYW5pbWF0aW9uKSB7XG4gICAgX2NvcmVJbml0dGVkIHx8IFNjcm9sbFRyaWdnZXIucmVnaXN0ZXIoZ3NhcCkgfHwgY29uc29sZS53YXJuKFwiUGxlYXNlIGdzYXAucmVnaXN0ZXJQbHVnaW4oU2Nyb2xsVHJpZ2dlcilcIik7XG5cbiAgICBfY29udGV4dCh0aGlzKTtcblxuICAgIHRoaXMuaW5pdCh2YXJzLCBhbmltYXRpb24pO1xuICB9XG5cbiAgdmFyIF9wcm90byA9IFNjcm9sbFRyaWdnZXIucHJvdG90eXBlO1xuXG4gIF9wcm90by5pbml0ID0gZnVuY3Rpb24gaW5pdCh2YXJzLCBhbmltYXRpb24pIHtcbiAgICB0aGlzLnByb2dyZXNzID0gdGhpcy5zdGFydCA9IDA7XG4gICAgdGhpcy52YXJzICYmIHRoaXMua2lsbCh0cnVlLCB0cnVlKTsgLy8gaW4gY2FzZSBpdCdzIGJlaW5nIGluaXR0ZWQgYWdhaW5cblxuICAgIGlmICghX2VuYWJsZWQpIHtcbiAgICAgIHRoaXMudXBkYXRlID0gdGhpcy5yZWZyZXNoID0gdGhpcy5raWxsID0gX3Bhc3NUaHJvdWdoO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhcnMgPSBfc2V0RGVmYXVsdHMoX2lzU3RyaW5nKHZhcnMpIHx8IF9pc051bWJlcih2YXJzKSB8fCB2YXJzLm5vZGVUeXBlID8ge1xuICAgICAgdHJpZ2dlcjogdmFyc1xuICAgIH0gOiB2YXJzLCBfZGVmYXVsdHMpO1xuXG4gICAgdmFyIF92YXJzID0gdmFycyxcbiAgICAgICAgb25VcGRhdGUgPSBfdmFycy5vblVwZGF0ZSxcbiAgICAgICAgdG9nZ2xlQ2xhc3MgPSBfdmFycy50b2dnbGVDbGFzcyxcbiAgICAgICAgaWQgPSBfdmFycy5pZCxcbiAgICAgICAgb25Ub2dnbGUgPSBfdmFycy5vblRvZ2dsZSxcbiAgICAgICAgb25SZWZyZXNoID0gX3ZhcnMub25SZWZyZXNoLFxuICAgICAgICBzY3J1YiA9IF92YXJzLnNjcnViLFxuICAgICAgICB0cmlnZ2VyID0gX3ZhcnMudHJpZ2dlcixcbiAgICAgICAgcGluID0gX3ZhcnMucGluLFxuICAgICAgICBwaW5TcGFjaW5nID0gX3ZhcnMucGluU3BhY2luZyxcbiAgICAgICAgaW52YWxpZGF0ZU9uUmVmcmVzaCA9IF92YXJzLmludmFsaWRhdGVPblJlZnJlc2gsXG4gICAgICAgIGFudGljaXBhdGVQaW4gPSBfdmFycy5hbnRpY2lwYXRlUGluLFxuICAgICAgICBvblNjcnViQ29tcGxldGUgPSBfdmFycy5vblNjcnViQ29tcGxldGUsXG4gICAgICAgIG9uU25hcENvbXBsZXRlID0gX3ZhcnMub25TbmFwQ29tcGxldGUsXG4gICAgICAgIG9uY2UgPSBfdmFycy5vbmNlLFxuICAgICAgICBzbmFwID0gX3ZhcnMuc25hcCxcbiAgICAgICAgcGluUmVwYXJlbnQgPSBfdmFycy5waW5SZXBhcmVudCxcbiAgICAgICAgcGluU3BhY2VyID0gX3ZhcnMucGluU3BhY2VyLFxuICAgICAgICBjb250YWluZXJBbmltYXRpb24gPSBfdmFycy5jb250YWluZXJBbmltYXRpb24sXG4gICAgICAgIGZhc3RTY3JvbGxFbmQgPSBfdmFycy5mYXN0U2Nyb2xsRW5kLFxuICAgICAgICBwcmV2ZW50T3ZlcmxhcHMgPSBfdmFycy5wcmV2ZW50T3ZlcmxhcHMsXG4gICAgICAgIGRpcmVjdGlvbiA9IHZhcnMuaG9yaXpvbnRhbCB8fCB2YXJzLmNvbnRhaW5lckFuaW1hdGlvbiAmJiB2YXJzLmhvcml6b250YWwgIT09IGZhbHNlID8gX2hvcml6b250YWwgOiBfdmVydGljYWwsXG4gICAgICAgIGlzVG9nZ2xlID0gIXNjcnViICYmIHNjcnViICE9PSAwLFxuICAgICAgICBzY3JvbGxlciA9IF9nZXRUYXJnZXQodmFycy5zY3JvbGxlciB8fCBfd2luKSxcbiAgICAgICAgc2Nyb2xsZXJDYWNoZSA9IGdzYXAuY29yZS5nZXRDYWNoZShzY3JvbGxlciksXG4gICAgICAgIGlzVmlld3BvcnQgPSBfaXNWaWV3cG9ydChzY3JvbGxlciksXG4gICAgICAgIHVzZUZpeGVkUG9zaXRpb24gPSAoXCJwaW5UeXBlXCIgaW4gdmFycyA/IHZhcnMucGluVHlwZSA6IF9nZXRQcm94eVByb3Aoc2Nyb2xsZXIsIFwicGluVHlwZVwiKSB8fCBpc1ZpZXdwb3J0ICYmIFwiZml4ZWRcIikgPT09IFwiZml4ZWRcIixcbiAgICAgICAgY2FsbGJhY2tzID0gW3ZhcnMub25FbnRlciwgdmFycy5vbkxlYXZlLCB2YXJzLm9uRW50ZXJCYWNrLCB2YXJzLm9uTGVhdmVCYWNrXSxcbiAgICAgICAgdG9nZ2xlQWN0aW9ucyA9IGlzVG9nZ2xlICYmIHZhcnMudG9nZ2xlQWN0aW9ucy5zcGxpdChcIiBcIiksXG4gICAgICAgIG1hcmtlcnMgPSBcIm1hcmtlcnNcIiBpbiB2YXJzID8gdmFycy5tYXJrZXJzIDogX2RlZmF1bHRzLm1hcmtlcnMsXG4gICAgICAgIGJvcmRlcldpZHRoID0gaXNWaWV3cG9ydCA/IDAgOiBwYXJzZUZsb2F0KF9nZXRDb21wdXRlZFN0eWxlKHNjcm9sbGVyKVtcImJvcmRlclwiICsgZGlyZWN0aW9uLnAyICsgX1dpZHRoXSkgfHwgMCxcbiAgICAgICAgc2VsZiA9IHRoaXMsXG4gICAgICAgIG9uUmVmcmVzaEluaXQgPSB2YXJzLm9uUmVmcmVzaEluaXQgJiYgZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIHZhcnMub25SZWZyZXNoSW5pdChzZWxmKTtcbiAgICB9LFxuICAgICAgICBnZXRTY3JvbGxlclNpemUgPSBfZ2V0U2l6ZUZ1bmMoc2Nyb2xsZXIsIGlzVmlld3BvcnQsIGRpcmVjdGlvbiksXG4gICAgICAgIGdldFNjcm9sbGVyT2Zmc2V0cyA9IF9nZXRPZmZzZXRzRnVuYyhzY3JvbGxlciwgaXNWaWV3cG9ydCksXG4gICAgICAgIGxhc3RTbmFwID0gMCxcbiAgICAgICAgbGFzdFJlZnJlc2ggPSAwLFxuICAgICAgICBwcmV2UHJvZ3Jlc3MgPSAwLFxuICAgICAgICBzY3JvbGxGdW5jID0gX2dldFNjcm9sbEZ1bmMoc2Nyb2xsZXIsIGRpcmVjdGlvbiksXG4gICAgICAgIHR3ZWVuVG8sXG4gICAgICAgIHBpbkNhY2hlLFxuICAgICAgICBzbmFwRnVuYyxcbiAgICAgICAgc2Nyb2xsMSxcbiAgICAgICAgc2Nyb2xsMixcbiAgICAgICAgc3RhcnQsXG4gICAgICAgIGVuZCxcbiAgICAgICAgbWFya2VyU3RhcnQsXG4gICAgICAgIG1hcmtlckVuZCxcbiAgICAgICAgbWFya2VyU3RhcnRUcmlnZ2VyLFxuICAgICAgICBtYXJrZXJFbmRUcmlnZ2VyLFxuICAgICAgICBtYXJrZXJWYXJzLFxuICAgICAgICBleGVjdXRpbmdPblJlZnJlc2gsXG4gICAgICAgIGNoYW5nZSxcbiAgICAgICAgcGluT3JpZ2luYWxTdGF0ZSxcbiAgICAgICAgcGluQWN0aXZlU3RhdGUsXG4gICAgICAgIHBpblN0YXRlLFxuICAgICAgICBzcGFjZXIsXG4gICAgICAgIG9mZnNldCxcbiAgICAgICAgcGluR2V0dGVyLFxuICAgICAgICBwaW5TZXR0ZXIsXG4gICAgICAgIHBpblN0YXJ0LFxuICAgICAgICBwaW5DaGFuZ2UsXG4gICAgICAgIHNwYWNpbmdTdGFydCxcbiAgICAgICAgc3BhY2VyU3RhdGUsXG4gICAgICAgIG1hcmtlclN0YXJ0U2V0dGVyLFxuICAgICAgICBwaW5Nb3ZlcyxcbiAgICAgICAgbWFya2VyRW5kU2V0dGVyLFxuICAgICAgICBjcyxcbiAgICAgICAgc25hcDEsXG4gICAgICAgIHNuYXAyLFxuICAgICAgICBzY3J1YlR3ZWVuLFxuICAgICAgICBzY3J1YlNtb290aCxcbiAgICAgICAgc25hcER1ckNsYW1wLFxuICAgICAgICBzbmFwRGVsYXllZENhbGwsXG4gICAgICAgIHByZXZTY3JvbGwsXG4gICAgICAgIHByZXZBbmltUHJvZ3Jlc3MsXG4gICAgICAgIGNhTWFya2VyU2V0dGVyLFxuICAgICAgICBjdXN0b21SZXZlcnRSZXR1cm47IC8vIGZvciB0aGUgc2FrZSBvZiBlZmZpY2llbmN5LCBfc3RhcnRDbGFtcC9fZW5kQ2xhbXAgc2VydmUgbGlrZSBhIHRydXRoeSB2YWx1ZSBpbmRpY2F0aW5nIHRoYXQgY2xhbXBpbmcgd2FzIGVuYWJsZWQgb24gdGhlIHN0YXJ0L2VuZCwgYW5kIEFMU08gc3RvcmUgdGhlIGFjdHVhbCBwcmUtY2xhbXBlZCBudW1lcmljIHZhbHVlLiBXZSB0YXAgaW50byB0aGF0IGluIFNjcm9sbFNtb290aGVyIGZvciBzcGVlZCBlZmZlY3RzLiBTbyBmb3IgZXhhbXBsZSwgaWYgc3RhcnQ9XCJjbGFtcCh0b3AgYm90dG9tKVwiIHJlc3VsdHMgaW4gYSBzdGFydCBvZiAtMTAwIG5hdHVyYWxseSwgaXQgd291bGQgZ2V0IGNsYW1wZWQgdG8gMCBidXQgLTEwMCB3b3VsZCBiZSBzdG9yZWQgaW4gX3N0YXJ0Q2xhbXAuXG5cblxuICAgIHNlbGYuX3N0YXJ0Q2xhbXAgPSBzZWxmLl9lbmRDbGFtcCA9IGZhbHNlO1xuICAgIHNlbGYuX2RpciA9IGRpcmVjdGlvbjtcbiAgICBhbnRpY2lwYXRlUGluICo9IDQ1O1xuICAgIHNlbGYuc2Nyb2xsZXIgPSBzY3JvbGxlcjtcbiAgICBzZWxmLnNjcm9sbCA9IGNvbnRhaW5lckFuaW1hdGlvbiA/IGNvbnRhaW5lckFuaW1hdGlvbi50aW1lLmJpbmQoY29udGFpbmVyQW5pbWF0aW9uKSA6IHNjcm9sbEZ1bmM7XG4gICAgc2Nyb2xsMSA9IHNjcm9sbEZ1bmMoKTtcbiAgICBzZWxmLnZhcnMgPSB2YXJzO1xuICAgIGFuaW1hdGlvbiA9IGFuaW1hdGlvbiB8fCB2YXJzLmFuaW1hdGlvbjtcblxuICAgIGlmIChcInJlZnJlc2hQcmlvcml0eVwiIGluIHZhcnMpIHtcbiAgICAgIF9zb3J0ID0gMTtcbiAgICAgIHZhcnMucmVmcmVzaFByaW9yaXR5ID09PSAtOTk5OSAmJiAoX3ByaW1hcnkgPSBzZWxmKTsgLy8gdXNlZCBieSBTY3JvbGxTbW9vdGhlclxuICAgIH1cblxuICAgIHNjcm9sbGVyQ2FjaGUudHdlZW5TY3JvbGwgPSBzY3JvbGxlckNhY2hlLnR3ZWVuU2Nyb2xsIHx8IHtcbiAgICAgIHRvcDogX2dldFR3ZWVuQ3JlYXRvcihzY3JvbGxlciwgX3ZlcnRpY2FsKSxcbiAgICAgIGxlZnQ6IF9nZXRUd2VlbkNyZWF0b3Ioc2Nyb2xsZXIsIF9ob3Jpem9udGFsKVxuICAgIH07XG4gICAgc2VsZi50d2VlblRvID0gdHdlZW5UbyA9IHNjcm9sbGVyQ2FjaGUudHdlZW5TY3JvbGxbZGlyZWN0aW9uLnBdO1xuXG4gICAgc2VsZi5zY3J1YkR1cmF0aW9uID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICBzY3J1YlNtb290aCA9IF9pc051bWJlcih2YWx1ZSkgJiYgdmFsdWU7XG5cbiAgICAgIGlmICghc2NydWJTbW9vdGgpIHtcbiAgICAgICAgc2NydWJUd2VlbiAmJiBzY3J1YlR3ZWVuLnByb2dyZXNzKDEpLmtpbGwoKTtcbiAgICAgICAgc2NydWJUd2VlbiA9IDA7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzY3J1YlR3ZWVuID8gc2NydWJUd2Vlbi5kdXJhdGlvbih2YWx1ZSkgOiBzY3J1YlR3ZWVuID0gZ3NhcC50byhhbmltYXRpb24sIHtcbiAgICAgICAgICBlYXNlOiBcImV4cG9cIixcbiAgICAgICAgICB0b3RhbFByb2dyZXNzOiBcIis9MFwiLFxuICAgICAgICAgIGluaGVyaXQ6IGZhbHNlLFxuICAgICAgICAgIGR1cmF0aW9uOiBzY3J1YlNtb290aCxcbiAgICAgICAgICBwYXVzZWQ6IHRydWUsXG4gICAgICAgICAgb25Db21wbGV0ZTogZnVuY3Rpb24gb25Db21wbGV0ZSgpIHtcbiAgICAgICAgICAgIHJldHVybiBvblNjcnViQ29tcGxldGUgJiYgb25TY3J1YkNvbXBsZXRlKHNlbGYpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIGlmIChhbmltYXRpb24pIHtcbiAgICAgIGFuaW1hdGlvbi52YXJzLmxhenkgPSBmYWxzZTtcbiAgICAgIGFuaW1hdGlvbi5faW5pdHRlZCAmJiAhc2VsZi5pc1JldmVydGVkIHx8IGFuaW1hdGlvbi52YXJzLmltbWVkaWF0ZVJlbmRlciAhPT0gZmFsc2UgJiYgdmFycy5pbW1lZGlhdGVSZW5kZXIgIT09IGZhbHNlICYmIGFuaW1hdGlvbi5kdXJhdGlvbigpICYmIGFuaW1hdGlvbi5yZW5kZXIoMCwgdHJ1ZSwgdHJ1ZSk7IC8vIHNwZWNpYWwgY2FzZTogaWYgdGhpcyBTY3JvbGxUcmlnZ2VyIGdldHMgcmUtaW5pdHRlZCwgYSBmcm9tKCkgdHdlZW4gd2l0aCBhIHN0YWdnZXIgY291bGQgZ2V0IGluaXR0ZWQgaW5pdGlhbGx5IGFuZCB0aGVuIHJldmVydGVkIG9uIHRoZSByZS1pbml0IHdoaWNoIG1lYW5zIGl0J2xsIG5lZWQgdG8gZ2V0IHJlbmRlcmVkIGFnYWluIGhlcmUgdG8gcHJvcGVybHkgZGlzcGxheSB0aGluZ3MuIE90aGVyd2lzZSwgU2VlIGh0dHBzOi8vZ3NhcC5jb20vZm9ydW1zL3RvcGljLzM2Nzc3LXNjcm9sbHNtb290aGVyLXNwbGl0dGV4dC1uZXh0anMvIGFuZCBodHRwczovL2NvZGVwZW4uaW8vR3JlZW5Tb2NrL3Blbi9lWVB5UHBkP2VkaXRvcnM9MDAxMFxuXG4gICAgICBzZWxmLmFuaW1hdGlvbiA9IGFuaW1hdGlvbi5wYXVzZSgpO1xuICAgICAgYW5pbWF0aW9uLnNjcm9sbFRyaWdnZXIgPSBzZWxmO1xuICAgICAgc2VsZi5zY3J1YkR1cmF0aW9uKHNjcnViKTtcbiAgICAgIHNuYXAxID0gMDtcbiAgICAgIGlkIHx8IChpZCA9IGFuaW1hdGlvbi52YXJzLmlkKTtcbiAgICB9XG5cbiAgICBpZiAoc25hcCkge1xuICAgICAgLy8gVE9ETzogcG90ZW50aWFsIGlkZWE6IHVzZSBsZWdpdGltYXRlIENTUyBzY3JvbGwgc25hcHBpbmcgYnkgcHVzaGluZyBpbnZpc2libGUgZWxlbWVudHMgaW50byB0aGUgRE9NIHRoYXQgc2VydmUgYXMgc25hcCBwb3NpdGlvbnMsIGFuZCB0b2dnbGUgdGhlIGRvY3VtZW50LnNjcm9sbGluZ0VsZW1lbnQuc3R5bGUuc2Nyb2xsU25hcFR5cGUgb25Ub2dnbGUuIFNlZSBodHRwczovL2NvZGVwZW4uaW8vR3JlZW5Tb2NrL3Blbi9KakxyZ1dNIGZvciBhIHF1aWNrIHByb29mIG9mIGNvbmNlcHQuXG4gICAgICBpZiAoIV9pc09iamVjdChzbmFwKSB8fCBzbmFwLnB1c2gpIHtcbiAgICAgICAgc25hcCA9IHtcbiAgICAgICAgICBzbmFwVG86IHNuYXBcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgXCJzY3JvbGxCZWhhdmlvclwiIGluIF9ib2R5LnN0eWxlICYmIGdzYXAuc2V0KGlzVmlld3BvcnQgPyBbX2JvZHksIF9kb2NFbF0gOiBzY3JvbGxlciwge1xuICAgICAgICBzY3JvbGxCZWhhdmlvcjogXCJhdXRvXCJcbiAgICAgIH0pOyAvLyBzbW9vdGggc2Nyb2xsaW5nIGRvZXNuJ3Qgd29yayB3aXRoIHNuYXAuXG5cbiAgICAgIF9zY3JvbGxlcnMuZm9yRWFjaChmdW5jdGlvbiAobykge1xuICAgICAgICByZXR1cm4gX2lzRnVuY3Rpb24obykgJiYgby50YXJnZXQgPT09IChpc1ZpZXdwb3J0ID8gX2RvYy5zY3JvbGxpbmdFbGVtZW50IHx8IF9kb2NFbCA6IHNjcm9sbGVyKSAmJiAoby5zbW9vdGggPSBmYWxzZSk7XG4gICAgICB9KTsgLy8gbm90ZTogc2V0IHNtb290aCB0byBmYWxzZSBvbiBib3RoIHRoZSB2ZXJ0aWNhbCBhbmQgaG9yaXpvbnRhbCBzY3JvbGwgZ2V0dGVycy9zZXR0ZXJzXG5cblxuICAgICAgc25hcEZ1bmMgPSBfaXNGdW5jdGlvbihzbmFwLnNuYXBUbykgPyBzbmFwLnNuYXBUbyA6IHNuYXAuc25hcFRvID09PSBcImxhYmVsc1wiID8gX2dldENsb3Nlc3RMYWJlbChhbmltYXRpb24pIDogc25hcC5zbmFwVG8gPT09IFwibGFiZWxzRGlyZWN0aW9uYWxcIiA/IF9nZXRMYWJlbEF0RGlyZWN0aW9uKGFuaW1hdGlvbikgOiBzbmFwLmRpcmVjdGlvbmFsICE9PSBmYWxzZSA/IGZ1bmN0aW9uICh2YWx1ZSwgc3QpIHtcbiAgICAgICAgcmV0dXJuIF9zbmFwRGlyZWN0aW9uYWwoc25hcC5zbmFwVG8pKHZhbHVlLCBfZ2V0VGltZSgpIC0gbGFzdFJlZnJlc2ggPCA1MDAgPyAwIDogc3QuZGlyZWN0aW9uKTtcbiAgICAgIH0gOiBnc2FwLnV0aWxzLnNuYXAoc25hcC5zbmFwVG8pO1xuICAgICAgc25hcER1ckNsYW1wID0gc25hcC5kdXJhdGlvbiB8fCB7XG4gICAgICAgIG1pbjogMC4xLFxuICAgICAgICBtYXg6IDJcbiAgICAgIH07XG4gICAgICBzbmFwRHVyQ2xhbXAgPSBfaXNPYmplY3Qoc25hcER1ckNsYW1wKSA/IF9jbGFtcChzbmFwRHVyQ2xhbXAubWluLCBzbmFwRHVyQ2xhbXAubWF4KSA6IF9jbGFtcChzbmFwRHVyQ2xhbXAsIHNuYXBEdXJDbGFtcCk7XG4gICAgICBzbmFwRGVsYXllZENhbGwgPSBnc2FwLmRlbGF5ZWRDYWxsKHNuYXAuZGVsYXkgfHwgc2NydWJTbW9vdGggLyAyIHx8IDAuMSwgZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Nyb2xsID0gc2Nyb2xsRnVuYygpLFxuICAgICAgICAgICAgcmVmcmVzaGVkUmVjZW50bHkgPSBfZ2V0VGltZSgpIC0gbGFzdFJlZnJlc2ggPCA1MDAsXG4gICAgICAgICAgICB0d2VlbiA9IHR3ZWVuVG8udHdlZW47XG5cbiAgICAgICAgaWYgKChyZWZyZXNoZWRSZWNlbnRseSB8fCBNYXRoLmFicyhzZWxmLmdldFZlbG9jaXR5KCkpIDwgMTApICYmICF0d2VlbiAmJiAhX3BvaW50ZXJJc0Rvd24gJiYgbGFzdFNuYXAgIT09IHNjcm9sbCkge1xuICAgICAgICAgIHZhciBwcm9ncmVzcyA9IChzY3JvbGwgLSBzdGFydCkgLyBjaGFuZ2UsXG4gICAgICAgICAgICAgIHRvdGFsUHJvZ3Jlc3MgPSBhbmltYXRpb24gJiYgIWlzVG9nZ2xlID8gYW5pbWF0aW9uLnRvdGFsUHJvZ3Jlc3MoKSA6IHByb2dyZXNzLFxuICAgICAgICAgICAgICB2ZWxvY2l0eSA9IHJlZnJlc2hlZFJlY2VudGx5ID8gMCA6ICh0b3RhbFByb2dyZXNzIC0gc25hcDIpIC8gKF9nZXRUaW1lKCkgLSBfdGltZTIpICogMTAwMCB8fCAwLFxuICAgICAgICAgICAgICBjaGFuZ2UxID0gZ3NhcC51dGlscy5jbGFtcCgtcHJvZ3Jlc3MsIDEgLSBwcm9ncmVzcywgX2Ficyh2ZWxvY2l0eSAvIDIpICogdmVsb2NpdHkgLyAwLjE4NSksXG4gICAgICAgICAgICAgIG5hdHVyYWxFbmQgPSBwcm9ncmVzcyArIChzbmFwLmluZXJ0aWEgPT09IGZhbHNlID8gMCA6IGNoYW5nZTEpLFxuICAgICAgICAgICAgICBlbmRWYWx1ZSxcbiAgICAgICAgICAgICAgZW5kU2Nyb2xsLFxuICAgICAgICAgICAgICBfc25hcCA9IHNuYXAsXG4gICAgICAgICAgICAgIG9uU3RhcnQgPSBfc25hcC5vblN0YXJ0LFxuICAgICAgICAgICAgICBfb25JbnRlcnJ1cHQgPSBfc25hcC5vbkludGVycnVwdCxcbiAgICAgICAgICAgICAgX29uQ29tcGxldGUgPSBfc25hcC5vbkNvbXBsZXRlO1xuICAgICAgICAgIGVuZFZhbHVlID0gc25hcEZ1bmMobmF0dXJhbEVuZCwgc2VsZik7XG4gICAgICAgICAgX2lzTnVtYmVyKGVuZFZhbHVlKSB8fCAoZW5kVmFsdWUgPSBuYXR1cmFsRW5kKTsgLy8gaW4gY2FzZSB0aGUgZnVuY3Rpb24gZGlkbid0IHJldHVybiBhIG51bWJlciwgZmFsbCBiYWNrIHRvIHVzaW5nIHRoZSBuYXR1cmFsRW5kXG5cbiAgICAgICAgICBlbmRTY3JvbGwgPSBNYXRoLnJvdW5kKHN0YXJ0ICsgZW5kVmFsdWUgKiBjaGFuZ2UpO1xuXG4gICAgICAgICAgaWYgKHNjcm9sbCA8PSBlbmQgJiYgc2Nyb2xsID49IHN0YXJ0ICYmIGVuZFNjcm9sbCAhPT0gc2Nyb2xsKSB7XG4gICAgICAgICAgICBpZiAodHdlZW4gJiYgIXR3ZWVuLl9pbml0dGVkICYmIHR3ZWVuLmRhdGEgPD0gX2FicyhlbmRTY3JvbGwgLSBzY3JvbGwpKSB7XG4gICAgICAgICAgICAgIC8vIHRoZXJlJ3MgYW4gb3ZlcmxhcHBpbmcgc25hcCEgU28gd2UgbXVzdCBmaWd1cmUgb3V0IHdoaWNoIG9uZSBpcyBjbG9zZXIgYW5kIGxldCB0aGF0IHR3ZWVuIGxpdmUuXG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHNuYXAuaW5lcnRpYSA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgY2hhbmdlMSA9IGVuZFZhbHVlIC0gcHJvZ3Jlc3M7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHR3ZWVuVG8oZW5kU2Nyb2xsLCB7XG4gICAgICAgICAgICAgIGR1cmF0aW9uOiBzbmFwRHVyQ2xhbXAoX2FicyhNYXRoLm1heChfYWJzKG5hdHVyYWxFbmQgLSB0b3RhbFByb2dyZXNzKSwgX2FicyhlbmRWYWx1ZSAtIHRvdGFsUHJvZ3Jlc3MpKSAqIDAuMTg1IC8gdmVsb2NpdHkgLyAwLjA1IHx8IDApKSxcbiAgICAgICAgICAgICAgZWFzZTogc25hcC5lYXNlIHx8IFwicG93ZXIzXCIsXG4gICAgICAgICAgICAgIGRhdGE6IF9hYnMoZW5kU2Nyb2xsIC0gc2Nyb2xsKSxcbiAgICAgICAgICAgICAgLy8gcmVjb3JkIHRoZSBkaXN0YW5jZSBzbyB0aGF0IGlmIGFub3RoZXIgc25hcCB0d2VlbiBvY2N1cnMgKGNvbmZsaWN0KSB3ZSBjYW4gcHJpb3JpdGl6ZSB0aGUgY2xvc2VzdCBzbmFwLlxuICAgICAgICAgICAgICBvbkludGVycnVwdDogZnVuY3Rpb24gb25JbnRlcnJ1cHQoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHNuYXBEZWxheWVkQ2FsbC5yZXN0YXJ0KHRydWUpICYmIF9vbkludGVycnVwdCAmJiBfb25JbnRlcnJ1cHQoc2VsZik7XG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIG9uQ29tcGxldGU6IGZ1bmN0aW9uIG9uQ29tcGxldGUoKSB7XG4gICAgICAgICAgICAgICAgc2VsZi51cGRhdGUoKTtcbiAgICAgICAgICAgICAgICBsYXN0U25hcCA9IHNjcm9sbEZ1bmMoKTtcblxuICAgICAgICAgICAgICAgIGlmIChhbmltYXRpb24pIHtcbiAgICAgICAgICAgICAgICAgIC8vIHRoZSByZXNvbHV0aW9uIG9mIHRoZSBzY3JvbGxiYXIgaXMgbGltaXRlZCwgc28gd2Ugc2hvdWxkIGNvcnJlY3QgdGhlIHNjcnViYmVkIGFuaW1hdGlvbidzIHBsYXloZWFkIGF0IHRoZSBlbmQgdG8gbWF0Y2ggRVhBQ1RMWSB3aGVyZSBpdCB3YXMgc3VwcG9zZWQgdG8gc25hcFxuICAgICAgICAgICAgICAgICAgc2NydWJUd2VlbiA/IHNjcnViVHdlZW4ucmVzZXRUbyhcInRvdGFsUHJvZ3Jlc3NcIiwgZW5kVmFsdWUsIGFuaW1hdGlvbi5fdFRpbWUgLyBhbmltYXRpb24uX3REdXIpIDogYW5pbWF0aW9uLnByb2dyZXNzKGVuZFZhbHVlKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBzbmFwMSA9IHNuYXAyID0gYW5pbWF0aW9uICYmICFpc1RvZ2dsZSA/IGFuaW1hdGlvbi50b3RhbFByb2dyZXNzKCkgOiBzZWxmLnByb2dyZXNzO1xuICAgICAgICAgICAgICAgIG9uU25hcENvbXBsZXRlICYmIG9uU25hcENvbXBsZXRlKHNlbGYpO1xuICAgICAgICAgICAgICAgIF9vbkNvbXBsZXRlICYmIF9vbkNvbXBsZXRlKHNlbGYpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LCBzY3JvbGwsIGNoYW5nZTEgKiBjaGFuZ2UsIGVuZFNjcm9sbCAtIHNjcm9sbCAtIGNoYW5nZTEgKiBjaGFuZ2UpO1xuICAgICAgICAgICAgb25TdGFydCAmJiBvblN0YXJ0KHNlbGYsIHR3ZWVuVG8udHdlZW4pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChzZWxmLmlzQWN0aXZlICYmIGxhc3RTbmFwICE9PSBzY3JvbGwpIHtcbiAgICAgICAgICBzbmFwRGVsYXllZENhbGwucmVzdGFydCh0cnVlKTtcbiAgICAgICAgfVxuICAgICAgfSkucGF1c2UoKTtcbiAgICB9XG5cbiAgICBpZCAmJiAoX2lkc1tpZF0gPSBzZWxmKTtcbiAgICB0cmlnZ2VyID0gc2VsZi50cmlnZ2VyID0gX2dldFRhcmdldCh0cmlnZ2VyIHx8IHBpbiAhPT0gdHJ1ZSAmJiBwaW4pOyAvLyBpZiBhIHRyaWdnZXIgaGFzIHNvbWUga2luZCBvZiBzY3JvbGwtcmVsYXRlZCBlZmZlY3QgYXBwbGllZCB0aGF0IGNvdWxkIGNvbnRhbWluYXRlIHRoZSBcInlcIiBvciBcInhcIiBwb3NpdGlvbiAobGlrZSBhIFNjcm9sbFNtb290aGVyIGVmZmVjdCksIHdlIG5lZWRlZCBhIHdheSB0byB0ZW1wb3JhcmlseSByZXZlcnQgaXQsIHNvIHdlIHVzZSB0aGUgc3RSZXZlcnQgcHJvcGVydHkgb2YgdGhlIGdzQ2FjaGUuIEl0IGNhbiByZXR1cm4gYW5vdGhlciBmdW5jdGlvbiB0aGF0IHdlJ2xsIGNhbGwgYXQgdGhlIGVuZCBzbyBpdCBjYW4gcmV0dXJuIHRvIGl0cyBub3JtYWwgc3RhdGUuXG5cbiAgICBjdXN0b21SZXZlcnRSZXR1cm4gPSB0cmlnZ2VyICYmIHRyaWdnZXIuX2dzYXAgJiYgdHJpZ2dlci5fZ3NhcC5zdFJldmVydDtcbiAgICBjdXN0b21SZXZlcnRSZXR1cm4gJiYgKGN1c3RvbVJldmVydFJldHVybiA9IGN1c3RvbVJldmVydFJldHVybihzZWxmKSk7XG4gICAgcGluID0gcGluID09PSB0cnVlID8gdHJpZ2dlciA6IF9nZXRUYXJnZXQocGluKTtcbiAgICBfaXNTdHJpbmcodG9nZ2xlQ2xhc3MpICYmICh0b2dnbGVDbGFzcyA9IHtcbiAgICAgIHRhcmdldHM6IHRyaWdnZXIsXG4gICAgICBjbGFzc05hbWU6IHRvZ2dsZUNsYXNzXG4gICAgfSk7XG5cbiAgICBpZiAocGluKSB7XG4gICAgICBwaW5TcGFjaW5nID09PSBmYWxzZSB8fCBwaW5TcGFjaW5nID09PSBfbWFyZ2luIHx8IChwaW5TcGFjaW5nID0gIXBpblNwYWNpbmcgJiYgcGluLnBhcmVudE5vZGUgJiYgcGluLnBhcmVudE5vZGUuc3R5bGUgJiYgX2dldENvbXB1dGVkU3R5bGUocGluLnBhcmVudE5vZGUpLmRpc3BsYXkgPT09IFwiZmxleFwiID8gZmFsc2UgOiBfcGFkZGluZyk7IC8vIGlmIHRoZSBwYXJlbnQgaXMgZGlzcGxheTogZmxleCwgZG9uJ3QgYXBwbHkgcGluU3BhY2luZyBieSBkZWZhdWx0LiBXZSBzaG91bGQgY2hlY2sgdGhhdCBwaW4ucGFyZW50Tm9kZSBpcyBhbiBlbGVtZW50IChub3Qgc2hhZG93IGRvbSB3aW5kb3cpXG5cbiAgICAgIHNlbGYucGluID0gcGluO1xuICAgICAgcGluQ2FjaGUgPSBnc2FwLmNvcmUuZ2V0Q2FjaGUocGluKTtcblxuICAgICAgaWYgKCFwaW5DYWNoZS5zcGFjZXIpIHtcbiAgICAgICAgLy8gcmVjb3JkIHRoZSBzcGFjZXIgYW5kIHBpbk9yaWdpbmFsU3RhdGUgb24gdGhlIGNhY2hlIGluIGNhc2Ugc29tZW9uZSB0cmllcyBwaW5uaW5nIHRoZSBzYW1lIGVsZW1lbnQgd2l0aCBNVUxUSVBMRSBTY3JvbGxUcmlnZ2VycyAtIHdlIGRvbid0IHdhbnQgdG8gaGF2ZSBtdWx0aXBsZSBzcGFjZXJzIG9yIHJlY29yZCB0aGUgXCJvcmlnaW5hbFwiIHBpbiBzdGF0ZSBhZnRlciBpdCBoYXMgYWxyZWFkeSBiZWVuIGFmZmVjdGVkIGJ5IGFub3RoZXIgU2Nyb2xsVHJpZ2dlci5cbiAgICAgICAgaWYgKHBpblNwYWNlcikge1xuICAgICAgICAgIHBpblNwYWNlciA9IF9nZXRUYXJnZXQocGluU3BhY2VyKTtcbiAgICAgICAgICBwaW5TcGFjZXIgJiYgIXBpblNwYWNlci5ub2RlVHlwZSAmJiAocGluU3BhY2VyID0gcGluU3BhY2VyLmN1cnJlbnQgfHwgcGluU3BhY2VyLm5hdGl2ZUVsZW1lbnQpOyAvLyBmb3IgUmVhY3QgJiBBbmd1bGFyXG5cbiAgICAgICAgICBwaW5DYWNoZS5zcGFjZXJJc05hdGl2ZSA9ICEhcGluU3BhY2VyO1xuICAgICAgICAgIHBpblNwYWNlciAmJiAocGluQ2FjaGUuc3BhY2VyU3RhdGUgPSBfZ2V0U3RhdGUocGluU3BhY2VyKSk7XG4gICAgICAgIH1cblxuICAgICAgICBwaW5DYWNoZS5zcGFjZXIgPSBzcGFjZXIgPSBwaW5TcGFjZXIgfHwgX2RvYy5jcmVhdGVFbGVtZW50KFwiZGl2XCIpO1xuICAgICAgICBzcGFjZXIuY2xhc3NMaXN0LmFkZChcInBpbi1zcGFjZXJcIik7XG4gICAgICAgIGlkICYmIHNwYWNlci5jbGFzc0xpc3QuYWRkKFwicGluLXNwYWNlci1cIiArIGlkKTtcbiAgICAgICAgcGluQ2FjaGUucGluU3RhdGUgPSBwaW5PcmlnaW5hbFN0YXRlID0gX2dldFN0YXRlKHBpbik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwaW5PcmlnaW5hbFN0YXRlID0gcGluQ2FjaGUucGluU3RhdGU7XG4gICAgICB9XG5cbiAgICAgIHZhcnMuZm9yY2UzRCAhPT0gZmFsc2UgJiYgZ3NhcC5zZXQocGluLCB7XG4gICAgICAgIGZvcmNlM0Q6IHRydWVcbiAgICAgIH0pO1xuICAgICAgc2VsZi5zcGFjZXIgPSBzcGFjZXIgPSBwaW5DYWNoZS5zcGFjZXI7XG4gICAgICBjcyA9IF9nZXRDb21wdXRlZFN0eWxlKHBpbik7XG4gICAgICBzcGFjaW5nU3RhcnQgPSBjc1twaW5TcGFjaW5nICsgZGlyZWN0aW9uLm9zMl07XG4gICAgICBwaW5HZXR0ZXIgPSBnc2FwLmdldFByb3BlcnR5KHBpbik7XG4gICAgICBwaW5TZXR0ZXIgPSBnc2FwLnF1aWNrU2V0dGVyKHBpbiwgZGlyZWN0aW9uLmEsIF9weCk7IC8vIHBpbi5maXJzdENoaWxkICYmICFfbWF4U2Nyb2xsKHBpbiwgZGlyZWN0aW9uKSAmJiAocGluLnN0eWxlLm92ZXJmbG93ID0gXCJoaWRkZW5cIik7IC8vIHByb3RlY3RzIGZyb20gY29sbGFwc2luZyBtYXJnaW5zLCBidXQgY2FuIGhhdmUgdW5pbnRlbmRlZCBjb25zZXF1ZW5jZXMgYXMgZGVtb25zdHJhdGVkIGhlcmU6IGh0dHBzOi8vY29kZXBlbi5pby9HcmVlblNvY2svcGVuLzFlNDJjN2E3M2JmYTQwOWQyY2YxZTE4NGU3YTQyNDhkIHNvIGl0IHdhcyByZW1vdmVkIGluIGZhdm9yIG9mIGp1c3QgdGVsbGluZyBwZW9wbGUgdG8gc2V0IHVwIHRoZWlyIENTUyB0byBhdm9pZCB0aGUgY29sbGFwc2luZyBtYXJnaW5zIChvdmVyZmxvdzogaGlkZGVuIHwgYXV0byBpcyBqdXN0IG9uZSBvcHRpb24uIEFub3RoZXIgaXMgYm9yZGVyLXRvcDogMXB4IHNvbGlkIHRyYW5zcGFyZW50KS5cblxuICAgICAgX3N3YXBQaW5JbihwaW4sIHNwYWNlciwgY3MpO1xuXG4gICAgICBwaW5TdGF0ZSA9IF9nZXRTdGF0ZShwaW4pO1xuICAgIH1cblxuICAgIGlmIChtYXJrZXJzKSB7XG4gICAgICBtYXJrZXJWYXJzID0gX2lzT2JqZWN0KG1hcmtlcnMpID8gX3NldERlZmF1bHRzKG1hcmtlcnMsIF9tYXJrZXJEZWZhdWx0cykgOiBfbWFya2VyRGVmYXVsdHM7XG4gICAgICBtYXJrZXJTdGFydFRyaWdnZXIgPSBfY3JlYXRlTWFya2VyKFwic2Nyb2xsZXItc3RhcnRcIiwgaWQsIHNjcm9sbGVyLCBkaXJlY3Rpb24sIG1hcmtlclZhcnMsIDApO1xuICAgICAgbWFya2VyRW5kVHJpZ2dlciA9IF9jcmVhdGVNYXJrZXIoXCJzY3JvbGxlci1lbmRcIiwgaWQsIHNjcm9sbGVyLCBkaXJlY3Rpb24sIG1hcmtlclZhcnMsIDAsIG1hcmtlclN0YXJ0VHJpZ2dlcik7XG4gICAgICBvZmZzZXQgPSBtYXJrZXJTdGFydFRyaWdnZXJbXCJvZmZzZXRcIiArIGRpcmVjdGlvbi5vcC5kMl07XG5cbiAgICAgIHZhciBjb250ZW50ID0gX2dldFRhcmdldChfZ2V0UHJveHlQcm9wKHNjcm9sbGVyLCBcImNvbnRlbnRcIikgfHwgc2Nyb2xsZXIpO1xuXG4gICAgICBtYXJrZXJTdGFydCA9IHRoaXMubWFya2VyU3RhcnQgPSBfY3JlYXRlTWFya2VyKFwic3RhcnRcIiwgaWQsIGNvbnRlbnQsIGRpcmVjdGlvbiwgbWFya2VyVmFycywgb2Zmc2V0LCAwLCBjb250YWluZXJBbmltYXRpb24pO1xuICAgICAgbWFya2VyRW5kID0gdGhpcy5tYXJrZXJFbmQgPSBfY3JlYXRlTWFya2VyKFwiZW5kXCIsIGlkLCBjb250ZW50LCBkaXJlY3Rpb24sIG1hcmtlclZhcnMsIG9mZnNldCwgMCwgY29udGFpbmVyQW5pbWF0aW9uKTtcbiAgICAgIGNvbnRhaW5lckFuaW1hdGlvbiAmJiAoY2FNYXJrZXJTZXR0ZXIgPSBnc2FwLnF1aWNrU2V0dGVyKFttYXJrZXJTdGFydCwgbWFya2VyRW5kXSwgZGlyZWN0aW9uLmEsIF9weCkpO1xuXG4gICAgICBpZiAoIXVzZUZpeGVkUG9zaXRpb24gJiYgIShfcHJveGllcy5sZW5ndGggJiYgX2dldFByb3h5UHJvcChzY3JvbGxlciwgXCJmaXhlZE1hcmtlcnNcIikgPT09IHRydWUpKSB7XG4gICAgICAgIF9tYWtlUG9zaXRpb25hYmxlKGlzVmlld3BvcnQgPyBfYm9keSA6IHNjcm9sbGVyKTtcblxuICAgICAgICBnc2FwLnNldChbbWFya2VyU3RhcnRUcmlnZ2VyLCBtYXJrZXJFbmRUcmlnZ2VyXSwge1xuICAgICAgICAgIGZvcmNlM0Q6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICAgIG1hcmtlclN0YXJ0U2V0dGVyID0gZ3NhcC5xdWlja1NldHRlcihtYXJrZXJTdGFydFRyaWdnZXIsIGRpcmVjdGlvbi5hLCBfcHgpO1xuICAgICAgICBtYXJrZXJFbmRTZXR0ZXIgPSBnc2FwLnF1aWNrU2V0dGVyKG1hcmtlckVuZFRyaWdnZXIsIGRpcmVjdGlvbi5hLCBfcHgpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChjb250YWluZXJBbmltYXRpb24pIHtcbiAgICAgIHZhciBvbGRPblVwZGF0ZSA9IGNvbnRhaW5lckFuaW1hdGlvbi52YXJzLm9uVXBkYXRlLFxuICAgICAgICAgIG9sZFBhcmFtcyA9IGNvbnRhaW5lckFuaW1hdGlvbi52YXJzLm9uVXBkYXRlUGFyYW1zO1xuICAgICAgY29udGFpbmVyQW5pbWF0aW9uLmV2ZW50Q2FsbGJhY2soXCJvblVwZGF0ZVwiLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHNlbGYudXBkYXRlKDAsIDAsIDEpO1xuICAgICAgICBvbGRPblVwZGF0ZSAmJiBvbGRPblVwZGF0ZS5hcHBseShjb250YWluZXJBbmltYXRpb24sIG9sZFBhcmFtcyB8fCBbXSk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBzZWxmLnByZXZpb3VzID0gZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIF90cmlnZ2Vyc1tfdHJpZ2dlcnMuaW5kZXhPZihzZWxmKSAtIDFdO1xuICAgIH07XG5cbiAgICBzZWxmLm5leHQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gX3RyaWdnZXJzW190cmlnZ2Vycy5pbmRleE9mKHNlbGYpICsgMV07XG4gICAgfTtcblxuICAgIHNlbGYucmV2ZXJ0ID0gZnVuY3Rpb24gKHJldmVydCwgdGVtcCkge1xuICAgICAgaWYgKCF0ZW1wKSB7XG4gICAgICAgIHJldHVybiBzZWxmLmtpbGwodHJ1ZSk7XG4gICAgICB9IC8vIGZvciBjb21wYXRpYmlsaXR5IHdpdGggZ3NhcC5jb250ZXh0KCkgYW5kIGdzYXAubWF0Y2hNZWRpYSgpIHdoaWNoIGNhbGwgcmV2ZXJ0KClcblxuXG4gICAgICB2YXIgciA9IHJldmVydCAhPT0gZmFsc2UgfHwgIXNlbGYuZW5hYmxlZCxcbiAgICAgICAgICBwcmV2UmVmcmVzaGluZyA9IF9yZWZyZXNoaW5nO1xuXG4gICAgICBpZiAociAhPT0gc2VsZi5pc1JldmVydGVkKSB7XG4gICAgICAgIGlmIChyKSB7XG4gICAgICAgICAgcHJldlNjcm9sbCA9IE1hdGgubWF4KHNjcm9sbEZ1bmMoKSwgc2VsZi5zY3JvbGwucmVjIHx8IDApOyAvLyByZWNvcmQgdGhlIHNjcm9sbCBzbyB3ZSBjYW4gcmV2ZXJ0IGxhdGVyIChyZXBvc2l0aW9uaW5nL3Bpbm5pbmcgdGhpbmdzIGNhbiBhZmZlY3Qgc2Nyb2xsIHBvc2l0aW9uKS4gSW4gdGhlIHN0YXRpYyByZWZyZXNoKCkgbWV0aG9kLCB3ZSBmaXJzdCByZWNvcmQgYWxsIHRoZSBzY3JvbGwgcG9zaXRpb25zIGFzIGEgcmVmZXJlbmNlLlxuXG4gICAgICAgICAgcHJldlByb2dyZXNzID0gc2VsZi5wcm9ncmVzcztcbiAgICAgICAgICBwcmV2QW5pbVByb2dyZXNzID0gYW5pbWF0aW9uICYmIGFuaW1hdGlvbi5wcm9ncmVzcygpO1xuICAgICAgICB9XG5cbiAgICAgICAgbWFya2VyU3RhcnQgJiYgW21hcmtlclN0YXJ0LCBtYXJrZXJFbmQsIG1hcmtlclN0YXJ0VHJpZ2dlciwgbWFya2VyRW5kVHJpZ2dlcl0uZm9yRWFjaChmdW5jdGlvbiAobSkge1xuICAgICAgICAgIHJldHVybiBtLnN0eWxlLmRpc3BsYXkgPSByID8gXCJub25lXCIgOiBcImJsb2NrXCI7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChyKSB7XG4gICAgICAgICAgX3JlZnJlc2hpbmcgPSBzZWxmO1xuICAgICAgICAgIHNlbGYudXBkYXRlKHIpOyAvLyBtYWtlIHN1cmUgdGhlIHBpbiBpcyBiYWNrIGluIGl0cyBvcmlnaW5hbCBwb3NpdGlvbiBzbyB0aGF0IGFsbCB0aGUgbWVhc3VyZW1lbnRzIGFyZSBjb3JyZWN0LiBkbyB0aGlzIEJFRk9SRSBzd2FwcGluZyB0aGUgcGluIG91dFxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHBpbiAmJiAoIXBpblJlcGFyZW50IHx8ICFzZWxmLmlzQWN0aXZlKSkge1xuICAgICAgICAgIGlmIChyKSB7XG4gICAgICAgICAgICBfc3dhcFBpbk91dChwaW4sIHNwYWNlciwgcGluT3JpZ2luYWxTdGF0ZSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIF9zd2FwUGluSW4ocGluLCBzcGFjZXIsIF9nZXRDb21wdXRlZFN0eWxlKHBpbiksIHNwYWNlclN0YXRlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByIHx8IHNlbGYudXBkYXRlKHIpOyAvLyB3aGVuIHdlJ3JlIHJlc3RvcmluZywgdGhlIHVwZGF0ZSBzaG91bGQgcnVuIEFGVEVSIHN3YXBwaW5nIHRoZSBwaW4gaW50byBpdHMgcGluLXNwYWNlci5cblxuICAgICAgICBfcmVmcmVzaGluZyA9IHByZXZSZWZyZXNoaW5nOyAvLyByZXN0b3JlLiBXZSBzZXQgaXQgdG8gdHJ1ZSBkdXJpbmcgdGhlIHVwZGF0ZSgpIHNvIHRoYXQgdGhpbmdzIGZpcmUgcHJvcGVybHkgaW4gdGhlcmUuXG5cbiAgICAgICAgc2VsZi5pc1JldmVydGVkID0gcjtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgc2VsZi5yZWZyZXNoID0gZnVuY3Rpb24gKHNvZnQsIGZvcmNlLCBwb3NpdGlvbiwgcGluT2Zmc2V0KSB7XG4gICAgICAvLyBwb3NpdGlvbiBpcyB0eXBpY2FsbHkgb25seSBkZWZpbmVkIGlmIGl0J3MgY29taW5nIGZyb20gc2V0UG9zaXRpb25zKCkgLSBpdCdzIGEgd2F5IHRvIHNraXAgdGhlIG5vcm1hbCBwYXJzaW5nLiBwaW5PZmZzZXQgaXMgYWxzbyBvbmx5IGZyb20gc2V0UG9zaXRpb25zKCkgYW5kIGlzIG1vc3RseSByZWxhdGVkIHRvIGZhbmN5IHN0dWZmIHdlIG5lZWQgdG8gZG8gaW4gU2Nyb2xsU21vb3RoZXIgd2l0aCBlZmZlY3RzXG4gICAgICBpZiAoKF9yZWZyZXNoaW5nIHx8ICFzZWxmLmVuYWJsZWQpICYmICFmb3JjZSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChwaW4gJiYgc29mdCAmJiBfbGFzdFNjcm9sbFRpbWUpIHtcbiAgICAgICAgX2FkZExpc3RlbmVyKFNjcm9sbFRyaWdnZXIsIFwic2Nyb2xsRW5kXCIsIF9zb2Z0UmVmcmVzaCk7XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAhX3JlZnJlc2hpbmdBbGwgJiYgb25SZWZyZXNoSW5pdCAmJiBvblJlZnJlc2hJbml0KHNlbGYpO1xuICAgICAgX3JlZnJlc2hpbmcgPSBzZWxmO1xuXG4gICAgICBpZiAodHdlZW5Uby50d2VlbiAmJiAhcG9zaXRpb24pIHtcbiAgICAgICAgLy8gd2Ugc2tpcCB0aGlzIGlmIGEgcG9zaXRpb24gaXMgcGFzc2VkIGluIGJlY2F1c2UgdHlwaWNhbGx5IHRoYXQncyBmcm9tIC5zZXRQb3NpdGlvbnMoKSBhbmQgaXQncyBiZXN0IHRvIGFsbG93IGluLXByb2dyZXNzIHNuYXBwaW5nIHRvIGNvbnRpbnVlLlxuICAgICAgICB0d2VlblRvLnR3ZWVuLmtpbGwoKTtcbiAgICAgICAgdHdlZW5Uby50d2VlbiA9IDA7XG4gICAgICB9XG5cbiAgICAgIHNjcnViVHdlZW4gJiYgc2NydWJUd2Vlbi5wYXVzZSgpO1xuICAgICAgaW52YWxpZGF0ZU9uUmVmcmVzaCAmJiBhbmltYXRpb24gJiYgYW5pbWF0aW9uLnJldmVydCh7XG4gICAgICAgIGtpbGw6IGZhbHNlXG4gICAgICB9KS5pbnZhbGlkYXRlKCk7XG4gICAgICBzZWxmLmlzUmV2ZXJ0ZWQgfHwgc2VsZi5yZXZlcnQodHJ1ZSwgdHJ1ZSk7XG4gICAgICBzZWxmLl9zdWJQaW5PZmZzZXQgPSBmYWxzZTsgLy8gd2UnbGwgc2V0IHRoaXMgdG8gdHJ1ZSBpbiB0aGUgc3ViLXBpbnMgaWYgd2UgZmluZCBhbnlcblxuICAgICAgdmFyIHNpemUgPSBnZXRTY3JvbGxlclNpemUoKSxcbiAgICAgICAgICBzY3JvbGxlckJvdW5kcyA9IGdldFNjcm9sbGVyT2Zmc2V0cygpLFxuICAgICAgICAgIG1heCA9IGNvbnRhaW5lckFuaW1hdGlvbiA/IGNvbnRhaW5lckFuaW1hdGlvbi5kdXJhdGlvbigpIDogX21heFNjcm9sbChzY3JvbGxlciwgZGlyZWN0aW9uKSxcbiAgICAgICAgICBpc0ZpcnN0UmVmcmVzaCA9IGNoYW5nZSA8PSAwLjAxLFxuICAgICAgICAgIG9mZnNldCA9IDAsXG4gICAgICAgICAgb3RoZXJQaW5PZmZzZXQgPSBwaW5PZmZzZXQgfHwgMCxcbiAgICAgICAgICBwYXJzZWRFbmQgPSBfaXNPYmplY3QocG9zaXRpb24pID8gcG9zaXRpb24uZW5kIDogdmFycy5lbmQsXG4gICAgICAgICAgcGFyc2VkRW5kVHJpZ2dlciA9IHZhcnMuZW5kVHJpZ2dlciB8fCB0cmlnZ2VyLFxuICAgICAgICAgIHBhcnNlZFN0YXJ0ID0gX2lzT2JqZWN0KHBvc2l0aW9uKSA/IHBvc2l0aW9uLnN0YXJ0IDogdmFycy5zdGFydCB8fCAodmFycy5zdGFydCA9PT0gMCB8fCAhdHJpZ2dlciA/IDAgOiBwaW4gPyBcIjAgMFwiIDogXCIwIDEwMCVcIiksXG4gICAgICAgICAgcGlubmVkQ29udGFpbmVyID0gc2VsZi5waW5uZWRDb250YWluZXIgPSB2YXJzLnBpbm5lZENvbnRhaW5lciAmJiBfZ2V0VGFyZ2V0KHZhcnMucGlubmVkQ29udGFpbmVyLCBzZWxmKSxcbiAgICAgICAgICB0cmlnZ2VySW5kZXggPSB0cmlnZ2VyICYmIE1hdGgubWF4KDAsIF90cmlnZ2Vycy5pbmRleE9mKHNlbGYpKSB8fCAwLFxuICAgICAgICAgIGkgPSB0cmlnZ2VySW5kZXgsXG4gICAgICAgICAgY3MsXG4gICAgICAgICAgYm91bmRzLFxuICAgICAgICAgIHNjcm9sbCxcbiAgICAgICAgICBpc1ZlcnRpY2FsLFxuICAgICAgICAgIG92ZXJyaWRlLFxuICAgICAgICAgIGN1clRyaWdnZXIsXG4gICAgICAgICAgY3VyUGluLFxuICAgICAgICAgIG9wcG9zaXRlU2Nyb2xsLFxuICAgICAgICAgIGluaXR0ZWQsXG4gICAgICAgICAgcmV2ZXJ0ZWRQaW5zLFxuICAgICAgICAgIGZvcmNlZE92ZXJmbG93LFxuICAgICAgICAgIG1hcmtlclN0YXJ0T2Zmc2V0LFxuICAgICAgICAgIG1hcmtlckVuZE9mZnNldDtcblxuICAgICAgaWYgKG1hcmtlcnMgJiYgX2lzT2JqZWN0KHBvc2l0aW9uKSkge1xuICAgICAgICAvLyBpZiB3ZSBhbHRlciB0aGUgc3RhcnQvZW5kIHBvc2l0aW9ucyB3aXRoIC5zZXRQb3NpdGlvbnMoKSwgaXQgZ2VuZXJhbGx5IGZlZWRzIGluIGFic29sdXRlIE5VTUJFUlMgd2hpY2ggZG9uJ3QgY29udmV5IGluZm9ybWF0aW9uIGFib3V0IHdoZXJlIHRvIGxpbmUgdXAgdGhlIG1hcmtlcnMsIHNvIHRvIGtlZXAgaXQgaW50dWl0aXZlLCB3ZSByZWNvcmQgaG93IGZhciB0aGUgdHJpZ2dlciBwb3NpdGlvbnMgc2hpZnQgYWZ0ZXIgYXBwbHlpbmcgdGhlIG5ldyBudW1iZXJzIGFuZCB0aGVuIG9mZnNldCBieSB0aGF0IG11Y2ggaW4gdGhlIG9wcG9zaXRlIGRpcmVjdGlvbi4gV2UgZG8gdGhlIHNhbWUgdG8gdGhlIGFzc29jaWF0ZWQgdHJpZ2dlciBtYXJrZXJzIHRvbyBvZiBjb3Vyc2UuXG4gICAgICAgIG1hcmtlclN0YXJ0T2Zmc2V0ID0gZ3NhcC5nZXRQcm9wZXJ0eShtYXJrZXJTdGFydFRyaWdnZXIsIGRpcmVjdGlvbi5wKTtcbiAgICAgICAgbWFya2VyRW5kT2Zmc2V0ID0gZ3NhcC5nZXRQcm9wZXJ0eShtYXJrZXJFbmRUcmlnZ2VyLCBkaXJlY3Rpb24ucCk7XG4gICAgICB9XG5cbiAgICAgIHdoaWxlIChpLS0pIHtcbiAgICAgICAgLy8gdXNlciBtaWdodCB0cnkgdG8gcGluIHRoZSBzYW1lIGVsZW1lbnQgbW9yZSB0aGFuIG9uY2UsIHNvIHdlIG11c3QgZmluZCBhbnkgcHJpb3IgdHJpZ2dlcnMgd2l0aCB0aGUgc2FtZSBwaW4sIHJldmVydCB0aGVtLCBhbmQgZGV0ZXJtaW5lIGhvdyBsb25nIHRoZXkncmUgcGlubmluZyBzbyB0aGF0IHdlIGNhbiBvZmZzZXQgdGhpbmdzIGFwcHJvcHJpYXRlbHkuIE1ha2Ugc3VyZSB3ZSByZXZlcnQgZnJvbSBsYXN0IHRvIGZpcnN0IHNvIHRoYXQgdGhpbmdzIFwicmV3aW5kXCIgcHJvcGVybHkuXG4gICAgICAgIGN1clRyaWdnZXIgPSBfdHJpZ2dlcnNbaV07XG4gICAgICAgIGN1clRyaWdnZXIuZW5kIHx8IGN1clRyaWdnZXIucmVmcmVzaCgwLCAxKSB8fCAoX3JlZnJlc2hpbmcgPSBzZWxmKTsgLy8gaWYgaXQncyBhIHRpbWVsaW5lLWJhc2VkIHRyaWdnZXIgdGhhdCBoYXNuJ3QgYmVlbiBmdWxseSBpbml0aWFsaXplZCB5ZXQgYmVjYXVzZSBpdCdzIHdhaXRpbmcgZm9yIDEgdGljaywganVzdCBmb3JjZSB0aGUgcmVmcmVzaCgpIGhlcmUsIG90aGVyd2lzZSBpZiBpdCBjb250YWlucyBhIHBpbiB0aGF0J3Mgc3VwcG9zZWQgdG8gYWZmZWN0IG90aGVyIFNjcm9sbFRyaWdnZXJzIGZ1cnRoZXIgZG93biB0aGUgcGFnZSwgdGhleSB3b24ndCBiZSBhZGp1c3RlZCBwcm9wZXJseS5cblxuICAgICAgICBjdXJQaW4gPSBjdXJUcmlnZ2VyLnBpbjtcblxuICAgICAgICBpZiAoY3VyUGluICYmIChjdXJQaW4gPT09IHRyaWdnZXIgfHwgY3VyUGluID09PSBwaW4gfHwgY3VyUGluID09PSBwaW5uZWRDb250YWluZXIpICYmICFjdXJUcmlnZ2VyLmlzUmV2ZXJ0ZWQpIHtcbiAgICAgICAgICByZXZlcnRlZFBpbnMgfHwgKHJldmVydGVkUGlucyA9IFtdKTtcbiAgICAgICAgICByZXZlcnRlZFBpbnMudW5zaGlmdChjdXJUcmlnZ2VyKTsgLy8gd2UnbGwgcmV2ZXJ0IGZyb20gZmlyc3QgdG8gbGFzdCB0byBtYWtlIHN1cmUgdGhpbmdzIHJlYWNoIHRoZWlyIGVuZCBzdGF0ZSBwcm9wZXJseVxuXG4gICAgICAgICAgY3VyVHJpZ2dlci5yZXZlcnQodHJ1ZSwgdHJ1ZSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY3VyVHJpZ2dlciAhPT0gX3RyaWdnZXJzW2ldKSB7XG4gICAgICAgICAgLy8gaW4gY2FzZSBpdCBnb3QgcmVtb3ZlZC5cbiAgICAgICAgICB0cmlnZ2VySW5kZXgtLTtcbiAgICAgICAgICBpLS07XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgX2lzRnVuY3Rpb24ocGFyc2VkU3RhcnQpICYmIChwYXJzZWRTdGFydCA9IHBhcnNlZFN0YXJ0KHNlbGYpKTtcbiAgICAgIHBhcnNlZFN0YXJ0ID0gX3BhcnNlQ2xhbXAocGFyc2VkU3RhcnQsIFwic3RhcnRcIiwgc2VsZik7XG4gICAgICBzdGFydCA9IF9wYXJzZVBvc2l0aW9uKHBhcnNlZFN0YXJ0LCB0cmlnZ2VyLCBzaXplLCBkaXJlY3Rpb24sIHNjcm9sbEZ1bmMoKSwgbWFya2VyU3RhcnQsIG1hcmtlclN0YXJ0VHJpZ2dlciwgc2VsZiwgc2Nyb2xsZXJCb3VuZHMsIGJvcmRlcldpZHRoLCB1c2VGaXhlZFBvc2l0aW9uLCBtYXgsIGNvbnRhaW5lckFuaW1hdGlvbiwgc2VsZi5fc3RhcnRDbGFtcCAmJiBcIl9zdGFydENsYW1wXCIpIHx8IChwaW4gPyAtMC4wMDEgOiAwKTtcbiAgICAgIF9pc0Z1bmN0aW9uKHBhcnNlZEVuZCkgJiYgKHBhcnNlZEVuZCA9IHBhcnNlZEVuZChzZWxmKSk7XG5cbiAgICAgIGlmIChfaXNTdHJpbmcocGFyc2VkRW5kKSAmJiAhcGFyc2VkRW5kLmluZGV4T2YoXCIrPVwiKSkge1xuICAgICAgICBpZiAofnBhcnNlZEVuZC5pbmRleE9mKFwiIFwiKSkge1xuICAgICAgICAgIHBhcnNlZEVuZCA9IChfaXNTdHJpbmcocGFyc2VkU3RhcnQpID8gcGFyc2VkU3RhcnQuc3BsaXQoXCIgXCIpWzBdIDogXCJcIikgKyBwYXJzZWRFbmQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgb2Zmc2V0ID0gX29mZnNldFRvUHgocGFyc2VkRW5kLnN1YnN0cigyKSwgc2l6ZSk7XG4gICAgICAgICAgcGFyc2VkRW5kID0gX2lzU3RyaW5nKHBhcnNlZFN0YXJ0KSA/IHBhcnNlZFN0YXJ0IDogKGNvbnRhaW5lckFuaW1hdGlvbiA/IGdzYXAudXRpbHMubWFwUmFuZ2UoMCwgY29udGFpbmVyQW5pbWF0aW9uLmR1cmF0aW9uKCksIGNvbnRhaW5lckFuaW1hdGlvbi5zY3JvbGxUcmlnZ2VyLnN0YXJ0LCBjb250YWluZXJBbmltYXRpb24uc2Nyb2xsVHJpZ2dlci5lbmQsIHN0YXJ0KSA6IHN0YXJ0KSArIG9mZnNldDsgLy8gX3BhcnNlUG9zaXRpb24gd29uJ3QgZmFjdG9yIGluIHRoZSBvZmZzZXQgaWYgdGhlIHN0YXJ0IGlzIGEgbnVtYmVyLCBzbyBkbyBpdCBoZXJlLlxuXG4gICAgICAgICAgcGFyc2VkRW5kVHJpZ2dlciA9IHRyaWdnZXI7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcGFyc2VkRW5kID0gX3BhcnNlQ2xhbXAocGFyc2VkRW5kLCBcImVuZFwiLCBzZWxmKTtcbiAgICAgIGVuZCA9IE1hdGgubWF4KHN0YXJ0LCBfcGFyc2VQb3NpdGlvbihwYXJzZWRFbmQgfHwgKHBhcnNlZEVuZFRyaWdnZXIgPyBcIjEwMCUgMFwiIDogbWF4KSwgcGFyc2VkRW5kVHJpZ2dlciwgc2l6ZSwgZGlyZWN0aW9uLCBzY3JvbGxGdW5jKCkgKyBvZmZzZXQsIG1hcmtlckVuZCwgbWFya2VyRW5kVHJpZ2dlciwgc2VsZiwgc2Nyb2xsZXJCb3VuZHMsIGJvcmRlcldpZHRoLCB1c2VGaXhlZFBvc2l0aW9uLCBtYXgsIGNvbnRhaW5lckFuaW1hdGlvbiwgc2VsZi5fZW5kQ2xhbXAgJiYgXCJfZW5kQ2xhbXBcIikpIHx8IC0wLjAwMTtcbiAgICAgIG9mZnNldCA9IDA7XG4gICAgICBpID0gdHJpZ2dlckluZGV4O1xuXG4gICAgICB3aGlsZSAoaS0tKSB7XG4gICAgICAgIGN1clRyaWdnZXIgPSBfdHJpZ2dlcnNbaV07XG4gICAgICAgIGN1clBpbiA9IGN1clRyaWdnZXIucGluO1xuXG4gICAgICAgIGlmIChjdXJQaW4gJiYgY3VyVHJpZ2dlci5zdGFydCAtIGN1clRyaWdnZXIuX3BpblB1c2ggPD0gc3RhcnQgJiYgIWNvbnRhaW5lckFuaW1hdGlvbiAmJiBjdXJUcmlnZ2VyLmVuZCA+IDApIHtcbiAgICAgICAgICBjcyA9IGN1clRyaWdnZXIuZW5kIC0gKHNlbGYuX3N0YXJ0Q2xhbXAgPyBNYXRoLm1heCgwLCBjdXJUcmlnZ2VyLnN0YXJ0KSA6IGN1clRyaWdnZXIuc3RhcnQpO1xuXG4gICAgICAgICAgaWYgKChjdXJQaW4gPT09IHRyaWdnZXIgJiYgY3VyVHJpZ2dlci5zdGFydCAtIGN1clRyaWdnZXIuX3BpblB1c2ggPCBzdGFydCB8fCBjdXJQaW4gPT09IHBpbm5lZENvbnRhaW5lcikgJiYgaXNOYU4ocGFyc2VkU3RhcnQpKSB7XG4gICAgICAgICAgICAvLyBudW1lcmljIHN0YXJ0IHZhbHVlcyBzaG91bGRuJ3QgYmUgb2Zmc2V0IGF0IGFsbCAtIHRyZWF0IHRoZW0gYXMgYWJzb2x1dGVcbiAgICAgICAgICAgIG9mZnNldCArPSBjcyAqICgxIC0gY3VyVHJpZ2dlci5wcm9ncmVzcyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY3VyUGluID09PSBwaW4gJiYgKG90aGVyUGluT2Zmc2V0ICs9IGNzKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBzdGFydCArPSBvZmZzZXQ7XG4gICAgICBlbmQgKz0gb2Zmc2V0O1xuICAgICAgc2VsZi5fc3RhcnRDbGFtcCAmJiAoc2VsZi5fc3RhcnRDbGFtcCArPSBvZmZzZXQpO1xuXG4gICAgICBpZiAoc2VsZi5fZW5kQ2xhbXAgJiYgIV9yZWZyZXNoaW5nQWxsKSB7XG4gICAgICAgIHNlbGYuX2VuZENsYW1wID0gZW5kIHx8IC0wLjAwMTtcbiAgICAgICAgZW5kID0gTWF0aC5taW4oZW5kLCBfbWF4U2Nyb2xsKHNjcm9sbGVyLCBkaXJlY3Rpb24pKTtcbiAgICAgIH1cblxuICAgICAgY2hhbmdlID0gZW5kIC0gc3RhcnQgfHwgKHN0YXJ0IC09IDAuMDEpICYmIDAuMDAxO1xuXG4gICAgICBpZiAoaXNGaXJzdFJlZnJlc2gpIHtcbiAgICAgICAgLy8gb24gdGhlIHZlcnkgZmlyc3QgcmVmcmVzaCgpLCB0aGUgcHJldlByb2dyZXNzIGNvdWxkbid0IGhhdmUgYmVlbiBhY2N1cmF0ZSB5ZXQgYmVjYXVzZSB0aGUgc3RhcnQvZW5kIHdlcmUgbmV2ZXIgY2FsY3VsYXRlZCwgc28gd2Ugc2V0IGl0IGhlcmUuIEJlZm9yZSAzLjExLjUsIGl0IGNvdWxkIGxlYWQgdG8gYW4gaW5hY2N1cmF0ZSBzY3JvbGwgcG9zaXRpb24gcmVzdG9yYXRpb24gd2l0aCBzbmFwcGluZy5cbiAgICAgICAgcHJldlByb2dyZXNzID0gZ3NhcC51dGlscy5jbGFtcCgwLCAxLCBnc2FwLnV0aWxzLm5vcm1hbGl6ZShzdGFydCwgZW5kLCBwcmV2U2Nyb2xsKSk7XG4gICAgICB9XG5cbiAgICAgIHNlbGYuX3BpblB1c2ggPSBvdGhlclBpbk9mZnNldDtcblxuICAgICAgaWYgKG1hcmtlclN0YXJ0ICYmIG9mZnNldCkge1xuICAgICAgICAvLyBvZmZzZXQgdGhlIG1hcmtlcnMgaWYgbmVjZXNzYXJ5XG4gICAgICAgIGNzID0ge307XG4gICAgICAgIGNzW2RpcmVjdGlvbi5hXSA9IFwiKz1cIiArIG9mZnNldDtcbiAgICAgICAgcGlubmVkQ29udGFpbmVyICYmIChjc1tkaXJlY3Rpb24ucF0gPSBcIi09XCIgKyBzY3JvbGxGdW5jKCkpO1xuICAgICAgICBnc2FwLnNldChbbWFya2VyU3RhcnQsIG1hcmtlckVuZF0sIGNzKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHBpbiAmJiAhKF9jbGFtcGluZ01heCAmJiBzZWxmLmVuZCA+PSBfbWF4U2Nyb2xsKHNjcm9sbGVyLCBkaXJlY3Rpb24pKSkge1xuICAgICAgICBjcyA9IF9nZXRDb21wdXRlZFN0eWxlKHBpbik7XG4gICAgICAgIGlzVmVydGljYWwgPSBkaXJlY3Rpb24gPT09IF92ZXJ0aWNhbDtcbiAgICAgICAgc2Nyb2xsID0gc2Nyb2xsRnVuYygpOyAvLyByZWNhbGN1bGF0ZSBiZWNhdXNlIHRoZSB0cmlnZ2VycyBjYW4gYWZmZWN0IHRoZSBzY3JvbGxcblxuICAgICAgICBwaW5TdGFydCA9IHBhcnNlRmxvYXQocGluR2V0dGVyKGRpcmVjdGlvbi5hKSkgKyBvdGhlclBpbk9mZnNldDtcblxuICAgICAgICBpZiAoIW1heCAmJiBlbmQgPiAxKSB7XG4gICAgICAgICAgLy8gbWFrZXMgc3VyZSB0aGUgc2Nyb2xsZXIgaGFzIGEgc2Nyb2xsYmFyLCBvdGhlcndpc2UgaWYgc29tZXRoaW5nIGhhcyB3aWR0aDogMTAwJSwgZm9yIGV4YW1wbGUsIGl0IHdvdWxkIGJlIHRvbyBiaWcgKGV4Y2x1ZGUgdGhlIHNjcm9sbGJhcikuIFNlZSBodHRwczovL2dzYXAuY29tL2ZvcnVtcy90b3BpYy8yNTE4Mi1zY3JvbGx0cmlnZ2VyLXdpZHRoLW9mLXBhZ2UtaW5jcmVhc2Utd2hlcmUtbWFya2Vycy1hcmUtc2V0LXRvLWZhbHNlL1xuICAgICAgICAgIGZvcmNlZE92ZXJmbG93ID0gKGlzVmlld3BvcnQgPyBfZG9jLnNjcm9sbGluZ0VsZW1lbnQgfHwgX2RvY0VsIDogc2Nyb2xsZXIpLnN0eWxlO1xuICAgICAgICAgIGZvcmNlZE92ZXJmbG93ID0ge1xuICAgICAgICAgICAgc3R5bGU6IGZvcmNlZE92ZXJmbG93LFxuICAgICAgICAgICAgdmFsdWU6IGZvcmNlZE92ZXJmbG93W1wib3ZlcmZsb3dcIiArIGRpcmVjdGlvbi5hLnRvVXBwZXJDYXNlKCldXG4gICAgICAgICAgfTtcblxuICAgICAgICAgIGlmIChpc1ZpZXdwb3J0ICYmIF9nZXRDb21wdXRlZFN0eWxlKF9ib2R5KVtcIm92ZXJmbG93XCIgKyBkaXJlY3Rpb24uYS50b1VwcGVyQ2FzZSgpXSAhPT0gXCJzY3JvbGxcIikge1xuICAgICAgICAgICAgLy8gYXZvaWQgYW4gZXh0cmEgc2Nyb2xsYmFyIGlmIEJPVEggPGh0bWw+IGFuZCA8Ym9keT4gaGF2ZSBvdmVyZmxvdyBzZXQgdG8gXCJzY3JvbGxcIlxuICAgICAgICAgICAgZm9yY2VkT3ZlcmZsb3cuc3R5bGVbXCJvdmVyZmxvd1wiICsgZGlyZWN0aW9uLmEudG9VcHBlckNhc2UoKV0gPSBcInNjcm9sbFwiO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIF9zd2FwUGluSW4ocGluLCBzcGFjZXIsIGNzKTtcblxuICAgICAgICBwaW5TdGF0ZSA9IF9nZXRTdGF0ZShwaW4pOyAvLyB0cmFuc2Zvcm1zIHdpbGwgaW50ZXJmZXJlIHdpdGggdGhlIHRvcC9sZWZ0L3JpZ2h0L2JvdHRvbSBwbGFjZW1lbnQsIHNvIHJlbW92ZSB0aGVtIHRlbXBvcmFyaWx5LiBnZXRCb3VuZGluZ0NsaWVudFJlY3QoKSBmYWN0b3JzIGluIHRyYW5zZm9ybXMuXG5cbiAgICAgICAgYm91bmRzID0gX2dldEJvdW5kcyhwaW4sIHRydWUpO1xuICAgICAgICBvcHBvc2l0ZVNjcm9sbCA9IHVzZUZpeGVkUG9zaXRpb24gJiYgX2dldFNjcm9sbEZ1bmMoc2Nyb2xsZXIsIGlzVmVydGljYWwgPyBfaG9yaXpvbnRhbCA6IF92ZXJ0aWNhbCkoKTtcblxuICAgICAgICBpZiAocGluU3BhY2luZykge1xuICAgICAgICAgIHNwYWNlclN0YXRlID0gW3BpblNwYWNpbmcgKyBkaXJlY3Rpb24ub3MyLCBjaGFuZ2UgKyBvdGhlclBpbk9mZnNldCArIF9weF07XG4gICAgICAgICAgc3BhY2VyU3RhdGUudCA9IHNwYWNlcjtcbiAgICAgICAgICBpID0gcGluU3BhY2luZyA9PT0gX3BhZGRpbmcgPyBfZ2V0U2l6ZShwaW4sIGRpcmVjdGlvbikgKyBjaGFuZ2UgKyBvdGhlclBpbk9mZnNldCA6IDA7XG5cbiAgICAgICAgICBpZiAoaSkge1xuICAgICAgICAgICAgc3BhY2VyU3RhdGUucHVzaChkaXJlY3Rpb24uZCwgaSArIF9weCk7IC8vIGZvciBib3gtc2l6aW5nOiBib3JkZXItYm94IChtdXN0IGluY2x1ZGUgcGFkZGluZykuXG5cbiAgICAgICAgICAgIHNwYWNlci5zdHlsZS5mbGV4QmFzaXMgIT09IFwiYXV0b1wiICYmIChzcGFjZXIuc3R5bGUuZmxleEJhc2lzID0gaSArIF9weCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgX3NldFN0YXRlKHNwYWNlclN0YXRlKTtcblxuICAgICAgICAgIGlmIChwaW5uZWRDb250YWluZXIpIHtcbiAgICAgICAgICAgIC8vIGluIFNjcm9sbFRyaWdnZXIucmVmcmVzaCgpLCB3ZSBuZWVkIHRvIHJlLWV2YWx1YXRlIHRoZSBwaW5Db250YWluZXIncyBzaXplIGJlY2F1c2UgdGhpcyBwaW5TcGFjaW5nIG1heSBzdHJldGNoIGl0IG91dCwgYnV0IHdlIGNhbid0IGp1c3QgYWRkIHRoZSBleGFjdCBkaXN0YW5jZSBiZWNhdXNlIGRlcGVuZGluZyBvbiBsYXlvdXQsIGl0IG1heSBub3QgcHVzaCB0aGluZ3MgZG93biBvciBpdCBtYXkgb25seSBkbyBzbyBwYXJ0aWFsbHkuXG4gICAgICAgICAgICBfdHJpZ2dlcnMuZm9yRWFjaChmdW5jdGlvbiAodCkge1xuICAgICAgICAgICAgICBpZiAodC5waW4gPT09IHBpbm5lZENvbnRhaW5lciAmJiB0LnZhcnMucGluU3BhY2luZyAhPT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICB0Ll9zdWJQaW5PZmZzZXQgPSB0cnVlO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB1c2VGaXhlZFBvc2l0aW9uICYmIHNjcm9sbEZ1bmMocHJldlNjcm9sbCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaSA9IF9nZXRTaXplKHBpbiwgZGlyZWN0aW9uKTtcbiAgICAgICAgICBpICYmIHNwYWNlci5zdHlsZS5mbGV4QmFzaXMgIT09IFwiYXV0b1wiICYmIChzcGFjZXIuc3R5bGUuZmxleEJhc2lzID0gaSArIF9weCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodXNlRml4ZWRQb3NpdGlvbikge1xuICAgICAgICAgIG92ZXJyaWRlID0ge1xuICAgICAgICAgICAgdG9wOiBib3VuZHMudG9wICsgKGlzVmVydGljYWwgPyBzY3JvbGwgLSBzdGFydCA6IG9wcG9zaXRlU2Nyb2xsKSArIF9weCxcbiAgICAgICAgICAgIGxlZnQ6IGJvdW5kcy5sZWZ0ICsgKGlzVmVydGljYWwgPyBvcHBvc2l0ZVNjcm9sbCA6IHNjcm9sbCAtIHN0YXJ0KSArIF9weCxcbiAgICAgICAgICAgIGJveFNpemluZzogXCJib3JkZXItYm94XCIsXG4gICAgICAgICAgICBwb3NpdGlvbjogXCJmaXhlZFwiXG4gICAgICAgICAgfTtcbiAgICAgICAgICBvdmVycmlkZVtfd2lkdGhdID0gb3ZlcnJpZGVbXCJtYXhcIiArIF9XaWR0aF0gPSBNYXRoLmNlaWwoYm91bmRzLndpZHRoKSArIF9weDtcbiAgICAgICAgICBvdmVycmlkZVtfaGVpZ2h0XSA9IG92ZXJyaWRlW1wibWF4XCIgKyBfSGVpZ2h0XSA9IE1hdGguY2VpbChib3VuZHMuaGVpZ2h0KSArIF9weDtcbiAgICAgICAgICBvdmVycmlkZVtfbWFyZ2luXSA9IG92ZXJyaWRlW19tYXJnaW4gKyBfVG9wXSA9IG92ZXJyaWRlW19tYXJnaW4gKyBfUmlnaHRdID0gb3ZlcnJpZGVbX21hcmdpbiArIF9Cb3R0b21dID0gb3ZlcnJpZGVbX21hcmdpbiArIF9MZWZ0XSA9IFwiMFwiO1xuICAgICAgICAgIG92ZXJyaWRlW19wYWRkaW5nXSA9IGNzW19wYWRkaW5nXTtcbiAgICAgICAgICBvdmVycmlkZVtfcGFkZGluZyArIF9Ub3BdID0gY3NbX3BhZGRpbmcgKyBfVG9wXTtcbiAgICAgICAgICBvdmVycmlkZVtfcGFkZGluZyArIF9SaWdodF0gPSBjc1tfcGFkZGluZyArIF9SaWdodF07XG4gICAgICAgICAgb3ZlcnJpZGVbX3BhZGRpbmcgKyBfQm90dG9tXSA9IGNzW19wYWRkaW5nICsgX0JvdHRvbV07XG4gICAgICAgICAgb3ZlcnJpZGVbX3BhZGRpbmcgKyBfTGVmdF0gPSBjc1tfcGFkZGluZyArIF9MZWZ0XTtcbiAgICAgICAgICBwaW5BY3RpdmVTdGF0ZSA9IF9jb3B5U3RhdGUocGluT3JpZ2luYWxTdGF0ZSwgb3ZlcnJpZGUsIHBpblJlcGFyZW50KTtcbiAgICAgICAgICBfcmVmcmVzaGluZ0FsbCAmJiBzY3JvbGxGdW5jKDApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGFuaW1hdGlvbikge1xuICAgICAgICAgIC8vIHRoZSBhbmltYXRpb24gbWlnaHQgYmUgYWZmZWN0aW5nIHRoZSB0cmFuc2Zvcm0sIHNvIHdlIG11c3QganVtcCB0byB0aGUgZW5kLCBjaGVjayB0aGUgdmFsdWUsIGFuZCBjb21wZW5zYXRlIGFjY29yZGluZ2x5LiBPdGhlcndpc2UsIHdoZW4gaXQgYmVjb21lcyB1bnBpbm5lZCwgdGhlIHBpblNldHRlcigpIHdpbGwgZ2V0IHNldCB0byBhIHZhbHVlIHRoYXQgZG9lc24ndCBpbmNsdWRlIHdoYXRldmVyIHRoZSBhbmltYXRpb24gZGlkLlxuICAgICAgICAgIGluaXR0ZWQgPSBhbmltYXRpb24uX2luaXR0ZWQ7IC8vIGlmIG5vdCwgd2UgbXVzdCBpbnZhbGlkYXRlKCkgYWZ0ZXIgdGhpcyBzdGVwLCBvdGhlcndpc2UgaXQgY291bGQgbG9jayBpbiBzdGFydGluZyB2YWx1ZXMgcHJlbWF0dXJlbHkuXG5cbiAgICAgICAgICBfc3VwcHJlc3NPdmVyd3JpdGVzKDEpO1xuXG4gICAgICAgICAgYW5pbWF0aW9uLnJlbmRlcihhbmltYXRpb24uZHVyYXRpb24oKSwgdHJ1ZSwgdHJ1ZSk7XG4gICAgICAgICAgcGluQ2hhbmdlID0gcGluR2V0dGVyKGRpcmVjdGlvbi5hKSAtIHBpblN0YXJ0ICsgY2hhbmdlICsgb3RoZXJQaW5PZmZzZXQ7XG4gICAgICAgICAgcGluTW92ZXMgPSBNYXRoLmFicyhjaGFuZ2UgLSBwaW5DaGFuZ2UpID4gMTtcbiAgICAgICAgICB1c2VGaXhlZFBvc2l0aW9uICYmIHBpbk1vdmVzICYmIHBpbkFjdGl2ZVN0YXRlLnNwbGljZShwaW5BY3RpdmVTdGF0ZS5sZW5ndGggLSAyLCAyKTsgLy8gdHJhbnNmb3JtIGlzIHRoZSBsYXN0IHByb3BlcnR5L3ZhbHVlIHNldCBpbiB0aGUgc3RhdGUgQXJyYXkuIFNpbmNlIHRoZSBhbmltYXRpb24gaXMgY29udHJvbGxpbmcgdGhhdCwgd2Ugc2hvdWxkIG9taXQgaXQuXG5cbiAgICAgICAgICBhbmltYXRpb24ucmVuZGVyKDAsIHRydWUsIHRydWUpO1xuICAgICAgICAgIGluaXR0ZWQgfHwgYW5pbWF0aW9uLmludmFsaWRhdGUodHJ1ZSk7XG4gICAgICAgICAgYW5pbWF0aW9uLnBhcmVudCB8fCBhbmltYXRpb24udG90YWxUaW1lKGFuaW1hdGlvbi50b3RhbFRpbWUoKSk7IC8vIGlmLCBmb3IgZXhhbXBsZSwgYSB0b2dnbGVBY3Rpb24gY2FsbGVkIHBsYXkoKSBhbmQgdGhlbiByZWZyZXNoKCkgaGFwcGVucyBhbmQgd2hlbiB3ZSByZW5kZXIoMSkgYWJvdmUsIGl0IHdvdWxkIGNhdXNlIHRoZSBhbmltYXRpb24gdG8gY29tcGxldGUgYW5kIGdldCByZW1vdmVkIGZyb20gaXRzIHBhcmVudCwgc28gdGhpcyBtYWtlcyBzdXJlIGl0IGdldHMgcHV0IGJhY2sgaW4uXG5cbiAgICAgICAgICBfc3VwcHJlc3NPdmVyd3JpdGVzKDApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHBpbkNoYW5nZSA9IGNoYW5nZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZvcmNlZE92ZXJmbG93ICYmIChmb3JjZWRPdmVyZmxvdy52YWx1ZSA/IGZvcmNlZE92ZXJmbG93LnN0eWxlW1wib3ZlcmZsb3dcIiArIGRpcmVjdGlvbi5hLnRvVXBwZXJDYXNlKCldID0gZm9yY2VkT3ZlcmZsb3cudmFsdWUgOiBmb3JjZWRPdmVyZmxvdy5zdHlsZS5yZW1vdmVQcm9wZXJ0eShcIm92ZXJmbG93LVwiICsgZGlyZWN0aW9uLmEpKTtcbiAgICAgIH0gZWxzZSBpZiAodHJpZ2dlciAmJiBzY3JvbGxGdW5jKCkgJiYgIWNvbnRhaW5lckFuaW1hdGlvbikge1xuICAgICAgICAvLyBpdCBtYXkgYmUgSU5TSURFIGEgcGlubmVkIGVsZW1lbnQsIHNvIHdhbGsgdXAgdGhlIHRyZWUgYW5kIGxvb2sgZm9yIGFueSBlbGVtZW50cyB3aXRoIF9waW5PZmZzZXQgdG8gY29tcGVuc2F0ZSBiZWNhdXNlIGFueXRoaW5nIHdpdGggcGluU3BhY2luZyB0aGF0J3MgYWxyZWFkeSBzY3JvbGxlZCB3b3VsZCB0aHJvdyBvZmYgdGhlIG1lYXN1cmVtZW50cyBpbiBnZXRCb3VuZGluZ0NsaWVudFJlY3QoKVxuICAgICAgICBib3VuZHMgPSB0cmlnZ2VyLnBhcmVudE5vZGU7XG5cbiAgICAgICAgd2hpbGUgKGJvdW5kcyAmJiBib3VuZHMgIT09IF9ib2R5KSB7XG4gICAgICAgICAgaWYgKGJvdW5kcy5fcGluT2Zmc2V0KSB7XG4gICAgICAgICAgICBzdGFydCAtPSBib3VuZHMuX3Bpbk9mZnNldDtcbiAgICAgICAgICAgIGVuZCAtPSBib3VuZHMuX3Bpbk9mZnNldDtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBib3VuZHMgPSBib3VuZHMucGFyZW50Tm9kZTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXZlcnRlZFBpbnMgJiYgcmV2ZXJ0ZWRQaW5zLmZvckVhY2goZnVuY3Rpb24gKHQpIHtcbiAgICAgICAgcmV0dXJuIHQucmV2ZXJ0KGZhbHNlLCB0cnVlKTtcbiAgICAgIH0pO1xuICAgICAgc2VsZi5zdGFydCA9IHN0YXJ0O1xuICAgICAgc2VsZi5lbmQgPSBlbmQ7XG4gICAgICBzY3JvbGwxID0gc2Nyb2xsMiA9IF9yZWZyZXNoaW5nQWxsID8gcHJldlNjcm9sbCA6IHNjcm9sbEZ1bmMoKTsgLy8gcmVzZXQgdmVsb2NpdHlcblxuICAgICAgaWYgKCFjb250YWluZXJBbmltYXRpb24gJiYgIV9yZWZyZXNoaW5nQWxsKSB7XG4gICAgICAgIHNjcm9sbDEgPCBwcmV2U2Nyb2xsICYmIHNjcm9sbEZ1bmMocHJldlNjcm9sbCk7XG4gICAgICAgIHNlbGYuc2Nyb2xsLnJlYyA9IDA7XG4gICAgICB9XG5cbiAgICAgIHNlbGYucmV2ZXJ0KGZhbHNlLCB0cnVlKTtcbiAgICAgIGxhc3RSZWZyZXNoID0gX2dldFRpbWUoKTtcblxuICAgICAgaWYgKHNuYXBEZWxheWVkQ2FsbCkge1xuICAgICAgICBsYXN0U25hcCA9IC0xOyAvLyBqdXN0IHNvIHNuYXBwaW5nIGdldHMgcmUtZW5hYmxlZCwgY2xlYXIgb3V0IGFueSByZWNvcmRlZCBsYXN0IHZhbHVlXG4gICAgICAgIC8vIHNlbGYuaXNBY3RpdmUgJiYgc2Nyb2xsRnVuYyhzdGFydCArIGNoYW5nZSAqIHByZXZQcm9ncmVzcyk7IC8vIHByZXZpb3VzbHkgdGhpcyBsaW5lIHdhcyBoZXJlIHRvIGVuc3VyZSB0aGF0IHdoZW4gc25hcHBpbmcga2lja3MgaW4sIGl0J3MgZnJvbSB0aGUgcHJldmlvdXMgcHJvZ3Jlc3MgYnV0IGluIHNvbWUgY2FzZXMgdGhhdCdzIG5vdCBkZXNpcmFibGUsIGxpa2UgYW4gYWxsLXBhZ2UgU2Nyb2xsVHJpZ2dlciB3aGVuIG5ldyBjb250ZW50IGdldHMgYWRkZWQgdG8gdGhlIHBhZ2UsIHRoYXQnZCB0b3RhbGx5IGNoYW5nZSB0aGUgcHJvZ3Jlc3MuXG5cbiAgICAgICAgc25hcERlbGF5ZWRDYWxsLnJlc3RhcnQodHJ1ZSk7XG4gICAgICB9XG5cbiAgICAgIF9yZWZyZXNoaW5nID0gMDtcbiAgICAgIGFuaW1hdGlvbiAmJiBpc1RvZ2dsZSAmJiAoYW5pbWF0aW9uLl9pbml0dGVkIHx8IHByZXZBbmltUHJvZ3Jlc3MpICYmIGFuaW1hdGlvbi5wcm9ncmVzcygpICE9PSBwcmV2QW5pbVByb2dyZXNzICYmIGFuaW1hdGlvbi5wcm9ncmVzcyhwcmV2QW5pbVByb2dyZXNzIHx8IDAsIHRydWUpLnJlbmRlcihhbmltYXRpb24udGltZSgpLCB0cnVlLCB0cnVlKTsgLy8gbXVzdCBmb3JjZSBhIHJlLXJlbmRlciBiZWNhdXNlIGlmIHNhdmVTdHlsZXMoKSB3YXMgdXNlZCBvbiB0aGUgdGFyZ2V0KHMpLCB0aGUgc3R5bGVzIGNvdWxkIGhhdmUgYmVlbiB3aXBlZCBvdXQgZHVyaW5nIHRoZSByZWZyZXNoKCkuXG5cbiAgICAgIGlmIChpc0ZpcnN0UmVmcmVzaCB8fCBwcmV2UHJvZ3Jlc3MgIT09IHNlbGYucHJvZ3Jlc3MgfHwgY29udGFpbmVyQW5pbWF0aW9uIHx8IGludmFsaWRhdGVPblJlZnJlc2gpIHtcbiAgICAgICAgLy8gZW5zdXJlcyB0aGF0IHRoZSBkaXJlY3Rpb24gaXMgc2V0IHByb3Blcmx5ICh3aGVuIHJlZnJlc2hpbmcsIHByb2dyZXNzIGlzIHNldCBiYWNrIHRvIDAgaW5pdGlhbGx5LCB0aGVuIGJhY2sgYWdhaW4gdG8gd2hlcmV2ZXIgaXQgbmVlZHMgdG8gYmUpIGFuZCB0aGF0IGNhbGxiYWNrcyBhcmUgdHJpZ2dlcmVkLlxuICAgICAgICBhbmltYXRpb24gJiYgIWlzVG9nZ2xlICYmIGFuaW1hdGlvbi50b3RhbFByb2dyZXNzKGNvbnRhaW5lckFuaW1hdGlvbiAmJiBzdGFydCA8IC0wLjAwMSAmJiAhcHJldlByb2dyZXNzID8gZ3NhcC51dGlscy5ub3JtYWxpemUoc3RhcnQsIGVuZCwgMCkgOiBwcmV2UHJvZ3Jlc3MsIHRydWUpOyAvLyB0byBhdm9pZCBpc3N1ZXMgd2hlcmUgYW5pbWF0aW9uIGNhbGxiYWNrcyBsaWtlIG9uU3RhcnQgYXJlbid0IHRyaWdnZXJlZC5cblxuICAgICAgICBzZWxmLnByb2dyZXNzID0gaXNGaXJzdFJlZnJlc2ggfHwgKHNjcm9sbDEgLSBzdGFydCkgLyBjaGFuZ2UgPT09IHByZXZQcm9ncmVzcyA/IDAgOiBwcmV2UHJvZ3Jlc3M7XG4gICAgICB9XG5cbiAgICAgIHBpbiAmJiBwaW5TcGFjaW5nICYmIChzcGFjZXIuX3Bpbk9mZnNldCA9IE1hdGgucm91bmQoc2VsZi5wcm9ncmVzcyAqIHBpbkNoYW5nZSkpO1xuICAgICAgc2NydWJUd2VlbiAmJiBzY3J1YlR3ZWVuLmludmFsaWRhdGUoKTtcblxuICAgICAgaWYgKCFpc05hTihtYXJrZXJTdGFydE9mZnNldCkpIHtcbiAgICAgICAgLy8gbnVtYmVycyB3ZXJlIHBhc3NlZCBpbiBmb3IgdGhlIHBvc2l0aW9uIHdoaWNoIGFyZSBhYnNvbHV0ZSwgc28gaW5zdGVhZCBvZiBqdXN0IHB1dHRpbmcgdGhlIG1hcmtlcnMgYXQgdGhlIHZlcnkgYm90dG9tIG9mIHRoZSB2aWV3cG9ydCwgd2UgZmlndXJlIG91dCBob3cgZmFyIHRoZXkgc2hpZnRlZCBkb3duIChpdCdzIHNhZmUgdG8gYXNzdW1lIHRoZXkgd2VyZSBvcmlnaW5hbGx5IHBvc2l0aW9uZWQgaW4gY2xvc2VyIHJlbGF0aW9uIHRvIHRoZSB0cmlnZ2VyIGVsZW1lbnQgd2l0aCB2YWx1ZXMgbGlrZSBcInRvcFwiLCBcImNlbnRlclwiLCBhIHBlcmNlbnRhZ2Ugb3Igd2hhdGV2ZXIsIHNvIHdlIG9mZnNldCB0aGF0IG11Y2ggaW4gdGhlIG9wcG9zaXRlIGRpcmVjdGlvbiB0byBiYXNpY2FsbHkgcmV2ZXJ0IHRoZW0gdG8gdGhlIHJlbGF0aXZlIHBvc2l0aW9uIHRoeSB3ZXJlIGF0IHByZXZpb3VzbHkuXG4gICAgICAgIG1hcmtlclN0YXJ0T2Zmc2V0IC09IGdzYXAuZ2V0UHJvcGVydHkobWFya2VyU3RhcnRUcmlnZ2VyLCBkaXJlY3Rpb24ucCk7XG4gICAgICAgIG1hcmtlckVuZE9mZnNldCAtPSBnc2FwLmdldFByb3BlcnR5KG1hcmtlckVuZFRyaWdnZXIsIGRpcmVjdGlvbi5wKTtcblxuICAgICAgICBfc2hpZnRNYXJrZXIobWFya2VyU3RhcnRUcmlnZ2VyLCBkaXJlY3Rpb24sIG1hcmtlclN0YXJ0T2Zmc2V0KTtcblxuICAgICAgICBfc2hpZnRNYXJrZXIobWFya2VyU3RhcnQsIGRpcmVjdGlvbiwgbWFya2VyU3RhcnRPZmZzZXQgLSAocGluT2Zmc2V0IHx8IDApKTtcblxuICAgICAgICBfc2hpZnRNYXJrZXIobWFya2VyRW5kVHJpZ2dlciwgZGlyZWN0aW9uLCBtYXJrZXJFbmRPZmZzZXQpO1xuXG4gICAgICAgIF9zaGlmdE1hcmtlcihtYXJrZXJFbmQsIGRpcmVjdGlvbiwgbWFya2VyRW5kT2Zmc2V0IC0gKHBpbk9mZnNldCB8fCAwKSk7XG4gICAgICB9XG5cbiAgICAgIGlzRmlyc3RSZWZyZXNoICYmICFfcmVmcmVzaGluZ0FsbCAmJiBzZWxmLnVwZGF0ZSgpOyAvLyBlZGdlIGNhc2UgLSB3aGVuIHlvdSByZWxvYWQgYSBwYWdlIHdoZW4gaXQncyBhbHJlYWR5IHNjcm9sbGVkIGRvd24sIHNvbWUgYnJvd3NlcnMgZmlyZSBhIFwic2Nyb2xsXCIgZXZlbnQgYmVmb3JlIERPTUNvbnRlbnRMb2FkZWQsIHRyaWdnZXJpbmcgYW4gdXBkYXRlQWxsKCkuIElmIHdlIGRvbid0IHVwZGF0ZSB0aGUgc2VsZi5wcm9ncmVzcyBhcyBwYXJ0IG9mIHJlZnJlc2goKSwgdGhlbiB3aGVuIGl0IGhhcHBlbnMgbmV4dCwgaXQgbWF5IHJlY29yZCBwcmV2UHJvZ3Jlc3MgYXMgMCB3aGVuIGl0IHJlYWxseSBzaG91bGRuJ3QsIHBvdGVudGlhbGx5IGNhdXNpbmcgYSBjYWxsYmFjayBpbiBhbiBhbmltYXRpb24gdG8gZmlyZSBhZ2Fpbi5cblxuICAgICAgaWYgKG9uUmVmcmVzaCAmJiAhX3JlZnJlc2hpbmdBbGwgJiYgIWV4ZWN1dGluZ09uUmVmcmVzaCkge1xuICAgICAgICAvLyB3aGVuIHJlZnJlc2hpbmcgYWxsLCB3ZSBkbyBleHRyYSB3b3JrIHRvIGNvcnJlY3QgcGlubmVkQ29udGFpbmVyIHNpemVzIGFuZCBlbnN1cmUgdGhpbmdzIGRvbid0IGV4Y2VlZCB0aGUgbWF4U2Nyb2xsLCBzbyB3ZSBzaG91bGQgZG8gYWxsIHRoZSByZWZyZXNoZXMgYXQgdGhlIGVuZCBhZnRlciBhbGwgdGhhdCB3b3JrIHNvIHRoYXQgdGhlIHN0YXJ0L2VuZCB2YWx1ZXMgYXJlIGNvcnJlY3RlZC5cbiAgICAgICAgZXhlY3V0aW5nT25SZWZyZXNoID0gdHJ1ZTtcbiAgICAgICAgb25SZWZyZXNoKHNlbGYpO1xuICAgICAgICBleGVjdXRpbmdPblJlZnJlc2ggPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgc2VsZi5nZXRWZWxvY2l0eSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiAoc2Nyb2xsRnVuYygpIC0gc2Nyb2xsMikgLyAoX2dldFRpbWUoKSAtIF90aW1lMikgKiAxMDAwIHx8IDA7XG4gICAgfTtcblxuICAgIHNlbGYuZW5kQW5pbWF0aW9uID0gZnVuY3Rpb24gKCkge1xuICAgICAgX2VuZEFuaW1hdGlvbihzZWxmLmNhbGxiYWNrQW5pbWF0aW9uKTtcblxuICAgICAgaWYgKGFuaW1hdGlvbikge1xuICAgICAgICBzY3J1YlR3ZWVuID8gc2NydWJUd2Vlbi5wcm9ncmVzcygxKSA6ICFhbmltYXRpb24ucGF1c2VkKCkgPyBfZW5kQW5pbWF0aW9uKGFuaW1hdGlvbiwgYW5pbWF0aW9uLnJldmVyc2VkKCkpIDogaXNUb2dnbGUgfHwgX2VuZEFuaW1hdGlvbihhbmltYXRpb24sIHNlbGYuZGlyZWN0aW9uIDwgMCwgMSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHNlbGYubGFiZWxUb1Njcm9sbCA9IGZ1bmN0aW9uIChsYWJlbCkge1xuICAgICAgcmV0dXJuIGFuaW1hdGlvbiAmJiBhbmltYXRpb24ubGFiZWxzICYmIChzdGFydCB8fCBzZWxmLnJlZnJlc2goKSB8fCBzdGFydCkgKyBhbmltYXRpb24ubGFiZWxzW2xhYmVsXSAvIGFuaW1hdGlvbi5kdXJhdGlvbigpICogY2hhbmdlIHx8IDA7XG4gICAgfTtcblxuICAgIHNlbGYuZ2V0VHJhaWxpbmcgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgICAgdmFyIGkgPSBfdHJpZ2dlcnMuaW5kZXhPZihzZWxmKSxcbiAgICAgICAgICBhID0gc2VsZi5kaXJlY3Rpb24gPiAwID8gX3RyaWdnZXJzLnNsaWNlKDAsIGkpLnJldmVyc2UoKSA6IF90cmlnZ2Vycy5zbGljZShpICsgMSk7XG5cbiAgICAgIHJldHVybiAoX2lzU3RyaW5nKG5hbWUpID8gYS5maWx0ZXIoZnVuY3Rpb24gKHQpIHtcbiAgICAgICAgcmV0dXJuIHQudmFycy5wcmV2ZW50T3ZlcmxhcHMgPT09IG5hbWU7XG4gICAgICB9KSA6IGEpLmZpbHRlcihmdW5jdGlvbiAodCkge1xuICAgICAgICByZXR1cm4gc2VsZi5kaXJlY3Rpb24gPiAwID8gdC5lbmQgPD0gc3RhcnQgOiB0LnN0YXJ0ID49IGVuZDtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICBzZWxmLnVwZGF0ZSA9IGZ1bmN0aW9uIChyZXNldCwgcmVjb3JkVmVsb2NpdHksIGZvcmNlRmFrZSkge1xuICAgICAgaWYgKGNvbnRhaW5lckFuaW1hdGlvbiAmJiAhZm9yY2VGYWtlICYmICFyZXNldCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHZhciBzY3JvbGwgPSBfcmVmcmVzaGluZ0FsbCA9PT0gdHJ1ZSA/IHByZXZTY3JvbGwgOiBzZWxmLnNjcm9sbCgpLFxuICAgICAgICAgIHAgPSByZXNldCA/IDAgOiAoc2Nyb2xsIC0gc3RhcnQpIC8gY2hhbmdlLFxuICAgICAgICAgIGNsaXBwZWQgPSBwIDwgMCA/IDAgOiBwID4gMSA/IDEgOiBwIHx8IDAsXG4gICAgICAgICAgcHJldlByb2dyZXNzID0gc2VsZi5wcm9ncmVzcyxcbiAgICAgICAgICBpc0FjdGl2ZSxcbiAgICAgICAgICB3YXNBY3RpdmUsXG4gICAgICAgICAgdG9nZ2xlU3RhdGUsXG4gICAgICAgICAgYWN0aW9uLFxuICAgICAgICAgIHN0YXRlQ2hhbmdlZCxcbiAgICAgICAgICB0b2dnbGVkLFxuICAgICAgICAgIGlzQXRNYXgsXG4gICAgICAgICAgaXNUYWtpbmdBY3Rpb247XG5cbiAgICAgIGlmIChyZWNvcmRWZWxvY2l0eSkge1xuICAgICAgICBzY3JvbGwyID0gc2Nyb2xsMTtcbiAgICAgICAgc2Nyb2xsMSA9IGNvbnRhaW5lckFuaW1hdGlvbiA/IHNjcm9sbEZ1bmMoKSA6IHNjcm9sbDtcblxuICAgICAgICBpZiAoc25hcCkge1xuICAgICAgICAgIHNuYXAyID0gc25hcDE7XG4gICAgICAgICAgc25hcDEgPSBhbmltYXRpb24gJiYgIWlzVG9nZ2xlID8gYW5pbWF0aW9uLnRvdGFsUHJvZ3Jlc3MoKSA6IGNsaXBwZWQ7XG4gICAgICAgIH1cbiAgICAgIH0gLy8gYW50aWNpcGF0ZSB0aGUgcGlubmluZyBhIGZldyB0aWNrcyBhaGVhZCBvZiB0aW1lIGJhc2VkIG9uIHZlbG9jaXR5IHRvIGF2b2lkIGEgdmlzdWFsIGdsaXRjaCBkdWUgdG8gdGhlIGZhY3QgdGhhdCBtb3N0IGJyb3dzZXJzIGRvIHNjcm9sbGluZyBvbiBhIHNlcGFyYXRlIHRocmVhZCAobm90IHN5bmNlZCB3aXRoIHJlcXVlc3RBbmltYXRpb25GcmFtZSkuXG5cblxuICAgICAgaWYgKGFudGljaXBhdGVQaW4gJiYgcGluICYmICFfcmVmcmVzaGluZyAmJiAhX3N0YXJ0dXAgJiYgX2xhc3RTY3JvbGxUaW1lKSB7XG4gICAgICAgIGlmICghY2xpcHBlZCAmJiBzdGFydCA8IHNjcm9sbCArIChzY3JvbGwgLSBzY3JvbGwyKSAvIChfZ2V0VGltZSgpIC0gX3RpbWUyKSAqIGFudGljaXBhdGVQaW4pIHtcbiAgICAgICAgICBjbGlwcGVkID0gMC4wMDAxO1xuICAgICAgICB9IGVsc2UgaWYgKGNsaXBwZWQgPT09IDEgJiYgZW5kID4gc2Nyb2xsICsgKHNjcm9sbCAtIHNjcm9sbDIpIC8gKF9nZXRUaW1lKCkgLSBfdGltZTIpICogYW50aWNpcGF0ZVBpbikge1xuICAgICAgICAgIGNsaXBwZWQgPSAwLjk5OTk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGNsaXBwZWQgIT09IHByZXZQcm9ncmVzcyAmJiBzZWxmLmVuYWJsZWQpIHtcbiAgICAgICAgaXNBY3RpdmUgPSBzZWxmLmlzQWN0aXZlID0gISFjbGlwcGVkICYmIGNsaXBwZWQgPCAxO1xuICAgICAgICB3YXNBY3RpdmUgPSAhIXByZXZQcm9ncmVzcyAmJiBwcmV2UHJvZ3Jlc3MgPCAxO1xuICAgICAgICB0b2dnbGVkID0gaXNBY3RpdmUgIT09IHdhc0FjdGl2ZTtcbiAgICAgICAgc3RhdGVDaGFuZ2VkID0gdG9nZ2xlZCB8fCAhIWNsaXBwZWQgIT09ICEhcHJldlByb2dyZXNzOyAvLyBjb3VsZCBnbyBmcm9tIHN0YXJ0IGFsbCB0aGUgd2F5IHRvIGVuZCwgdGh1cyBpdCBkaWRuJ3QgdG9nZ2xlIGJ1dCBpdCBkaWQgY2hhbmdlIHN0YXRlIGluIGEgc2Vuc2UgKG1heSBuZWVkIHRvIGZpcmUgYSBjYWxsYmFjaylcblxuICAgICAgICBzZWxmLmRpcmVjdGlvbiA9IGNsaXBwZWQgPiBwcmV2UHJvZ3Jlc3MgPyAxIDogLTE7XG4gICAgICAgIHNlbGYucHJvZ3Jlc3MgPSBjbGlwcGVkO1xuXG4gICAgICAgIGlmIChzdGF0ZUNoYW5nZWQgJiYgIV9yZWZyZXNoaW5nKSB7XG4gICAgICAgICAgdG9nZ2xlU3RhdGUgPSBjbGlwcGVkICYmICFwcmV2UHJvZ3Jlc3MgPyAwIDogY2xpcHBlZCA9PT0gMSA/IDEgOiBwcmV2UHJvZ3Jlc3MgPT09IDEgPyAyIDogMzsgLy8gMCA9IGVudGVyLCAxID0gbGVhdmUsIDIgPSBlbnRlckJhY2ssIDMgPSBsZWF2ZUJhY2sgKHdlIHByaW9yaXRpemUgdGhlIEZJUlNUIGVuY291bnRlciwgdGh1cyBpZiB5b3Ugc2Nyb2xsIHJlYWxseSBmYXN0IHBhc3QgdGhlIG9uRW50ZXIgYW5kIG9uTGVhdmUgaW4gb25lIHRpY2ssIGl0J2QgcHJpb3JpdGl6ZSBvbkVudGVyLlxuXG4gICAgICAgICAgaWYgKGlzVG9nZ2xlKSB7XG4gICAgICAgICAgICBhY3Rpb24gPSAhdG9nZ2xlZCAmJiB0b2dnbGVBY3Rpb25zW3RvZ2dsZVN0YXRlICsgMV0gIT09IFwibm9uZVwiICYmIHRvZ2dsZUFjdGlvbnNbdG9nZ2xlU3RhdGUgKyAxXSB8fCB0b2dnbGVBY3Rpb25zW3RvZ2dsZVN0YXRlXTsgLy8gaWYgaXQgZGlkbid0IHRvZ2dsZSwgdGhhdCBtZWFucyBpdCBzaG90IHJpZ2h0IHBhc3QgYW5kIHNpbmNlIHdlIHByaW9yaXRpemUgdGhlIFwiZW50ZXJcIiBhY3Rpb24sIHdlIHNob3VsZCBzd2l0Y2ggdG8gdGhlIFwibGVhdmVcIiBpbiB0aGlzIGNhc2UgKGJ1dCBvbmx5IGlmIG9uZSBpcyBkZWZpbmVkKVxuXG4gICAgICAgICAgICBpc1Rha2luZ0FjdGlvbiA9IGFuaW1hdGlvbiAmJiAoYWN0aW9uID09PSBcImNvbXBsZXRlXCIgfHwgYWN0aW9uID09PSBcInJlc2V0XCIgfHwgYWN0aW9uIGluIGFuaW1hdGlvbik7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcHJldmVudE92ZXJsYXBzICYmICh0b2dnbGVkIHx8IGlzVGFraW5nQWN0aW9uKSAmJiAoaXNUYWtpbmdBY3Rpb24gfHwgc2NydWIgfHwgIWFuaW1hdGlvbikgJiYgKF9pc0Z1bmN0aW9uKHByZXZlbnRPdmVybGFwcykgPyBwcmV2ZW50T3ZlcmxhcHMoc2VsZikgOiBzZWxmLmdldFRyYWlsaW5nKHByZXZlbnRPdmVybGFwcykuZm9yRWFjaChmdW5jdGlvbiAodCkge1xuICAgICAgICAgIHJldHVybiB0LmVuZEFuaW1hdGlvbigpO1xuICAgICAgICB9KSk7XG5cbiAgICAgICAgaWYgKCFpc1RvZ2dsZSkge1xuICAgICAgICAgIGlmIChzY3J1YlR3ZWVuICYmICFfcmVmcmVzaGluZyAmJiAhX3N0YXJ0dXApIHtcbiAgICAgICAgICAgIHNjcnViVHdlZW4uX2RwLl90aW1lIC0gc2NydWJUd2Vlbi5fc3RhcnQgIT09IHNjcnViVHdlZW4uX3RpbWUgJiYgc2NydWJUd2Vlbi5yZW5kZXIoc2NydWJUd2Vlbi5fZHAuX3RpbWUgLSBzY3J1YlR3ZWVuLl9zdGFydCk7IC8vIGlmIHRoZXJlJ3MgYSBzY3J1YiBvbiBib3RoIHRoZSBjb250YWluZXIgYW5pbWF0aW9uIGFuZCB0aGlzIG9uZSAob3IgYSBTY3JvbGxTbW9vdGhlciksIHRoZSB1cGRhdGUgb3JkZXIgd291bGQgY2F1c2UgdGhpcyBvbmUgbm90IHRvIGhhdmUgcmVuZGVyZWQgeWV0LCBzbyBpdCB3b3VsZG4ndCBtYWtlIGFueSBwcm9ncmVzcyBiZWZvcmUgd2UgLnJlc3RhcnQoKSBpdCBoZWFkaW5nIHRvd2FyZCB0aGUgbmV3IHByb2dyZXNzIHNvIGl0J2QgYXBwZWFyIHN0dWNrIHRodXMgd2UgZm9yY2UgYSByZW5kZXIgaGVyZS5cblxuICAgICAgICAgICAgaWYgKHNjcnViVHdlZW4ucmVzZXRUbykge1xuICAgICAgICAgICAgICBzY3J1YlR3ZWVuLnJlc2V0VG8oXCJ0b3RhbFByb2dyZXNzXCIsIGNsaXBwZWQsIGFuaW1hdGlvbi5fdFRpbWUgLyBhbmltYXRpb24uX3REdXIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgLy8gbGVnYWN5IHN1cHBvcnQgKGNvdXJ0ZXN5KSwgYmVmb3JlIDMuMTAuMFxuICAgICAgICAgICAgICBzY3J1YlR3ZWVuLnZhcnMudG90YWxQcm9ncmVzcyA9IGNsaXBwZWQ7XG4gICAgICAgICAgICAgIHNjcnViVHdlZW4uaW52YWxpZGF0ZSgpLnJlc3RhcnQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2UgaWYgKGFuaW1hdGlvbikge1xuICAgICAgICAgICAgYW5pbWF0aW9uLnRvdGFsUHJvZ3Jlc3MoY2xpcHBlZCwgISEoX3JlZnJlc2hpbmcgJiYgKGxhc3RSZWZyZXNoIHx8IHJlc2V0KSkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwaW4pIHtcbiAgICAgICAgICByZXNldCAmJiBwaW5TcGFjaW5nICYmIChzcGFjZXIuc3R5bGVbcGluU3BhY2luZyArIGRpcmVjdGlvbi5vczJdID0gc3BhY2luZ1N0YXJ0KTtcblxuICAgICAgICAgIGlmICghdXNlRml4ZWRQb3NpdGlvbikge1xuICAgICAgICAgICAgcGluU2V0dGVyKF9yb3VuZChwaW5TdGFydCArIHBpbkNoYW5nZSAqIGNsaXBwZWQpKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKHN0YXRlQ2hhbmdlZCkge1xuICAgICAgICAgICAgaXNBdE1heCA9ICFyZXNldCAmJiBjbGlwcGVkID4gcHJldlByb2dyZXNzICYmIGVuZCArIDEgPiBzY3JvbGwgJiYgc2Nyb2xsICsgMSA+PSBfbWF4U2Nyb2xsKHNjcm9sbGVyLCBkaXJlY3Rpb24pOyAvLyBpZiBpdCdzIGF0IHRoZSBWRVJZIGVuZCBvZiB0aGUgcGFnZSwgZG9uJ3Qgc3dpdGNoIGF3YXkgZnJvbSBwb3NpdGlvbjogZml4ZWQgYmVjYXVzZSBpdCdzIHBvaW50bGVzcyBhbmQgaXQgY291bGQgY2F1c2UgYSBicmllZiBmbGFzaCB3aGVuIHRoZSB1c2VyIHNjcm9sbHMgYmFjayB1cCAod2hlbiBpdCBnZXRzIHBpbm5lZCBhZ2FpbilcblxuICAgICAgICAgICAgaWYgKHBpblJlcGFyZW50KSB7XG4gICAgICAgICAgICAgIGlmICghcmVzZXQgJiYgKGlzQWN0aXZlIHx8IGlzQXRNYXgpKSB7XG4gICAgICAgICAgICAgICAgdmFyIGJvdW5kcyA9IF9nZXRCb3VuZHMocGluLCB0cnVlKSxcbiAgICAgICAgICAgICAgICAgICAgX29mZnNldCA9IHNjcm9sbCAtIHN0YXJ0O1xuXG4gICAgICAgICAgICAgICAgX3JlcGFyZW50KHBpbiwgX2JvZHksIGJvdW5kcy50b3AgKyAoZGlyZWN0aW9uID09PSBfdmVydGljYWwgPyBfb2Zmc2V0IDogMCkgKyBfcHgsIGJvdW5kcy5sZWZ0ICsgKGRpcmVjdGlvbiA9PT0gX3ZlcnRpY2FsID8gMCA6IF9vZmZzZXQpICsgX3B4KTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBfcmVwYXJlbnQocGluLCBzcGFjZXIpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIF9zZXRTdGF0ZShpc0FjdGl2ZSB8fCBpc0F0TWF4ID8gcGluQWN0aXZlU3RhdGUgOiBwaW5TdGF0ZSk7XG5cbiAgICAgICAgICAgIHBpbk1vdmVzICYmIGNsaXBwZWQgPCAxICYmIGlzQWN0aXZlIHx8IHBpblNldHRlcihwaW5TdGFydCArIChjbGlwcGVkID09PSAxICYmICFpc0F0TWF4ID8gcGluQ2hhbmdlIDogMCkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHNuYXAgJiYgIXR3ZWVuVG8udHdlZW4gJiYgIV9yZWZyZXNoaW5nICYmICFfc3RhcnR1cCAmJiBzbmFwRGVsYXllZENhbGwucmVzdGFydCh0cnVlKTtcbiAgICAgICAgdG9nZ2xlQ2xhc3MgJiYgKHRvZ2dsZWQgfHwgb25jZSAmJiBjbGlwcGVkICYmIChjbGlwcGVkIDwgMSB8fCAhX2xpbWl0Q2FsbGJhY2tzKSkgJiYgX3RvQXJyYXkodG9nZ2xlQ2xhc3MudGFyZ2V0cykuZm9yRWFjaChmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgICByZXR1cm4gZWwuY2xhc3NMaXN0W2lzQWN0aXZlIHx8IG9uY2UgPyBcImFkZFwiIDogXCJyZW1vdmVcIl0odG9nZ2xlQ2xhc3MuY2xhc3NOYW1lKTtcbiAgICAgICAgfSk7IC8vIGNsYXNzZXMgY291bGQgYWZmZWN0IHBvc2l0aW9uaW5nLCBzbyBkbyBpdCBldmVuIGlmIHJlc2V0IG9yIHJlZnJlc2hpbmcgaXMgdHJ1ZS5cblxuICAgICAgICBvblVwZGF0ZSAmJiAhaXNUb2dnbGUgJiYgIXJlc2V0ICYmIG9uVXBkYXRlKHNlbGYpO1xuXG4gICAgICAgIGlmIChzdGF0ZUNoYW5nZWQgJiYgIV9yZWZyZXNoaW5nKSB7XG4gICAgICAgICAgaWYgKGlzVG9nZ2xlKSB7XG4gICAgICAgICAgICBpZiAoaXNUYWtpbmdBY3Rpb24pIHtcbiAgICAgICAgICAgICAgaWYgKGFjdGlvbiA9PT0gXCJjb21wbGV0ZVwiKSB7XG4gICAgICAgICAgICAgICAgYW5pbWF0aW9uLnBhdXNlKCkudG90YWxQcm9ncmVzcygxKTtcbiAgICAgICAgICAgICAgfSBlbHNlIGlmIChhY3Rpb24gPT09IFwicmVzZXRcIikge1xuICAgICAgICAgICAgICAgIGFuaW1hdGlvbi5yZXN0YXJ0KHRydWUpLnBhdXNlKCk7XG4gICAgICAgICAgICAgIH0gZWxzZSBpZiAoYWN0aW9uID09PSBcInJlc3RhcnRcIikge1xuICAgICAgICAgICAgICAgIGFuaW1hdGlvbi5yZXN0YXJ0KHRydWUpO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGFuaW1hdGlvblthY3Rpb25dKCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgb25VcGRhdGUgJiYgb25VcGRhdGUoc2VsZik7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHRvZ2dsZWQgfHwgIV9saW1pdENhbGxiYWNrcykge1xuICAgICAgICAgICAgLy8gb24gc3RhcnR1cCwgdGhlIHBhZ2UgY291bGQgYmUgc2Nyb2xsZWQgYW5kIHdlIGRvbid0IHdhbnQgdG8gZmlyZSBjYWxsYmFja3MgdGhhdCBkaWRuJ3QgdG9nZ2xlLiBGb3IgZXhhbXBsZSBvbkVudGVyIHNob3VsZG4ndCBmaXJlIGlmIHRoZSBTY3JvbGxUcmlnZ2VyIGlzbid0IGFjdHVhbGx5IGVudGVyZWQuXG4gICAgICAgICAgICBvblRvZ2dsZSAmJiB0b2dnbGVkICYmIF9jYWxsYmFjayhzZWxmLCBvblRvZ2dsZSk7XG4gICAgICAgICAgICBjYWxsYmFja3NbdG9nZ2xlU3RhdGVdICYmIF9jYWxsYmFjayhzZWxmLCBjYWxsYmFja3NbdG9nZ2xlU3RhdGVdKTtcbiAgICAgICAgICAgIG9uY2UgJiYgKGNsaXBwZWQgPT09IDEgPyBzZWxmLmtpbGwoZmFsc2UsIDEpIDogY2FsbGJhY2tzW3RvZ2dsZVN0YXRlXSA9IDApOyAvLyBhIGNhbGxiYWNrIHNob3VsZG4ndCBiZSBjYWxsZWQgYWdhaW4gaWYgb25jZSBpcyB0cnVlLlxuXG4gICAgICAgICAgICBpZiAoIXRvZ2dsZWQpIHtcbiAgICAgICAgICAgICAgLy8gaXQncyBwb3NzaWJsZSB0byBnbyBjb21wbGV0ZWx5IHBhc3QsIGxpa2UgZnJvbSBiZWZvcmUgdGhlIHN0YXJ0IHRvIGFmdGVyIHRoZSBlbmQgKG9yIHZpY2UtdmVyc2EpIGluIHdoaWNoIGNhc2UgQk9USCBjYWxsYmFja3Mgc2hvdWxkIGJlIGZpcmVkIGluIHRoYXQgb3JkZXJcbiAgICAgICAgICAgICAgdG9nZ2xlU3RhdGUgPSBjbGlwcGVkID09PSAxID8gMSA6IDM7XG4gICAgICAgICAgICAgIGNhbGxiYWNrc1t0b2dnbGVTdGF0ZV0gJiYgX2NhbGxiYWNrKHNlbGYsIGNhbGxiYWNrc1t0b2dnbGVTdGF0ZV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChmYXN0U2Nyb2xsRW5kICYmICFpc0FjdGl2ZSAmJiBNYXRoLmFicyhzZWxmLmdldFZlbG9jaXR5KCkpID4gKF9pc051bWJlcihmYXN0U2Nyb2xsRW5kKSA/IGZhc3RTY3JvbGxFbmQgOiAyNTAwKSkge1xuICAgICAgICAgICAgX2VuZEFuaW1hdGlvbihzZWxmLmNhbGxiYWNrQW5pbWF0aW9uKTtcblxuICAgICAgICAgICAgc2NydWJUd2VlbiA/IHNjcnViVHdlZW4ucHJvZ3Jlc3MoMSkgOiBfZW5kQW5pbWF0aW9uKGFuaW1hdGlvbiwgYWN0aW9uID09PSBcInJldmVyc2VcIiA/IDEgOiAhY2xpcHBlZCwgMSk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKGlzVG9nZ2xlICYmIG9uVXBkYXRlICYmICFfcmVmcmVzaGluZykge1xuICAgICAgICAgIG9uVXBkYXRlKHNlbGYpO1xuICAgICAgICB9XG4gICAgICB9IC8vIHVwZGF0ZSBhYnNvbHV0ZWx5LXBvc2l0aW9uZWQgbWFya2VycyAob25seSBpZiB0aGUgc2Nyb2xsZXIgaXNuJ3QgdGhlIHZpZXdwb3J0KVxuXG5cbiAgICAgIGlmIChtYXJrZXJFbmRTZXR0ZXIpIHtcbiAgICAgICAgdmFyIG4gPSBjb250YWluZXJBbmltYXRpb24gPyBzY3JvbGwgLyBjb250YWluZXJBbmltYXRpb24uZHVyYXRpb24oKSAqIChjb250YWluZXJBbmltYXRpb24uX2NhU2Nyb2xsRGlzdCB8fCAwKSA6IHNjcm9sbDtcbiAgICAgICAgbWFya2VyU3RhcnRTZXR0ZXIobiArIChtYXJrZXJTdGFydFRyaWdnZXIuX2lzRmxpcHBlZCA/IDEgOiAwKSk7XG4gICAgICAgIG1hcmtlckVuZFNldHRlcihuKTtcbiAgICAgIH1cblxuICAgICAgY2FNYXJrZXJTZXR0ZXIgJiYgY2FNYXJrZXJTZXR0ZXIoLXNjcm9sbCAvIGNvbnRhaW5lckFuaW1hdGlvbi5kdXJhdGlvbigpICogKGNvbnRhaW5lckFuaW1hdGlvbi5fY2FTY3JvbGxEaXN0IHx8IDApKTtcbiAgICB9O1xuXG4gICAgc2VsZi5lbmFibGUgPSBmdW5jdGlvbiAocmVzZXQsIHJlZnJlc2gpIHtcbiAgICAgIGlmICghc2VsZi5lbmFibGVkKSB7XG4gICAgICAgIHNlbGYuZW5hYmxlZCA9IHRydWU7XG5cbiAgICAgICAgX2FkZExpc3RlbmVyKHNjcm9sbGVyLCBcInJlc2l6ZVwiLCBfb25SZXNpemUpO1xuXG4gICAgICAgIGlzVmlld3BvcnQgfHwgX2FkZExpc3RlbmVyKHNjcm9sbGVyLCBcInNjcm9sbFwiLCBfb25TY3JvbGwpO1xuICAgICAgICBvblJlZnJlc2hJbml0ICYmIF9hZGRMaXN0ZW5lcihTY3JvbGxUcmlnZ2VyLCBcInJlZnJlc2hJbml0XCIsIG9uUmVmcmVzaEluaXQpO1xuXG4gICAgICAgIGlmIChyZXNldCAhPT0gZmFsc2UpIHtcbiAgICAgICAgICBzZWxmLnByb2dyZXNzID0gcHJldlByb2dyZXNzID0gMDtcbiAgICAgICAgICBzY3JvbGwxID0gc2Nyb2xsMiA9IGxhc3RTbmFwID0gc2Nyb2xsRnVuYygpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmVmcmVzaCAhPT0gZmFsc2UgJiYgc2VsZi5yZWZyZXNoKCk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHNlbGYuZ2V0VHdlZW4gPSBmdW5jdGlvbiAoc25hcCkge1xuICAgICAgcmV0dXJuIHNuYXAgJiYgdHdlZW5UbyA/IHR3ZWVuVG8udHdlZW4gOiBzY3J1YlR3ZWVuO1xuICAgIH07XG5cbiAgICBzZWxmLnNldFBvc2l0aW9ucyA9IGZ1bmN0aW9uIChuZXdTdGFydCwgbmV3RW5kLCBrZWVwQ2xhbXAsIHBpbk9mZnNldCkge1xuICAgICAgLy8gZG9lc24ndCBwZXJzaXN0IGFmdGVyIHJlZnJlc2goKSEgSW50ZW5kZWQgdG8gYmUgYSB3YXkgdG8gb3ZlcnJpZGUgdmFsdWVzIHRoYXQgd2VyZSBzZXQgZHVyaW5nIHJlZnJlc2goKSwgbGlrZSB5b3UgY291bGQgc2V0IGl0IGluIG9uUmVmcmVzaCgpXG4gICAgICBpZiAoY29udGFpbmVyQW5pbWF0aW9uKSB7XG4gICAgICAgIC8vIGNvbnZlcnQgcmF0aW9zIGludG8gc2Nyb2xsIHBvc2l0aW9ucy4gUmVtZW1iZXIsIHN0YXJ0L2VuZCB2YWx1ZXMgb24gU2Nyb2xsVHJpZ2dlcnMgdGhhdCBoYXZlIGEgY29udGFpbmVyQW5pbWF0aW9uIHJlZmVyIHRvIHRoZSB0aW1lIChpbiBzZWNvbmRzKSwgTk9UIHNjcm9sbCBwb3NpdGlvbnMuXG4gICAgICAgIHZhciBzdCA9IGNvbnRhaW5lckFuaW1hdGlvbi5zY3JvbGxUcmlnZ2VyLFxuICAgICAgICAgICAgZHVyYXRpb24gPSBjb250YWluZXJBbmltYXRpb24uZHVyYXRpb24oKSxcbiAgICAgICAgICAgIF9jaGFuZ2UgPSBzdC5lbmQgLSBzdC5zdGFydDtcblxuICAgICAgICBuZXdTdGFydCA9IHN0LnN0YXJ0ICsgX2NoYW5nZSAqIG5ld1N0YXJ0IC8gZHVyYXRpb247XG4gICAgICAgIG5ld0VuZCA9IHN0LnN0YXJ0ICsgX2NoYW5nZSAqIG5ld0VuZCAvIGR1cmF0aW9uO1xuICAgICAgfVxuXG4gICAgICBzZWxmLnJlZnJlc2goZmFsc2UsIGZhbHNlLCB7XG4gICAgICAgIHN0YXJ0OiBfa2VlcENsYW1wKG5ld1N0YXJ0LCBrZWVwQ2xhbXAgJiYgISFzZWxmLl9zdGFydENsYW1wKSxcbiAgICAgICAgZW5kOiBfa2VlcENsYW1wKG5ld0VuZCwga2VlcENsYW1wICYmICEhc2VsZi5fZW5kQ2xhbXApXG4gICAgICB9LCBwaW5PZmZzZXQpO1xuICAgICAgc2VsZi51cGRhdGUoKTtcbiAgICB9O1xuXG4gICAgc2VsZi5hZGp1c3RQaW5TcGFjaW5nID0gZnVuY3Rpb24gKGFtb3VudCkge1xuICAgICAgaWYgKHNwYWNlclN0YXRlICYmIGFtb3VudCkge1xuICAgICAgICB2YXIgaSA9IHNwYWNlclN0YXRlLmluZGV4T2YoZGlyZWN0aW9uLmQpICsgMTtcbiAgICAgICAgc3BhY2VyU3RhdGVbaV0gPSBwYXJzZUZsb2F0KHNwYWNlclN0YXRlW2ldKSArIGFtb3VudCArIF9weDtcbiAgICAgICAgc3BhY2VyU3RhdGVbMV0gPSBwYXJzZUZsb2F0KHNwYWNlclN0YXRlWzFdKSArIGFtb3VudCArIF9weDtcblxuICAgICAgICBfc2V0U3RhdGUoc3BhY2VyU3RhdGUpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBzZWxmLmRpc2FibGUgPSBmdW5jdGlvbiAocmVzZXQsIGFsbG93QW5pbWF0aW9uKSB7XG4gICAgICBpZiAoc2VsZi5lbmFibGVkKSB7XG4gICAgICAgIHJlc2V0ICE9PSBmYWxzZSAmJiBzZWxmLnJldmVydCh0cnVlLCB0cnVlKTtcbiAgICAgICAgc2VsZi5lbmFibGVkID0gc2VsZi5pc0FjdGl2ZSA9IGZhbHNlO1xuICAgICAgICBhbGxvd0FuaW1hdGlvbiB8fCBzY3J1YlR3ZWVuICYmIHNjcnViVHdlZW4ucGF1c2UoKTtcbiAgICAgICAgcHJldlNjcm9sbCA9IDA7XG4gICAgICAgIHBpbkNhY2hlICYmIChwaW5DYWNoZS51bmNhY2hlID0gMSk7XG4gICAgICAgIG9uUmVmcmVzaEluaXQgJiYgX3JlbW92ZUxpc3RlbmVyKFNjcm9sbFRyaWdnZXIsIFwicmVmcmVzaEluaXRcIiwgb25SZWZyZXNoSW5pdCk7XG5cbiAgICAgICAgaWYgKHNuYXBEZWxheWVkQ2FsbCkge1xuICAgICAgICAgIHNuYXBEZWxheWVkQ2FsbC5wYXVzZSgpO1xuICAgICAgICAgIHR3ZWVuVG8udHdlZW4gJiYgdHdlZW5Uby50d2Vlbi5raWxsKCkgJiYgKHR3ZWVuVG8udHdlZW4gPSAwKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghaXNWaWV3cG9ydCkge1xuICAgICAgICAgIHZhciBpID0gX3RyaWdnZXJzLmxlbmd0aDtcblxuICAgICAgICAgIHdoaWxlIChpLS0pIHtcbiAgICAgICAgICAgIGlmIChfdHJpZ2dlcnNbaV0uc2Nyb2xsZXIgPT09IHNjcm9sbGVyICYmIF90cmlnZ2Vyc1tpXSAhPT0gc2VsZikge1xuICAgICAgICAgICAgICByZXR1cm47IC8vZG9uJ3QgcmVtb3ZlIHRoZSBsaXN0ZW5lcnMgaWYgdGhlcmUgYXJlIHN0aWxsIG90aGVyIHRyaWdnZXJzIHJlZmVyZW5jaW5nIGl0LlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIF9yZW1vdmVMaXN0ZW5lcihzY3JvbGxlciwgXCJyZXNpemVcIiwgX29uUmVzaXplKTtcblxuICAgICAgICAgIGlzVmlld3BvcnQgfHwgX3JlbW92ZUxpc3RlbmVyKHNjcm9sbGVyLCBcInNjcm9sbFwiLCBfb25TY3JvbGwpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIHNlbGYua2lsbCA9IGZ1bmN0aW9uIChyZXZlcnQsIGFsbG93QW5pbWF0aW9uKSB7XG4gICAgICBzZWxmLmRpc2FibGUocmV2ZXJ0LCBhbGxvd0FuaW1hdGlvbik7XG4gICAgICBzY3J1YlR3ZWVuICYmICFhbGxvd0FuaW1hdGlvbiAmJiBzY3J1YlR3ZWVuLmtpbGwoKTtcbiAgICAgIGlkICYmIGRlbGV0ZSBfaWRzW2lkXTtcblxuICAgICAgdmFyIGkgPSBfdHJpZ2dlcnMuaW5kZXhPZihzZWxmKTtcblxuICAgICAgaSA+PSAwICYmIF90cmlnZ2Vycy5zcGxpY2UoaSwgMSk7XG4gICAgICBpID09PSBfaSAmJiBfZGlyZWN0aW9uID4gMCAmJiBfaS0tOyAvLyBpZiB3ZSdyZSBpbiB0aGUgbWlkZGxlIG9mIGEgcmVmcmVzaCgpIG9yIHVwZGF0ZSgpLCBzcGxpY2luZyB3b3VsZCBjYXVzZSBza2lwcyBpbiB0aGUgaW5kZXgsIHNvIGFkanVzdC4uLlxuICAgICAgLy8gaWYgbm8gb3RoZXIgU2Nyb2xsVHJpZ2dlciBpbnN0YW5jZXMgb2YgdGhlIHNhbWUgc2Nyb2xsZXIgYXJlIGZvdW5kLCB3aXBlIG91dCBhbnkgcmVjb3JkZWQgc2Nyb2xsIHBvc2l0aW9uLiBPdGhlcndpc2UsIGluIGEgc2luZ2xlIHBhZ2UgYXBwbGljYXRpb24sIGZvciBleGFtcGxlLCBpdCBjb3VsZCBtYWludGFpbiBzY3JvbGwgcG9zaXRpb24gd2hlbiBpdCByZWFsbHkgc2hvdWxkbid0LlxuXG4gICAgICBpID0gMDtcblxuICAgICAgX3RyaWdnZXJzLmZvckVhY2goZnVuY3Rpb24gKHQpIHtcbiAgICAgICAgcmV0dXJuIHQuc2Nyb2xsZXIgPT09IHNlbGYuc2Nyb2xsZXIgJiYgKGkgPSAxKTtcbiAgICAgIH0pO1xuXG4gICAgICBpIHx8IF9yZWZyZXNoaW5nQWxsIHx8IChzZWxmLnNjcm9sbC5yZWMgPSAwKTtcblxuICAgICAgaWYgKGFuaW1hdGlvbikge1xuICAgICAgICBhbmltYXRpb24uc2Nyb2xsVHJpZ2dlciA9IG51bGw7XG4gICAgICAgIHJldmVydCAmJiBhbmltYXRpb24ucmV2ZXJ0KHtcbiAgICAgICAgICBraWxsOiBmYWxzZVxuICAgICAgICB9KTtcbiAgICAgICAgYWxsb3dBbmltYXRpb24gfHwgYW5pbWF0aW9uLmtpbGwoKTtcbiAgICAgIH1cblxuICAgICAgbWFya2VyU3RhcnQgJiYgW21hcmtlclN0YXJ0LCBtYXJrZXJFbmQsIG1hcmtlclN0YXJ0VHJpZ2dlciwgbWFya2VyRW5kVHJpZ2dlcl0uZm9yRWFjaChmdW5jdGlvbiAobSkge1xuICAgICAgICByZXR1cm4gbS5wYXJlbnROb2RlICYmIG0ucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChtKTtcbiAgICAgIH0pO1xuICAgICAgX3ByaW1hcnkgPT09IHNlbGYgJiYgKF9wcmltYXJ5ID0gMCk7XG5cbiAgICAgIGlmIChwaW4pIHtcbiAgICAgICAgcGluQ2FjaGUgJiYgKHBpbkNhY2hlLnVuY2FjaGUgPSAxKTtcbiAgICAgICAgaSA9IDA7XG5cbiAgICAgICAgX3RyaWdnZXJzLmZvckVhY2goZnVuY3Rpb24gKHQpIHtcbiAgICAgICAgICByZXR1cm4gdC5waW4gPT09IHBpbiAmJiBpKys7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGkgfHwgKHBpbkNhY2hlLnNwYWNlciA9IDApOyAvLyBpZiB0aGVyZSBhcmVuJ3QgYW55IG1vcmUgU2Nyb2xsVHJpZ2dlcnMgd2l0aCB0aGUgc2FtZSBwaW4sIHJlbW92ZSB0aGUgc3BhY2VyLCBvdGhlcndpc2UgaXQgY291bGQgYmUgY29udGFtaW5hdGVkIHdpdGggb2xkL3N0YWxlIHZhbHVlcyBpZiB0aGUgdXNlciByZS1jcmVhdGVzIGEgU2Nyb2xsVHJpZ2dlciBmb3IgdGhlIHNhbWUgZWxlbWVudC5cbiAgICAgIH1cblxuICAgICAgdmFycy5vbktpbGwgJiYgdmFycy5vbktpbGwoc2VsZik7XG4gICAgfTtcblxuICAgIF90cmlnZ2Vycy5wdXNoKHNlbGYpO1xuXG4gICAgc2VsZi5lbmFibGUoZmFsc2UsIGZhbHNlKTtcbiAgICBjdXN0b21SZXZlcnRSZXR1cm4gJiYgY3VzdG9tUmV2ZXJ0UmV0dXJuKHNlbGYpO1xuXG4gICAgaWYgKGFuaW1hdGlvbiAmJiBhbmltYXRpb24uYWRkICYmICFjaGFuZ2UpIHtcbiAgICAgIC8vIGlmIHRoZSBhbmltYXRpb24gaXMgYSB0aW1lbGluZSwgaXQgbWF5IG5vdCBoYXZlIGJlZW4gcG9wdWxhdGVkIHlldCwgc28gaXQgd291bGRuJ3QgcmVuZGVyIGF0IHRoZSBwcm9wZXIgcGxhY2Ugb24gdGhlIGZpcnN0IHJlZnJlc2goKSwgdGh1cyB3ZSBzaG91bGQgc2NoZWR1bGUgb25lIGZvciB0aGUgbmV4dCB0aWNrLiBJZiBcImNoYW5nZVwiIGlzIGRlZmluZWQsIHdlIGtub3cgaXQgbXVzdCBiZSByZS1lbmFibGluZywgdGh1cyB3ZSBjYW4gcmVmcmVzaCgpIHJpZ2h0IGF3YXkuXG4gICAgICB2YXIgdXBkYXRlRnVuYyA9IHNlbGYudXBkYXRlOyAvLyBzb21lIGJyb3dzZXJzIG1heSBmaXJlIGEgc2Nyb2xsIGV2ZW50IEJFRk9SRSBhIHRpY2sgZWxhcHNlcyBhbmQvb3IgdGhlIERPTUNvbnRlbnRMb2FkZWQgZmlyZXMuIFNvIHRoZXJlJ3MgYSBjaGFuY2UgdXBkYXRlKCkgd2lsbCBiZSBjYWxsZWQgQkVGT1JFIGEgcmVmcmVzaCgpIGhhcyBoYXBwZW5lZCBvbiBhIFRpbWVsaW5lLWF0dGFjaGVkIFNjcm9sbFRyaWdnZXIgd2hpY2ggbWVhbnMgdGhlIHN0YXJ0L2VuZCB3b24ndCBiZSBjYWxjdWxhdGVkIHlldC4gV2UgZG9uJ3Qgd2FudCB0byBhZGQgY29uZGl0aW9uYWwgbG9naWMgaW5zaWRlIHRoZSB1cGRhdGUoKSBtZXRob2QgKGxpa2UgY2hlY2sgdG8gc2VlIGlmIGVuZCBpcyBkZWZpbmVkIGFuZCBpZiBub3QsIGZvcmNlIGEgcmVmcmVzaCgpKSBiZWNhdXNlIHRoYXQncyBhIGZ1bmN0aW9uIHRoYXQgZ2V0cyBoaXQgYSBMT1QgKHBlcmZvcm1hbmNlKS4gU28gd2Ugc3dhcCBvdXQgdGhlIHJlYWwgdXBkYXRlKCkgbWV0aG9kIGZvciB0aGlzIG9uZSB0aGF0J2xsIHJlLWF0dGFjaCBpdCB0aGUgZmlyc3QgdGltZSBpdCBnZXRzIGNhbGxlZCBhbmQgb2YgY291cnNlIGZvcmNlcyBhIHJlZnJlc2goKS5cblxuICAgICAgc2VsZi51cGRhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHNlbGYudXBkYXRlID0gdXBkYXRlRnVuYztcbiAgICAgICAgc3RhcnQgfHwgZW5kIHx8IHNlbGYucmVmcmVzaCgpO1xuICAgICAgfTtcblxuICAgICAgZ3NhcC5kZWxheWVkQ2FsbCgwLjAxLCBzZWxmLnVwZGF0ZSk7XG4gICAgICBjaGFuZ2UgPSAwLjAxO1xuICAgICAgc3RhcnQgPSBlbmQgPSAwO1xuICAgIH0gZWxzZSB7XG4gICAgICBzZWxmLnJlZnJlc2goKTtcbiAgICB9XG5cbiAgICBwaW4gJiYgX3F1ZXVlUmVmcmVzaEFsbCgpOyAvLyBwaW5uaW5nIGNvdWxkIGFmZmVjdCB0aGUgcG9zaXRpb25zIG9mIG90aGVyIHRoaW5ncywgc28gbWFrZSBzdXJlIHdlIHF1ZXVlIGEgZnVsbCByZWZyZXNoKClcbiAgfTtcblxuICBTY3JvbGxUcmlnZ2VyLnJlZ2lzdGVyID0gZnVuY3Rpb24gcmVnaXN0ZXIoY29yZSkge1xuICAgIGlmICghX2NvcmVJbml0dGVkKSB7XG4gICAgICBnc2FwID0gY29yZSB8fCBfZ2V0R1NBUCgpO1xuICAgICAgX3dpbmRvd0V4aXN0cygpICYmIHdpbmRvdy5kb2N1bWVudCAmJiBTY3JvbGxUcmlnZ2VyLmVuYWJsZSgpO1xuICAgICAgX2NvcmVJbml0dGVkID0gX2VuYWJsZWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIF9jb3JlSW5pdHRlZDtcbiAgfTtcblxuICBTY3JvbGxUcmlnZ2VyLmRlZmF1bHRzID0gZnVuY3Rpb24gZGVmYXVsdHMoY29uZmlnKSB7XG4gICAgaWYgKGNvbmZpZykge1xuICAgICAgZm9yICh2YXIgcCBpbiBjb25maWcpIHtcbiAgICAgICAgX2RlZmF1bHRzW3BdID0gY29uZmlnW3BdO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBfZGVmYXVsdHM7XG4gIH07XG5cbiAgU2Nyb2xsVHJpZ2dlci5kaXNhYmxlID0gZnVuY3Rpb24gZGlzYWJsZShyZXNldCwga2lsbCkge1xuICAgIF9lbmFibGVkID0gMDtcblxuICAgIF90cmlnZ2Vycy5mb3JFYWNoKGZ1bmN0aW9uICh0cmlnZ2VyKSB7XG4gICAgICByZXR1cm4gdHJpZ2dlcltraWxsID8gXCJraWxsXCIgOiBcImRpc2FibGVcIl0ocmVzZXQpO1xuICAgIH0pO1xuXG4gICAgX3JlbW92ZUxpc3RlbmVyKF93aW4sIFwid2hlZWxcIiwgX29uU2Nyb2xsKTtcblxuICAgIF9yZW1vdmVMaXN0ZW5lcihfZG9jLCBcInNjcm9sbFwiLCBfb25TY3JvbGwpO1xuXG4gICAgY2xlYXJJbnRlcnZhbChfc3luY0ludGVydmFsKTtcblxuICAgIF9yZW1vdmVMaXN0ZW5lcihfZG9jLCBcInRvdWNoY2FuY2VsXCIsIF9wYXNzVGhyb3VnaCk7XG5cbiAgICBfcmVtb3ZlTGlzdGVuZXIoX2JvZHksIFwidG91Y2hzdGFydFwiLCBfcGFzc1Rocm91Z2gpO1xuXG4gICAgX211bHRpTGlzdGVuZXIoX3JlbW92ZUxpc3RlbmVyLCBfZG9jLCBcInBvaW50ZXJkb3duLHRvdWNoc3RhcnQsbW91c2Vkb3duXCIsIF9wb2ludGVyRG93bkhhbmRsZXIpO1xuXG4gICAgX211bHRpTGlzdGVuZXIoX3JlbW92ZUxpc3RlbmVyLCBfZG9jLCBcInBvaW50ZXJ1cCx0b3VjaGVuZCxtb3VzZXVwXCIsIF9wb2ludGVyVXBIYW5kbGVyKTtcblxuICAgIF9yZXNpemVEZWxheS5raWxsKCk7XG5cbiAgICBfaXRlcmF0ZUF1dG9SZWZyZXNoKF9yZW1vdmVMaXN0ZW5lcik7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IF9zY3JvbGxlcnMubGVuZ3RoOyBpICs9IDMpIHtcbiAgICAgIF93aGVlbExpc3RlbmVyKF9yZW1vdmVMaXN0ZW5lciwgX3Njcm9sbGVyc1tpXSwgX3Njcm9sbGVyc1tpICsgMV0pO1xuXG4gICAgICBfd2hlZWxMaXN0ZW5lcihfcmVtb3ZlTGlzdGVuZXIsIF9zY3JvbGxlcnNbaV0sIF9zY3JvbGxlcnNbaSArIDJdKTtcbiAgICB9XG4gIH07XG5cbiAgU2Nyb2xsVHJpZ2dlci5lbmFibGUgPSBmdW5jdGlvbiBlbmFibGUoKSB7XG4gICAgX3dpbiA9IHdpbmRvdztcbiAgICBfZG9jID0gZG9jdW1lbnQ7XG4gICAgX2RvY0VsID0gX2RvYy5kb2N1bWVudEVsZW1lbnQ7XG4gICAgX2JvZHkgPSBfZG9jLmJvZHk7XG5cbiAgICBpZiAoZ3NhcCkge1xuICAgICAgX3RvQXJyYXkgPSBnc2FwLnV0aWxzLnRvQXJyYXk7XG4gICAgICBfY2xhbXAgPSBnc2FwLnV0aWxzLmNsYW1wO1xuICAgICAgX2NvbnRleHQgPSBnc2FwLmNvcmUuY29udGV4dCB8fCBfcGFzc1Rocm91Z2g7XG4gICAgICBfc3VwcHJlc3NPdmVyd3JpdGVzID0gZ3NhcC5jb3JlLnN1cHByZXNzT3ZlcndyaXRlcyB8fCBfcGFzc1Rocm91Z2g7XG4gICAgICBfc2Nyb2xsUmVzdG9yYXRpb24gPSBfd2luLmhpc3Rvcnkuc2Nyb2xsUmVzdG9yYXRpb24gfHwgXCJhdXRvXCI7XG4gICAgICBfbGFzdFNjcm9sbCA9IF93aW4ucGFnZVlPZmZzZXQ7XG4gICAgICBnc2FwLmNvcmUuZ2xvYmFscyhcIlNjcm9sbFRyaWdnZXJcIiwgU2Nyb2xsVHJpZ2dlcik7IC8vIG11c3QgcmVnaXN0ZXIgdGhlIGdsb2JhbCBtYW51YWxseSBiZWNhdXNlIGluIEludGVybmV0IEV4cGxvcmVyLCBmdW5jdGlvbnMgKGNsYXNzZXMpIGRvbid0IGhhdmUgYSBcIm5hbWVcIiBwcm9wZXJ0eS5cblxuICAgICAgaWYgKF9ib2R5KSB7XG4gICAgICAgIF9lbmFibGVkID0gMTtcbiAgICAgICAgX2RpdjEwMHZoID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKTsgLy8gdG8gc29sdmUgbW9iaWxlIGJyb3dzZXIgYWRkcmVzcyBiYXIgc2hvdy9oaWRlIHJlc2l6aW5nLCB3ZSBzaG91bGRuJ3QgcmVseSBvbiB3aW5kb3cuaW5uZXJIZWlnaHQuIEluc3RlYWQsIHVzZSBhIDxkaXY+IHdpdGggaXRzIGhlaWdodCBzZXQgdG8gMTAwdmggYW5kIG1lYXN1cmUgdGhhdCBzaW5jZSB0aGF0J3Mgd2hhdCB0aGUgc2Nyb2xsaW5nIGlzIGJhc2VkIG9uIGFueXdheSBhbmQgaXQncyBub3QgYWZmZWN0ZWQgYnkgYWRkcmVzcyBiYXIgc2hvd2luZy9oaWRpbmcuXG5cbiAgICAgICAgX2RpdjEwMHZoLnN0eWxlLmhlaWdodCA9IFwiMTAwdmhcIjtcbiAgICAgICAgX2RpdjEwMHZoLnN0eWxlLnBvc2l0aW9uID0gXCJhYnNvbHV0ZVwiO1xuXG4gICAgICAgIF9yZWZyZXNoMTAwdmgoKTtcblxuICAgICAgICBfcmFmQnVnRml4KCk7XG5cbiAgICAgICAgT2JzZXJ2ZXIucmVnaXN0ZXIoZ3NhcCk7IC8vIGlzVG91Y2ggaXMgMCBpZiBubyB0b3VjaCwgMSBpZiBPTkxZIHRvdWNoLCBhbmQgMiBpZiBpdCBjYW4gYWNjb21tb2RhdGUgdG91Y2ggYnV0IGFsc28gb3RoZXIgdHlwZXMgbGlrZSBtb3VzZS9wb2ludGVyLlxuXG4gICAgICAgIFNjcm9sbFRyaWdnZXIuaXNUb3VjaCA9IE9ic2VydmVyLmlzVG91Y2g7XG4gICAgICAgIF9maXhJT1NCdWcgPSBPYnNlcnZlci5pc1RvdWNoICYmIC8oaVBhZHxpUGhvbmV8aVBvZHxNYWMpL2cudGVzdChuYXZpZ2F0b3IudXNlckFnZW50KTsgLy8gc2luY2UgMjAxNywgaU9TIGhhcyBoYWQgYSBidWcgdGhhdCBjYXVzZXMgZXZlbnQuY2xpZW50WC9ZIHRvIGJlIGluYWNjdXJhdGUgd2hlbiBhIHNjcm9sbCBvY2N1cnMsIHRodXMgd2UgbXVzdCBhbHRlcm5hdGUgaWdub3JpbmcgZXZlcnkgb3RoZXIgdG91Y2htb3ZlIGV2ZW50IHRvIHdvcmsgYXJvdW5kIGl0LiBTZWUgaHR0cHM6Ly9idWdzLndlYmtpdC5vcmcvc2hvd19idWcuY2dpP2lkPTE4MTk1NCBhbmQgaHR0cHM6Ly9jb2RlcGVuLmlvL0dyZWVuU29jay9wZW4vRXhiclBOYS8wODdjZWYxOTdkYzM1NDQ1YTA5NTFlODkzNWM0MTUwM1xuXG4gICAgICAgIF9pZ25vcmVNb2JpbGVSZXNpemUgPSBPYnNlcnZlci5pc1RvdWNoID09PSAxO1xuXG4gICAgICAgIF9hZGRMaXN0ZW5lcihfd2luLCBcIndoZWVsXCIsIF9vblNjcm9sbCk7IC8vIG1vc3RseSBmb3IgM3JkIHBhcnR5IHNtb290aCBzY3JvbGxpbmcgbGlicmFyaWVzLlxuXG5cbiAgICAgICAgX3Jvb3QgPSBbX3dpbiwgX2RvYywgX2RvY0VsLCBfYm9keV07XG5cbiAgICAgICAgaWYgKGdzYXAubWF0Y2hNZWRpYSkge1xuICAgICAgICAgIFNjcm9sbFRyaWdnZXIubWF0Y2hNZWRpYSA9IGZ1bmN0aW9uICh2YXJzKSB7XG4gICAgICAgICAgICB2YXIgbW0gPSBnc2FwLm1hdGNoTWVkaWEoKSxcbiAgICAgICAgICAgICAgICBwO1xuXG4gICAgICAgICAgICBmb3IgKHAgaW4gdmFycykge1xuICAgICAgICAgICAgICBtbS5hZGQocCwgdmFyc1twXSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBtbTtcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgZ3NhcC5hZGRFdmVudExpc3RlbmVyKFwibWF0Y2hNZWRpYUluaXRcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIF9yZXZlcnRBbGwoKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBnc2FwLmFkZEV2ZW50TGlzdGVuZXIoXCJtYXRjaE1lZGlhUmV2ZXJ0XCIsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBfcmV2ZXJ0UmVjb3JkZWQoKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBnc2FwLmFkZEV2ZW50TGlzdGVuZXIoXCJtYXRjaE1lZGlhXCIsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIF9yZWZyZXNoQWxsKDAsIDEpO1xuXG4gICAgICAgICAgICBfZGlzcGF0Y2goXCJtYXRjaE1lZGlhXCIpO1xuICAgICAgICAgIH0pO1xuICAgICAgICAgIGdzYXAubWF0Y2hNZWRpYShcIihvcmllbnRhdGlvbjogcG9ydHJhaXQpXCIsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIC8vIHdoZW4gb3JpZW50YXRpb24gY2hhbmdlcywgd2Ugc2hvdWxkIHRha2UgbmV3IGJhc2UgbWVhc3VyZW1lbnRzIGZvciB0aGUgaWdub3JlTW9iaWxlUmVzaXplIGZlYXR1cmUuXG4gICAgICAgICAgICBfc2V0QmFzZURpbWVuc2lvbnMoKTtcblxuICAgICAgICAgICAgcmV0dXJuIF9zZXRCYXNlRGltZW5zaW9ucztcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zb2xlLndhcm4oXCJSZXF1aXJlcyBHU0FQIDMuMTEuMCBvciBsYXRlclwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIF9zZXRCYXNlRGltZW5zaW9ucygpO1xuXG4gICAgICAgIF9hZGRMaXN0ZW5lcihfZG9jLCBcInNjcm9sbFwiLCBfb25TY3JvbGwpOyAvLyBzb21lIGJyb3dzZXJzIChsaWtlIENocm9tZSksIHRoZSB3aW5kb3cgc3RvcHMgZGlzcGF0Y2hpbmcgc2Nyb2xsIGV2ZW50cyBvbiB0aGUgd2luZG93IGlmIHlvdSBzY3JvbGwgcmVhbGx5IGZhc3QsIGJ1dCBpdCdzIGNvbnNpc3RlbnQgb24gdGhlIGRvY3VtZW50IVxuXG5cbiAgICAgICAgdmFyIGJvZHlTdHlsZSA9IF9ib2R5LnN0eWxlLFxuICAgICAgICAgICAgYm9yZGVyID0gYm9keVN0eWxlLmJvcmRlclRvcFN0eWxlLFxuICAgICAgICAgICAgQW5pbWF0aW9uUHJvdG8gPSBnc2FwLmNvcmUuQW5pbWF0aW9uLnByb3RvdHlwZSxcbiAgICAgICAgICAgIGJvdW5kcyxcbiAgICAgICAgICAgIGk7XG4gICAgICAgIEFuaW1hdGlvblByb3RvLnJldmVydCB8fCBPYmplY3QuZGVmaW5lUHJvcGVydHkoQW5pbWF0aW9uUHJvdG8sIFwicmV2ZXJ0XCIsIHtcbiAgICAgICAgICB2YWx1ZTogZnVuY3Rpb24gdmFsdWUoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy50aW1lKC0wLjAxLCB0cnVlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pOyAvLyBvbmx5IGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eSAoQW5pbWF0aW9uLnJldmVydCgpIHdhcyBhZGRlZCBhZnRlciAzLjEwLjQpXG5cbiAgICAgICAgYm9keVN0eWxlLmJvcmRlclRvcFN0eWxlID0gXCJzb2xpZFwiOyAvLyB3b3JrcyBhcm91bmQgYW4gaXNzdWUgd2hlcmUgYSBtYXJnaW4gb2YgYSBjaGlsZCBlbGVtZW50IGNvdWxkIHRocm93IG9mZiB0aGUgYm91bmRzIG9mIHRoZSBfYm9keSwgbWFraW5nIGl0IHNlZW0gbGlrZSB0aGVyZSdzIGEgbWFyZ2luIHdoZW4gdGhlcmUgYWN0dWFsbHkgaXNuJ3QuIFRoZSBib3JkZXIgZW5zdXJlcyB0aGF0IHRoZSBib3VuZHMgYXJlIGFjY3VyYXRlLlxuXG4gICAgICAgIGJvdW5kcyA9IF9nZXRCb3VuZHMoX2JvZHkpO1xuICAgICAgICBfdmVydGljYWwubSA9IE1hdGgucm91bmQoYm91bmRzLnRvcCArIF92ZXJ0aWNhbC5zYygpKSB8fCAwOyAvLyBhY2NvbW1vZGF0ZSB0aGUgb2Zmc2V0IG9mIHRoZSA8Ym9keT4gY2F1c2VkIGJ5IG1hcmdpbnMgYW5kL29yIHBhZGRpbmdcblxuICAgICAgICBfaG9yaXpvbnRhbC5tID0gTWF0aC5yb3VuZChib3VuZHMubGVmdCArIF9ob3Jpem9udGFsLnNjKCkpIHx8IDA7XG4gICAgICAgIGJvcmRlciA/IGJvZHlTdHlsZS5ib3JkZXJUb3BTdHlsZSA9IGJvcmRlciA6IGJvZHlTdHlsZS5yZW1vdmVQcm9wZXJ0eShcImJvcmRlci10b3Atc3R5bGVcIik7IC8vIFRPRE86ICg/KSBtYXliZSBtb3ZlIHRvIGxldmVyYWdpbmcgdGhlIHZlbG9jaXR5IG1lY2hhbmlzbSBpbiBPYnNlcnZlciBhbmQgc2tpcCBpbnRlcnZhbHMuXG5cbiAgICAgICAgX3N5bmNJbnRlcnZhbCA9IHNldEludGVydmFsKF9zeW5jLCAyNTApO1xuICAgICAgICBnc2FwLmRlbGF5ZWRDYWxsKDAuNSwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIHJldHVybiBfc3RhcnR1cCA9IDA7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIF9hZGRMaXN0ZW5lcihfZG9jLCBcInRvdWNoY2FuY2VsXCIsIF9wYXNzVGhyb3VnaCk7IC8vIHNvbWUgb2xkZXIgQW5kcm9pZCBkZXZpY2VzIGludGVybWl0dGVudGx5IHN0b3AgZGlzcGF0Y2hpbmcgXCJ0b3VjaG1vdmVcIiBldmVudHMgaWYgd2UgZG9uJ3QgbGlzdGVuIGZvciBcInRvdWNoY2FuY2VsXCIgb24gdGhlIGRvY3VtZW50LlxuXG5cbiAgICAgICAgX2FkZExpc3RlbmVyKF9ib2R5LCBcInRvdWNoc3RhcnRcIiwgX3Bhc3NUaHJvdWdoKTsgLy93b3JrcyBhcm91bmQgU2FmYXJpIGJ1ZzogaHR0cHM6Ly9nc2FwLmNvbS9mb3J1bXMvdG9waWMvMjE0NTAtZHJhZ2dhYmxlLWluLWlmcmFtZS1vbi1tb2JpbGUtaXMtYnVnZ3kvXG5cblxuICAgICAgICBfbXVsdGlMaXN0ZW5lcihfYWRkTGlzdGVuZXIsIF9kb2MsIFwicG9pbnRlcmRvd24sdG91Y2hzdGFydCxtb3VzZWRvd25cIiwgX3BvaW50ZXJEb3duSGFuZGxlcik7XG5cbiAgICAgICAgX211bHRpTGlzdGVuZXIoX2FkZExpc3RlbmVyLCBfZG9jLCBcInBvaW50ZXJ1cCx0b3VjaGVuZCxtb3VzZXVwXCIsIF9wb2ludGVyVXBIYW5kbGVyKTtcblxuICAgICAgICBfdHJhbnNmb3JtUHJvcCA9IGdzYXAudXRpbHMuY2hlY2tQcmVmaXgoXCJ0cmFuc2Zvcm1cIik7XG5cbiAgICAgICAgX3N0YXRlUHJvcHMucHVzaChfdHJhbnNmb3JtUHJvcCk7XG5cbiAgICAgICAgX2NvcmVJbml0dGVkID0gX2dldFRpbWUoKTtcbiAgICAgICAgX3Jlc2l6ZURlbGF5ID0gZ3NhcC5kZWxheWVkQ2FsbCgwLjIsIF9yZWZyZXNoQWxsKS5wYXVzZSgpO1xuICAgICAgICBfYXV0b1JlZnJlc2ggPSBbX2RvYywgXCJ2aXNpYmlsaXR5Y2hhbmdlXCIsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICB2YXIgdyA9IF93aW4uaW5uZXJXaWR0aCxcbiAgICAgICAgICAgICAgaCA9IF93aW4uaW5uZXJIZWlnaHQ7XG5cbiAgICAgICAgICBpZiAoX2RvYy5oaWRkZW4pIHtcbiAgICAgICAgICAgIF9wcmV2V2lkdGggPSB3O1xuICAgICAgICAgICAgX3ByZXZIZWlnaHQgPSBoO1xuICAgICAgICAgIH0gZWxzZSBpZiAoX3ByZXZXaWR0aCAhPT0gdyB8fCBfcHJldkhlaWdodCAhPT0gaCkge1xuICAgICAgICAgICAgX29uUmVzaXplKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9LCBfZG9jLCBcIkRPTUNvbnRlbnRMb2FkZWRcIiwgX3JlZnJlc2hBbGwsIF93aW4sIFwibG9hZFwiLCBfcmVmcmVzaEFsbCwgX3dpbiwgXCJyZXNpemVcIiwgX29uUmVzaXplXTtcblxuICAgICAgICBfaXRlcmF0ZUF1dG9SZWZyZXNoKF9hZGRMaXN0ZW5lcik7XG5cbiAgICAgICAgX3RyaWdnZXJzLmZvckVhY2goZnVuY3Rpb24gKHRyaWdnZXIpIHtcbiAgICAgICAgICByZXR1cm4gdHJpZ2dlci5lbmFibGUoMCwgMSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBfc2Nyb2xsZXJzLmxlbmd0aDsgaSArPSAzKSB7XG4gICAgICAgICAgX3doZWVsTGlzdGVuZXIoX3JlbW92ZUxpc3RlbmVyLCBfc2Nyb2xsZXJzW2ldLCBfc2Nyb2xsZXJzW2kgKyAxXSk7XG5cbiAgICAgICAgICBfd2hlZWxMaXN0ZW5lcihfcmVtb3ZlTGlzdGVuZXIsIF9zY3JvbGxlcnNbaV0sIF9zY3JvbGxlcnNbaSArIDJdKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICBTY3JvbGxUcmlnZ2VyLmNvbmZpZyA9IGZ1bmN0aW9uIGNvbmZpZyh2YXJzKSB7XG4gICAgXCJsaW1pdENhbGxiYWNrc1wiIGluIHZhcnMgJiYgKF9saW1pdENhbGxiYWNrcyA9ICEhdmFycy5saW1pdENhbGxiYWNrcyk7XG4gICAgdmFyIG1zID0gdmFycy5zeW5jSW50ZXJ2YWw7XG4gICAgbXMgJiYgY2xlYXJJbnRlcnZhbChfc3luY0ludGVydmFsKSB8fCAoX3N5bmNJbnRlcnZhbCA9IG1zKSAmJiBzZXRJbnRlcnZhbChfc3luYywgbXMpO1xuICAgIFwiaWdub3JlTW9iaWxlUmVzaXplXCIgaW4gdmFycyAmJiAoX2lnbm9yZU1vYmlsZVJlc2l6ZSA9IFNjcm9sbFRyaWdnZXIuaXNUb3VjaCA9PT0gMSAmJiB2YXJzLmlnbm9yZU1vYmlsZVJlc2l6ZSk7XG5cbiAgICBpZiAoXCJhdXRvUmVmcmVzaEV2ZW50c1wiIGluIHZhcnMpIHtcbiAgICAgIF9pdGVyYXRlQXV0b1JlZnJlc2goX3JlbW92ZUxpc3RlbmVyKSB8fCBfaXRlcmF0ZUF1dG9SZWZyZXNoKF9hZGRMaXN0ZW5lciwgdmFycy5hdXRvUmVmcmVzaEV2ZW50cyB8fCBcIm5vbmVcIik7XG4gICAgICBfaWdub3JlUmVzaXplID0gKHZhcnMuYXV0b1JlZnJlc2hFdmVudHMgKyBcIlwiKS5pbmRleE9mKFwicmVzaXplXCIpID09PSAtMTtcbiAgICB9XG4gIH07XG5cbiAgU2Nyb2xsVHJpZ2dlci5zY3JvbGxlclByb3h5ID0gZnVuY3Rpb24gc2Nyb2xsZXJQcm94eSh0YXJnZXQsIHZhcnMpIHtcbiAgICB2YXIgdCA9IF9nZXRUYXJnZXQodGFyZ2V0KSxcbiAgICAgICAgaSA9IF9zY3JvbGxlcnMuaW5kZXhPZih0KSxcbiAgICAgICAgaXNWaWV3cG9ydCA9IF9pc1ZpZXdwb3J0KHQpO1xuXG4gICAgaWYgKH5pKSB7XG4gICAgICBfc2Nyb2xsZXJzLnNwbGljZShpLCBpc1ZpZXdwb3J0ID8gNiA6IDIpO1xuICAgIH1cblxuICAgIGlmICh2YXJzKSB7XG4gICAgICBpc1ZpZXdwb3J0ID8gX3Byb3hpZXMudW5zaGlmdChfd2luLCB2YXJzLCBfYm9keSwgdmFycywgX2RvY0VsLCB2YXJzKSA6IF9wcm94aWVzLnVuc2hpZnQodCwgdmFycyk7XG4gICAgfVxuICB9O1xuXG4gIFNjcm9sbFRyaWdnZXIuY2xlYXJNYXRjaE1lZGlhID0gZnVuY3Rpb24gY2xlYXJNYXRjaE1lZGlhKHF1ZXJ5KSB7XG4gICAgX3RyaWdnZXJzLmZvckVhY2goZnVuY3Rpb24gKHQpIHtcbiAgICAgIHJldHVybiB0Ll9jdHggJiYgdC5fY3R4LnF1ZXJ5ID09PSBxdWVyeSAmJiB0Ll9jdHgua2lsbCh0cnVlLCB0cnVlKTtcbiAgICB9KTtcbiAgfTtcblxuICBTY3JvbGxUcmlnZ2VyLmlzSW5WaWV3cG9ydCA9IGZ1bmN0aW9uIGlzSW5WaWV3cG9ydChlbGVtZW50LCByYXRpbywgaG9yaXpvbnRhbCkge1xuICAgIHZhciBib3VuZHMgPSAoX2lzU3RyaW5nKGVsZW1lbnQpID8gX2dldFRhcmdldChlbGVtZW50KSA6IGVsZW1lbnQpLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLFxuICAgICAgICBvZmZzZXQgPSBib3VuZHNbaG9yaXpvbnRhbCA/IF93aWR0aCA6IF9oZWlnaHRdICogcmF0aW8gfHwgMDtcbiAgICByZXR1cm4gaG9yaXpvbnRhbCA/IGJvdW5kcy5yaWdodCAtIG9mZnNldCA+IDAgJiYgYm91bmRzLmxlZnQgKyBvZmZzZXQgPCBfd2luLmlubmVyV2lkdGggOiBib3VuZHMuYm90dG9tIC0gb2Zmc2V0ID4gMCAmJiBib3VuZHMudG9wICsgb2Zmc2V0IDwgX3dpbi5pbm5lckhlaWdodDtcbiAgfTtcblxuICBTY3JvbGxUcmlnZ2VyLnBvc2l0aW9uSW5WaWV3cG9ydCA9IGZ1bmN0aW9uIHBvc2l0aW9uSW5WaWV3cG9ydChlbGVtZW50LCByZWZlcmVuY2VQb2ludCwgaG9yaXpvbnRhbCkge1xuICAgIF9pc1N0cmluZyhlbGVtZW50KSAmJiAoZWxlbWVudCA9IF9nZXRUYXJnZXQoZWxlbWVudCkpO1xuICAgIHZhciBib3VuZHMgPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLFxuICAgICAgICBzaXplID0gYm91bmRzW2hvcml6b250YWwgPyBfd2lkdGggOiBfaGVpZ2h0XSxcbiAgICAgICAgb2Zmc2V0ID0gcmVmZXJlbmNlUG9pbnQgPT0gbnVsbCA/IHNpemUgLyAyIDogcmVmZXJlbmNlUG9pbnQgaW4gX2tleXdvcmRzID8gX2tleXdvcmRzW3JlZmVyZW5jZVBvaW50XSAqIHNpemUgOiB+cmVmZXJlbmNlUG9pbnQuaW5kZXhPZihcIiVcIikgPyBwYXJzZUZsb2F0KHJlZmVyZW5jZVBvaW50KSAqIHNpemUgLyAxMDAgOiBwYXJzZUZsb2F0KHJlZmVyZW5jZVBvaW50KSB8fCAwO1xuICAgIHJldHVybiBob3Jpem9udGFsID8gKGJvdW5kcy5sZWZ0ICsgb2Zmc2V0KSAvIF93aW4uaW5uZXJXaWR0aCA6IChib3VuZHMudG9wICsgb2Zmc2V0KSAvIF93aW4uaW5uZXJIZWlnaHQ7XG4gIH07XG5cbiAgU2Nyb2xsVHJpZ2dlci5raWxsQWxsID0gZnVuY3Rpb24ga2lsbEFsbChhbGxvd0xpc3RlbmVycykge1xuICAgIF90cmlnZ2Vycy5zbGljZSgwKS5mb3JFYWNoKGZ1bmN0aW9uICh0KSB7XG4gICAgICByZXR1cm4gdC52YXJzLmlkICE9PSBcIlNjcm9sbFNtb290aGVyXCIgJiYgdC5raWxsKCk7XG4gICAgfSk7XG5cbiAgICBpZiAoYWxsb3dMaXN0ZW5lcnMgIT09IHRydWUpIHtcbiAgICAgIHZhciBsaXN0ZW5lcnMgPSBfbGlzdGVuZXJzLmtpbGxBbGwgfHwgW107XG4gICAgICBfbGlzdGVuZXJzID0ge307XG4gICAgICBsaXN0ZW5lcnMuZm9yRWFjaChmdW5jdGlvbiAoZikge1xuICAgICAgICByZXR1cm4gZigpO1xuICAgICAgfSk7XG4gICAgfVxuICB9O1xuXG4gIHJldHVybiBTY3JvbGxUcmlnZ2VyO1xufSgpO1xuU2Nyb2xsVHJpZ2dlci52ZXJzaW9uID0gXCIzLjEyLjVcIjtcblxuU2Nyb2xsVHJpZ2dlci5zYXZlU3R5bGVzID0gZnVuY3Rpb24gKHRhcmdldHMpIHtcbiAgcmV0dXJuIHRhcmdldHMgPyBfdG9BcnJheSh0YXJnZXRzKS5mb3JFYWNoKGZ1bmN0aW9uICh0YXJnZXQpIHtcbiAgICAvLyBzYXZlZCBzdHlsZXMgYXJlIHJlY29yZGVkIGluIGEgY29uc2VjdXRpdmUgYWx0ZXJuYXRpbmcgQXJyYXksIGxpa2UgW2VsZW1lbnQsIGNzc1RleHQsIHRyYW5zZm9ybSBhdHRyaWJ1dGUsIGNhY2hlLCBtYXRjaE1lZGlhLCAuLi5dXG4gICAgaWYgKHRhcmdldCAmJiB0YXJnZXQuc3R5bGUpIHtcbiAgICAgIHZhciBpID0gX3NhdmVkU3R5bGVzLmluZGV4T2YodGFyZ2V0KTtcblxuICAgICAgaSA+PSAwICYmIF9zYXZlZFN0eWxlcy5zcGxpY2UoaSwgNSk7XG5cbiAgICAgIF9zYXZlZFN0eWxlcy5wdXNoKHRhcmdldCwgdGFyZ2V0LnN0eWxlLmNzc1RleHQsIHRhcmdldC5nZXRCQm94ICYmIHRhcmdldC5nZXRBdHRyaWJ1dGUoXCJ0cmFuc2Zvcm1cIiksIGdzYXAuY29yZS5nZXRDYWNoZSh0YXJnZXQpLCBfY29udGV4dCgpKTtcbiAgICB9XG4gIH0pIDogX3NhdmVkU3R5bGVzO1xufTtcblxuU2Nyb2xsVHJpZ2dlci5yZXZlcnQgPSBmdW5jdGlvbiAoc29mdCwgbWVkaWEpIHtcbiAgcmV0dXJuIF9yZXZlcnRBbGwoIXNvZnQsIG1lZGlhKTtcbn07XG5cblNjcm9sbFRyaWdnZXIuY3JlYXRlID0gZnVuY3Rpb24gKHZhcnMsIGFuaW1hdGlvbikge1xuICByZXR1cm4gbmV3IFNjcm9sbFRyaWdnZXIodmFycywgYW5pbWF0aW9uKTtcbn07XG5cblNjcm9sbFRyaWdnZXIucmVmcmVzaCA9IGZ1bmN0aW9uIChzYWZlKSB7XG4gIHJldHVybiBzYWZlID8gX29uUmVzaXplKCkgOiAoX2NvcmVJbml0dGVkIHx8IFNjcm9sbFRyaWdnZXIucmVnaXN0ZXIoKSkgJiYgX3JlZnJlc2hBbGwodHJ1ZSk7XG59O1xuXG5TY3JvbGxUcmlnZ2VyLnVwZGF0ZSA9IGZ1bmN0aW9uIChmb3JjZSkge1xuICByZXR1cm4gKytfc2Nyb2xsZXJzLmNhY2hlICYmIF91cGRhdGVBbGwoZm9yY2UgPT09IHRydWUgPyAyIDogMCk7XG59O1xuXG5TY3JvbGxUcmlnZ2VyLmNsZWFyU2Nyb2xsTWVtb3J5ID0gX2NsZWFyU2Nyb2xsTWVtb3J5O1xuXG5TY3JvbGxUcmlnZ2VyLm1heFNjcm9sbCA9IGZ1bmN0aW9uIChlbGVtZW50LCBob3Jpem9udGFsKSB7XG4gIHJldHVybiBfbWF4U2Nyb2xsKGVsZW1lbnQsIGhvcml6b250YWwgPyBfaG9yaXpvbnRhbCA6IF92ZXJ0aWNhbCk7XG59O1xuXG5TY3JvbGxUcmlnZ2VyLmdldFNjcm9sbEZ1bmMgPSBmdW5jdGlvbiAoZWxlbWVudCwgaG9yaXpvbnRhbCkge1xuICByZXR1cm4gX2dldFNjcm9sbEZ1bmMoX2dldFRhcmdldChlbGVtZW50KSwgaG9yaXpvbnRhbCA/IF9ob3Jpem9udGFsIDogX3ZlcnRpY2FsKTtcbn07XG5cblNjcm9sbFRyaWdnZXIuZ2V0QnlJZCA9IGZ1bmN0aW9uIChpZCkge1xuICByZXR1cm4gX2lkc1tpZF07XG59O1xuXG5TY3JvbGxUcmlnZ2VyLmdldEFsbCA9IGZ1bmN0aW9uICgpIHtcbiAgcmV0dXJuIF90cmlnZ2Vycy5maWx0ZXIoZnVuY3Rpb24gKHQpIHtcbiAgICByZXR1cm4gdC52YXJzLmlkICE9PSBcIlNjcm9sbFNtb290aGVyXCI7XG4gIH0pO1xufTsgLy8gaXQncyBjb21tb24gZm9yIHBlb3BsZSB0byBTY3JvbGxUcmlnZ2VyLmdldEFsbCh0ID0+IHQua2lsbCgpKSBvbiBwYWdlIHJvdXRlcywgZm9yIGV4YW1wbGUsIGFuZCB3ZSBkb24ndCB3YW50IGl0IHRvIHJ1aW4gc21vb3RoIHNjcm9sbGluZyBieSBraWxsaW5nIHRoZSBtYWluIFNjcm9sbFNtb290aGVyIG9uZS5cblxuXG5TY3JvbGxUcmlnZ2VyLmlzU2Nyb2xsaW5nID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gISFfbGFzdFNjcm9sbFRpbWU7XG59O1xuXG5TY3JvbGxUcmlnZ2VyLnNuYXBEaXJlY3Rpb25hbCA9IF9zbmFwRGlyZWN0aW9uYWw7XG5cblNjcm9sbFRyaWdnZXIuYWRkRXZlbnRMaXN0ZW5lciA9IGZ1bmN0aW9uICh0eXBlLCBjYWxsYmFjaykge1xuICB2YXIgYSA9IF9saXN0ZW5lcnNbdHlwZV0gfHwgKF9saXN0ZW5lcnNbdHlwZV0gPSBbXSk7XG4gIH5hLmluZGV4T2YoY2FsbGJhY2spIHx8IGEucHVzaChjYWxsYmFjayk7XG59O1xuXG5TY3JvbGxUcmlnZ2VyLnJlbW92ZUV2ZW50TGlzdGVuZXIgPSBmdW5jdGlvbiAodHlwZSwgY2FsbGJhY2spIHtcbiAgdmFyIGEgPSBfbGlzdGVuZXJzW3R5cGVdLFxuICAgICAgaSA9IGEgJiYgYS5pbmRleE9mKGNhbGxiYWNrKTtcbiAgaSA+PSAwICYmIGEuc3BsaWNlKGksIDEpO1xufTtcblxuU2Nyb2xsVHJpZ2dlci5iYXRjaCA9IGZ1bmN0aW9uICh0YXJnZXRzLCB2YXJzKSB7XG4gIHZhciByZXN1bHQgPSBbXSxcbiAgICAgIHZhcnNDb3B5ID0ge30sXG4gICAgICBpbnRlcnZhbCA9IHZhcnMuaW50ZXJ2YWwgfHwgMC4wMTYsXG4gICAgICBiYXRjaE1heCA9IHZhcnMuYmF0Y2hNYXggfHwgMWU5LFxuICAgICAgcHJveHlDYWxsYmFjayA9IGZ1bmN0aW9uIHByb3h5Q2FsbGJhY2sodHlwZSwgY2FsbGJhY2spIHtcbiAgICB2YXIgZWxlbWVudHMgPSBbXSxcbiAgICAgICAgdHJpZ2dlcnMgPSBbXSxcbiAgICAgICAgZGVsYXkgPSBnc2FwLmRlbGF5ZWRDYWxsKGludGVydmFsLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjYWxsYmFjayhlbGVtZW50cywgdHJpZ2dlcnMpO1xuICAgICAgZWxlbWVudHMgPSBbXTtcbiAgICAgIHRyaWdnZXJzID0gW107XG4gICAgfSkucGF1c2UoKTtcbiAgICByZXR1cm4gZnVuY3Rpb24gKHNlbGYpIHtcbiAgICAgIGVsZW1lbnRzLmxlbmd0aCB8fCBkZWxheS5yZXN0YXJ0KHRydWUpO1xuICAgICAgZWxlbWVudHMucHVzaChzZWxmLnRyaWdnZXIpO1xuICAgICAgdHJpZ2dlcnMucHVzaChzZWxmKTtcbiAgICAgIGJhdGNoTWF4IDw9IGVsZW1lbnRzLmxlbmd0aCAmJiBkZWxheS5wcm9ncmVzcygxKTtcbiAgICB9O1xuICB9LFxuICAgICAgcDtcblxuICBmb3IgKHAgaW4gdmFycykge1xuICAgIHZhcnNDb3B5W3BdID0gcC5zdWJzdHIoMCwgMikgPT09IFwib25cIiAmJiBfaXNGdW5jdGlvbih2YXJzW3BdKSAmJiBwICE9PSBcIm9uUmVmcmVzaEluaXRcIiA/IHByb3h5Q2FsbGJhY2socCwgdmFyc1twXSkgOiB2YXJzW3BdO1xuICB9XG5cbiAgaWYgKF9pc0Z1bmN0aW9uKGJhdGNoTWF4KSkge1xuICAgIGJhdGNoTWF4ID0gYmF0Y2hNYXgoKTtcblxuICAgIF9hZGRMaXN0ZW5lcihTY3JvbGxUcmlnZ2VyLCBcInJlZnJlc2hcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIGJhdGNoTWF4ID0gdmFycy5iYXRjaE1heCgpO1xuICAgIH0pO1xuICB9XG5cbiAgX3RvQXJyYXkodGFyZ2V0cykuZm9yRWFjaChmdW5jdGlvbiAodGFyZ2V0KSB7XG4gICAgdmFyIGNvbmZpZyA9IHt9O1xuXG4gICAgZm9yIChwIGluIHZhcnNDb3B5KSB7XG4gICAgICBjb25maWdbcF0gPSB2YXJzQ29weVtwXTtcbiAgICB9XG5cbiAgICBjb25maWcudHJpZ2dlciA9IHRhcmdldDtcbiAgICByZXN1bHQucHVzaChTY3JvbGxUcmlnZ2VyLmNyZWF0ZShjb25maWcpKTtcbiAgfSk7XG5cbiAgcmV0dXJuIHJlc3VsdDtcbn07IC8vIHRvIHJlZHVjZSBmaWxlIHNpemUuIGNsYW1wcyB0aGUgc2Nyb2xsIGFuZCBhbHNvIHJldHVybnMgYSBkdXJhdGlvbiBtdWx0aXBsaWVyIHNvIHRoYXQgaWYgdGhlIHNjcm9sbCBnZXRzIGNob3BwZWQgc2hvcnRlciwgdGhlIGR1cmF0aW9uIGdldHMgY3VydGFpbGVkIGFzIHdlbGwgKG90aGVyd2lzZSBpZiB5b3UncmUgdmVyeSBjbG9zZSB0byB0aGUgdG9wIG9mIHRoZSBwYWdlLCBmb3IgZXhhbXBsZSwgYW5kIHN3aXBlIHVwIHJlYWxseSBmYXN0LCBpdCdsbCBzdWRkZW5seSBzbG93IGRvd24gYW5kIHRha2UgYSBsb25nIHRpbWUgdG8gcmVhY2ggdGhlIHRvcCkuXG5cblxudmFyIF9jbGFtcFNjcm9sbEFuZEdldER1cmF0aW9uTXVsdGlwbGllciA9IGZ1bmN0aW9uIF9jbGFtcFNjcm9sbEFuZEdldER1cmF0aW9uTXVsdGlwbGllcihzY3JvbGxGdW5jLCBjdXJyZW50LCBlbmQsIG1heCkge1xuICBjdXJyZW50ID4gbWF4ID8gc2Nyb2xsRnVuYyhtYXgpIDogY3VycmVudCA8IDAgJiYgc2Nyb2xsRnVuYygwKTtcbiAgcmV0dXJuIGVuZCA+IG1heCA/IChtYXggLSBjdXJyZW50KSAvIChlbmQgLSBjdXJyZW50KSA6IGVuZCA8IDAgPyBjdXJyZW50IC8gKGN1cnJlbnQgLSBlbmQpIDogMTtcbn0sXG4gICAgX2FsbG93TmF0aXZlUGFubmluZyA9IGZ1bmN0aW9uIF9hbGxvd05hdGl2ZVBhbm5pbmcodGFyZ2V0LCBkaXJlY3Rpb24pIHtcbiAgaWYgKGRpcmVjdGlvbiA9PT0gdHJ1ZSkge1xuICAgIHRhcmdldC5zdHlsZS5yZW1vdmVQcm9wZXJ0eShcInRvdWNoLWFjdGlvblwiKTtcbiAgfSBlbHNlIHtcbiAgICB0YXJnZXQuc3R5bGUudG91Y2hBY3Rpb24gPSBkaXJlY3Rpb24gPT09IHRydWUgPyBcImF1dG9cIiA6IGRpcmVjdGlvbiA/IFwicGFuLVwiICsgZGlyZWN0aW9uICsgKE9ic2VydmVyLmlzVG91Y2ggPyBcIiBwaW5jaC16b29tXCIgOiBcIlwiKSA6IFwibm9uZVwiOyAvLyBub3RlOiBGaXJlZm94IGRvZXNuJ3Qgc3VwcG9ydCBpdCBwaW5jaC16b29tIHByb3Blcmx5LCBhdCBsZWFzdCBpbiBhZGRpdGlvbiB0byBhIHBhbi14IG9yIHBhbi15LlxuICB9XG5cbiAgdGFyZ2V0ID09PSBfZG9jRWwgJiYgX2FsbG93TmF0aXZlUGFubmluZyhfYm9keSwgZGlyZWN0aW9uKTtcbn0sXG4gICAgX292ZXJmbG93ID0ge1xuICBhdXRvOiAxLFxuICBzY3JvbGw6IDFcbn0sXG4gICAgX25lc3RlZFNjcm9sbCA9IGZ1bmN0aW9uIF9uZXN0ZWRTY3JvbGwoX3JlZjUpIHtcbiAgdmFyIGV2ZW50ID0gX3JlZjUuZXZlbnQsXG4gICAgICB0YXJnZXQgPSBfcmVmNS50YXJnZXQsXG4gICAgICBheGlzID0gX3JlZjUuYXhpcztcblxuICB2YXIgbm9kZSA9IChldmVudC5jaGFuZ2VkVG91Y2hlcyA/IGV2ZW50LmNoYW5nZWRUb3VjaGVzWzBdIDogZXZlbnQpLnRhcmdldCxcbiAgICAgIGNhY2hlID0gbm9kZS5fZ3NhcCB8fCBnc2FwLmNvcmUuZ2V0Q2FjaGUobm9kZSksXG4gICAgICB0aW1lID0gX2dldFRpbWUoKSxcbiAgICAgIGNzO1xuXG4gIGlmICghY2FjaGUuX2lzU2Nyb2xsVCB8fCB0aW1lIC0gY2FjaGUuX2lzU2Nyb2xsVCA+IDIwMDApIHtcbiAgICAvLyBjYWNoZSBmb3IgMiBzZWNvbmRzIHRvIGltcHJvdmUgcGVyZm9ybWFuY2UuXG4gICAgd2hpbGUgKG5vZGUgJiYgbm9kZSAhPT0gX2JvZHkgJiYgKG5vZGUuc2Nyb2xsSGVpZ2h0IDw9IG5vZGUuY2xpZW50SGVpZ2h0ICYmIG5vZGUuc2Nyb2xsV2lkdGggPD0gbm9kZS5jbGllbnRXaWR0aCB8fCAhKF9vdmVyZmxvd1soY3MgPSBfZ2V0Q29tcHV0ZWRTdHlsZShub2RlKSkub3ZlcmZsb3dZXSB8fCBfb3ZlcmZsb3dbY3Mub3ZlcmZsb3dYXSkpKSB7XG4gICAgICBub2RlID0gbm9kZS5wYXJlbnROb2RlO1xuICAgIH1cblxuICAgIGNhY2hlLl9pc1Njcm9sbCA9IG5vZGUgJiYgbm9kZSAhPT0gdGFyZ2V0ICYmICFfaXNWaWV3cG9ydChub2RlKSAmJiAoX292ZXJmbG93WyhjcyA9IF9nZXRDb21wdXRlZFN0eWxlKG5vZGUpKS5vdmVyZmxvd1ldIHx8IF9vdmVyZmxvd1tjcy5vdmVyZmxvd1hdKTtcbiAgICBjYWNoZS5faXNTY3JvbGxUID0gdGltZTtcbiAgfVxuXG4gIGlmIChjYWNoZS5faXNTY3JvbGwgfHwgYXhpcyA9PT0gXCJ4XCIpIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICBldmVudC5fZ3NhcEFsbG93ID0gdHJ1ZTtcbiAgfVxufSxcbiAgICAvLyBjYXB0dXJlIGV2ZW50cyBvbiBzY3JvbGxhYmxlIGVsZW1lbnRzIElOU0lERSB0aGUgPGJvZHk+IGFuZCBhbGxvdyB0aG9zZSBieSBjYWxsaW5nIHN0b3BQcm9wYWdhdGlvbigpIHdoZW4gd2UgZmluZCBhIHNjcm9sbGFibGUgYW5jZXN0b3Jcbl9pbnB1dE9ic2VydmVyID0gZnVuY3Rpb24gX2lucHV0T2JzZXJ2ZXIodGFyZ2V0LCB0eXBlLCBpbnB1dHMsIG5lc3RlZCkge1xuICByZXR1cm4gT2JzZXJ2ZXIuY3JlYXRlKHtcbiAgICB0YXJnZXQ6IHRhcmdldCxcbiAgICBjYXB0dXJlOiB0cnVlLFxuICAgIGRlYm91bmNlOiBmYWxzZSxcbiAgICBsb2NrQXhpczogdHJ1ZSxcbiAgICB0eXBlOiB0eXBlLFxuICAgIG9uV2hlZWw6IG5lc3RlZCA9IG5lc3RlZCAmJiBfbmVzdGVkU2Nyb2xsLFxuICAgIG9uUHJlc3M6IG5lc3RlZCxcbiAgICBvbkRyYWc6IG5lc3RlZCxcbiAgICBvblNjcm9sbDogbmVzdGVkLFxuICAgIG9uRW5hYmxlOiBmdW5jdGlvbiBvbkVuYWJsZSgpIHtcbiAgICAgIHJldHVybiBpbnB1dHMgJiYgX2FkZExpc3RlbmVyKF9kb2MsIE9ic2VydmVyLmV2ZW50VHlwZXNbMF0sIF9jYXB0dXJlSW5wdXRzLCBmYWxzZSwgdHJ1ZSk7XG4gICAgfSxcbiAgICBvbkRpc2FibGU6IGZ1bmN0aW9uIG9uRGlzYWJsZSgpIHtcbiAgICAgIHJldHVybiBfcmVtb3ZlTGlzdGVuZXIoX2RvYywgT2JzZXJ2ZXIuZXZlbnRUeXBlc1swXSwgX2NhcHR1cmVJbnB1dHMsIHRydWUpO1xuICAgIH1cbiAgfSk7XG59LFxuICAgIF9pbnB1dEV4cCA9IC8oaW5wdXR8bGFiZWx8c2VsZWN0fHRleHRhcmVhKS9pLFxuICAgIF9pbnB1dElzRm9jdXNlZCxcbiAgICBfY2FwdHVyZUlucHV0cyA9IGZ1bmN0aW9uIF9jYXB0dXJlSW5wdXRzKGUpIHtcbiAgdmFyIGlzSW5wdXQgPSBfaW5wdXRFeHAudGVzdChlLnRhcmdldC50YWdOYW1lKTtcblxuICBpZiAoaXNJbnB1dCB8fCBfaW5wdXRJc0ZvY3VzZWQpIHtcbiAgICBlLl9nc2FwQWxsb3cgPSB0cnVlO1xuICAgIF9pbnB1dElzRm9jdXNlZCA9IGlzSW5wdXQ7XG4gIH1cbn0sXG4gICAgX2dldFNjcm9sbE5vcm1hbGl6ZXIgPSBmdW5jdGlvbiBfZ2V0U2Nyb2xsTm9ybWFsaXplcih2YXJzKSB7XG4gIF9pc09iamVjdCh2YXJzKSB8fCAodmFycyA9IHt9KTtcbiAgdmFycy5wcmV2ZW50RGVmYXVsdCA9IHZhcnMuaXNOb3JtYWxpemVyID0gdmFycy5hbGxvd0NsaWNrcyA9IHRydWU7XG4gIHZhcnMudHlwZSB8fCAodmFycy50eXBlID0gXCJ3aGVlbCx0b3VjaFwiKTtcbiAgdmFycy5kZWJvdW5jZSA9ICEhdmFycy5kZWJvdW5jZTtcbiAgdmFycy5pZCA9IHZhcnMuaWQgfHwgXCJub3JtYWxpemVyXCI7XG5cbiAgdmFyIF92YXJzMiA9IHZhcnMsXG4gICAgICBub3JtYWxpemVTY3JvbGxYID0gX3ZhcnMyLm5vcm1hbGl6ZVNjcm9sbFgsXG4gICAgICBtb21lbnR1bSA9IF92YXJzMi5tb21lbnR1bSxcbiAgICAgIGFsbG93TmVzdGVkU2Nyb2xsID0gX3ZhcnMyLmFsbG93TmVzdGVkU2Nyb2xsLFxuICAgICAgb25SZWxlYXNlID0gX3ZhcnMyLm9uUmVsZWFzZSxcbiAgICAgIHNlbGYsXG4gICAgICBtYXhZLFxuICAgICAgdGFyZ2V0ID0gX2dldFRhcmdldCh2YXJzLnRhcmdldCkgfHwgX2RvY0VsLFxuICAgICAgc21vb3RoZXIgPSBnc2FwLmNvcmUuZ2xvYmFscygpLlNjcm9sbFNtb290aGVyLFxuICAgICAgc21vb3RoZXJJbnN0YW5jZSA9IHNtb290aGVyICYmIHNtb290aGVyLmdldCgpLFxuICAgICAgY29udGVudCA9IF9maXhJT1NCdWcgJiYgKHZhcnMuY29udGVudCAmJiBfZ2V0VGFyZ2V0KHZhcnMuY29udGVudCkgfHwgc21vb3RoZXJJbnN0YW5jZSAmJiB2YXJzLmNvbnRlbnQgIT09IGZhbHNlICYmICFzbW9vdGhlckluc3RhbmNlLnNtb290aCgpICYmIHNtb290aGVySW5zdGFuY2UuY29udGVudCgpKSxcbiAgICAgIHNjcm9sbEZ1bmNZID0gX2dldFNjcm9sbEZ1bmModGFyZ2V0LCBfdmVydGljYWwpLFxuICAgICAgc2Nyb2xsRnVuY1ggPSBfZ2V0U2Nyb2xsRnVuYyh0YXJnZXQsIF9ob3Jpem9udGFsKSxcbiAgICAgIHNjYWxlID0gMSxcbiAgICAgIGluaXRpYWxTY2FsZSA9IChPYnNlcnZlci5pc1RvdWNoICYmIF93aW4udmlzdWFsVmlld3BvcnQgPyBfd2luLnZpc3VhbFZpZXdwb3J0LnNjYWxlICogX3dpbi52aXN1YWxWaWV3cG9ydC53aWR0aCA6IF93aW4ub3V0ZXJXaWR0aCkgLyBfd2luLmlubmVyV2lkdGgsXG4gICAgICB3aGVlbFJlZnJlc2ggPSAwLFxuICAgICAgcmVzb2x2ZU1vbWVudHVtRHVyYXRpb24gPSBfaXNGdW5jdGlvbihtb21lbnR1bSkgPyBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIG1vbWVudHVtKHNlbGYpO1xuICB9IDogZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBtb21lbnR1bSB8fCAyLjg7XG4gIH0sXG4gICAgICBsYXN0UmVmcmVzaElELFxuICAgICAgc2tpcFRvdWNoTW92ZSxcbiAgICAgIGlucHV0T2JzZXJ2ZXIgPSBfaW5wdXRPYnNlcnZlcih0YXJnZXQsIHZhcnMudHlwZSwgdHJ1ZSwgYWxsb3dOZXN0ZWRTY3JvbGwpLFxuICAgICAgcmVzdW1lVG91Y2hNb3ZlID0gZnVuY3Rpb24gcmVzdW1lVG91Y2hNb3ZlKCkge1xuICAgIHJldHVybiBza2lwVG91Y2hNb3ZlID0gZmFsc2U7XG4gIH0sXG4gICAgICBzY3JvbGxDbGFtcFggPSBfcGFzc1Rocm91Z2gsXG4gICAgICBzY3JvbGxDbGFtcFkgPSBfcGFzc1Rocm91Z2gsXG4gICAgICB1cGRhdGVDbGFtcHMgPSBmdW5jdGlvbiB1cGRhdGVDbGFtcHMoKSB7XG4gICAgbWF4WSA9IF9tYXhTY3JvbGwodGFyZ2V0LCBfdmVydGljYWwpO1xuICAgIHNjcm9sbENsYW1wWSA9IF9jbGFtcChfZml4SU9TQnVnID8gMSA6IDAsIG1heFkpO1xuICAgIG5vcm1hbGl6ZVNjcm9sbFggJiYgKHNjcm9sbENsYW1wWCA9IF9jbGFtcCgwLCBfbWF4U2Nyb2xsKHRhcmdldCwgX2hvcml6b250YWwpKSk7XG4gICAgbGFzdFJlZnJlc2hJRCA9IF9yZWZyZXNoSUQ7XG4gIH0sXG4gICAgICByZW1vdmVDb250ZW50T2Zmc2V0ID0gZnVuY3Rpb24gcmVtb3ZlQ29udGVudE9mZnNldCgpIHtcbiAgICBjb250ZW50Ll9nc2FwLnkgPSBfcm91bmQocGFyc2VGbG9hdChjb250ZW50Ll9nc2FwLnkpICsgc2Nyb2xsRnVuY1kub2Zmc2V0KSArIFwicHhcIjtcbiAgICBjb250ZW50LnN0eWxlLnRyYW5zZm9ybSA9IFwibWF0cml4M2QoMSwgMCwgMCwgMCwgMCwgMSwgMCwgMCwgMCwgMCwgMSwgMCwgMCwgXCIgKyBwYXJzZUZsb2F0KGNvbnRlbnQuX2dzYXAueSkgKyBcIiwgMCwgMSlcIjtcbiAgICBzY3JvbGxGdW5jWS5vZmZzZXQgPSBzY3JvbGxGdW5jWS5jYWNoZUlEID0gMDtcbiAgfSxcbiAgICAgIGlnbm9yZURyYWcgPSBmdW5jdGlvbiBpZ25vcmVEcmFnKCkge1xuICAgIGlmIChza2lwVG91Y2hNb3ZlKSB7XG4gICAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUocmVzdW1lVG91Y2hNb3ZlKTtcblxuICAgICAgdmFyIG9mZnNldCA9IF9yb3VuZChzZWxmLmRlbHRhWSAvIDIpLFxuICAgICAgICAgIHNjcm9sbCA9IHNjcm9sbENsYW1wWShzY3JvbGxGdW5jWS52IC0gb2Zmc2V0KTtcblxuICAgICAgaWYgKGNvbnRlbnQgJiYgc2Nyb2xsICE9PSBzY3JvbGxGdW5jWS52ICsgc2Nyb2xsRnVuY1kub2Zmc2V0KSB7XG4gICAgICAgIHNjcm9sbEZ1bmNZLm9mZnNldCA9IHNjcm9sbCAtIHNjcm9sbEZ1bmNZLnY7XG5cbiAgICAgICAgdmFyIHkgPSBfcm91bmQoKHBhcnNlRmxvYXQoY29udGVudCAmJiBjb250ZW50Ll9nc2FwLnkpIHx8IDApIC0gc2Nyb2xsRnVuY1kub2Zmc2V0KTtcblxuICAgICAgICBjb250ZW50LnN0eWxlLnRyYW5zZm9ybSA9IFwibWF0cml4M2QoMSwgMCwgMCwgMCwgMCwgMSwgMCwgMCwgMCwgMCwgMSwgMCwgMCwgXCIgKyB5ICsgXCIsIDAsIDEpXCI7XG4gICAgICAgIGNvbnRlbnQuX2dzYXAueSA9IHkgKyBcInB4XCI7XG4gICAgICAgIHNjcm9sbEZ1bmNZLmNhY2hlSUQgPSBfc2Nyb2xsZXJzLmNhY2hlO1xuXG4gICAgICAgIF91cGRhdGVBbGwoKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgc2Nyb2xsRnVuY1kub2Zmc2V0ICYmIHJlbW92ZUNvbnRlbnRPZmZzZXQoKTtcbiAgICBza2lwVG91Y2hNb3ZlID0gdHJ1ZTtcbiAgfSxcbiAgICAgIHR3ZWVuLFxuICAgICAgc3RhcnRTY3JvbGxYLFxuICAgICAgc3RhcnRTY3JvbGxZLFxuICAgICAgb25TdG9wRGVsYXllZENhbGwsXG4gICAgICBvblJlc2l6ZSA9IGZ1bmN0aW9uIG9uUmVzaXplKCkge1xuICAgIC8vIGlmIHRoZSB3aW5kb3cgcmVzaXplcywgbGlrZSBvbiBhbiBpUGhvbmUgd2hpY2ggQXBwbGUgRk9SQ0VTIHRoZSBhZGRyZXNzIGJhciB0byBzaG93L2hpZGUgZXZlbiBpZiB3ZSBldmVudC5wcmV2ZW50RGVmYXVsdCgpLCBpdCBtYXkgYmUgc2Nyb2xsaW5nIHRvbyBmYXIgbm93IHRoYXQgdGhlIGFkZHJlc3MgYmFyIGlzIHNob3dpbmcsIHNvIHdlIG11c3QgZHluYW1pY2FsbHkgYWRqdXN0IHRoZSBtb21lbnR1bSB0d2Vlbi5cbiAgICB1cGRhdGVDbGFtcHMoKTtcblxuICAgIGlmICh0d2Vlbi5pc0FjdGl2ZSgpICYmIHR3ZWVuLnZhcnMuc2Nyb2xsWSA+IG1heFkpIHtcbiAgICAgIHNjcm9sbEZ1bmNZKCkgPiBtYXhZID8gdHdlZW4ucHJvZ3Jlc3MoMSkgJiYgc2Nyb2xsRnVuY1kobWF4WSkgOiB0d2Vlbi5yZXNldFRvKFwic2Nyb2xsWVwiLCBtYXhZKTtcbiAgICB9XG4gIH07XG5cbiAgY29udGVudCAmJiBnc2FwLnNldChjb250ZW50LCB7XG4gICAgeTogXCIrPTBcIlxuICB9KTsgLy8gdG8gZW5zdXJlIHRoZXJlJ3MgYSBjYWNoZSAoZWxlbWVudC5fZ3NhcClcblxuICB2YXJzLmlnbm9yZUNoZWNrID0gZnVuY3Rpb24gKGUpIHtcbiAgICByZXR1cm4gX2ZpeElPU0J1ZyAmJiBlLnR5cGUgPT09IFwidG91Y2htb3ZlXCIgJiYgaWdub3JlRHJhZyhlKSB8fCBzY2FsZSA+IDEuMDUgJiYgZS50eXBlICE9PSBcInRvdWNoc3RhcnRcIiB8fCBzZWxmLmlzR2VzdHVyaW5nIHx8IGUudG91Y2hlcyAmJiBlLnRvdWNoZXMubGVuZ3RoID4gMTtcbiAgfTtcblxuICB2YXJzLm9uUHJlc3MgPSBmdW5jdGlvbiAoKSB7XG4gICAgc2tpcFRvdWNoTW92ZSA9IGZhbHNlO1xuICAgIHZhciBwcmV2U2NhbGUgPSBzY2FsZTtcbiAgICBzY2FsZSA9IF9yb3VuZCgoX3dpbi52aXN1YWxWaWV3cG9ydCAmJiBfd2luLnZpc3VhbFZpZXdwb3J0LnNjYWxlIHx8IDEpIC8gaW5pdGlhbFNjYWxlKTtcbiAgICB0d2Vlbi5wYXVzZSgpO1xuICAgIHByZXZTY2FsZSAhPT0gc2NhbGUgJiYgX2FsbG93TmF0aXZlUGFubmluZyh0YXJnZXQsIHNjYWxlID4gMS4wMSA/IHRydWUgOiBub3JtYWxpemVTY3JvbGxYID8gZmFsc2UgOiBcInhcIik7XG4gICAgc3RhcnRTY3JvbGxYID0gc2Nyb2xsRnVuY1goKTtcbiAgICBzdGFydFNjcm9sbFkgPSBzY3JvbGxGdW5jWSgpO1xuICAgIHVwZGF0ZUNsYW1wcygpO1xuICAgIGxhc3RSZWZyZXNoSUQgPSBfcmVmcmVzaElEO1xuICB9O1xuXG4gIHZhcnMub25SZWxlYXNlID0gdmFycy5vbkdlc3R1cmVTdGFydCA9IGZ1bmN0aW9uIChzZWxmLCB3YXNEcmFnZ2luZykge1xuICAgIHNjcm9sbEZ1bmNZLm9mZnNldCAmJiByZW1vdmVDb250ZW50T2Zmc2V0KCk7XG5cbiAgICBpZiAoIXdhc0RyYWdnaW5nKSB7XG4gICAgICBvblN0b3BEZWxheWVkQ2FsbC5yZXN0YXJ0KHRydWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICBfc2Nyb2xsZXJzLmNhY2hlKys7IC8vIG1ha2Ugc3VyZSB3ZSdyZSBwdWxsaW5nIHRoZSBub24tY2FjaGVkIHZhbHVlXG4gICAgICAvLyBhbHRlcm5hdGUgYWxnb3JpdGhtOiBkdXJYID0gTWF0aC5taW4oNiwgTWF0aC5hYnMoc2VsZi52ZWxvY2l0eVggLyA4MDApKSxcdGR1ciA9IE1hdGgubWF4KGR1clgsIE1hdGgubWluKDYsIE1hdGguYWJzKHNlbGYudmVsb2NpdHlZIC8gODAwKSkpOyBkdXIgPSBkdXIgKiAoMC40ICsgKDEgLSBfcG93ZXI0SW4oZHVyIC8gNikpICogMC42KSkgKiAobW9tZW50dW1TcGVlZCB8fCAxKVxuXG4gICAgICB2YXIgZHVyID0gcmVzb2x2ZU1vbWVudHVtRHVyYXRpb24oKSxcbiAgICAgICAgICBjdXJyZW50U2Nyb2xsLFxuICAgICAgICAgIGVuZFNjcm9sbDtcblxuICAgICAgaWYgKG5vcm1hbGl6ZVNjcm9sbFgpIHtcbiAgICAgICAgY3VycmVudFNjcm9sbCA9IHNjcm9sbEZ1bmNYKCk7XG4gICAgICAgIGVuZFNjcm9sbCA9IGN1cnJlbnRTY3JvbGwgKyBkdXIgKiAwLjA1ICogLXNlbGYudmVsb2NpdHlYIC8gMC4yMjc7IC8vIHRoZSBjb25zdGFudCAuMjI3IGlzIGZyb20gcG93ZXI0KDAuMDUpLiB2ZWxvY2l0eSBpcyBpbnZlcnRlZCBiZWNhdXNlIHNjcm9sbGluZyBnb2VzIGluIHRoZSBvcHBvc2l0ZSBkaXJlY3Rpb24uXG5cbiAgICAgICAgZHVyICo9IF9jbGFtcFNjcm9sbEFuZEdldER1cmF0aW9uTXVsdGlwbGllcihzY3JvbGxGdW5jWCwgY3VycmVudFNjcm9sbCwgZW5kU2Nyb2xsLCBfbWF4U2Nyb2xsKHRhcmdldCwgX2hvcml6b250YWwpKTtcbiAgICAgICAgdHdlZW4udmFycy5zY3JvbGxYID0gc2Nyb2xsQ2xhbXBYKGVuZFNjcm9sbCk7XG4gICAgICB9XG5cbiAgICAgIGN1cnJlbnRTY3JvbGwgPSBzY3JvbGxGdW5jWSgpO1xuICAgICAgZW5kU2Nyb2xsID0gY3VycmVudFNjcm9sbCArIGR1ciAqIDAuMDUgKiAtc2VsZi52ZWxvY2l0eVkgLyAwLjIyNzsgLy8gdGhlIGNvbnN0YW50IC4yMjcgaXMgZnJvbSBwb3dlcjQoMC4wNSlcblxuICAgICAgZHVyICo9IF9jbGFtcFNjcm9sbEFuZEdldER1cmF0aW9uTXVsdGlwbGllcihzY3JvbGxGdW5jWSwgY3VycmVudFNjcm9sbCwgZW5kU2Nyb2xsLCBfbWF4U2Nyb2xsKHRhcmdldCwgX3ZlcnRpY2FsKSk7XG4gICAgICB0d2Vlbi52YXJzLnNjcm9sbFkgPSBzY3JvbGxDbGFtcFkoZW5kU2Nyb2xsKTtcbiAgICAgIHR3ZWVuLmludmFsaWRhdGUoKS5kdXJhdGlvbihkdXIpLnBsYXkoMC4wMSk7XG5cbiAgICAgIGlmIChfZml4SU9TQnVnICYmIHR3ZWVuLnZhcnMuc2Nyb2xsWSA+PSBtYXhZIHx8IGN1cnJlbnRTY3JvbGwgPj0gbWF4WSAtIDEpIHtcbiAgICAgICAgLy8gaU9TIGJ1ZzogaXQnbGwgc2hvdyB0aGUgYWRkcmVzcyBiYXIgYnV0IE5PVCBmaXJlIHRoZSB3aW5kb3cgXCJyZXNpemVcIiBldmVudCB1bnRpbCB0aGUgYW5pbWF0aW9uIGlzIGRvbmUgYnV0IHdlIG11c3QgcHJvdGVjdCBhZ2FpbnN0IG92ZXJzaG9vdCBzbyB3ZSBsZXZlcmFnZSBhbiBvblVwZGF0ZSB0byBkbyBzby5cbiAgICAgICAgZ3NhcC50byh7fSwge1xuICAgICAgICAgIG9uVXBkYXRlOiBvblJlc2l6ZSxcbiAgICAgICAgICBkdXJhdGlvbjogZHVyXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIG9uUmVsZWFzZSAmJiBvblJlbGVhc2Uoc2VsZik7XG4gIH07XG5cbiAgdmFycy5vbldoZWVsID0gZnVuY3Rpb24gKCkge1xuICAgIHR3ZWVuLl90cyAmJiB0d2Vlbi5wYXVzZSgpO1xuXG4gICAgaWYgKF9nZXRUaW1lKCkgLSB3aGVlbFJlZnJlc2ggPiAxMDAwKSB7XG4gICAgICAvLyBhZnRlciAxIHNlY29uZCwgcmVmcmVzaCB0aGUgY2xhbXBzIG90aGVyd2lzZSB0aGF0J2xsIG9ubHkgaGFwcGVuIHdoZW4gU2Nyb2xsVHJpZ2dlci5yZWZyZXNoKCkgaXMgY2FsbGVkIG9yIGZvciB0b3VjaC1zY3JvbGxpbmcuXG4gICAgICBsYXN0UmVmcmVzaElEID0gMDtcbiAgICAgIHdoZWVsUmVmcmVzaCA9IF9nZXRUaW1lKCk7XG4gICAgfVxuICB9O1xuXG4gIHZhcnMub25DaGFuZ2UgPSBmdW5jdGlvbiAoc2VsZiwgZHgsIGR5LCB4QXJyYXksIHlBcnJheSkge1xuICAgIF9yZWZyZXNoSUQgIT09IGxhc3RSZWZyZXNoSUQgJiYgdXBkYXRlQ2xhbXBzKCk7XG4gICAgZHggJiYgbm9ybWFsaXplU2Nyb2xsWCAmJiBzY3JvbGxGdW5jWChzY3JvbGxDbGFtcFgoeEFycmF5WzJdID09PSBkeCA/IHN0YXJ0U2Nyb2xsWCArIChzZWxmLnN0YXJ0WCAtIHNlbGYueCkgOiBzY3JvbGxGdW5jWCgpICsgZHggLSB4QXJyYXlbMV0pKTsgLy8gZm9yIG1vcmUgcHJlY2lzaW9uLCB3ZSB0cmFjayBwb2ludGVyL3RvdWNoIG1vdmVtZW50IGZyb20gdGhlIHN0YXJ0LCBvdGhlcndpc2UgaXQnbGwgZHJpZnQuXG5cbiAgICBpZiAoZHkpIHtcbiAgICAgIHNjcm9sbEZ1bmNZLm9mZnNldCAmJiByZW1vdmVDb250ZW50T2Zmc2V0KCk7XG4gICAgICB2YXIgaXNUb3VjaCA9IHlBcnJheVsyXSA9PT0gZHksXG4gICAgICAgICAgeSA9IGlzVG91Y2ggPyBzdGFydFNjcm9sbFkgKyBzZWxmLnN0YXJ0WSAtIHNlbGYueSA6IHNjcm9sbEZ1bmNZKCkgKyBkeSAtIHlBcnJheVsxXSxcbiAgICAgICAgICB5Q2xhbXBlZCA9IHNjcm9sbENsYW1wWSh5KTtcbiAgICAgIGlzVG91Y2ggJiYgeSAhPT0geUNsYW1wZWQgJiYgKHN0YXJ0U2Nyb2xsWSArPSB5Q2xhbXBlZCAtIHkpO1xuICAgICAgc2Nyb2xsRnVuY1koeUNsYW1wZWQpO1xuICAgIH1cblxuICAgIChkeSB8fCBkeCkgJiYgX3VwZGF0ZUFsbCgpO1xuICB9O1xuXG4gIHZhcnMub25FbmFibGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgX2FsbG93TmF0aXZlUGFubmluZyh0YXJnZXQsIG5vcm1hbGl6ZVNjcm9sbFggPyBmYWxzZSA6IFwieFwiKTtcblxuICAgIFNjcm9sbFRyaWdnZXIuYWRkRXZlbnRMaXN0ZW5lcihcInJlZnJlc2hcIiwgb25SZXNpemUpO1xuXG4gICAgX2FkZExpc3RlbmVyKF93aW4sIFwicmVzaXplXCIsIG9uUmVzaXplKTtcblxuICAgIGlmIChzY3JvbGxGdW5jWS5zbW9vdGgpIHtcbiAgICAgIHNjcm9sbEZ1bmNZLnRhcmdldC5zdHlsZS5zY3JvbGxCZWhhdmlvciA9IFwiYXV0b1wiO1xuICAgICAgc2Nyb2xsRnVuY1kuc21vb3RoID0gc2Nyb2xsRnVuY1guc21vb3RoID0gZmFsc2U7XG4gICAgfVxuXG4gICAgaW5wdXRPYnNlcnZlci5lbmFibGUoKTtcbiAgfTtcblxuICB2YXJzLm9uRGlzYWJsZSA9IGZ1bmN0aW9uICgpIHtcbiAgICBfYWxsb3dOYXRpdmVQYW5uaW5nKHRhcmdldCwgdHJ1ZSk7XG5cbiAgICBfcmVtb3ZlTGlzdGVuZXIoX3dpbiwgXCJyZXNpemVcIiwgb25SZXNpemUpO1xuXG4gICAgU2Nyb2xsVHJpZ2dlci5yZW1vdmVFdmVudExpc3RlbmVyKFwicmVmcmVzaFwiLCBvblJlc2l6ZSk7XG4gICAgaW5wdXRPYnNlcnZlci5raWxsKCk7XG4gIH07XG5cbiAgdmFycy5sb2NrQXhpcyA9IHZhcnMubG9ja0F4aXMgIT09IGZhbHNlO1xuICBzZWxmID0gbmV3IE9ic2VydmVyKHZhcnMpO1xuICBzZWxmLmlPUyA9IF9maXhJT1NCdWc7IC8vIHVzZWQgaW4gdGhlIE9ic2VydmVyIGdldENhY2hlZFNjcm9sbCgpIGZ1bmN0aW9uIHRvIHdvcmsgYXJvdW5kIGFuIGlPUyBidWcgdGhhdCB3cmVha3MgaGF2b2Mgd2l0aCBUb3VjaEV2ZW50LmNsaWVudFkgaWYgd2UgYWxsb3cgc2Nyb2xsIHRvIGdvIGFsbCB0aGUgd2F5IGJhY2sgdG8gMC5cblxuICBfZml4SU9TQnVnICYmICFzY3JvbGxGdW5jWSgpICYmIHNjcm9sbEZ1bmNZKDEpOyAvLyBpT1MgYnVnIGNhdXNlcyBldmVudC5jbGllbnRZIHZhbHVlcyB0byBmcmVhayBvdXQgKHdpbGRseSBpbmFjY3VyYXRlKSBpZiB0aGUgc2Nyb2xsIHBvc2l0aW9uIGlzIGV4YWN0bHkgMC5cblxuICBfZml4SU9TQnVnICYmIGdzYXAudGlja2VyLmFkZChfcGFzc1Rocm91Z2gpOyAvLyBwcmV2ZW50IHRoZSB0aWNrZXIgZnJvbSBzbGVlcGluZ1xuXG4gIG9uU3RvcERlbGF5ZWRDYWxsID0gc2VsZi5fZGM7XG4gIHR3ZWVuID0gZ3NhcC50byhzZWxmLCB7XG4gICAgZWFzZTogXCJwb3dlcjRcIixcbiAgICBwYXVzZWQ6IHRydWUsXG4gICAgaW5oZXJpdDogZmFsc2UsXG4gICAgc2Nyb2xsWDogbm9ybWFsaXplU2Nyb2xsWCA/IFwiKz0wLjFcIiA6IFwiKz0wXCIsXG4gICAgc2Nyb2xsWTogXCIrPTAuMVwiLFxuICAgIG1vZGlmaWVyczoge1xuICAgICAgc2Nyb2xsWTogX2ludGVycnVwdGlvblRyYWNrZXIoc2Nyb2xsRnVuY1ksIHNjcm9sbEZ1bmNZKCksIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHR3ZWVuLnBhdXNlKCk7XG4gICAgICB9KVxuICAgIH0sXG4gICAgb25VcGRhdGU6IF91cGRhdGVBbGwsXG4gICAgb25Db21wbGV0ZTogb25TdG9wRGVsYXllZENhbGwudmFycy5vbkNvbXBsZXRlXG4gIH0pOyAvLyB3ZSBuZWVkIHRoZSBtb2RpZmllciB0byBzZW5zZSBpZiB0aGUgc2Nyb2xsIHBvc2l0aW9uIGlzIGFsdGVyZWQgb3V0c2lkZSBvZiB0aGUgbW9tZW50dW0gdHdlZW4gKGxpa2Ugd2l0aCBhIHNjcm9sbFRvIHR3ZWVuKSBzbyB3ZSBjYW4gcGF1c2UoKSBpdCB0byBwcmV2ZW50IGNvbmZsaWN0cy5cblxuICByZXR1cm4gc2VsZjtcbn07XG5cblNjcm9sbFRyaWdnZXIuc29ydCA9IGZ1bmN0aW9uIChmdW5jKSB7XG4gIHJldHVybiBfdHJpZ2dlcnMuc29ydChmdW5jIHx8IGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgcmV0dXJuIChhLnZhcnMucmVmcmVzaFByaW9yaXR5IHx8IDApICogLTFlNiArIGEuc3RhcnQgLSAoYi5zdGFydCArIChiLnZhcnMucmVmcmVzaFByaW9yaXR5IHx8IDApICogLTFlNik7XG4gIH0pO1xufTtcblxuU2Nyb2xsVHJpZ2dlci5vYnNlcnZlID0gZnVuY3Rpb24gKHZhcnMpIHtcbiAgcmV0dXJuIG5ldyBPYnNlcnZlcih2YXJzKTtcbn07XG5cblNjcm9sbFRyaWdnZXIubm9ybWFsaXplU2Nyb2xsID0gZnVuY3Rpb24gKHZhcnMpIHtcbiAgaWYgKHR5cGVvZiB2YXJzID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgcmV0dXJuIF9ub3JtYWxpemVyO1xuICB9XG5cbiAgaWYgKHZhcnMgPT09IHRydWUgJiYgX25vcm1hbGl6ZXIpIHtcbiAgICByZXR1cm4gX25vcm1hbGl6ZXIuZW5hYmxlKCk7XG4gIH1cblxuICBpZiAodmFycyA9PT0gZmFsc2UpIHtcbiAgICBfbm9ybWFsaXplciAmJiBfbm9ybWFsaXplci5raWxsKCk7XG4gICAgX25vcm1hbGl6ZXIgPSB2YXJzO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIHZhciBub3JtYWxpemVyID0gdmFycyBpbnN0YW5jZW9mIE9ic2VydmVyID8gdmFycyA6IF9nZXRTY3JvbGxOb3JtYWxpemVyKHZhcnMpO1xuICBfbm9ybWFsaXplciAmJiBfbm9ybWFsaXplci50YXJnZXQgPT09IG5vcm1hbGl6ZXIudGFyZ2V0ICYmIF9ub3JtYWxpemVyLmtpbGwoKTtcbiAgX2lzVmlld3BvcnQobm9ybWFsaXplci50YXJnZXQpICYmIChfbm9ybWFsaXplciA9IG5vcm1hbGl6ZXIpO1xuICByZXR1cm4gbm9ybWFsaXplcjtcbn07XG5cblNjcm9sbFRyaWdnZXIuY29yZSA9IHtcbiAgLy8gc21hbGxlciBmaWxlIHNpemUgd2F5IHRvIGxldmVyYWdlIGluIFNjcm9sbFNtb290aGVyIGFuZCBPYnNlcnZlclxuICBfZ2V0VmVsb2NpdHlQcm9wOiBfZ2V0VmVsb2NpdHlQcm9wLFxuICBfaW5wdXRPYnNlcnZlcjogX2lucHV0T2JzZXJ2ZXIsXG4gIF9zY3JvbGxlcnM6IF9zY3JvbGxlcnMsXG4gIF9wcm94aWVzOiBfcHJveGllcyxcbiAgYnJpZGdlOiB7XG4gICAgLy8gd2hlbiBub3JtYWxpemVTY3JvbGwgc2V0cyB0aGUgc2Nyb2xsIHBvc2l0aW9uIChzcyA9IHNldFNjcm9sbClcbiAgICBzczogZnVuY3Rpb24gc3MoKSB7XG4gICAgICBfbGFzdFNjcm9sbFRpbWUgfHwgX2Rpc3BhdGNoKFwic2Nyb2xsU3RhcnRcIik7XG4gICAgICBfbGFzdFNjcm9sbFRpbWUgPSBfZ2V0VGltZSgpO1xuICAgIH0sXG4gICAgLy8gYSB3YXkgdG8gZ2V0IHRoZSBfcmVmcmVzaGluZyB2YWx1ZSBpbiBPYnNlcnZlclxuICAgIHJlZjogZnVuY3Rpb24gcmVmKCkge1xuICAgICAgcmV0dXJuIF9yZWZyZXNoaW5nO1xuICAgIH1cbiAgfVxufTtcbl9nZXRHU0FQKCkgJiYgZ3NhcC5yZWdpc3RlclBsdWdpbihTY3JvbGxUcmlnZ2VyKTtcbmV4cG9ydCB7IFNjcm9sbFRyaWdnZXIgYXMgZGVmYXVsdCB9OyIsIi8qIVxuICogU2Nyb2xsVG9QbHVnaW4gMy4xMi41XG4gKiBodHRwczovL2dzYXAuY29tXG4gKlxuICogQGxpY2Vuc2UgQ29weXJpZ2h0IDIwMDgtMjAyNCwgR3JlZW5Tb2NrLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogU3ViamVjdCB0byB0aGUgdGVybXMgYXQgaHR0cHM6Ly9nc2FwLmNvbS9zdGFuZGFyZC1saWNlbnNlIG9yIGZvclxuICogQ2x1YiBHU0FQIG1lbWJlcnMsIHRoZSBhZ3JlZW1lbnQgaXNzdWVkIHdpdGggdGhhdCBtZW1iZXJzaGlwLlxuICogQGF1dGhvcjogSmFjayBEb3lsZSwgamFja0BncmVlbnNvY2suY29tXG4qL1xuXG4vKiBlc2xpbnQtZGlzYWJsZSAqL1xudmFyIGdzYXAsXG4gICAgX2NvcmVJbml0dGVkLFxuICAgIF93aW5kb3csXG4gICAgX2RvY0VsLFxuICAgIF9ib2R5LFxuICAgIF90b0FycmF5LFxuICAgIF9jb25maWcsXG4gICAgU2Nyb2xsVHJpZ2dlcixcbiAgICBfd2luZG93RXhpc3RzID0gZnVuY3Rpb24gX3dpbmRvd0V4aXN0cygpIHtcbiAgcmV0dXJuIHR5cGVvZiB3aW5kb3cgIT09IFwidW5kZWZpbmVkXCI7XG59LFxuICAgIF9nZXRHU0FQID0gZnVuY3Rpb24gX2dldEdTQVAoKSB7XG4gIHJldHVybiBnc2FwIHx8IF93aW5kb3dFeGlzdHMoKSAmJiAoZ3NhcCA9IHdpbmRvdy5nc2FwKSAmJiBnc2FwLnJlZ2lzdGVyUGx1Z2luICYmIGdzYXA7XG59LFxuICAgIF9pc1N0cmluZyA9IGZ1bmN0aW9uIF9pc1N0cmluZyh2YWx1ZSkge1xuICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiO1xufSxcbiAgICBfaXNGdW5jdGlvbiA9IGZ1bmN0aW9uIF9pc0Z1bmN0aW9uKHZhbHVlKSB7XG4gIHJldHVybiB0eXBlb2YgdmFsdWUgPT09IFwiZnVuY3Rpb25cIjtcbn0sXG4gICAgX21heCA9IGZ1bmN0aW9uIF9tYXgoZWxlbWVudCwgYXhpcykge1xuICB2YXIgZGltID0gYXhpcyA9PT0gXCJ4XCIgPyBcIldpZHRoXCIgOiBcIkhlaWdodFwiLFxuICAgICAgc2Nyb2xsID0gXCJzY3JvbGxcIiArIGRpbSxcbiAgICAgIGNsaWVudCA9IFwiY2xpZW50XCIgKyBkaW07XG4gIHJldHVybiBlbGVtZW50ID09PSBfd2luZG93IHx8IGVsZW1lbnQgPT09IF9kb2NFbCB8fCBlbGVtZW50ID09PSBfYm9keSA/IE1hdGgubWF4KF9kb2NFbFtzY3JvbGxdLCBfYm9keVtzY3JvbGxdKSAtIChfd2luZG93W1wiaW5uZXJcIiArIGRpbV0gfHwgX2RvY0VsW2NsaWVudF0gfHwgX2JvZHlbY2xpZW50XSkgOiBlbGVtZW50W3Njcm9sbF0gLSBlbGVtZW50W1wib2Zmc2V0XCIgKyBkaW1dO1xufSxcbiAgICBfYnVpbGRHZXR0ZXIgPSBmdW5jdGlvbiBfYnVpbGRHZXR0ZXIoZSwgYXhpcykge1xuICAvL3Bhc3MgaW4gYW4gZWxlbWVudCBhbmQgYW4gYXhpcyAoXCJ4XCIgb3IgXCJ5XCIpIGFuZCBpdCdsbCByZXR1cm4gYSBnZXR0ZXIgZnVuY3Rpb24gZm9yIHRoZSBzY3JvbGwgcG9zaXRpb24gb2YgdGhhdCBlbGVtZW50IChsaWtlIHNjcm9sbFRvcCBvciBzY3JvbGxMZWZ0LCBhbHRob3VnaCBpZiB0aGUgZWxlbWVudCBpcyB0aGUgd2luZG93LCBpdCdsbCB1c2UgdGhlIHBhZ2VYT2Zmc2V0L3BhZ2VZT2Zmc2V0IG9yIHRoZSBkb2N1bWVudEVsZW1lbnQncyBzY3JvbGxUb3Avc2Nyb2xsTGVmdCBvciBkb2N1bWVudC5ib2R5J3MuIEJhc2ljYWxseSB0aGlzIHN0cmVhbWxpbmVzIHRoaW5ncyBhbmQgbWFrZXMgYSB2ZXJ5IGZhc3QgZ2V0dGVyIGFjcm9zcyBicm93c2Vycy5cbiAgdmFyIHAgPSBcInNjcm9sbFwiICsgKGF4aXMgPT09IFwieFwiID8gXCJMZWZ0XCIgOiBcIlRvcFwiKTtcblxuICBpZiAoZSA9PT0gX3dpbmRvdykge1xuICAgIGlmIChlLnBhZ2VYT2Zmc2V0ICE9IG51bGwpIHtcbiAgICAgIHAgPSBcInBhZ2VcIiArIGF4aXMudG9VcHBlckNhc2UoKSArIFwiT2Zmc2V0XCI7XG4gICAgfSBlbHNlIHtcbiAgICAgIGUgPSBfZG9jRWxbcF0gIT0gbnVsbCA/IF9kb2NFbCA6IF9ib2R5O1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIGVbcF07XG4gIH07XG59LFxuICAgIF9jbGVhbiA9IGZ1bmN0aW9uIF9jbGVhbih2YWx1ZSwgaW5kZXgsIHRhcmdldCwgdGFyZ2V0cykge1xuICBfaXNGdW5jdGlvbih2YWx1ZSkgJiYgKHZhbHVlID0gdmFsdWUoaW5kZXgsIHRhcmdldCwgdGFyZ2V0cykpO1xuXG4gIGlmICh0eXBlb2YgdmFsdWUgIT09IFwib2JqZWN0XCIpIHtcbiAgICByZXR1cm4gX2lzU3RyaW5nKHZhbHVlKSAmJiB2YWx1ZSAhPT0gXCJtYXhcIiAmJiB2YWx1ZS5jaGFyQXQoMSkgIT09IFwiPVwiID8ge1xuICAgICAgeDogdmFsdWUsXG4gICAgICB5OiB2YWx1ZVxuICAgIH0gOiB7XG4gICAgICB5OiB2YWx1ZVxuICAgIH07IC8vaWYgd2UgZG9uJ3QgcmVjZWl2ZSBhbiBvYmplY3QgYXMgdGhlIHBhcmFtZXRlciwgYXNzdW1lIHRoZSB1c2VyIGludGVuZHMgXCJ5XCIuXG4gIH0gZWxzZSBpZiAodmFsdWUubm9kZVR5cGUpIHtcbiAgICByZXR1cm4ge1xuICAgICAgeTogdmFsdWUsXG4gICAgICB4OiB2YWx1ZVxuICAgIH07XG4gIH0gZWxzZSB7XG4gICAgdmFyIHJlc3VsdCA9IHt9LFxuICAgICAgICBwO1xuXG4gICAgZm9yIChwIGluIHZhbHVlKSB7XG4gICAgICByZXN1bHRbcF0gPSBwICE9PSBcIm9uQXV0b0tpbGxcIiAmJiBfaXNGdW5jdGlvbih2YWx1ZVtwXSkgPyB2YWx1ZVtwXShpbmRleCwgdGFyZ2V0LCB0YXJnZXRzKSA6IHZhbHVlW3BdO1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbn0sXG4gICAgX2dldE9mZnNldCA9IGZ1bmN0aW9uIF9nZXRPZmZzZXQoZWxlbWVudCwgY29udGFpbmVyKSB7XG4gIGVsZW1lbnQgPSBfdG9BcnJheShlbGVtZW50KVswXTtcblxuICBpZiAoIWVsZW1lbnQgfHwgIWVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KSB7XG4gICAgcmV0dXJuIGNvbnNvbGUud2FybihcInNjcm9sbFRvIHRhcmdldCBkb2Vzbid0IGV4aXN0LiBVc2luZyAwXCIpIHx8IHtcbiAgICAgIHg6IDAsXG4gICAgICB5OiAwXG4gICAgfTtcbiAgfVxuXG4gIHZhciByZWN0ID0gZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKSxcbiAgICAgIGlzUm9vdCA9ICFjb250YWluZXIgfHwgY29udGFpbmVyID09PSBfd2luZG93IHx8IGNvbnRhaW5lciA9PT0gX2JvZHksXG4gICAgICBjUmVjdCA9IGlzUm9vdCA/IHtcbiAgICB0b3A6IF9kb2NFbC5jbGllbnRUb3AgLSAoX3dpbmRvdy5wYWdlWU9mZnNldCB8fCBfZG9jRWwuc2Nyb2xsVG9wIHx8IF9ib2R5LnNjcm9sbFRvcCB8fCAwKSxcbiAgICBsZWZ0OiBfZG9jRWwuY2xpZW50TGVmdCAtIChfd2luZG93LnBhZ2VYT2Zmc2V0IHx8IF9kb2NFbC5zY3JvbGxMZWZ0IHx8IF9ib2R5LnNjcm9sbExlZnQgfHwgMClcbiAgfSA6IGNvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKSxcbiAgICAgIG9mZnNldHMgPSB7XG4gICAgeDogcmVjdC5sZWZ0IC0gY1JlY3QubGVmdCxcbiAgICB5OiByZWN0LnRvcCAtIGNSZWN0LnRvcFxuICB9O1xuXG4gIGlmICghaXNSb290ICYmIGNvbnRhaW5lcikge1xuICAgIC8vb25seSBhZGQgdGhlIGN1cnJlbnQgc2Nyb2xsIHBvc2l0aW9uIGlmIGl0J3Mgbm90IHRoZSB3aW5kb3cvYm9keS5cbiAgICBvZmZzZXRzLnggKz0gX2J1aWxkR2V0dGVyKGNvbnRhaW5lciwgXCJ4XCIpKCk7XG4gICAgb2Zmc2V0cy55ICs9IF9idWlsZEdldHRlcihjb250YWluZXIsIFwieVwiKSgpO1xuICB9XG5cbiAgcmV0dXJuIG9mZnNldHM7XG59LFxuICAgIF9wYXJzZVZhbCA9IGZ1bmN0aW9uIF9wYXJzZVZhbCh2YWx1ZSwgdGFyZ2V0LCBheGlzLCBjdXJyZW50VmFsLCBvZmZzZXQpIHtcbiAgcmV0dXJuICFpc05hTih2YWx1ZSkgJiYgdHlwZW9mIHZhbHVlICE9PSBcIm9iamVjdFwiID8gcGFyc2VGbG9hdCh2YWx1ZSkgLSBvZmZzZXQgOiBfaXNTdHJpbmcodmFsdWUpICYmIHZhbHVlLmNoYXJBdCgxKSA9PT0gXCI9XCIgPyBwYXJzZUZsb2F0KHZhbHVlLnN1YnN0cigyKSkgKiAodmFsdWUuY2hhckF0KDApID09PSBcIi1cIiA/IC0xIDogMSkgKyBjdXJyZW50VmFsIC0gb2Zmc2V0IDogdmFsdWUgPT09IFwibWF4XCIgPyBfbWF4KHRhcmdldCwgYXhpcykgLSBvZmZzZXQgOiBNYXRoLm1pbihfbWF4KHRhcmdldCwgYXhpcyksIF9nZXRPZmZzZXQodmFsdWUsIHRhcmdldClbYXhpc10gLSBvZmZzZXQpO1xufSxcbiAgICBfaW5pdENvcmUgPSBmdW5jdGlvbiBfaW5pdENvcmUoKSB7XG4gIGdzYXAgPSBfZ2V0R1NBUCgpO1xuXG4gIGlmIChfd2luZG93RXhpc3RzKCkgJiYgZ3NhcCAmJiB0eXBlb2YgZG9jdW1lbnQgIT09IFwidW5kZWZpbmVkXCIgJiYgZG9jdW1lbnQuYm9keSkge1xuICAgIF93aW5kb3cgPSB3aW5kb3c7XG4gICAgX2JvZHkgPSBkb2N1bWVudC5ib2R5O1xuICAgIF9kb2NFbCA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudDtcbiAgICBfdG9BcnJheSA9IGdzYXAudXRpbHMudG9BcnJheTtcbiAgICBnc2FwLmNvbmZpZyh7XG4gICAgICBhdXRvS2lsbFRocmVzaG9sZDogN1xuICAgIH0pO1xuICAgIF9jb25maWcgPSBnc2FwLmNvbmZpZygpO1xuICAgIF9jb3JlSW5pdHRlZCA9IDE7XG4gIH1cbn07XG5cbmV4cG9ydCB2YXIgU2Nyb2xsVG9QbHVnaW4gPSB7XG4gIHZlcnNpb246IFwiMy4xMi41XCIsXG4gIG5hbWU6IFwic2Nyb2xsVG9cIixcbiAgcmF3VmFyczogMSxcbiAgcmVnaXN0ZXI6IGZ1bmN0aW9uIHJlZ2lzdGVyKGNvcmUpIHtcbiAgICBnc2FwID0gY29yZTtcblxuICAgIF9pbml0Q29yZSgpO1xuICB9LFxuICBpbml0OiBmdW5jdGlvbiBpbml0KHRhcmdldCwgdmFsdWUsIHR3ZWVuLCBpbmRleCwgdGFyZ2V0cykge1xuICAgIF9jb3JlSW5pdHRlZCB8fCBfaW5pdENvcmUoKTtcbiAgICB2YXIgZGF0YSA9IHRoaXMsXG4gICAgICAgIHNuYXBUeXBlID0gZ3NhcC5nZXRQcm9wZXJ0eSh0YXJnZXQsIFwic2Nyb2xsU25hcFR5cGVcIik7XG4gICAgZGF0YS5pc1dpbiA9IHRhcmdldCA9PT0gX3dpbmRvdztcbiAgICBkYXRhLnRhcmdldCA9IHRhcmdldDtcbiAgICBkYXRhLnR3ZWVuID0gdHdlZW47XG4gICAgdmFsdWUgPSBfY2xlYW4odmFsdWUsIGluZGV4LCB0YXJnZXQsIHRhcmdldHMpO1xuICAgIGRhdGEudmFycyA9IHZhbHVlO1xuICAgIGRhdGEuYXV0b0tpbGwgPSAhIXZhbHVlLmF1dG9LaWxsO1xuICAgIGRhdGEuZ2V0WCA9IF9idWlsZEdldHRlcih0YXJnZXQsIFwieFwiKTtcbiAgICBkYXRhLmdldFkgPSBfYnVpbGRHZXR0ZXIodGFyZ2V0LCBcInlcIik7XG4gICAgZGF0YS54ID0gZGF0YS54UHJldiA9IGRhdGEuZ2V0WCgpO1xuICAgIGRhdGEueSA9IGRhdGEueVByZXYgPSBkYXRhLmdldFkoKTtcbiAgICBTY3JvbGxUcmlnZ2VyIHx8IChTY3JvbGxUcmlnZ2VyID0gZ3NhcC5jb3JlLmdsb2JhbHMoKS5TY3JvbGxUcmlnZ2VyKTtcbiAgICBnc2FwLmdldFByb3BlcnR5KHRhcmdldCwgXCJzY3JvbGxCZWhhdmlvclwiKSA9PT0gXCJzbW9vdGhcIiAmJiBnc2FwLnNldCh0YXJnZXQsIHtcbiAgICAgIHNjcm9sbEJlaGF2aW9yOiBcImF1dG9cIlxuICAgIH0pO1xuXG4gICAgaWYgKHNuYXBUeXBlICYmIHNuYXBUeXBlICE9PSBcIm5vbmVcIikge1xuICAgICAgLy8gZGlzYWJsZSBzY3JvbGwgc25hcHBpbmcgdG8gYXZvaWQgc3RyYW5nZSBiZWhhdmlvclxuICAgICAgZGF0YS5zbmFwID0gMTtcbiAgICAgIGRhdGEuc25hcElubGluZSA9IHRhcmdldC5zdHlsZS5zY3JvbGxTbmFwVHlwZTtcbiAgICAgIHRhcmdldC5zdHlsZS5zY3JvbGxTbmFwVHlwZSA9IFwibm9uZVwiO1xuICAgIH1cblxuICAgIGlmICh2YWx1ZS54ICE9IG51bGwpIHtcbiAgICAgIGRhdGEuYWRkKGRhdGEsIFwieFwiLCBkYXRhLngsIF9wYXJzZVZhbCh2YWx1ZS54LCB0YXJnZXQsIFwieFwiLCBkYXRhLngsIHZhbHVlLm9mZnNldFggfHwgMCksIGluZGV4LCB0YXJnZXRzKTtcblxuICAgICAgZGF0YS5fcHJvcHMucHVzaChcInNjcm9sbFRvX3hcIik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRhdGEuc2tpcFggPSAxO1xuICAgIH1cblxuICAgIGlmICh2YWx1ZS55ICE9IG51bGwpIHtcbiAgICAgIGRhdGEuYWRkKGRhdGEsIFwieVwiLCBkYXRhLnksIF9wYXJzZVZhbCh2YWx1ZS55LCB0YXJnZXQsIFwieVwiLCBkYXRhLnksIHZhbHVlLm9mZnNldFkgfHwgMCksIGluZGV4LCB0YXJnZXRzKTtcblxuICAgICAgZGF0YS5fcHJvcHMucHVzaChcInNjcm9sbFRvX3lcIik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRhdGEuc2tpcFkgPSAxO1xuICAgIH1cbiAgfSxcbiAgcmVuZGVyOiBmdW5jdGlvbiByZW5kZXIocmF0aW8sIGRhdGEpIHtcbiAgICB2YXIgcHQgPSBkYXRhLl9wdCxcbiAgICAgICAgdGFyZ2V0ID0gZGF0YS50YXJnZXQsXG4gICAgICAgIHR3ZWVuID0gZGF0YS50d2VlbixcbiAgICAgICAgYXV0b0tpbGwgPSBkYXRhLmF1dG9LaWxsLFxuICAgICAgICB4UHJldiA9IGRhdGEueFByZXYsXG4gICAgICAgIHlQcmV2ID0gZGF0YS55UHJldixcbiAgICAgICAgaXNXaW4gPSBkYXRhLmlzV2luLFxuICAgICAgICBzbmFwID0gZGF0YS5zbmFwLFxuICAgICAgICBzbmFwSW5saW5lID0gZGF0YS5zbmFwSW5saW5lLFxuICAgICAgICB4LFxuICAgICAgICB5LFxuICAgICAgICB5RGlmLFxuICAgICAgICB4RGlmLFxuICAgICAgICB0aHJlc2hvbGQ7XG5cbiAgICB3aGlsZSAocHQpIHtcbiAgICAgIHB0LnIocmF0aW8sIHB0LmQpO1xuICAgICAgcHQgPSBwdC5fbmV4dDtcbiAgICB9XG5cbiAgICB4ID0gaXNXaW4gfHwgIWRhdGEuc2tpcFggPyBkYXRhLmdldFgoKSA6IHhQcmV2O1xuICAgIHkgPSBpc1dpbiB8fCAhZGF0YS5za2lwWSA/IGRhdGEuZ2V0WSgpIDogeVByZXY7XG4gICAgeURpZiA9IHkgLSB5UHJldjtcbiAgICB4RGlmID0geCAtIHhQcmV2O1xuICAgIHRocmVzaG9sZCA9IF9jb25maWcuYXV0b0tpbGxUaHJlc2hvbGQ7XG5cbiAgICBpZiAoZGF0YS54IDwgMCkge1xuICAgICAgLy9jYW4ndCBzY3JvbGwgdG8gYSBwb3NpdGlvbiBsZXNzIHRoYW4gMCEgTWlnaHQgaGFwcGVuIGlmIHNvbWVvbmUgdXNlcyBhIEJhY2suZWFzZU91dCBvciBFbGFzdGljLmVhc2VPdXQgd2hlbiBzY3JvbGxpbmcgYmFjayB0byB0aGUgdG9wIG9mIHRoZSBwYWdlIChmb3IgZXhhbXBsZSlcbiAgICAgIGRhdGEueCA9IDA7XG4gICAgfVxuXG4gICAgaWYgKGRhdGEueSA8IDApIHtcbiAgICAgIGRhdGEueSA9IDA7XG4gICAgfVxuXG4gICAgaWYgKGF1dG9LaWxsKSB7XG4gICAgICAvL25vdGU6IGlPUyBoYXMgYSBidWcgdGhhdCB0aHJvd3Mgb2ZmIHRoZSBzY3JvbGwgYnkgc2V2ZXJhbCBwaXhlbHMsIHNvIHdlIG5lZWQgdG8gY2hlY2sgaWYgaXQncyB3aXRoaW4gNyBwaXhlbHMgb2YgdGhlIHByZXZpb3VzIG9uZSB0aGF0IHdlIHNldCBpbnN0ZWFkIG9mIGp1c3QgbG9va2luZyBmb3IgYW4gZXhhY3QgbWF0Y2guXG4gICAgICBpZiAoIWRhdGEuc2tpcFggJiYgKHhEaWYgPiB0aHJlc2hvbGQgfHwgeERpZiA8IC10aHJlc2hvbGQpICYmIHggPCBfbWF4KHRhcmdldCwgXCJ4XCIpKSB7XG4gICAgICAgIGRhdGEuc2tpcFggPSAxOyAvL2lmIHRoZSB1c2VyIHNjcm9sbHMgc2VwYXJhdGVseSwgd2Ugc2hvdWxkIHN0b3AgdHdlZW5pbmchXG4gICAgICB9XG5cbiAgICAgIGlmICghZGF0YS5za2lwWSAmJiAoeURpZiA+IHRocmVzaG9sZCB8fCB5RGlmIDwgLXRocmVzaG9sZCkgJiYgeSA8IF9tYXgodGFyZ2V0LCBcInlcIikpIHtcbiAgICAgICAgZGF0YS5za2lwWSA9IDE7IC8vaWYgdGhlIHVzZXIgc2Nyb2xscyBzZXBhcmF0ZWx5LCB3ZSBzaG91bGQgc3RvcCB0d2VlbmluZyFcbiAgICAgIH1cblxuICAgICAgaWYgKGRhdGEuc2tpcFggJiYgZGF0YS5za2lwWSkge1xuICAgICAgICB0d2Vlbi5raWxsKCk7XG4gICAgICAgIGRhdGEudmFycy5vbkF1dG9LaWxsICYmIGRhdGEudmFycy5vbkF1dG9LaWxsLmFwcGx5KHR3ZWVuLCBkYXRhLnZhcnMub25BdXRvS2lsbFBhcmFtcyB8fCBbXSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGlzV2luKSB7XG4gICAgICBfd2luZG93LnNjcm9sbFRvKCFkYXRhLnNraXBYID8gZGF0YS54IDogeCwgIWRhdGEuc2tpcFkgPyBkYXRhLnkgOiB5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgZGF0YS5za2lwWSB8fCAodGFyZ2V0LnNjcm9sbFRvcCA9IGRhdGEueSk7XG4gICAgICBkYXRhLnNraXBYIHx8ICh0YXJnZXQuc2Nyb2xsTGVmdCA9IGRhdGEueCk7XG4gICAgfVxuXG4gICAgaWYgKHNuYXAgJiYgKHJhdGlvID09PSAxIHx8IHJhdGlvID09PSAwKSkge1xuICAgICAgeSA9IHRhcmdldC5zY3JvbGxUb3A7XG4gICAgICB4ID0gdGFyZ2V0LnNjcm9sbExlZnQ7XG4gICAgICBzbmFwSW5saW5lID8gdGFyZ2V0LnN0eWxlLnNjcm9sbFNuYXBUeXBlID0gc25hcElubGluZSA6IHRhcmdldC5zdHlsZS5yZW1vdmVQcm9wZXJ0eShcInNjcm9sbC1zbmFwLXR5cGVcIik7XG4gICAgICB0YXJnZXQuc2Nyb2xsVG9wID0geSArIDE7IC8vIGJ1ZyBpbiBTYWZhcmkgY2F1c2VzIHRoZSBlbGVtZW50IHRvIHRvdGFsbHkgcmVzZXQgaXRzIHNjcm9sbCBwb3NpdGlvbiB3aGVuIHNjcm9sbC1zbmFwLXR5cGUgY2hhbmdlcywgc28gd2UgbmVlZCB0byBzZXQgaXQgdG8gYSBzbGlnaHRseSBkaWZmZXJlbnQgdmFsdWUgYW5kIHRoZW4gYmFjayBhZ2FpbiB0byB3b3JrIGFyb3VuZCB0aGlzIGJ1Zy5cblxuICAgICAgdGFyZ2V0LnNjcm9sbExlZnQgPSB4ICsgMTtcbiAgICAgIHRhcmdldC5zY3JvbGxUb3AgPSB5O1xuICAgICAgdGFyZ2V0LnNjcm9sbExlZnQgPSB4O1xuICAgIH1cblxuICAgIGRhdGEueFByZXYgPSBkYXRhLng7XG4gICAgZGF0YS55UHJldiA9IGRhdGEueTtcbiAgICBTY3JvbGxUcmlnZ2VyICYmIFNjcm9sbFRyaWdnZXIudXBkYXRlKCk7XG4gIH0sXG4gIGtpbGw6IGZ1bmN0aW9uIGtpbGwocHJvcGVydHkpIHtcbiAgICB2YXIgYm90aCA9IHByb3BlcnR5ID09PSBcInNjcm9sbFRvXCIsXG4gICAgICAgIGkgPSB0aGlzLl9wcm9wcy5pbmRleE9mKHByb3BlcnR5KTtcblxuICAgIGlmIChib3RoIHx8IHByb3BlcnR5ID09PSBcInNjcm9sbFRvX3hcIikge1xuICAgICAgdGhpcy5za2lwWCA9IDE7XG4gICAgfVxuXG4gICAgaWYgKGJvdGggfHwgcHJvcGVydHkgPT09IFwic2Nyb2xsVG9feVwiKSB7XG4gICAgICB0aGlzLnNraXBZID0gMTtcbiAgICB9XG5cbiAgICBpID4gLTEgJiYgdGhpcy5fcHJvcHMuc3BsaWNlKGksIDEpO1xuICAgIHJldHVybiAhdGhpcy5fcHJvcHMubGVuZ3RoO1xuICB9XG59O1xuU2Nyb2xsVG9QbHVnaW4ubWF4ID0gX21heDtcblNjcm9sbFRvUGx1Z2luLmdldE9mZnNldCA9IF9nZXRPZmZzZXQ7XG5TY3JvbGxUb1BsdWdpbi5idWlsZEdldHRlciA9IF9idWlsZEdldHRlcjtcbl9nZXRHU0FQKCkgJiYgZ3NhcC5yZWdpc3RlclBsdWdpbihTY3JvbGxUb1BsdWdpbik7XG5leHBvcnQgeyBTY3JvbGxUb1BsdWdpbiBhcyBkZWZhdWx0IH07IiwiaW1wb3J0IGdzYXAgZnJvbSAnZ3NhcCc7XG5pbXBvcnQgU2Nyb2xsVG9QbHVnaW4gZnJvbSBcImdzYXAvU2Nyb2xsVG9QbHVnaW5cIjtcbmltcG9ydCB7IHNjcm9sbFRvLCBjbG9zZUNoYXB0ZXJNb2RhbCB9IGZyb20gJ0Fzc2V0cy9qcy9jb21tb24nO1xuaW1wb3J0ICogYXMgU2Nyb2xsTWFnaWMgZnJvbSBcInNjcm9sbG1hZ2ljXCI7XG5nc2FwLnJlZ2lzdGVyUGx1Z2luKFNjcm9sbFRvUGx1Z2luKTtcbmxldCBuYXZiYXIsIGxhbmc7XG5jb25zdCBjb250cm9sbGVyID0gbmV3IFNjcm9sbE1hZ2ljLkNvbnRyb2xsZXIoKTtcbmNvbnN0IHZ3ID0gd2luZG93LmlubmVyV2lkdGg7XG5jb25zdCBhY3RpdmVQYWdlID0gd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLnNwbGl0KCdhbGxhZ3JhbmRlLXBpcmVsbGkvJylbMV0ucmVwbGFjZSgnLmh0bWwnLCAnJyk7XG5jb25zdCBuYXZiYXJNZW51QmVoYXZpb3JzID0gKCkgPT4ge1xuICBjb25zdCBuYXZiYXJXcmFwcGVyID0gbmF2YmFyLnF1ZXJ5U2VsZWN0b3IoJy5uYXZiYXJfd3JhcHBlcicpO1xuICBjb25zdCBuYXZiYXJMb2dvID0gbmF2YmFyV3JhcHBlci5xdWVyeVNlbGVjdG9yKCcubmF2YmFyX3dyYXBwZXItbG9nb3MgLmFsbGFncmFuZGUnKTtcbiAgY29uc3QgbmF2YmFyTWVudSA9IG5hdmJhcldyYXBwZXIucXVlcnlTZWxlY3RvcignLm5hdmJhcl93cmFwcGVyLW1lbnUnKTtcbiAgY29uc3QgbmF2YmFyTWVudUxpbmsgPSBuYXZiYXJNZW51LnF1ZXJ5U2VsZWN0b3JBbGwoJy5uYXZiYXJfd3JhcHBlci1tZW51LS1uYXZpZ2F0aW9uTWVudV9saW5rJyk7XG4gIG5hdmJhckxvZ28uYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoKSA9PiB7XG4gICAgbGV0IGhvbWVVcmwgPSAnJztcbiAgICAvLyBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLm1haW4uaXNCdWlsZGVkUHJvZCcpKSB7XG4gICAgLy8gICAgIGhvbWVVcmwgPSAnaW5kZXguaHRtbCc7XG4gICAgLy8gfSBlbHNlIHtcbiAgICAvLyAgICAgaG9tZVVybCA9ICcnO1xuICAgIC8vIH1cbiAgICBpZiAobGFuZyA9PT0gJ2l0Jykge1xuICAgICAgd2luZG93LmxvY2F0aW9uLmhyZWYgPSBgL2dsb2JhbC9pdC1pdC9hbGxhZ3JhbmRlLXBpcmVsbGkvJHtob21lVXJsfWA7XG4gICAgfSBlbHNlIGlmIChsYW5nID09PSAnZW4nKSB7XG4gICAgICB3aW5kb3cubG9jYXRpb24uaHJlZiA9IGAvZ2xvYmFsL2VuLXd3L2FsbGFncmFuZGUtcGlyZWxsaS8ke2hvbWVVcmx9YDtcbiAgICB9XG4gIH0pO1xuICBuYXZiYXJNZW51TGluay5mb3JFYWNoKGxpbmsgPT4ge1xuICAgIGNvbnN0IGxpbmtBbmNob3IgPSBsaW5rLmdldEF0dHJpYnV0ZSgnaHJlZicpO1xuICAgIGlmIChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGxpbmtBbmNob3IpKSB7XG4gICAgICBsaW5rLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZSA9PiB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgaWYgKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5jaGFwdGVyTW9kYWwgLnNlY3Rpb25DaGFwdGVyJykpIHtcbiAgICAgICAgICBjbG9zZUNoYXB0ZXJNb2RhbCgpO1xuICAgICAgICB9XG4gICAgICAgIHNjcm9sbFRvKGxpbmtBbmNob3IpO1xuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxpbmsuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBlID0+IHtcbiAgICAgICAgaWYgKGxpbmtBbmNob3IgIT09ICd2b3lhZ2VzJyAmJiBsaW5rQW5jaG9yICE9PSAndm95YWdlcy5odG1sJykge1xuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICBzZXNzaW9uU3RvcmFnZS5zZXRJdGVtKCdhbmNob3InLCBsaW5rQW5jaG9yKTtcbiAgICAgICAgICBuYXZiYXJMb2dvLmNsaWNrKCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgfSk7XG4gIGlmIChhY3RpdmVQYWdlID09PSAnJyB8fCBhY3RpdmVQYWdlID09PSAnaW5kZXgnIHx8IGFjdGl2ZVBhZ2UgPT09ICdpbmRleC5odG1sJykge1xuICAgIG5ldyBTY3JvbGxNYWdpYy5TY2VuZSh7XG4gICAgICB0cmlnZ2VyRWxlbWVudDogJyMnICsgZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnNlY3Rpb25WaXN1YWwnKS5jbG9zZXN0KCdzZWN0aW9uJykubmV4dEVsZW1lbnRTaWJsaW5nLmdldEF0dHJpYnV0ZSgnaWQnKSxcbiAgICAgIHRyaWdnZXJIb29rOiAwLjMsXG4gICAgICByZXZlcnNlOiB0cnVlXG4gICAgfSkuc2V0Q2xhc3NUb2dnbGUobmF2YmFyLCAnaGlkZGVuJykuYWRkVG8oY29udHJvbGxlcik7XG4gIH0gZWxzZSBpZiAoYWN0aXZlUGFnZSAhPT0gJ3ZveWFnZXMnICYmIGFjdGl2ZVBhZ2UgIT09ICd2b3lhZ2VzLmh0bWwnKSB7XG4gICAgbmF2YmFyLnF1ZXJ5U2VsZWN0b3JBbGwoJy5uYXZiYXJfd3JhcHBlci1tZW51LS1uYXZpZ2F0aW9uTWVudV9saW5rJylbMV0uY2xhc3NMaXN0LmFkZCgnYWN0aXZlJyk7XG4gIH0gZWxzZSB7XG4gICAgbmF2YmFyLnF1ZXJ5U2VsZWN0b3IoYC5uYXZiYXJfd3JhcHBlci1tZW51LS1uYXZpZ2F0aW9uTWVudV9saW5rW2hyZWY9XCIke2FjdGl2ZVBhZ2V9XCJdYCkuY2xhc3NMaXN0LmFkZCgnYWN0aXZlJyk7XG4gIH1cbn07XG5jb25zdCBuYXZiYXJCdXJnZXJDbGljayA9ICgpID0+IHtcbiAgY29uc3QgbmF2YmFyQnVyZ2VyID0gbmF2YmFyLnF1ZXJ5U2VsZWN0b3IoJy5uYXZiYXJfd3JhcHBlci1idXJnZXInKTtcbiAgbmF2YmFyQnVyZ2VyLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4ge1xuICAgIGlmIChuYXZiYXIuY2xhc3NMaXN0LmNvbnRhaW5zKCduYXZiYXItLW9wZW4nKSkge1xuICAgICAgbmF2YmFyLmNsYXNzTGlzdC5yZW1vdmUoJ25hdmJhci0tb3BlbicpO1xuICAgIH0gZWxzZSB7XG4gICAgICBuYXZiYXIuY2xhc3NMaXN0LmFkZCgnbmF2YmFyLS1vcGVuJyk7XG4gICAgfVxuICB9KTtcbn07XG5jb25zdCBsYW5nU3VnZ2VzdGlvbk9wZW4gPSAoKSA9PiB7XG4gIGNvbnN0IGxhbmdTZWxlY3QgPSBuYXZiYXIucXVlcnlTZWxlY3RvcignLmxhbmdTZWxlY3QnKTtcbiAgY29uc3QgbGFuZ1NlbGVjdFNlbGVjdGVkID0gbGFuZ1NlbGVjdC5xdWVyeVNlbGVjdG9yKCcubGFuZ1NlbGVjdC1zZWxlY3RlZCBzcGFuJyk7XG4gIGNvbnN0IGxhbmdTdWdnZXN0aW9ucyA9IGxhbmdTZWxlY3QucXVlcnlTZWxlY3RvcignLmxhbmdTZWxlY3Qtc3VnZ2VzdGlvbnMnKTtcbiAgY29uc3QgbGFuZ1N1Z2dlc3Rpb25zT3B0aW9ucyA9IGxhbmdTdWdnZXN0aW9ucy5xdWVyeVNlbGVjdG9yQWxsKCcubGFuZ1NlbGVjdC1zdWdnZXN0aW9ucy0tbGFuZycpO1xuICBjb25zdCBsYW5nU3VnZ2VzdGlvbnNPcHRpb25zSGVpZ2h0ID0gbGFuZ1N1Z2dlc3Rpb25zT3B0aW9uc1swXS5jbGllbnRIZWlnaHQ7XG4gIGNvbnN0IGxhbmdTdWdnZXN0aW9uc09wdGlvbnNMZW5ndGggPSBsYW5nU3VnZ2VzdGlvbnNPcHRpb25zLmxlbmd0aDtcbiAgbGFuZ1NlbGVjdC5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGUgPT4ge1xuICAgIGlmIChsYW5nU2VsZWN0U2VsZWN0ZWQucGFyZW50Tm9kZS5jbGFzc0xpc3QuY29udGFpbnMoJ29wZW4nKSkge1xuICAgICAgbGFuZ1NlbGVjdFNlbGVjdGVkLnBhcmVudE5vZGUuY2xhc3NMaXN0LnJlbW92ZSgnb3BlbicpO1xuICAgICAgbGFuZ1N1Z2dlc3Rpb25zLnN0eWxlLmhlaWdodCA9IDA7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxhbmdTZWxlY3RTZWxlY3RlZC5wYXJlbnROb2RlLmNsYXNzTGlzdC5hZGQoJ29wZW4nKTtcbiAgICAgIGxhbmdTdWdnZXN0aW9ucy5zdHlsZS5oZWlnaHQgPSBsYW5nU3VnZ2VzdGlvbnNPcHRpb25zSGVpZ2h0ICogbGFuZ1N1Z2dlc3Rpb25zT3B0aW9uc0xlbmd0aCArICdweCc7XG4gICAgfVxuICB9KTtcbiAgbGFuZ1N1Z2dlc3Rpb25zT3B0aW9ucy5mb3JFYWNoKG9wdGlvbiA9PiB7XG4gICAgb3B0aW9uLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZSA9PiB7XG4gICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICBpZiAobGFuZyA9PT0gJ2l0JyAmJiB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUuaW5kZXhPZignZW4td3cnKSA9PT0gLTEpIHtcbiAgICAgICAgd2luZG93LmxvY2F0aW9uLmhyZWYgPSBgL2dsb2JhbC9lbi13dy9hbGxhZ3JhbmRlLXBpcmVsbGkvJHthY3RpdmVQYWdlfWA7XG4gICAgICB9IGVsc2UgaWYgKGxhbmcgPT09ICdlbicgJiYgd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLmluZGV4T2YoJ2l0LWl0JykgPT09IC0xKSB7XG4gICAgICAgIHdpbmRvdy5sb2NhdGlvbi5ocmVmID0gYC9nbG9iYWwvaXQtaXQvYWxsYWdyYW5kZS1waXJlbGxpLyR7YWN0aXZlUGFnZX1gO1xuICAgICAgfVxuICAgIH0pO1xuICB9KTtcbn07XG5jb25zdCBzaG93TmF2YmFyID0gKCkgPT4ge1xuICBuYXZiYXIuY2xhc3NMaXN0LnJlbW92ZSgnaGlkZGVuJyk7XG59O1xuY29uc3QgaGlkZU5hdmJhciA9ICgpID0+IHtcbiAgbmF2YmFyLmNsYXNzTGlzdC5hZGQoJ2hpZGRlbicpO1xufTtcbmlmICh3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUuaW5kZXhPZignaXQtaXQnKSA+IC0xKSB7XG4gIGxhbmcgPSAnaXQnO1xufSBlbHNlIGlmICh3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUuaW5kZXhPZignZW4td3cnKSA+IC0xKSB7XG4gIGxhbmcgPSAnZW4nO1xufVxuZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmxhbmdTZWxlY3Qtc2VsZWN0ZWQgc3BhbicpLmlubmVySFRNTCA9IGxhbmc7XG5kb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgKCkgPT4ge1xuICBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLm5hdmJhcicpKSB7XG4gICAgbmF2YmFyID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLm5hdmJhcicpO1xuICAgIG5hdmJhck1lbnVCZWhhdmlvcnMoKTtcbiAgICBuYXZiYXJCdXJnZXJDbGljaygpO1xuICAgIGxhbmdTdWdnZXN0aW9uT3BlbigpO1xuICB9XG59KTtcbmV4cG9ydCB7IHNob3dOYXZiYXIsIGhpZGVOYXZiYXIgfTsiLCIvL1ZlbmRvciBzY3JpcHRzXG5pbXBvcnQgZ3NhcCwgeyBFeHBvIH0gZnJvbSBcImdzYXBcIjtcbmltcG9ydCB7IGJsb2NrRG9jdW1lbnRTY3JvbGwsIGNsb3NlQ2hhcHRlck1vZGFsIH0gZnJvbSAnQXNzZXRzL2pzL2NvbW1vbic7XG5pbXBvcnQgeyBjaGFwdGVyT3BlbkNsaWNrIH0gZnJvbSAnQ29tcG9uZW50cy9jaGFwdGVyL2NoYXB0ZXInO1xuaW1wb3J0IHsgc2hvd05hdmJhciB9IGZyb20gJ0NvbXBvbmVudHMvbmF2YmFyL25hdmJhcic7XG5jb25zdCB2dyA9IHdpbmRvdy5vdXRlcldpZHRoO1xubGV0IGNoYXB0ZXJNb2RhbDtcbmNvbnN0IGNoYXB0ZXJNb2RhbEJ1aWxkID0gdXJsID0+IHtcbiAgY29uc3QgYm9keSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2JvZHknKTtcbiAgYm9keS5jbGFzc0xpc3QuYWRkKCdhbmltYXRpbmcnKTtcbiAgZ3NhcC50byhjaGFwdGVyTW9kYWwsIHtcbiAgICB0b3A6IDAsXG4gICAgb3BhY2l0eTogMSxcbiAgICBzY2FsZTogMSxcbiAgICBkdXJhdGlvbjogMSxcbiAgICBlYXNlOiBFeHBvLmVhc2VJbk91dCxcbiAgICBvbkNvbXBsZXRlOiAoKSA9PiB7XG4gICAgICBibG9ja0RvY3VtZW50U2Nyb2xsKCk7XG4gICAgfVxuICB9KTtcbiAgc2hvd05hdmJhcigpO1xuICBpZiAoIXdpbmRvdy5YTUxIdHRwUmVxdWVzdCkgcmV0dXJuO1xuICBsZXQgeGhyID0gbmV3IFhNTEh0dHBSZXF1ZXN0KCk7XG4gIGNvbnN0IHVybFRvQ2FsbCA9IHdpbmRvdy5sb2NhdGlvbi5ob3N0ICE9PSAnbG9jYWxob3N0OjQwMDAnID8gdXJsIDogYCR7dXJsfS5odG1sYDtcbiAgeGhyLm9wZW4oJ0dFVCcsIHVybFRvQ2FsbCk7XG4gIHhoci5hZGRFdmVudExpc3RlbmVyKCdsb2FkJywgKCkgPT4ge1xuICAgIGNvbnN0IGNvbnRlbnRUb0luamVjdFRpdGxlID0geGhyLnJlc3BvbnNlLnF1ZXJ5U2VsZWN0b3IoJ3RpdGxlJykuaW5uZXJIVE1MO1xuICAgIGNvbnN0IGNvbnRlbnRUb0luamVjdCA9IHhoci5yZXNwb25zZS5xdWVyeVNlbGVjdG9yKCcjdG9JbmplY3QnKS5pbm5lckhUTUw7XG4gICAgY2hhcHRlck1vZGFsLmlubmVySFRNTCA9IGNvbnRlbnRUb0luamVjdDtcbiAgICB3aW5kb3cuaGlzdG9yeS5wdXNoU3RhdGUobnVsbCwgY29udGVudFRvSW5qZWN0VGl0bGUsIHVybCk7XG4gICAgZG9jdW1lbnQudGl0bGUgPSBjb250ZW50VG9JbmplY3RUaXRsZTtcbiAgICBjaGFwdGVyT3BlbkNsaWNrKCk7XG4gICAgd2luZG93LmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KCdwb3BzdGF0ZScpKTtcbiAgICBib2R5LmNsYXNzTGlzdC5yZW1vdmUoJ2FuaW1hdGluZycpO1xuICB9KTtcbiAgeGhyLnJlc3BvbnNlVHlwZSA9ICdkb2N1bWVudCc7XG4gIHhoci5zZW5kKCk7XG4gIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdwb3BzdGF0ZScsIGUgPT4ge1xuICAgIGNvbnNvbGUubG9nKGUpO1xuICAgIGlmICghYm9keS5jbGFzc0xpc3QuY29udGFpbnMoJ2FuaW1hdGluZycpKSB7XG4gICAgICBjbG9zZUNoYXB0ZXJNb2RhbCgpO1xuICAgIH1cbiAgfSk7XG59O1xud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ0RPTUNvbnRlbnRMb2FkZWQnLCAoKSA9PiB7XG4gIGlmIChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuY2hhcHRlck1vZGFsJykpIHtcbiAgICBjaGFwdGVyTW9kYWwgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuY2hhcHRlck1vZGFsJyk7XG4gIH1cbn0pO1xuZXhwb3J0IGRlZmF1bHQgY2hhcHRlck1vZGFsQnVpbGQ7IiwiLy9WZW5kb3Igc2NyaXB0c1xuaW1wb3J0IGNoYXB0ZXJNb2RhbEJ1aWxkIGZyb20gJ0NvbXBvbmVudHMvY2hhcHRlck1vZGFsL2NoYXB0ZXJNb2RhbCc7XG5pbXBvcnQgeyBjbG9zZUNoYXB0ZXJNb2RhbCB9IGZyb20gJ0Fzc2V0cy9qcy9jb21tb24nO1xuY29uc3QgWVRQbGF5ZXIgPSByZXF1aXJlKCd5dC1wbGF5ZXInKTtcbmNvbnN0IGNoYXB0ZXJPcGVuSGFuZGxlciA9IGNoYXB0ZXJOYW1lID0+IHtcbiAgbGV0IHBhdGg7XG4gIGNvbnN0IGFjdGl2ZVBhZ2UgPSB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUuc3BsaXQoJ2FsbGFncmFuZGUtcGlyZWxsaS8nKVsxXTtcbiAgaWYgKHdpbmRvdy5sb2NhdGlvbi5ocmVmLmluZGV4T2YoJ2VuLXd3JykgPiAtMSkge1xuICAgIHBhdGggPSBgL2dsb2JhbC9lbi13dy9hbGxhZ3JhbmRlLXBpcmVsbGkvJHtjaGFwdGVyTmFtZX1gO1xuICB9IGVsc2UgaWYgKHdpbmRvdy5sb2NhdGlvbi5ocmVmLmluZGV4T2YoJ2l0LWl0JykgPiAtMSkge1xuICAgIHBhdGggPSBgL2dsb2JhbC9pdC1pdC9hbGxhZ3JhbmRlLXBpcmVsbGkvJHtjaGFwdGVyTmFtZX1gO1xuICB9XG4gIGlmIChhY3RpdmVQYWdlID09PSAnJyB8fCBhY3RpdmVQYWdlID09PSAnaW5kZXgnIHx8IGFjdGl2ZVBhZ2UgPT09ICdpbmRleC5odG1sJykge1xuICAgIGNoYXB0ZXJNb2RhbEJ1aWxkKGNoYXB0ZXJOYW1lKTtcbiAgfSBlbHNlIHtcbiAgICBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmNoYXB0ZXJNb2RhbCcpKSB7XG4gICAgICBjbG9zZUNoYXB0ZXJNb2RhbCgpO1xuICAgIH1cbiAgICB3aW5kb3cubG9jYXRpb24uaHJlZiA9IHBhdGg7XG4gIH1cbn07XG5jb25zdCBjaGFwdGVyT3BlbkNsaWNrID0gKCkgPT4ge1xuICBjb25zdCBjaGFwdGVyTmF2aWdhdGlvblByZXYgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuc2VjdGlvbkNoYXB0ZXJfbmF2aWdhdGlvbi1wcmV2Jyk7XG4gIGlmIChjaGFwdGVyTmF2aWdhdGlvblByZXYpIHtcbiAgICBjb25zdCBjaGFwdGVyTmF2aWdhdGlvblByZXZOYW1lID0gY2hhcHRlck5hdmlnYXRpb25QcmV2LmdldEF0dHJpYnV0ZSgnZGF0YS1uYW1lJyk7XG4gICAgY2hhcHRlck5hdmlnYXRpb25QcmV2LmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4ge1xuICAgICAgbGV0IGNoYXB0ZXJOYW1lO1xuICAgICAgaWYgKHdpbmRvdy5sb2NhdGlvbi5ob3N0ICE9IFwibG9jYWxob3N0OjMwMDBcIikge1xuICAgICAgICBjaGFwdGVyTmFtZSA9IGAke2NoYXB0ZXJOYXZpZ2F0aW9uUHJldk5hbWV9YDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNoYXB0ZXJOYW1lID0gYCR7Y2hhcHRlck5hdmlnYXRpb25QcmV2TmFtZX0uaHRtbGA7XG4gICAgICB9XG4gICAgICBjaGFwdGVyT3BlbkhhbmRsZXIoY2hhcHRlck5hbWUpO1xuICAgIH0pO1xuICB9XG4gIGNvbnN0IGNoYXB0ZXJOYXZpZ2F0aW9uTmV4dCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uQ2hhcHRlcl9uYXZpZ2F0aW9uLW5leHQnKTtcbiAgaWYgKGNoYXB0ZXJOYXZpZ2F0aW9uTmV4dCkge1xuICAgIGNvbnN0IGNoYXB0ZXJOYXZpZ2F0aW9uTmV4dE5hbWUgPSBjaGFwdGVyTmF2aWdhdGlvbk5leHQ/LmdldEF0dHJpYnV0ZSgnZGF0YS1uYW1lJyk7XG4gICAgY2hhcHRlck5hdmlnYXRpb25OZXh0LmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4ge1xuICAgICAgbGV0IGNoYXB0ZXJOYW1lO1xuICAgICAgaWYgKHdpbmRvdy5sb2NhdGlvbi5ob3N0ICE9IFwibG9jYWxob3N0OjMwMDBcIikge1xuICAgICAgICBjaGFwdGVyTmFtZSA9IGAke2NoYXB0ZXJOYXZpZ2F0aW9uTmV4dE5hbWV9YDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNoYXB0ZXJOYW1lID0gYCR7Y2hhcHRlck5hdmlnYXRpb25OZXh0TmFtZX0uaHRtbGA7XG4gICAgICB9XG4gICAgICBjaGFwdGVyT3BlbkhhbmRsZXIoY2hhcHRlck5hbWUpO1xuICAgIH0pO1xuICB9XG59O1xuY29uc3QgcGxheWVySW5pdCA9ICgpID0+IHtcbiAgY29uc3QgY2hhcHRlciA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uQ2hhcHRlcicpO1xuICBjb25zdCB2aWRlb1JvdyA9IGNoYXB0ZXIucXVlcnlTZWxlY3RvcignLnNlY3Rpb25DaGFwdGVyX3Jvdy1pbWcudmlkZW8nKTtcbiAgY29uc3QgdmlkZW9QbGF5ZXIgPSB2aWRlb1Jvdy5xdWVyeVNlbGVjdG9yKCcudmlkZW9QbGF5ZXInKTtcbiAgY29uc3QgdmlkZW9QbGF5ZXJJRCA9IHZpZGVvUGxheWVyLmdldEF0dHJpYnV0ZSgnZGF0YS11cmwtaWQnKTtcbiAgY29uc3QgcGxheWVyID0gbmV3IFlUUGxheWVyKHZpZGVvUGxheWVyLCB7XG4gICAgaGVpZ2h0OiAnMTAwJScsXG4gICAgd2lkdGg6ICcxMDAlJ1xuICB9KTtcbiAgcGxheWVyLmxvYWQodmlkZW9QbGF5ZXJJRCk7XG4gIHBsYXllci5zZXRWb2x1bWUoMzApO1xuICBjb25zdCBwbGF5QnV0dG9uID0gY2hhcHRlci5xdWVyeVNlbGVjdG9yKCcucGxheUJ1dHRvbicpO1xuICBwbGF5QnV0dG9uLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4ge1xuICAgIHZpZGVvUm93LmNsYXNzTGlzdC5hZGQoJ3BsYXlpbmdWaWRlbycpO1xuICAgIHBsYXllci5wbGF5KCk7XG4gIH0pO1xuICBwbGF5ZXIub24oJ3BhdXNlZCcsICgpID0+IHtcbiAgICB2aWRlb1Jvdy5jbGFzc0xpc3QucmVtb3ZlKCdwbGF5aW5nVmlkZW8nKTtcbiAgfSk7XG59O1xuY29uc3QgY2hlY2tFbXB0eUNoYXB0ZXIgPSAoKSA9PiB7XG4gIGNvbnN0IGNoYXB0ZXIgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuc2VjdGlvbkNoYXB0ZXInKTtcbiAgY29uc3QgY2hhcHRlck5hdmlnYXRpb24gPSBjaGFwdGVyLnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uQ2hhcHRlcl9uYXZpZ2F0aW9uJyk7XG4gIGNvbnN0IHByZXZDaGFwdGVyID0gY2hhcHRlck5hdmlnYXRpb24ucXVlcnlTZWxlY3RvcignLnNlY3Rpb25DaGFwdGVyX25hdmlnYXRpb24tcHJldicpO1xuICBjb25zdCBuZXh0Q2hhcHRlciA9IGNoYXB0ZXJOYXZpZ2F0aW9uLnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uQ2hhcHRlcl9uYXZpZ2F0aW9uLW5leHQnKTtcbiAgaWYgKHByZXZDaGFwdGVyLmdldEF0dHJpYnV0ZSgnZGF0YS1uYW1lJykgPT09ICcnKSB7XG4gICAgcHJldkNoYXB0ZXIuc3R5bGUub3BhY2l0eSA9IDA7XG4gICAgcHJldkNoYXB0ZXIuc3R5bGUudmlzaWJpbGl0eSA9ICdoaWRkZW4nO1xuICB9XG4gIGlmIChuZXh0Q2hhcHRlci5nZXRBdHRyaWJ1dGUoJ2RhdGEtbmFtZScpID09PSAnJykge1xuICAgIG5leHRDaGFwdGVyLnN0eWxlLm9wYWNpdHkgPSAwO1xuICAgIG5leHRDaGFwdGVyLnN0eWxlLnZpc2liaWxpdHkgPSAnaGlkZGVuJztcbiAgfVxufTtcbndpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgKCkgPT4ge1xuICBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnNlY3Rpb25DaGFwdGVyJykpIHtcbiAgICBjaGFwdGVyT3BlbkNsaWNrKCk7XG4gICAgcGxheWVySW5pdCgpO1xuICAgIGNoZWNrRW1wdHlDaGFwdGVyKCk7XG4gIH1cbn0pO1xuZXhwb3J0IHsgY2hhcHRlck9wZW5IYW5kbGVyLCBjaGFwdGVyT3BlbkNsaWNrLCBwbGF5ZXJJbml0IH07IiwiLy9WZW5kb3Igc2NyaXB0c1xuaW1wb3J0IGdzYXAsIHsgUG93ZXIyLCBFeHBvIH0gZnJvbSBcImdzYXBcIjtcbmltcG9ydCBTY3JvbGxUcmlnZ2VyIGZyb20gXCJnc2FwL1Njcm9sbFRyaWdnZXJcIjtcbmltcG9ydCBTY3JvbGxUb1BsdWdpbiBmcm9tIFwiZ3NhcC9TY3JvbGxUb1BsdWdpblwiO1xuaW1wb3J0ICogYXMgU2Nyb2xsTWFnaWMgZnJvbSBcInNjcm9sbG1hZ2ljXCI7XG5pbXBvcnQgeyBTY3JvbGxNYWdpY1BsdWdpbkdzYXAgfSBmcm9tIFwic2Nyb2xsbWFnaWMtcGx1Z2luLWdzYXBcIjtcbi8vSlNPTkJ1aWxkXG5pbXBvcnQgeyBwbGF5ZXJJbml0IH0gZnJvbSBcIkNvbXBvbmVudHMvY2hhcHRlci9jaGFwdGVyXCI7XG5pbXBvcnQgeyBoaWRlTmF2YmFyIH0gZnJvbSAnQ29tcG9uZW50cy9uYXZiYXIvbmF2YmFyJztcblNjcm9sbE1hZ2ljUGx1Z2luR3NhcChTY3JvbGxNYWdpYywgZ3NhcCk7XG5nc2FwLnJlZ2lzdGVyUGx1Z2luKFNjcm9sbFRyaWdnZXIpO1xuZ3NhcC5yZWdpc3RlclBsdWdpbihTY3JvbGxUb1BsdWdpbik7XG5jb25zdCBjb250cm9sbGVyID0gbmV3IFNjcm9sbE1hZ2ljLkNvbnRyb2xsZXIoKTtcbmNvbnN0IHZ3ID0gd2luZG93Lm91dGVyV2lkdGg7XG5jb25zdCB2aCA9IHdpbmRvdy5vdXRlckhlaWdodDtcbmxldCBhY3RpdmVVcmw7XG5jb25zdCBzZXRSZWFsVmlld0hlaWdodCA9ICgpID0+IHtcbiAgY29uc3Qgd2luZG93SGVpZ2h0ID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodDtcbiAgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnN0eWxlLnNldFByb3BlcnR5KCctLXZoJywgYCR7d2luZG93SGVpZ2h0fXB4YCk7XG59O1xuY29uc3QgcGFyYWxsYXhFZmZlY3QgPSAoKSA9PiB7XG4gIGlmIChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdbZGF0YS1zcGVlZF0nKSkge1xuICAgIGNvbnN0IHZlcnRpY2FsRWxlbWVudHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCdbZGF0YS1zcGVlZF0nKTtcbiAgICB2ZXJ0aWNhbEVsZW1lbnRzLmZvckVhY2goZWwgPT4ge1xuICAgICAgaWYgKCFlbC5jbGFzc0xpc3QuY29udGFpbnMoJ3NlY3Rpb25DcmVkaXRzX2JhY2tncm91bmQnKSkge1xuICAgICAgICBsZXQgZGlyZWN0aW9uLCBtb2x0aXBsaWNhdG9yO1xuICAgICAgICBpZiAoZWwuY2xhc3NMaXN0LmNvbnRhaW5zKCdzZWN0aW9uVmlzdWFsLXNoaXAnKSkge1xuICAgICAgICAgIGRpcmVjdGlvbiA9ICd4JztcbiAgICAgICAgICBtb2x0aXBsaWNhdG9yID0gMTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBkaXJlY3Rpb24gPSAneSc7XG4gICAgICAgICAgbW9sdGlwbGljYXRvciA9IC0xO1xuICAgICAgICB9XG4gICAgICAgIGxldCBzcGVlZDtcbiAgICAgICAgaWYgKHZ3IDwgNDU2ICYmIGVsLmdldEF0dHJpYnV0ZShcImRhdGEtc3BlZWQtbW9iaWxlXCIpKSB7XG4gICAgICAgICAgc3BlZWQgPSBlbC5nZXRBdHRyaWJ1dGUoXCJkYXRhLXNwZWVkLW1vYmlsZVwiKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzcGVlZCA9IGVsLmdldEF0dHJpYnV0ZShcImRhdGEtc3BlZWRcIik7XG4gICAgICAgIH1cbiAgICAgICAgZ3NhcC50byhlbCwge1xuICAgICAgICAgIFtkaXJlY3Rpb25dOiBtb2x0aXBsaWNhdG9yICogcGFyc2VGbG9hdChzcGVlZCkgKiAoZWwub2Zmc2V0SGVpZ2h0IC8gMyksXG4gICAgICAgICAgZWFzZTogXCJub25lXCIsXG4gICAgICAgICAgc2Nyb2xsVHJpZ2dlcjoge1xuICAgICAgICAgICAgdHJpZ2dlcjogZWwuY2xvc2VzdCgnc2VjdGlvbicpLFxuICAgICAgICAgICAgc3RhcnQ6IDMwLFxuICAgICAgICAgICAgZW5kOiBcImJvdHRvbSB0b3BcIixcbiAgICAgICAgICAgIGludmFsaWRhdGVPblJlZnJlc2g6IHRydWUsXG4gICAgICAgICAgICBzY3J1YjogdHJ1ZVxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCB0d2VlbiA9IGdzYXAudG8oZWwsIHtcbiAgICAgICAgICB5OiAnKz0zMDAnXG4gICAgICAgIH0pO1xuICAgICAgICBuZXcgU2Nyb2xsTWFnaWMuU2NlbmUoe1xuICAgICAgICAgIHRyaWdnZXJFbGVtZW50OiBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuc2VjdGlvbk1hcCcpLFxuICAgICAgICAgIHRyaWdnZXJIb29rOiAwLjksXG4gICAgICAgICAgZHVyYXRpb246IHZoICogMlxuICAgICAgICB9KS5zZXRUd2Vlbih0d2VlbikuYWRkVG8oY29udHJvbGxlcik7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cbn07XG5jb25zdCBob3Jpem9udGFsUGFyYWxsYXhFZmZlY3QgPSAoKSA9PiB7XG4gIGlmIChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuSG9yaXpvbnRhbFBhcmFsbGF4JykpIHtcbiAgICBjb25zdCBob3Jpem9udGFsRWxlbWVudHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcuSG9yaXpvbnRhbFBhcmFsbGF4Jyk7XG4gICAgaG9yaXpvbnRhbEVsZW1lbnRzLmZvckVhY2goaG9yaXpvbnRhbEVsZW1lbnQgPT4ge1xuICAgICAgbGV0IHhWYWx1ZSwgc3BhblhWYWx1ZWw7XG4gICAgICBpZiAoaG9yaXpvbnRhbEVsZW1lbnQuY2xvc2VzdCgnc2VjdGlvbicpLmNsYXNzTGlzdC5jb250YWlucygnc2VjdGlvblNvY2lhbCcpKSB7XG4gICAgICAgIHhWYWx1ZSA9IFwiLTIwJVwiO1xuICAgICAgICBpZiAodncgPj0gMTAyNSkge1xuICAgICAgICAgIHNwYW5YVmFsdWVsID0gXCItNTAlXCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgc3BhblhWYWx1ZWwgPSBcIjAlXCI7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmICh2dyA+PSAxMDI1KSB7XG4gICAgICAgICAgeFZhbHVlID0gJy01MCUnO1xuICAgICAgICAgIHNwYW5YVmFsdWVsID0gXCIwXCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgeFZhbHVlID0gJzAnO1xuICAgICAgICAgIHNwYW5YVmFsdWVsID0gXCItMjAlXCI7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGdzYXAudG8oaG9yaXpvbnRhbEVsZW1lbnQsIHtcbiAgICAgICAgeDogeFZhbHVlLFxuICAgICAgICBlYXNlOiBcIm5vbmVcIixcbiAgICAgICAgc2Nyb2xsVHJpZ2dlcjoge1xuICAgICAgICAgIHRyaWdnZXI6IGhvcml6b250YWxFbGVtZW50LFxuICAgICAgICAgIHN0YXJ0OiAndG9wIGJvdHRvbScsXG4gICAgICAgICAgZW5kOiBcImJvdHRvbSB0b3BcIixcbiAgICAgICAgICBpbnZhbGlkYXRlT25SZWZyZXNoOiB0cnVlLFxuICAgICAgICAgIHNjcnViOiB0cnVlXG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgaWYgKGhvcml6b250YWxFbGVtZW50LmNsYXNzTGlzdC5jb250YWlucygnbXVsdGlsaW5lJykpIHtcbiAgICAgICAgaWYgKHZ3IDwgNDU2IHx8IGhvcml6b250YWxFbGVtZW50LmNsYXNzTGlzdC5jb250YWlucygnc2VjdGlvblNvY2lhbF90aXRsZScpKSB7XG4gICAgICAgICAgY29uc3QgbGFzdFJvdyA9IGhvcml6b250YWxFbGVtZW50LnF1ZXJ5U2VsZWN0b3IoJ3NwYW46bGFzdC1vZi10eXBlJyk7XG4gICAgICAgICAgZ3NhcC50byhsYXN0Um93LCB7XG4gICAgICAgICAgICB4OiBzcGFuWFZhbHVlbCxcbiAgICAgICAgICAgIGVhc2U6IFwibm9uZVwiLFxuICAgICAgICAgICAgc2Nyb2xsVHJpZ2dlcjoge1xuICAgICAgICAgICAgICB0cmlnZ2VyOiBob3Jpem9udGFsRWxlbWVudCxcbiAgICAgICAgICAgICAgc3RhcnQ6ICd0b3AgYm90dG9tJyxcbiAgICAgICAgICAgICAgZW5kOiBcImJvdHRvbSB0b3BcIixcbiAgICAgICAgICAgICAgaW52YWxpZGF0ZU9uUmVmcmVzaDogdHJ1ZSxcbiAgICAgICAgICAgICAgc2NydWI6IHRydWVcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9XG59O1xuY29uc3QgZ29Ub05leHRTZWN0aW9uID0gKCkgPT4ge1xuICBjb25zdCB0cmlnZ2VyRWxlbWVudHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcuU2Nyb2xsVG8nKTtcbiAgaWYgKHRyaWdnZXJFbGVtZW50cykge1xuICAgIHRyaWdnZXJFbGVtZW50cy5mb3JFYWNoKHRyaWdnZXIgPT4ge1xuICAgICAgdHJpZ2dlci5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGUgPT4ge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGNvbnN0IG5leHRTZWN0aW9uID0gdHJpZ2dlci5jbG9zZXN0KCdzZWN0aW9uJykubmV4dEVsZW1lbnRTaWJsaW5nO1xuICAgICAgICAvLyBsZXQgb2Zmc2V0O1xuICAgICAgICAvLyBpZiAodncgPj0gNzY5KSB7XG4gICAgICAgIC8vICAgICBvZmZzZXQgPSAxMDA7XG4gICAgICAgIC8vIH0gZWxzZSB7XG4gICAgICAgIC8vICAgICBvZmZzZXQgPSA2NDtcbiAgICAgICAgLy8gfVxuXG4gICAgICAgIGdzYXAudG8od2luZG93LCB7XG4gICAgICAgICAgc2Nyb2xsVG86IHtcbiAgICAgICAgICAgIHk6IG5leHRTZWN0aW9uLFxuICAgICAgICAgICAgLy8gb2Zmc2V0WTogb2Zmc2V0LFxuICAgICAgICAgICAgYXV0b0tpbGw6IGZhbHNlXG4gICAgICAgICAgfSxcbiAgICAgICAgICBkdXJhdGlvbjogMSxcbiAgICAgICAgICBlYXNlOiBQb3dlcjIuZWFzZUluT3V0XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbn07XG5jb25zdCBzY3JvbGxUbyA9IGFuY2hvciA9PiB7XG4gIC8vIGxldCBvZmZzZXQ7XG4gIC8vIGlmICh2dyA+PSAxMDI1KSB7XG4gIC8vICAgICBvZmZzZXQgPSAxMDA7XG4gIC8vIH0gZWxzZSB7XG4gIC8vICAgICBvZmZzZXQgPSA2NDtcbiAgLy8gfVxuICBnc2FwLnRvKHdpbmRvdywge1xuICAgIHNjcm9sbFRvOiB7XG4gICAgICB5OiBhbmNob3IsXG4gICAgICAvLyBvZmZzZXRZOiBvZmZzZXQsXG4gICAgICBhdXRvS2lsbDogZmFsc2VcbiAgICB9LFxuICAgIGR1cmF0aW9uOiAxLFxuICAgIGVhc2U6IFBvd2VyMi5lYXNlSW5PdXRcbiAgfSk7XG59O1xuY29uc3QgcmV2ZWFsT25WaWV3cG9ydCA9ICgpID0+IHtcbiAgY29uc3Qgc2VjdGlvbnNUb1JldmVhbCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5Ub1JldmVhbCcpO1xuICBpZiAoc2VjdGlvbnNUb1JldmVhbCkge1xuICAgIHNlY3Rpb25zVG9SZXZlYWwuZm9yRWFjaChyZXZlYWwgPT4ge1xuICAgICAgaWYgKHJldmVhbC5jbGFzc0xpc3QuY29udGFpbnMoJ3NlY3Rpb25DaGFwdGVyX3JvdycpKSB7XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgIHJldmVhbC5jbGFzc0xpc3QuYWRkKCd2aXNpYmxlJyk7XG4gICAgICAgIH0sIDYwMCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBuZXcgU2Nyb2xsTWFnaWMuU2NlbmUoe1xuICAgICAgICAgIHRyaWdnZXJFbGVtZW50OiByZXZlYWwsXG4gICAgICAgICAgZHVyYXRpb246IHZoICsgcmV2ZWFsLmNsaWVudEhlaWdodCxcbiAgICAgICAgICB0cmlnZ2VySG9vazogLjgsXG4gICAgICAgICAgcmV2ZXJzZTogdHJ1ZVxuICAgICAgICB9KS5zZXRDbGFzc1RvZ2dsZShyZXZlYWwsIFwidmlzaWJsZVwiKS5hZGRUbyhjb250cm9sbGVyKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxufTtcbmNvbnN0IGJsb2NrRG9jdW1lbnRTY3JvbGwgPSAoKSA9PiB7XG4gIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2JvZHknKS5jbGFzc0xpc3QuYWRkKCdibG9ja1Njcm9sbCcpO1xuICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdib2R5JykuYWRkRXZlbnRMaXN0ZW5lcigndG91Y2htb3ZlJywgZSA9PiB7XG4gICAgaWYgKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ2JvZHknKS5jbGFzc0xpc3QuY29udGFpbnMoJ2Jsb2NrU2Nyb2xsJykpIHtcbiAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG4gIH0pO1xufTtcbmNvbnN0IGVuYWJsZURvY3VtZW50U2Nyb2xsID0gKCkgPT4ge1xuICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdib2R5JykuY2xhc3NMaXN0LnJlbW92ZSgnYmxvY2tTY3JvbGwnKTtcbn07XG5jb25zdCBjbG9zZUNoYXB0ZXJNb2RhbCA9ICgpID0+IHtcbiAgY29uc3QgY2hhcHRlck1vZGFsID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmNoYXB0ZXJNb2RhbCcpO1xuICBjb25zdCBuYXZiYXIgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcubmF2YmFyJyk7XG4gIGdzYXAudG8oY2hhcHRlck1vZGFsLCB7XG4gICAgdG9wOiAnMTAwdncnLFxuICAgIG9wYWNpdHk6IDAsXG4gICAgc2NhbGU6IC45LFxuICAgIGR1cmF0aW9uOiAxLFxuICAgIGVhc2U6IEV4cG8uZWFzZUluT3V0XG4gIH0pO1xuICB3aW5kb3cuaGlzdG9yeS5wdXNoU3RhdGUobnVsbCwgJycsIGFjdGl2ZVVybCk7XG4gIGRvY3VtZW50LnRpdGxlID0gJ1BpcmVsbGkgfCBBbGxhZ3JhbmRlJztcbiAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLm1haW4nKS5yZW1vdmVBdHRyaWJ1dGUoJ3N0eWxlJyk7XG4gIG5hdmJhci5xdWVyeVNlbGVjdG9yKCcuYWN0aXZlJykuY2xhc3NMaXN0LnJlbW92ZSgnYWN0aXZlJyk7XG4gIGhpZGVOYXZiYXIoKTtcbiAgZW5hYmxlRG9jdW1lbnRTY3JvbGwoKTtcbn07XG5jb25zdCBiYWNrRnVuY3Rpb24gPSAoKSA9PiB7XG4gIGlmIChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuYXJyb3ctbGluay5yZXZlcnNlJykpIHtcbiAgICBjb25zdCBiYWNrID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmFycm93LWxpbmsucmV2ZXJzZScpO1xuICAgIGJhY2suYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBlID0+IHtcbiAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgIGlmIChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuY2hhcHRlck1vZGFsJykpIHtcbiAgICAgICAgY2xvc2VDaGFwdGVyTW9kYWwoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGhpc3RvcnkuYmFjaygpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG59O1xuY29uc3Qgc2Vzc2lvblN0b3JhZ2VDaGVjayA9ICgpID0+IHtcbiAgaWYgKHNlc3Npb25TdG9yYWdlLmFuY2hvcikge1xuICAgIHNjcm9sbFRvKHNlc3Npb25TdG9yYWdlLmFuY2hvcik7XG4gICAgc2Vzc2lvblN0b3JhZ2UucmVtb3ZlSXRlbSgnYW5jaG9yJyk7XG4gIH1cbn07XG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignRE9NQ29udGVudExvYWRlZCcsICgpID0+IHtcbiAgbGV0IGxhbmc7XG4gIGlmICh3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUuaW5kZXhPZignaXQtaXQnKSA+IC0xKSB7XG4gICAgbGFuZyA9ICdpdCc7XG4gICAgYWN0aXZlVXJsID0gJy9nbG9iYWwvaXQtaXQvYWxsYWdyYW5kZS1waXJlbGxpLyc7XG4gIH0gZWxzZSBpZiAod2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLmluZGV4T2YoJ2VuLXd3JykgPiAtMSkge1xuICAgIGxhbmcgPSAnZW4nO1xuICAgIGFjdGl2ZVVybCA9ICcvZ2xvYmFsL2VuLXd3L2FsbGFncmFuZGUtcGlyZWxsaS8nO1xuICB9XG4gIHNldFJlYWxWaWV3SGVpZ2h0KCk7XG4gIHBhcmFsbGF4RWZmZWN0KCk7XG4gIGhvcml6b250YWxQYXJhbGxheEVmZmVjdCgpO1xuICBnb1RvTmV4dFNlY3Rpb24oKTtcbiAgcmV2ZWFsT25WaWV3cG9ydCgpO1xuICBiYWNrRnVuY3Rpb24oKTtcbiAgc2Vzc2lvblN0b3JhZ2VDaGVjaygpO1xufSk7XG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigncG9wc3RhdGUnLCBlID0+IHtcbiAgY29uc3QgbmF2YmFyID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLm5hdmJhcicpO1xuICBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmNoYXB0ZXJNb2RhbCAuc2VjdGlvbkNoYXB0ZXInKSkge1xuICAgIHJldmVhbE9uVmlld3BvcnQoKTtcbiAgICBiYWNrRnVuY3Rpb24oKTtcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHBsYXllckluaXQoKTtcbiAgICB9LCAxMDAwKTtcbiAgICBjb25zdCBtYXBJZCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uTWFwJykuZ2V0QXR0cmlidXRlKCdpZCcpO1xuICAgIG5hdmJhci5xdWVyeVNlbGVjdG9yKGBbaHJlZj1cIiMke21hcElkfVwiXWApLmNsYXNzTGlzdC5hZGQoJ2FjdGl2ZScpO1xuICB9XG4gIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdvbmJlZm9yZXVubG9hZCcsICgpID0+IHtcbiAgICBjbG9zZUNoYXB0ZXJNb2RhbCgpO1xuICB9KTtcbn0pO1xud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsICgpID0+IHtcbiAgc2V0UmVhbFZpZXdIZWlnaHQoKTtcbn0pO1xuLy8gZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignbGF6eWJlZm9yZXVudmVpbCcsIGZ1bmN0aW9uKGUpe1xuLy8gICAgIGhvcml6b250YWxQYXJhbGxheEVmZmVjdCgpO1xuLy8gfSk7XG5cbmV4cG9ydCB7IHNjcm9sbFRvLCBibG9ja0RvY3VtZW50U2Nyb2xsLCBlbmFibGVEb2N1bWVudFNjcm9sbCwgY2xvc2VDaGFwdGVyTW9kYWwgfTsiLCIvL1ZlbmRvciBzY3JpcHRzXG5pbXBvcnQgZ3NhcCBmcm9tIFwiZ3NhcFwiO1xubGV0IHZ3ID0gd2luZG93Lm91dGVyV2lkdGg7XG5sZXQgdmlzdWFsO1xuY29uc3QgdGV4dEZhZGVJbiA9ICgpID0+IHtcbiAgY29uc3QgdHJhbnN0aXRpb25UaW1pbmcgPSAxO1xuICBsZXQgdmlzdWFsVGltZWxpbmUgPSBnc2FwLnRpbWVsaW5lKCk7XG4gIGxldCB2aXN1YWxDYW52YXM7XG4gIGlmICh2dyA8IDQ1Nikge1xuICAgIHZpc3VhbENhbnZhcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uVmlzdWFsLWNhbnZhcy0tbW9iaWxlJyk7XG4gIH0gZWxzZSB7XG4gICAgdmlzdWFsQ2FudmFzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnNlY3Rpb25WaXN1YWwtY2FudmFzLS1kZXNrdG9wJyk7XG4gIH1cbiAgY29uc3QgdmlzdWFsU2hpcCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uVmlzdWFsLXNoaXAnKTtcbiAgY29uc3QgdmlzdWFsRW5nSGVhZGVyID0gdmlzdWFsLnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uVmlzdWFsLWVuZ0hlYWRlcicpO1xuICBjb25zdCB2aXN1YWxTdWJ0aXRsZSA9IHZpc3VhbC5xdWVyeVNlbGVjdG9yKCcuc2VjdGlvblZpc3VhbC1zdWJ0aXRsZScpO1xuICBjb25zdCB2aXN1YWxIZWFkaW5nID0gdmlzdWFsLnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uVmlzdWFsLWhlYWRpbmcnKTtcbiAgY29uc3QgdmlzdWFsSGVhZGluZ1NwYW4gPSB2aXN1YWxIZWFkaW5nLnF1ZXJ5U2VsZWN0b3JBbGwoJ3NwYW4nKTtcbiAgY29uc3QgdmlzdWFsc2Nyb2xsVHJpZ2dlciA9IHZpc3VhbC5xdWVyeVNlbGVjdG9yKCcuc2VjdGlvblZpc3VhbC1zY3JvbGxUcmlnZ2VyJyk7XG4gIHZpc3VhbFRpbWVsaW5lLnRvKHZpc3VhbENhbnZhcywge1xuICAgIG9wYWNpdHk6IDEsXG4gICAgZHVyYXRpb246IHRyYW5zdGl0aW9uVGltaW5nICogMlxuICB9LCAwKS50byh2aXN1YWxTaGlwLCB7XG4gICAgb3BhY2l0eTogMSxcbiAgICBkdXJhdGlvbjogdHJhbnN0aXRpb25UaW1pbmcgKiAyXG4gIH0sIDApLnRvKHZpc3VhbEVuZ0hlYWRlciwge1xuICAgIG9wYWNpdHk6IDEsXG4gICAgZHVyYXRpb246IHRyYW5zdGl0aW9uVGltaW5nICogMlxuICB9LCB0cmFuc3RpdGlvblRpbWluZyAqIDIpLnRvKHZpc3VhbFN1YnRpdGxlLCB7XG4gICAgb3BhY2l0eTogMSxcbiAgICBkdXJhdGlvbjogdHJhbnN0aXRpb25UaW1pbmcgKiAyXG4gIH0sIHRyYW5zdGl0aW9uVGltaW5nICogMik7XG4gIHZpc3VhbEhlYWRpbmdTcGFuLmZvckVhY2goKHZpc3VhbFNwYW4sIGkpID0+IHtcbiAgICB2aXN1YWxUaW1lbGluZS50byh2aXN1YWxTcGFuLCB7XG4gICAgICBvcGFjaXR5OiAxLFxuICAgICAgeTogMCxcbiAgICAgIGR1cmF0aW9uOiB0cmFuc3RpdGlvblRpbWluZ1xuICAgIH0sIHRyYW5zdGl0aW9uVGltaW5nIC8gMiAqIGkpO1xuICB9KTtcbiAgdmlzdWFsVGltZWxpbmUudG8odmlzdWFsc2Nyb2xsVHJpZ2dlciwge1xuICAgIG9wYWNpdHk6IDEsXG4gICAgZHVyYXRpb246IHRyYW5zdGl0aW9uVGltaW5nICogMlxuICB9LCB0cmFuc3RpdGlvblRpbWluZyAqIDIpO1xuICB2aXN1YWxUaW1lbGluZS5wbGF5KCk7XG59O1xuY29uc3QgYXF1YXJlbGxlSW5pdCA9ICgpID0+IHtcbiAgbGV0IGltYWdlO1xuICBpZiAodncgPCA0NTYpIHtcbiAgICBpbWFnZSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uVmlzdWFsLWNhbnZhcy0tbW9iaWxlJyk7XG4gIH0gZWxzZSB7XG4gICAgaW1hZ2UgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuc2VjdGlvblZpc3VhbC1jYW52YXMtLWRlc2t0b3AnKTtcbiAgfVxuICBjb25zdCBpbWFnZU1hc2sgPSB2aXN1YWwucXVlcnlTZWxlY3RvcignLnNlY3Rpb25WaXN1YWwtbWFzaycpLmdldEF0dHJpYnV0ZSgnc3JjJyk7XG4gIGxldCBkaXJlY3Rpb24gPSAnZm9yd2FyZCc7XG4gIGxldCBhcXVhcmVsbGUgPSBuZXcgQXF1YXJlbGxlKGltYWdlLCBpbWFnZU1hc2ssIHtcbiAgICBhdXRvcGxheTogdHJ1ZSxcbiAgICBmcm9tQW1wbGl0dWRlOiAxMCxcbiAgICB0b0FtcGxpdHVkZTogMTAsXG4gICAgZnJvbU9mZnNldDogMTAwLFxuICAgIGZyb21GcmVxdWVuY3k6IDQsXG4gICAgdG9GcmVxdWVuY3k6IDVcbiAgfSk7XG4gIGFxdWFyZWxsZS5hZGRFdmVudExpc3RlbmVyKCdjcmVhdGVkJywgZnVuY3Rpb24gKCkge1xuICAgIHZhciBjYW52YXMgPSB0aGlzLmdldENhbnZhcygpO1xuICAgIGlmICh2dyA8IDQ1Nikge1xuICAgICAgY2FudmFzLmNsYXNzTGlzdC5hZGQoJ3NlY3Rpb25WaXN1YWwtY2FudmFzLS1tb2JpbGUnKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY2FudmFzLmNsYXNzTGlzdC5hZGQoJ3NlY3Rpb25WaXN1YWwtY2FudmFzLS1kZXNrdG9wJyk7XG4gICAgfVxuICAgIGNhbnZhcy5yZW1vdmVBdHRyaWJ1dGUoJ3N0eWxlJyk7XG4gICAgaW1hZ2UucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUoY2FudmFzLCBpbWFnZS5uZXh0U2libGluZyk7XG4gICAgaW1hZ2UucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChpbWFnZSk7XG4gIH0pO1xuXG4gIC8vU2ltbHVhdGUgbG9vcFxuICBhcXVhcmVsbGUuYWRkRXZlbnRMaXN0ZW5lcignc3RvcHBlZCcsIGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoZGlyZWN0aW9uID09PSAnZm9yd2FyZCcpIHtcbiAgICAgIGFxdWFyZWxsZS5yZXZlcnNlKCk7XG4gICAgICBhcXVhcmVsbGUucGxheSgpO1xuICAgICAgZGlyZWN0aW9uID0gJ2JhY2t3YXJkJztcbiAgICB9IGVsc2Uge1xuICAgICAgYXF1YXJlbGxlLnJldmVyc2UoKTtcbiAgICAgIGFxdWFyZWxsZS5wbGF5KCk7XG4gICAgICBkaXJlY3Rpb24gPSAnZm9yd2FyZCc7XG4gICAgfVxuICB9KTtcbiAgYXF1YXJlbGxlLmFkZEV2ZW50TGlzdGVuZXIoJ2NyZWF0ZWQnLCAoKSA9PiB7XG4gICAgdGV4dEZhZGVJbigpO1xuICB9KTtcbn07XG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignRE9NQ29udGVudExvYWRlZCcsICgpID0+IHtcbiAgaWYgKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uVmlzdWFsJykpIHtcbiAgICB2aXN1YWwgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuc2VjdGlvblZpc3VhbCcpO1xuICAgIHRleHRGYWRlSW4oKTtcbiAgICBhcXVhcmVsbGVJbml0KCk7XG4gIH1cbn0pO1xud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsICgpID0+IHtcbiAgaWYgKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uVmlzdWFsJykpIHtcbiAgICB2dyA9IHdpbmRvdy5vdXRlcldpZHRoO1xuICAgIGFxdWFyZWxsZUluaXQoKTtcbiAgfVxufSk7IiwiLy9WZW5kb3Igc2NyaXB0c1xuaW1wb3J0IGdzYXAsIHsgQ2lyYyB9IGZyb20gXCJnc2FwXCI7XG5pbXBvcnQgKiBhcyBTY3JvbGxNYWdpYyBmcm9tIFwic2Nyb2xsbWFnaWNcIjtcbmNvbnN0IFlUUGxheWVyID0gcmVxdWlyZSgneXQtcGxheWVyJyk7XG5jb25zdCBjb250cm9sbGVyID0gbmV3IFNjcm9sbE1hZ2ljLkNvbnRyb2xsZXIoKTtcbmxldCB2dyA9IHdpbmRvdy5vdXRlcldpZHRoO1xubGV0IHZoID0gd2luZG93Lm91dGVySGVpZ2h0O1xuY29uc3QgYmVkZ2VDdXN0b21SZXZlYWwgPSBhbHRlcm5hdGVTZWN0aW9uID0+IHtcbiAgY29uc3QgYmVkZ2UgPSBhbHRlcm5hdGVTZWN0aW9uLnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uQWx0ZXJuYXRlX2JhZGdlJyk7XG4gIGlmIChiZWRnZSkge1xuICAgIG5ldyBTY3JvbGxNYWdpYy5TY2VuZSh7XG4gICAgICB0cmlnZ2VyRWxlbWVudDogYmVkZ2UsXG4gICAgICB0cmlnZ2VySG9vazogLjksXG4gICAgICBkdXJhdGlvbjogdmggLSBiZWRnZS5jbGllbnRIZWlnaHQsXG4gICAgICByZXZlcnNlOiB0cnVlXG4gICAgfSkuc2V0Q2xhc3NUb2dnbGUoYmVkZ2UsIFwidmlzaWJsZVwiKS5hZGRUbyhjb250cm9sbGVyKTtcbiAgfVxufTtcbmNvbnN0IHBsYXlWaWRlbyA9IGFsdGVybmF0ZVNlY3Rpb24gPT4ge1xuICBjb25zdCBhbHRlcm5hdGVTZWN0aW9uV3JhcHBlciA9IGFsdGVybmF0ZVNlY3Rpb24ucXVlcnlTZWxlY3RvcignLnNlY3Rpb25BbHRlcm5hdGVfd3JhcHBlcicpO1xuICBjb25zdCB2aWRlb1BsYXllciA9IGFsdGVybmF0ZVNlY3Rpb24ucXVlcnlTZWxlY3RvcignLnZpZGVvUGxheWVyJyk7XG4gIGlmICh2aWRlb1BsYXllcikge1xuICAgIGNvbnN0IHBsYXlCdXR0b24gPSBhbHRlcm5hdGVTZWN0aW9uLnF1ZXJ5U2VsZWN0b3IoJy5wbGF5QnV0dG9uJyk7XG4gICAgY29uc3QgdmlkZW9UcmlnZ2VyID0gYWx0ZXJuYXRlU2VjdGlvbi5xdWVyeVNlbGVjdG9yKCcudmlkZW9UcmlnZ2VyJyk7XG4gICAgY29uc3QgY2xvc2VCdXR0b24gPSBhbHRlcm5hdGVTZWN0aW9uLnF1ZXJ5U2VsZWN0b3IoJy5jbG9zZUJ1dHRvbicpO1xuICAgIGNvbnN0IHZpZGVvSWQgPSB2aWRlb1BsYXllci5nZXRBdHRyaWJ1dGUoJ2RhdGEtdXJsLWlkJyk7XG4gICAgY29uc3QgYWx0ZXJuYXRlU2VjdGlvbldyYXBwZXJJbWFnZSA9IGFsdGVybmF0ZVNlY3Rpb25XcmFwcGVyLnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uQWx0ZXJuYXRlX3dyYXBwZXItaW1hZ2UnKTtcbiAgICBjb25zdCBhbHRlcm5hdGVTZWN0aW9uV3JhcHBlckltYWdlQmcgPSBhbHRlcm5hdGVTZWN0aW9uV3JhcHBlckltYWdlLnF1ZXJ5U2VsZWN0b3IoJ2ltZycpO1xuICAgIGNvbnN0IGFsdGVybmF0ZVNlY3Rpb25XcmFwcGVyVGV4dCA9IGFsdGVybmF0ZVNlY3Rpb25XcmFwcGVyLnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uQWx0ZXJuYXRlX3dyYXBwZXItdGV4dCcpO1xuICAgIGNvbnN0IHBsYXllciA9IG5ldyBZVFBsYXllcih2aWRlb1BsYXllciwge1xuICAgICAgaGVpZ2h0OiAnMTAwJScsXG4gICAgICB3aWR0aDogJzEwMCUnXG4gICAgfSk7XG4gICAgcGxheWVyLmxvYWQodmlkZW9JZCk7XG4gICAgcGxheWVyLnNldFZvbHVtZSgzMCk7XG4gICAgbGV0IHZpZGVvUmV2ZWFsVGltZWxpbmUgPSAnJztcbiAgICBjb25zdCB0aW1lbGluZUJ1aWxkID0gdHlwZSA9PiB7XG4gICAgICBpZiAodHlwZSA9PT0gJ3Jlc2l6ZScpIHtcbiAgICAgICAgdmlkZW9SZXZlYWxUaW1lbGluZSA9ICcnO1xuICAgICAgfVxuICAgICAgaWYgKHZpZGVvUmV2ZWFsVGltZWxpbmUgPT09ICcnKSB7XG4gICAgICAgIGNvbnN0IGFuaW1hdGlvblRpbWUgPSAxO1xuICAgICAgICBjb25zdCBhbHRlcm5hdGVTZWN0aW9uV3JhcHBlcldpZHRoID0gYWx0ZXJuYXRlU2VjdGlvbldyYXBwZXIuY2xpZW50V2lkdGg7XG4gICAgICAgIGNvbnN0IGFsdGVybmF0ZVNlY3Rpb25XcmFwcGVySGVpZ2h0ID0gYWx0ZXJuYXRlU2VjdGlvbldyYXBwZXIuY2xpZW50SGVpZ2h0O1xuICAgICAgICBjb25zdCBhbHRlcm5hdGVTZWN0aW9uV3JhcHBlckltYWdlV2lkdGggPSBhbHRlcm5hdGVTZWN0aW9uV3JhcHBlckltYWdlLmNsaWVudFdpZHRoO1xuICAgICAgICBjb25zdCBhbHRlcm5hdGVTZWN0aW9uV3JhcHBlckltYWdlSGVpZ2h0ID0gYWx0ZXJuYXRlU2VjdGlvbldyYXBwZXJJbWFnZS5jbGllbnRIZWlnaHQ7XG4gICAgICAgIGNvbnN0IGFsdGVybmF0ZVNlY3Rpb25XcmFwcGVyVGV4dEhlaWdodCA9IGFsdGVybmF0ZVNlY3Rpb25XcmFwcGVyVGV4dC5jbGllbnRIZWlnaHQ7XG4gICAgICAgIGNvbnN0IHZpZGVvV3JhcHBlciA9IGFsdGVybmF0ZVNlY3Rpb24ucXVlcnlTZWxlY3RvcignLnZpZGVvUGxheWVyJyk7XG4gICAgICAgIHZpZGVvUmV2ZWFsVGltZWxpbmUgPSBnc2FwLnRpbWVsaW5lKHtcbiAgICAgICAgICBwYXVzZWQ6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICAgIGlmICh2dyA+PSAxMDI1KSB7XG4gICAgICAgICAgdmlkZW9SZXZlYWxUaW1lbGluZS5zZXQoYWx0ZXJuYXRlU2VjdGlvbldyYXBwZXJJbWFnZSwge1xuICAgICAgICAgICAgd2lkdGg6IGFsdGVybmF0ZVNlY3Rpb25XcmFwcGVySW1hZ2VXaWR0aCxcbiAgICAgICAgICAgIGZsZXg6ICdub25lJ1xuICAgICAgICAgIH0pLnNldCh2aWRlb1dyYXBwZXIsIHtcbiAgICAgICAgICAgIHdpZHRoOiBhbHRlcm5hdGVTZWN0aW9uV3JhcHBlckltYWdlV2lkdGggLSAzMixcbiAgICAgICAgICAgIGhlaWdodDogYWx0ZXJuYXRlU2VjdGlvbldyYXBwZXJJbWFnZUhlaWdodFxuICAgICAgICAgIH0sIDApLnRvKHBsYXlCdXR0b24sIHtcbiAgICAgICAgICAgIG9wYWNpdHk6IDAsXG4gICAgICAgICAgICB2aXNpYmlsaXR5OiAnaGlkZGVuJyxcbiAgICAgICAgICAgIGR1cmF0aW9uOiBhbmltYXRpb25UaW1lIC8gMixcbiAgICAgICAgICAgIGVhc2U6IENpcmMuZWFzZUluT3V0XG4gICAgICAgICAgfSwgMCkudG8oYWx0ZXJuYXRlU2VjdGlvbldyYXBwZXJUZXh0LCB7XG4gICAgICAgICAgICB4OiAnMTAwJScsXG4gICAgICAgICAgICBoZWlnaHQ6IGFsdGVybmF0ZVNlY3Rpb25XcmFwcGVyVGV4dEhlaWdodCxcbiAgICAgICAgICAgIG9wYWNpdHk6IDAsXG4gICAgICAgICAgICBkdXJhdGlvbjogYW5pbWF0aW9uVGltZSxcbiAgICAgICAgICAgIGVhc2U6IENpcmMuZWFzZUluT3V0XG4gICAgICAgICAgfSwgMCkudG8oY2xvc2VCdXR0b24sIHtcbiAgICAgICAgICAgIG9wYWNpdHk6IDEsXG4gICAgICAgICAgICB2aXNpYmlsaXR5OiAndmlzaWJsZScsXG4gICAgICAgICAgICBkdXJhdGlvbjogYW5pbWF0aW9uVGltZSAvIDIsXG4gICAgICAgICAgICBlYXNlOiBDaXJjLmVhc2VJbk91dFxuICAgICAgICAgIH0sIGFuaW1hdGlvblRpbWUgLyAyKS50byhhbHRlcm5hdGVTZWN0aW9uV3JhcHBlckltYWdlLCB7XG4gICAgICAgICAgICB3aWR0aDogYWx0ZXJuYXRlU2VjdGlvbldyYXBwZXJXaWR0aCxcbiAgICAgICAgICAgIGhlaWdodDogYWx0ZXJuYXRlU2VjdGlvbldyYXBwZXJJbWFnZUhlaWdodCxcbiAgICAgICAgICAgIHBhZGRpbmc6IDAsXG4gICAgICAgICAgICBmbGV4OiAnbm9uZScsXG4gICAgICAgICAgICBkdXJhdGlvbjogYW5pbWF0aW9uVGltZSxcbiAgICAgICAgICAgIGVhc2U6IENpcmMuZWFzZUluT3V0XG4gICAgICAgICAgfSwgYW5pbWF0aW9uVGltZSAvIDIpLnRvKGFsdGVybmF0ZVNlY3Rpb25XcmFwcGVySW1hZ2VCZywge1xuICAgICAgICAgICAgZmlsdGVyOiBcImJsdXIoM3B4KVwiLFxuICAgICAgICAgICAgZHVyYXRpb246IGFuaW1hdGlvblRpbWUsXG4gICAgICAgICAgICBlYXNlOiBDaXJjLmVhc2VJbk91dFxuICAgICAgICAgIH0sIGFuaW1hdGlvblRpbWUgLyAyKS50byh2aWRlb1dyYXBwZXIsIHtcbiAgICAgICAgICAgIG9wYWNpdHk6IDEsXG4gICAgICAgICAgICB2aXNpYmlsaXR5OiAndmlzaWJsZScsXG4gICAgICAgICAgICBkdXJhdGlvbjogYW5pbWF0aW9uVGltZSxcbiAgICAgICAgICAgIGVhc2U6IENpcmMuZWFzZUluT3V0XG4gICAgICAgICAgfSwgYW5pbWF0aW9uVGltZSAvIDIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZpZGVvUmV2ZWFsVGltZWxpbmUuc2V0KGFsdGVybmF0ZVNlY3Rpb25XcmFwcGVySW1hZ2UsIHtcbiAgICAgICAgICAgIHdpZHRoOiBhbHRlcm5hdGVTZWN0aW9uV3JhcHBlckltYWdlV2lkdGgsXG4gICAgICAgICAgICBmbGV4OiAnbm9uZSdcbiAgICAgICAgICB9KS5zZXQodmlkZW9XcmFwcGVyLCB7XG4gICAgICAgICAgICB3aWR0aDogYWx0ZXJuYXRlU2VjdGlvbldyYXBwZXJJbWFnZVdpZHRoLFxuICAgICAgICAgICAgaGVpZ2h0OiBhbHRlcm5hdGVTZWN0aW9uV3JhcHBlckltYWdlSGVpZ2h0XG4gICAgICAgICAgfSwgMCkudG8ocGxheUJ1dHRvbiwge1xuICAgICAgICAgICAgb3BhY2l0eTogMCxcbiAgICAgICAgICAgIHZpc2liaWxpdHk6ICdoaWRkZW4nLFxuICAgICAgICAgICAgZHVyYXRpb246IGFuaW1hdGlvblRpbWUgLyAyLFxuICAgICAgICAgICAgZWFzZTogQ2lyYy5lYXNlSW5PdXRcbiAgICAgICAgICB9LCAwKS50byhjbG9zZUJ1dHRvbiwge1xuICAgICAgICAgICAgb3BhY2l0eTogMSxcbiAgICAgICAgICAgIHZpc2liaWxpdHk6ICd2aXNpYmxlJyxcbiAgICAgICAgICAgIGR1cmF0aW9uOiBhbmltYXRpb25UaW1lIC8gMixcbiAgICAgICAgICAgIGVhc2U6IENpcmMuZWFzZUluT3V0XG4gICAgICAgICAgfSwgMCkudG8oYWx0ZXJuYXRlU2VjdGlvbldyYXBwZXJUZXh0LCB7XG4gICAgICAgICAgICB5OiAnLTEwMCUnLFxuICAgICAgICAgICAgb3BhY2l0eTogMCxcbiAgICAgICAgICAgIGR1cmF0aW9uOiBhbmltYXRpb25UaW1lLFxuICAgICAgICAgICAgZWFzZTogQ2lyYy5lYXNlSW5PdXRcbiAgICAgICAgICB9LCAwKS50byhhbHRlcm5hdGVTZWN0aW9uV3JhcHBlckltYWdlLCB7XG4gICAgICAgICAgICBwYWRkaW5nOiAwLFxuICAgICAgICAgICAgaGVpZ2h0OiBhbHRlcm5hdGVTZWN0aW9uV3JhcHBlckhlaWdodCxcbiAgICAgICAgICAgIGZsZXg6ICdub25lJyxcbiAgICAgICAgICAgIGR1cmF0aW9uOiBhbmltYXRpb25UaW1lLFxuICAgICAgICAgICAgZWFzZTogQ2lyYy5lYXNlSW5PdXRcbiAgICAgICAgICB9LCAwKS50byhhbHRlcm5hdGVTZWN0aW9uV3JhcHBlckltYWdlQmcsIHtcbiAgICAgICAgICAgIGZpbHRlcjogXCJibHVyKDNweClcIixcbiAgICAgICAgICAgIGhlaWdodDogYWx0ZXJuYXRlU2VjdGlvbldyYXBwZXJIZWlnaHQsXG4gICAgICAgICAgICB3aWR0aDogJ2F1dG8nLFxuICAgICAgICAgICAgZHVyYXRpb246IGFuaW1hdGlvblRpbWUsXG4gICAgICAgICAgICBlYXNlOiBDaXJjLmVhc2VJbk91dFxuICAgICAgICAgIH0sIDApLnRvKHZpZGVvV3JhcHBlciwge1xuICAgICAgICAgICAgb3BhY2l0eTogMSxcbiAgICAgICAgICAgIHZpc2liaWxpdHk6ICd2aXNpYmxlJyxcbiAgICAgICAgICAgIGR1cmF0aW9uOiBhbmltYXRpb25UaW1lLFxuICAgICAgICAgICAgZWFzZTogQ2lyYy5lYXNlSW5PdXRcbiAgICAgICAgICB9LCAwKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG4gICAgcGxheWVyLm9uKCd1bnN0YXJ0ZWQnLCAoKSA9PiB7XG4gICAgICB0aW1lbGluZUJ1aWxkKCk7XG4gICAgfSk7XG4gICAgcGxheUJ1dHRvbi5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsICgpID0+IHtcbiAgICAgIHZpZGVvUmV2ZWFsVGltZWxpbmUucGxheSgpO1xuICAgICAgcGxheWVyLnBsYXkoKTtcbiAgICB9KTtcbiAgICBjbG9zZUJ1dHRvbi5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsICgpID0+IHtcbiAgICAgIHZpZGVvUmV2ZWFsVGltZWxpbmUucmV2ZXJzZSgpO1xuICAgICAgcGxheWVyLnBhdXNlKCk7XG4gICAgfSk7XG4gICAgdmlkZW9UcmlnZ2VyLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZSA9PiB7XG4gICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICBwbGF5QnV0dG9uLmNsaWNrKCk7XG4gICAgfSk7XG4gICAgcGxheWVyLm9uKCdlbmRlZCcsICgpID0+IHtcbiAgICAgIHZpZGVvUmV2ZWFsVGltZWxpbmUucmV2ZXJzZSgpO1xuICAgICAgdmlkZW9SZXZlYWxUaW1lbGluZSA9ICcnO1xuICAgICAgcGxheWVyLnBhdXNlKCk7XG4gICAgICBwbGF5ZXIuc2VlaygwKTtcbiAgICB9KTtcbiAgICBjb25zdCB2dyA9IHdpbmRvdy5pbm5lcldpZHRoO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdyZXNpemUnLCAoKSA9PiB7XG4gICAgICBpZiAod2luZG93LmlubmVyV2lkdGggIT09IHZ3KSB7XG4gICAgICAgIGFsdGVybmF0ZVNlY3Rpb25XcmFwcGVySW1hZ2UucmVtb3ZlQXR0cmlidXRlKCdzdHlsZScpO1xuICAgICAgICBhbHRlcm5hdGVTZWN0aW9uV3JhcHBlckltYWdlQmcucmVtb3ZlQXR0cmlidXRlKCdzdHlsZScpO1xuICAgICAgICBhbHRlcm5hdGVTZWN0aW9uV3JhcHBlclRleHQucmVtb3ZlQXR0cmlidXRlKCdzdHlsZScpO1xuICAgICAgICBwbGF5QnV0dG9uLnJlbW92ZUF0dHJpYnV0ZSgnc3R5bGUnKTtcbiAgICAgICAgY2xvc2VCdXR0b24ucmVtb3ZlQXR0cmlidXRlKCdzdHlsZScpO1xuICAgICAgICBhbHRlcm5hdGVTZWN0aW9uLnF1ZXJ5U2VsZWN0b3IoJy52aWRlb1BsYXllcicpLnJlbW92ZUF0dHJpYnV0ZSgnc3R5bGUnKTtcbiAgICAgICAgdGltZWxpbmVCdWlsZCgncmVzaXplJyk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cbn07XG5kb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgKCkgPT4ge1xuICBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLnNlY3Rpb25BbHRlcm5hdGUnKSkge1xuICAgIGNvbnN0IGFsdGVybmF0ZVNlY3Rpb25zID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLnNlY3Rpb25BbHRlcm5hdGUnKTtcbiAgICBhbHRlcm5hdGVTZWN0aW9ucy5mb3JFYWNoKGFsdGVybmF0ZVNlY3Rpb24gPT4ge1xuICAgICAgYmVkZ2VDdXN0b21SZXZlYWwoYWx0ZXJuYXRlU2VjdGlvbik7XG4gICAgICBwbGF5VmlkZW8oYWx0ZXJuYXRlU2VjdGlvbik7XG4gICAgfSk7XG4gIH1cbn0pO1xud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsICgpID0+IHtcbiAgdncgPSB3aW5kb3cub3V0ZXJXaWR0aDtcbn0pO1xuZXhwb3J0IGRlZmF1bHQgcGxheVZpZGVvOyIsImltcG9ydCBnc2FwIGZyb20gXCJnc2FwXCI7XG5pbXBvcnQgU2Nyb2xsVG9QbHVnaW4gZnJvbSBcImdzYXAvU2Nyb2xsVG9QbHVnaW5cIjtcbmltcG9ydCB7IGNoYXB0ZXJPcGVuSGFuZGxlciB9IGZyb20gJ0NvbXBvbmVudHMvY2hhcHRlci9jaGFwdGVyJztcbmdzYXAucmVnaXN0ZXJQbHVnaW4oU2Nyb2xsVG9QbHVnaW4pO1xubGV0IG1hcDtcbmNvbnN0IGNoYXB0ZXJzQ2xpY2sgPSAoKSA9PiB7XG4gIGNvbnN0IG1hcFdyYXBwZXIgPSBtYXAucXVlcnlTZWxlY3RvcignLnNlY3Rpb25NYXBfYmFja2dyb3VuZC13cmFwcGVyJyk7XG4gIGNvbnN0IG1hcFdyYXBwZXJDaGFwdGVycyA9IG1hcFdyYXBwZXIucXVlcnlTZWxlY3RvckFsbCgnLnNlY3Rpb25NYXBfYmFja2dyb3VuZC13cmFwcGVyLWNoYXB0ZXInKTtcbiAgbWFwV3JhcHBlckNoYXB0ZXJzLmZvckVhY2goY2hhcHRlciA9PiB7XG4gICAgY2hhcHRlci5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGUgPT4ge1xuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgbGV0IGNoYXB0ZXJOYW1lO1xuICAgICAgaWYgKHdpbmRvdy5sb2NhdGlvbi5ob3N0ICE9IFwibG9jYWxob3N0OjMwMDBcIikge1xuICAgICAgICBjaGFwdGVyTmFtZSA9IGAke2NoYXB0ZXIuZ2V0QXR0cmlidXRlKCdkYXRhLWNoYXB0ZXInKX1gO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY2hhcHRlck5hbWUgPSBgJHtjaGFwdGVyLmdldEF0dHJpYnV0ZSgnZGF0YS1jaGFwdGVyJyl9Lmh0bWxgO1xuICAgICAgfVxuICAgICAgY2hhcHRlck9wZW5IYW5kbGVyKGNoYXB0ZXJOYW1lKTtcbiAgICB9KTtcbiAgfSk7XG59O1xuXG4vLyBjb25zdCBtYXBCdWlsZCA9IChkYXRhKSA9PiB7XG4vLyAgICAgY29uc3QgbWFwV3JhcHBlciA9IG1hcC5xdWVyeVNlbGVjdG9yKCcuc2VjdGlvbk1hcF9iYWNrZ3JvdW5kLXdyYXBwZXInKTtcblxuLy8gICAgIGxldCBtYXBDaGFwdGVyTWFya3VwID0gJyc7XG4vLyAgICAgZGF0YS5tYXAuY2hhcHRlcnMuZm9yRWFjaCgoY2hhcHRlciwgaSkgPT4ge1xuLy8gICAgICAgICBtYXBDaGFwdGVyTWFya3VwICs9IGBcbi8vICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzZWN0aW9uTWFwX2JhY2tncm91bmQtd3JhcHBlci1jaGFwdGVyXCIgZGF0YS1vcmRlcj1cIiR7aX1cIiBkYXRhLWNoYXB0ZXI9XCIke2NoYXB0ZXIubGlua31cIj5cbi8vICAgICAgICAgICAgICAgICA8cCBjbGFzcz1cInNlY3Rpb25NYXBfYmFja2dyb3VuZC13cmFwcGVyLWNoYXB0ZXItLXRpdGxlXCI+JHtjaGFwdGVyLnRpdGxlfTwvcD5cbi8vICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic2VjdGlvbk1hcF9iYWNrZ3JvdW5kLXdyYXBwZXItY2hhcHRlci0tYnVsbGV0XCI+XG4vLyAgICAgICAgICAgICAgICAgICAgIDxzdmcgd2lkdGg9XCIxNVwiIGhlaWdodD1cIjE0XCIgdmlld0JveD1cIjAgMCAxNSAxNFwiIGZpbGw9XCJub25lXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiPlxuLy8gICAgICAgICAgICAgICAgICAgICAgICAgPHBhdGggZmlsbC1ydWxlPVwiZXZlbm9kZFwiIGNsaXAtcnVsZT1cImV2ZW5vZGRcIiBkPVwiTTguNTE5NDUgMC4zNzUxODZMMTQuOTczMyA2Ljc3Mjc5TDguNTIyMjYgMTMuMjI2Nkw3Ljg3NTQgMTIuNTc4N0wxMy4yMjE3IDcuMjMyNDVMMC4wMjUzNDk0IDcuMjMyNDVMMC4wMjUzNDkzIDYuMzE2N0wxMy4yMTQ5IDYuMzE2N0w3Ljg3NDY0IDEuMDI1NzNMOC41MTk0NSAwLjM3NTE4NlpcIiBmaWxsPVwiIzIxM0Y1QlwiLz5cbi8vICAgICAgICAgICAgICAgICAgICAgPC9zdmc+XG4vLyAgICAgICAgICAgICAgICAgPC9kaXY+XG4vLyAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInNlY3Rpb25NYXBfYmFja2dyb3VuZC13cmFwcGVyLWNoYXB0ZXItLWltYWdlXCI+XG4vLyAgICAgICAgICAgICAgICAgICAgIDxpbWcgc3JjPVwiJHtjaGFwdGVyLmltYWdlfVwiIC8+XG4vLyAgICAgICAgICAgICAgICAgPC9kaXY+XG4vLyAgICAgICAgICAgICA8L2Rpdj5cbi8vICAgICAgICAgYDtcbi8vICAgICB9KTtcbi8vICAgICBtYXBXcmFwcGVyLmlubmVySFRNTCA9IG1hcENoYXB0ZXJNYXJrdXA7XG4vLyAgICAgY2hhcHRlcnNDbGljaygpO1xuLy8gfVxuXG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignRE9NQ29udGVudExvYWRlZCcsICgpID0+IHtcbiAgaWYgKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5zZWN0aW9uTWFwJykpIHtcbiAgICBtYXAgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuc2VjdGlvbk1hcCcpO1xuICAgIGNoYXB0ZXJzQ2xpY2soKTtcbiAgfVxufSk7XG5cbi8vIGV4cG9ydCBkZWZhdWx0IG1hcEJ1aWxkOyIsIi8qKlxuICogU1NSIFdpbmRvdyA0LjAuMlxuICogQmV0dGVyIGhhbmRsaW5nIGZvciB3aW5kb3cgb2JqZWN0IGluIFNTUiBlbnZpcm9ubWVudFxuICogaHR0cHM6Ly9naXRodWIuY29tL25vbGltaXRzNHdlYi9zc3Itd2luZG93XG4gKlxuICogQ29weXJpZ2h0IDIwMjEsIFZsYWRpbWlyIEtoYXJsYW1waWRpXG4gKlxuICogTGljZW5zZWQgdW5kZXIgTUlUXG4gKlxuICogUmVsZWFzZWQgb246IERlY2VtYmVyIDEzLCAyMDIxXG4gKi9cbi8qIGVzbGludC1kaXNhYmxlIG5vLXBhcmFtLXJlYXNzaWduICovXG5mdW5jdGlvbiBpc09iamVjdChvYmopIHtcbiAgICByZXR1cm4gKG9iaiAhPT0gbnVsbCAmJlxuICAgICAgICB0eXBlb2Ygb2JqID09PSAnb2JqZWN0JyAmJlxuICAgICAgICAnY29uc3RydWN0b3InIGluIG9iaiAmJlxuICAgICAgICBvYmouY29uc3RydWN0b3IgPT09IE9iamVjdCk7XG59XG5mdW5jdGlvbiBleHRlbmQodGFyZ2V0ID0ge30sIHNyYyA9IHt9KSB7XG4gICAgT2JqZWN0LmtleXMoc3JjKS5mb3JFYWNoKChrZXkpID0+IHtcbiAgICAgICAgaWYgKHR5cGVvZiB0YXJnZXRba2V5XSA9PT0gJ3VuZGVmaW5lZCcpXG4gICAgICAgICAgICB0YXJnZXRba2V5XSA9IHNyY1trZXldO1xuICAgICAgICBlbHNlIGlmIChpc09iamVjdChzcmNba2V5XSkgJiZcbiAgICAgICAgICAgIGlzT2JqZWN0KHRhcmdldFtrZXldKSAmJlxuICAgICAgICAgICAgT2JqZWN0LmtleXMoc3JjW2tleV0pLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGV4dGVuZCh0YXJnZXRba2V5XSwgc3JjW2tleV0pO1xuICAgICAgICB9XG4gICAgfSk7XG59XG5cbmNvbnN0IHNzckRvY3VtZW50ID0ge1xuICAgIGJvZHk6IHt9LFxuICAgIGFkZEV2ZW50TGlzdGVuZXIoKSB7IH0sXG4gICAgcmVtb3ZlRXZlbnRMaXN0ZW5lcigpIHsgfSxcbiAgICBhY3RpdmVFbGVtZW50OiB7XG4gICAgICAgIGJsdXIoKSB7IH0sXG4gICAgICAgIG5vZGVOYW1lOiAnJyxcbiAgICB9LFxuICAgIHF1ZXJ5U2VsZWN0b3IoKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH0sXG4gICAgcXVlcnlTZWxlY3RvckFsbCgpIHtcbiAgICAgICAgcmV0dXJuIFtdO1xuICAgIH0sXG4gICAgZ2V0RWxlbWVudEJ5SWQoKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH0sXG4gICAgY3JlYXRlRXZlbnQoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBpbml0RXZlbnQoKSB7IH0sXG4gICAgICAgIH07XG4gICAgfSxcbiAgICBjcmVhdGVFbGVtZW50KCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgY2hpbGRyZW46IFtdLFxuICAgICAgICAgICAgY2hpbGROb2RlczogW10sXG4gICAgICAgICAgICBzdHlsZToge30sXG4gICAgICAgICAgICBzZXRBdHRyaWJ1dGUoKSB7IH0sXG4gICAgICAgICAgICBnZXRFbGVtZW50c0J5VGFnTmFtZSgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgICAgICB9LFxuICAgICAgICB9O1xuICAgIH0sXG4gICAgY3JlYXRlRWxlbWVudE5TKCkge1xuICAgICAgICByZXR1cm4ge307XG4gICAgfSxcbiAgICBpbXBvcnROb2RlKCkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9LFxuICAgIGxvY2F0aW9uOiB7XG4gICAgICAgIGhhc2g6ICcnLFxuICAgICAgICBob3N0OiAnJyxcbiAgICAgICAgaG9zdG5hbWU6ICcnLFxuICAgICAgICBocmVmOiAnJyxcbiAgICAgICAgb3JpZ2luOiAnJyxcbiAgICAgICAgcGF0aG5hbWU6ICcnLFxuICAgICAgICBwcm90b2NvbDogJycsXG4gICAgICAgIHNlYXJjaDogJycsXG4gICAgfSxcbn07XG5mdW5jdGlvbiBnZXREb2N1bWVudCgpIHtcbiAgICBjb25zdCBkb2MgPSB0eXBlb2YgZG9jdW1lbnQgIT09ICd1bmRlZmluZWQnID8gZG9jdW1lbnQgOiB7fTtcbiAgICBleHRlbmQoZG9jLCBzc3JEb2N1bWVudCk7XG4gICAgcmV0dXJuIGRvYztcbn1cblxuY29uc3Qgc3NyV2luZG93ID0ge1xuICAgIGRvY3VtZW50OiBzc3JEb2N1bWVudCxcbiAgICBuYXZpZ2F0b3I6IHtcbiAgICAgICAgdXNlckFnZW50OiAnJyxcbiAgICB9LFxuICAgIGxvY2F0aW9uOiB7XG4gICAgICAgIGhhc2g6ICcnLFxuICAgICAgICBob3N0OiAnJyxcbiAgICAgICAgaG9zdG5hbWU6ICcnLFxuICAgICAgICBocmVmOiAnJyxcbiAgICAgICAgb3JpZ2luOiAnJyxcbiAgICAgICAgcGF0aG5hbWU6ICcnLFxuICAgICAgICBwcm90b2NvbDogJycsXG4gICAgICAgIHNlYXJjaDogJycsXG4gICAgfSxcbiAgICBoaXN0b3J5OiB7XG4gICAgICAgIHJlcGxhY2VTdGF0ZSgpIHsgfSxcbiAgICAgICAgcHVzaFN0YXRlKCkgeyB9LFxuICAgICAgICBnbygpIHsgfSxcbiAgICAgICAgYmFjaygpIHsgfSxcbiAgICB9LFxuICAgIEN1c3RvbUV2ZW50OiBmdW5jdGlvbiBDdXN0b21FdmVudCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcbiAgICBhZGRFdmVudExpc3RlbmVyKCkgeyB9LFxuICAgIHJlbW92ZUV2ZW50TGlzdGVuZXIoKSB7IH0sXG4gICAgZ2V0Q29tcHV0ZWRTdHlsZSgpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGdldFByb3BlcnR5VmFsdWUoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgfTtcbiAgICB9LFxuICAgIEltYWdlKCkgeyB9LFxuICAgIERhdGUoKSB7IH0sXG4gICAgc2NyZWVuOiB7fSxcbiAgICBzZXRUaW1lb3V0KCkgeyB9LFxuICAgIGNsZWFyVGltZW91dCgpIHsgfSxcbiAgICBtYXRjaE1lZGlhKCkge1xuICAgICAgICByZXR1cm4ge307XG4gICAgfSxcbiAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoY2FsbGJhY2spIHtcbiAgICAgICAgaWYgKHR5cGVvZiBzZXRUaW1lb3V0ID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgY2FsbGJhY2soKTtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzZXRUaW1lb3V0KGNhbGxiYWNrLCAwKTtcbiAgICB9LFxuICAgIGNhbmNlbEFuaW1hdGlvbkZyYW1lKGlkKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygc2V0VGltZW91dCA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjbGVhclRpbWVvdXQoaWQpO1xuICAgIH0sXG59O1xuZnVuY3Rpb24gZ2V0V2luZG93KCkge1xuICAgIGNvbnN0IHdpbiA9IHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnID8gd2luZG93IDoge307XG4gICAgZXh0ZW5kKHdpbiwgc3NyV2luZG93KTtcbiAgICByZXR1cm4gd2luO1xufVxuXG5leHBvcnQgeyBleHRlbmQsIGdldERvY3VtZW50LCBnZXRXaW5kb3csIHNzckRvY3VtZW50LCBzc3JXaW5kb3cgfTtcbiIsIi8qKlxuICogRG9tNyA0LjAuNlxuICogTWluaW1hbGlzdGljIEphdmFTY3JpcHQgbGlicmFyeSBmb3IgRE9NIG1hbmlwdWxhdGlvbiwgd2l0aCBhIGpRdWVyeS1jb21wYXRpYmxlIEFQSVxuICogaHR0cHM6Ly9mcmFtZXdvcms3LmlvL2RvY3MvZG9tNy5odG1sXG4gKlxuICogQ29weXJpZ2h0IDIwMjMsIFZsYWRpbWlyIEtoYXJsYW1waWRpXG4gKlxuICogTGljZW5zZWQgdW5kZXIgTUlUXG4gKlxuICogUmVsZWFzZWQgb246IEZlYnJ1YXJ5IDIsIDIwMjNcbiAqL1xuaW1wb3J0IHsgZ2V0V2luZG93LCBnZXREb2N1bWVudCB9IGZyb20gJ3Nzci13aW5kb3cnO1xuXG4vKiBlc2xpbnQtZGlzYWJsZSBuby1wcm90byAqL1xuZnVuY3Rpb24gbWFrZVJlYWN0aXZlKG9iaikge1xuICBjb25zdCBwcm90byA9IG9iai5fX3Byb3RvX187XG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShvYmosICdfX3Byb3RvX18nLCB7XG4gICAgZ2V0KCkge1xuICAgICAgcmV0dXJuIHByb3RvO1xuICAgIH0sXG5cbiAgICBzZXQodmFsdWUpIHtcbiAgICAgIHByb3RvLl9fcHJvdG9fXyA9IHZhbHVlO1xuICAgIH1cblxuICB9KTtcbn1cblxuY2xhc3MgRG9tNyBleHRlbmRzIEFycmF5IHtcbiAgY29uc3RydWN0b3IoaXRlbXMpIHtcbiAgICBpZiAodHlwZW9mIGl0ZW1zID09PSAnbnVtYmVyJykge1xuICAgICAgc3VwZXIoaXRlbXMpO1xuICAgIH0gZWxzZSB7XG4gICAgICBzdXBlciguLi4oaXRlbXMgfHwgW10pKTtcbiAgICAgIG1ha2VSZWFjdGl2ZSh0aGlzKTtcbiAgICB9XG4gIH1cblxufVxuXG5mdW5jdGlvbiBhcnJheUZsYXQoYXJyID0gW10pIHtcbiAgY29uc3QgcmVzID0gW107XG4gIGFyci5mb3JFYWNoKGVsID0+IHtcbiAgICBpZiAoQXJyYXkuaXNBcnJheShlbCkpIHtcbiAgICAgIHJlcy5wdXNoKC4uLmFycmF5RmxhdChlbCkpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXMucHVzaChlbCk7XG4gICAgfVxuICB9KTtcbiAgcmV0dXJuIHJlcztcbn1cbmZ1bmN0aW9uIGFycmF5RmlsdGVyKGFyciwgY2FsbGJhY2spIHtcbiAgcmV0dXJuIEFycmF5LnByb3RvdHlwZS5maWx0ZXIuY2FsbChhcnIsIGNhbGxiYWNrKTtcbn1cbmZ1bmN0aW9uIGFycmF5VW5pcXVlKGFycikge1xuICBjb25zdCB1bmlxdWVBcnJheSA9IFtdO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXJyLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgaWYgKHVuaXF1ZUFycmF5LmluZGV4T2YoYXJyW2ldKSA9PT0gLTEpIHVuaXF1ZUFycmF5LnB1c2goYXJyW2ldKTtcbiAgfVxuXG4gIHJldHVybiB1bmlxdWVBcnJheTtcbn1cbmZ1bmN0aW9uIHRvQ2FtZWxDYXNlKHN0cmluZykge1xuICByZXR1cm4gc3RyaW5nLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvLSguKS9nLCAobWF0Y2gsIGdyb3VwKSA9PiBncm91cC50b1VwcGVyQ2FzZSgpKTtcbn1cblxuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG5cbmZ1bmN0aW9uIHFzYShzZWxlY3RvciwgY29udGV4dCkge1xuICBpZiAodHlwZW9mIHNlbGVjdG9yICE9PSAnc3RyaW5nJykge1xuICAgIHJldHVybiBbc2VsZWN0b3JdO1xuICB9XG5cbiAgY29uc3QgYSA9IFtdO1xuICBjb25zdCByZXMgPSBjb250ZXh0LnF1ZXJ5U2VsZWN0b3JBbGwoc2VsZWN0b3IpO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgcmVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgYS5wdXNoKHJlc1tpXSk7XG4gIH1cblxuICByZXR1cm4gYTtcbn1cblxuZnVuY3Rpb24gJChzZWxlY3RvciwgY29udGV4dCkge1xuICBjb25zdCB3aW5kb3cgPSBnZXRXaW5kb3coKTtcbiAgY29uc3QgZG9jdW1lbnQgPSBnZXREb2N1bWVudCgpO1xuICBsZXQgYXJyID0gW107XG5cbiAgaWYgKCFjb250ZXh0ICYmIHNlbGVjdG9yIGluc3RhbmNlb2YgRG9tNykge1xuICAgIHJldHVybiBzZWxlY3RvcjtcbiAgfVxuXG4gIGlmICghc2VsZWN0b3IpIHtcbiAgICByZXR1cm4gbmV3IERvbTcoYXJyKTtcbiAgfVxuXG4gIGlmICh0eXBlb2Ygc2VsZWN0b3IgPT09ICdzdHJpbmcnKSB7XG4gICAgY29uc3QgaHRtbCA9IHNlbGVjdG9yLnRyaW0oKTtcblxuICAgIGlmIChodG1sLmluZGV4T2YoJzwnKSA+PSAwICYmIGh0bWwuaW5kZXhPZignPicpID49IDApIHtcbiAgICAgIGxldCB0b0NyZWF0ZSA9ICdkaXYnO1xuICAgICAgaWYgKGh0bWwuaW5kZXhPZignPGxpJykgPT09IDApIHRvQ3JlYXRlID0gJ3VsJztcbiAgICAgIGlmIChodG1sLmluZGV4T2YoJzx0cicpID09PSAwKSB0b0NyZWF0ZSA9ICd0Ym9keSc7XG4gICAgICBpZiAoaHRtbC5pbmRleE9mKCc8dGQnKSA9PT0gMCB8fCBodG1sLmluZGV4T2YoJzx0aCcpID09PSAwKSB0b0NyZWF0ZSA9ICd0cic7XG4gICAgICBpZiAoaHRtbC5pbmRleE9mKCc8dGJvZHknKSA9PT0gMCkgdG9DcmVhdGUgPSAndGFibGUnO1xuICAgICAgaWYgKGh0bWwuaW5kZXhPZignPG9wdGlvbicpID09PSAwKSB0b0NyZWF0ZSA9ICdzZWxlY3QnO1xuICAgICAgY29uc3QgdGVtcFBhcmVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQodG9DcmVhdGUpO1xuICAgICAgdGVtcFBhcmVudC5pbm5lckhUTUwgPSBodG1sO1xuXG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRlbXBQYXJlbnQuY2hpbGROb2Rlcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICBhcnIucHVzaCh0ZW1wUGFyZW50LmNoaWxkTm9kZXNbaV0pO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBhcnIgPSBxc2Eoc2VsZWN0b3IudHJpbSgpLCBjb250ZXh0IHx8IGRvY3VtZW50KTtcbiAgICB9IC8vIGFyciA9IHFzYShzZWxlY3RvciwgZG9jdW1lbnQpO1xuXG4gIH0gZWxzZSBpZiAoc2VsZWN0b3Iubm9kZVR5cGUgfHwgc2VsZWN0b3IgPT09IHdpbmRvdyB8fCBzZWxlY3RvciA9PT0gZG9jdW1lbnQpIHtcbiAgICBhcnIucHVzaChzZWxlY3Rvcik7XG4gIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShzZWxlY3RvcikpIHtcbiAgICBpZiAoc2VsZWN0b3IgaW5zdGFuY2VvZiBEb203KSByZXR1cm4gc2VsZWN0b3I7XG4gICAgYXJyID0gc2VsZWN0b3I7XG4gIH1cblxuICByZXR1cm4gbmV3IERvbTcoYXJyYXlVbmlxdWUoYXJyKSk7XG59XG5cbiQuZm4gPSBEb203LnByb3RvdHlwZTtcblxuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG5cbmZ1bmN0aW9uIGFkZENsYXNzKC4uLmNsYXNzZXMpIHtcbiAgY29uc3QgY2xhc3NOYW1lcyA9IGFycmF5RmxhdChjbGFzc2VzLm1hcChjID0+IGMuc3BsaXQoJyAnKSkpO1xuICB0aGlzLmZvckVhY2goZWwgPT4ge1xuICAgIGVsLmNsYXNzTGlzdC5hZGQoLi4uY2xhc3NOYW1lcyk7XG4gIH0pO1xuICByZXR1cm4gdGhpcztcbn1cblxuZnVuY3Rpb24gcmVtb3ZlQ2xhc3MoLi4uY2xhc3Nlcykge1xuICBjb25zdCBjbGFzc05hbWVzID0gYXJyYXlGbGF0KGNsYXNzZXMubWFwKGMgPT4gYy5zcGxpdCgnICcpKSk7XG4gIHRoaXMuZm9yRWFjaChlbCA9PiB7XG4gICAgZWwuY2xhc3NMaXN0LnJlbW92ZSguLi5jbGFzc05hbWVzKTtcbiAgfSk7XG4gIHJldHVybiB0aGlzO1xufVxuXG5mdW5jdGlvbiB0b2dnbGVDbGFzcyguLi5jbGFzc2VzKSB7XG4gIGNvbnN0IGNsYXNzTmFtZXMgPSBhcnJheUZsYXQoY2xhc3Nlcy5tYXAoYyA9PiBjLnNwbGl0KCcgJykpKTtcbiAgdGhpcy5mb3JFYWNoKGVsID0+IHtcbiAgICBjbGFzc05hbWVzLmZvckVhY2goY2xhc3NOYW1lID0+IHtcbiAgICAgIGVsLmNsYXNzTGlzdC50b2dnbGUoY2xhc3NOYW1lKTtcbiAgICB9KTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGhhc0NsYXNzKC4uLmNsYXNzZXMpIHtcbiAgY29uc3QgY2xhc3NOYW1lcyA9IGFycmF5RmxhdChjbGFzc2VzLm1hcChjID0+IGMuc3BsaXQoJyAnKSkpO1xuICByZXR1cm4gYXJyYXlGaWx0ZXIodGhpcywgZWwgPT4ge1xuICAgIHJldHVybiBjbGFzc05hbWVzLmZpbHRlcihjbGFzc05hbWUgPT4gZWwuY2xhc3NMaXN0LmNvbnRhaW5zKGNsYXNzTmFtZSkpLmxlbmd0aCA+IDA7XG4gIH0pLmxlbmd0aCA+IDA7XG59XG5cbmZ1bmN0aW9uIGF0dHIoYXR0cnMsIHZhbHVlKSB7XG4gIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAxICYmIHR5cGVvZiBhdHRycyA9PT0gJ3N0cmluZycpIHtcbiAgICAvLyBHZXQgYXR0clxuICAgIGlmICh0aGlzWzBdKSByZXR1cm4gdGhpc1swXS5nZXRBdHRyaWJ1dGUoYXR0cnMpO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH0gLy8gU2V0IGF0dHJzXG5cblxuICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMikge1xuICAgICAgLy8gU3RyaW5nXG4gICAgICB0aGlzW2ldLnNldEF0dHJpYnV0ZShhdHRycywgdmFsdWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBPYmplY3RcbiAgICAgIGZvciAoY29uc3QgYXR0ck5hbWUgaW4gYXR0cnMpIHtcbiAgICAgICAgdGhpc1tpXVthdHRyTmFtZV0gPSBhdHRyc1thdHRyTmFtZV07XG4gICAgICAgIHRoaXNbaV0uc2V0QXR0cmlidXRlKGF0dHJOYW1lLCBhdHRyc1thdHRyTmFtZV0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufVxuXG5mdW5jdGlvbiByZW1vdmVBdHRyKGF0dHIpIHtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhpc1tpXS5yZW1vdmVBdHRyaWJ1dGUoYXR0cik7XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn1cblxuZnVuY3Rpb24gcHJvcChwcm9wcywgdmFsdWUpIHtcbiAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDEgJiYgdHlwZW9mIHByb3BzID09PSAnc3RyaW5nJykge1xuICAgIC8vIEdldCBwcm9wXG4gICAgaWYgKHRoaXNbMF0pIHJldHVybiB0aGlzWzBdW3Byb3BzXTtcbiAgfSBlbHNlIHtcbiAgICAvLyBTZXQgcHJvcHNcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAyKSB7XG4gICAgICAgIC8vIFN0cmluZ1xuICAgICAgICB0aGlzW2ldW3Byb3BzXSA9IHZhbHVlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gT2JqZWN0XG4gICAgICAgIGZvciAoY29uc3QgcHJvcE5hbWUgaW4gcHJvcHMpIHtcbiAgICAgICAgICB0aGlzW2ldW3Byb3BOYW1lXSA9IHByb3BzW3Byb3BOYW1lXTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgcmV0dXJuIHRoaXM7XG59XG5cbmZ1bmN0aW9uIGRhdGEoa2V5LCB2YWx1ZSkge1xuICBsZXQgZWw7XG5cbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBlbCA9IHRoaXNbMF07XG4gICAgaWYgKCFlbCkgcmV0dXJuIHVuZGVmaW5lZDsgLy8gR2V0IHZhbHVlXG5cbiAgICBpZiAoZWwuZG9tN0VsZW1lbnREYXRhU3RvcmFnZSAmJiBrZXkgaW4gZWwuZG9tN0VsZW1lbnREYXRhU3RvcmFnZSkge1xuICAgICAgcmV0dXJuIGVsLmRvbTdFbGVtZW50RGF0YVN0b3JhZ2Vba2V5XTtcbiAgICB9XG5cbiAgICBjb25zdCBkYXRhS2V5ID0gZWwuZ2V0QXR0cmlidXRlKGBkYXRhLSR7a2V5fWApO1xuXG4gICAgaWYgKGRhdGFLZXkpIHtcbiAgICAgIHJldHVybiBkYXRhS2V5O1xuICAgIH1cblxuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH0gLy8gU2V0IHZhbHVlXG5cblxuICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICBlbCA9IHRoaXNbaV07XG4gICAgaWYgKCFlbC5kb203RWxlbWVudERhdGFTdG9yYWdlKSBlbC5kb203RWxlbWVudERhdGFTdG9yYWdlID0ge307XG4gICAgZWwuZG9tN0VsZW1lbnREYXRhU3RvcmFnZVtrZXldID0gdmFsdWU7XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn1cblxuZnVuY3Rpb24gcmVtb3ZlRGF0YShrZXkpIHtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgY29uc3QgZWwgPSB0aGlzW2ldO1xuXG4gICAgaWYgKGVsLmRvbTdFbGVtZW50RGF0YVN0b3JhZ2UgJiYgZWwuZG9tN0VsZW1lbnREYXRhU3RvcmFnZVtrZXldKSB7XG4gICAgICBlbC5kb203RWxlbWVudERhdGFTdG9yYWdlW2tleV0gPSBudWxsO1xuICAgICAgZGVsZXRlIGVsLmRvbTdFbGVtZW50RGF0YVN0b3JhZ2Vba2V5XTtcbiAgICB9XG4gIH1cbn1cblxuZnVuY3Rpb24gZGF0YXNldCgpIHtcbiAgY29uc3QgZWwgPSB0aGlzWzBdO1xuICBpZiAoIWVsKSByZXR1cm4gdW5kZWZpbmVkO1xuICBjb25zdCBkYXRhc2V0ID0ge307IC8vIGVzbGludC1kaXNhYmxlLWxpbmVcblxuICBpZiAoZWwuZGF0YXNldCkge1xuICAgIGZvciAoY29uc3QgZGF0YUtleSBpbiBlbC5kYXRhc2V0KSB7XG4gICAgICBkYXRhc2V0W2RhdGFLZXldID0gZWwuZGF0YXNldFtkYXRhS2V5XTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBlbC5hdHRyaWJ1dGVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICBjb25zdCBhdHRyID0gZWwuYXR0cmlidXRlc1tpXTtcblxuICAgICAgaWYgKGF0dHIubmFtZS5pbmRleE9mKCdkYXRhLScpID49IDApIHtcbiAgICAgICAgZGF0YXNldFt0b0NhbWVsQ2FzZShhdHRyLm5hbWUuc3BsaXQoJ2RhdGEtJylbMV0pXSA9IGF0dHIudmFsdWU7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZm9yIChjb25zdCBrZXkgaW4gZGF0YXNldCkge1xuICAgIGlmIChkYXRhc2V0W2tleV0gPT09ICdmYWxzZScpIGRhdGFzZXRba2V5XSA9IGZhbHNlO2Vsc2UgaWYgKGRhdGFzZXRba2V5XSA9PT0gJ3RydWUnKSBkYXRhc2V0W2tleV0gPSB0cnVlO2Vsc2UgaWYgKHBhcnNlRmxvYXQoZGF0YXNldFtrZXldKSA9PT0gZGF0YXNldFtrZXldICogMSkgZGF0YXNldFtrZXldICo9IDE7XG4gIH1cblxuICByZXR1cm4gZGF0YXNldDtcbn1cblxuZnVuY3Rpb24gdmFsKHZhbHVlKSB7XG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgLy8gZ2V0IHZhbHVlXG4gICAgY29uc3QgZWwgPSB0aGlzWzBdO1xuICAgIGlmICghZWwpIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgICBpZiAoZWwubXVsdGlwbGUgJiYgZWwubm9kZU5hbWUudG9Mb3dlckNhc2UoKSA9PT0gJ3NlbGVjdCcpIHtcbiAgICAgIGNvbnN0IHZhbHVlcyA9IFtdO1xuXG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGVsLnNlbGVjdGVkT3B0aW9ucy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICB2YWx1ZXMucHVzaChlbC5zZWxlY3RlZE9wdGlvbnNbaV0udmFsdWUpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdmFsdWVzO1xuICAgIH1cblxuICAgIHJldHVybiBlbC52YWx1ZTtcbiAgfSAvLyBzZXQgdmFsdWVcblxuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgIGNvbnN0IGVsID0gdGhpc1tpXTtcblxuICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSAmJiBlbC5tdWx0aXBsZSAmJiBlbC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpID09PSAnc2VsZWN0Jykge1xuICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBlbC5vcHRpb25zLmxlbmd0aDsgaiArPSAxKSB7XG4gICAgICAgIGVsLm9wdGlvbnNbal0uc2VsZWN0ZWQgPSB2YWx1ZS5pbmRleE9mKGVsLm9wdGlvbnNbal0udmFsdWUpID49IDA7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGVsLnZhbHVlID0gdmFsdWU7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXM7XG59XG5cbmZ1bmN0aW9uIHZhbHVlKHZhbHVlKSB7XG4gIHJldHVybiB0aGlzLnZhbCh2YWx1ZSk7XG59XG5cbmZ1bmN0aW9uIHRyYW5zZm9ybSh0cmFuc2Zvcm0pIHtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhpc1tpXS5zdHlsZS50cmFuc2Zvcm0gPSB0cmFuc2Zvcm07XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn1cblxuZnVuY3Rpb24gdHJhbnNpdGlvbihkdXJhdGlvbikge1xuICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGlzW2ldLnN0eWxlLnRyYW5zaXRpb25EdXJhdGlvbiA9IHR5cGVvZiBkdXJhdGlvbiAhPT0gJ3N0cmluZycgPyBgJHtkdXJhdGlvbn1tc2AgOiBkdXJhdGlvbjtcbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufVxuXG5mdW5jdGlvbiBvbiguLi5hcmdzKSB7XG4gIGxldCBbZXZlbnRUeXBlLCB0YXJnZXRTZWxlY3RvciwgbGlzdGVuZXIsIGNhcHR1cmVdID0gYXJncztcblxuICBpZiAodHlwZW9mIGFyZ3NbMV0gPT09ICdmdW5jdGlvbicpIHtcbiAgICBbZXZlbnRUeXBlLCBsaXN0ZW5lciwgY2FwdHVyZV0gPSBhcmdzO1xuICAgIHRhcmdldFNlbGVjdG9yID0gdW5kZWZpbmVkO1xuICB9XG5cbiAgaWYgKCFjYXB0dXJlKSBjYXB0dXJlID0gZmFsc2U7XG5cbiAgZnVuY3Rpb24gaGFuZGxlTGl2ZUV2ZW50KGUpIHtcbiAgICBjb25zdCB0YXJnZXQgPSBlLnRhcmdldDtcbiAgICBpZiAoIXRhcmdldCkgcmV0dXJuO1xuICAgIGNvbnN0IGV2ZW50RGF0YSA9IGUudGFyZ2V0LmRvbTdFdmVudERhdGEgfHwgW107XG5cbiAgICBpZiAoZXZlbnREYXRhLmluZGV4T2YoZSkgPCAwKSB7XG4gICAgICBldmVudERhdGEudW5zaGlmdChlKTtcbiAgICB9XG5cbiAgICBpZiAoJCh0YXJnZXQpLmlzKHRhcmdldFNlbGVjdG9yKSkgbGlzdGVuZXIuYXBwbHkodGFyZ2V0LCBldmVudERhdGEpO2Vsc2Uge1xuICAgICAgY29uc3QgcGFyZW50cyA9ICQodGFyZ2V0KS5wYXJlbnRzKCk7IC8vIGVzbGludC1kaXNhYmxlLWxpbmVcblxuICAgICAgZm9yIChsZXQgayA9IDA7IGsgPCBwYXJlbnRzLmxlbmd0aDsgayArPSAxKSB7XG4gICAgICAgIGlmICgkKHBhcmVudHNba10pLmlzKHRhcmdldFNlbGVjdG9yKSkgbGlzdGVuZXIuYXBwbHkocGFyZW50c1trXSwgZXZlbnREYXRhKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBoYW5kbGVFdmVudChlKSB7XG4gICAgY29uc3QgZXZlbnREYXRhID0gZSAmJiBlLnRhcmdldCA/IGUudGFyZ2V0LmRvbTdFdmVudERhdGEgfHwgW10gOiBbXTtcblxuICAgIGlmIChldmVudERhdGEuaW5kZXhPZihlKSA8IDApIHtcbiAgICAgIGV2ZW50RGF0YS51bnNoaWZ0KGUpO1xuICAgIH1cblxuICAgIGxpc3RlbmVyLmFwcGx5KHRoaXMsIGV2ZW50RGF0YSk7XG4gIH1cblxuICBjb25zdCBldmVudHMgPSBldmVudFR5cGUuc3BsaXQoJyAnKTtcbiAgbGV0IGo7XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgY29uc3QgZWwgPSB0aGlzW2ldO1xuXG4gICAgaWYgKCF0YXJnZXRTZWxlY3Rvcikge1xuICAgICAgZm9yIChqID0gMDsgaiA8IGV2ZW50cy5sZW5ndGg7IGogKz0gMSkge1xuICAgICAgICBjb25zdCBldmVudCA9IGV2ZW50c1tqXTtcbiAgICAgICAgaWYgKCFlbC5kb203TGlzdGVuZXJzKSBlbC5kb203TGlzdGVuZXJzID0ge307XG4gICAgICAgIGlmICghZWwuZG9tN0xpc3RlbmVyc1tldmVudF0pIGVsLmRvbTdMaXN0ZW5lcnNbZXZlbnRdID0gW107XG4gICAgICAgIGVsLmRvbTdMaXN0ZW5lcnNbZXZlbnRdLnB1c2goe1xuICAgICAgICAgIGxpc3RlbmVyLFxuICAgICAgICAgIHByb3h5TGlzdGVuZXI6IGhhbmRsZUV2ZW50XG4gICAgICAgIH0pO1xuICAgICAgICBlbC5hZGRFdmVudExpc3RlbmVyKGV2ZW50LCBoYW5kbGVFdmVudCwgY2FwdHVyZSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIExpdmUgZXZlbnRzXG4gICAgICBmb3IgKGogPSAwOyBqIDwgZXZlbnRzLmxlbmd0aDsgaiArPSAxKSB7XG4gICAgICAgIGNvbnN0IGV2ZW50ID0gZXZlbnRzW2pdO1xuICAgICAgICBpZiAoIWVsLmRvbTdMaXZlTGlzdGVuZXJzKSBlbC5kb203TGl2ZUxpc3RlbmVycyA9IHt9O1xuICAgICAgICBpZiAoIWVsLmRvbTdMaXZlTGlzdGVuZXJzW2V2ZW50XSkgZWwuZG9tN0xpdmVMaXN0ZW5lcnNbZXZlbnRdID0gW107XG4gICAgICAgIGVsLmRvbTdMaXZlTGlzdGVuZXJzW2V2ZW50XS5wdXNoKHtcbiAgICAgICAgICBsaXN0ZW5lcixcbiAgICAgICAgICBwcm94eUxpc3RlbmVyOiBoYW5kbGVMaXZlRXZlbnRcbiAgICAgICAgfSk7XG4gICAgICAgIGVsLmFkZEV2ZW50TGlzdGVuZXIoZXZlbnQsIGhhbmRsZUxpdmVFdmVudCwgY2FwdHVyZSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXM7XG59XG5cbmZ1bmN0aW9uIG9mZiguLi5hcmdzKSB7XG4gIGxldCBbZXZlbnRUeXBlLCB0YXJnZXRTZWxlY3RvciwgbGlzdGVuZXIsIGNhcHR1cmVdID0gYXJncztcblxuICBpZiAodHlwZW9mIGFyZ3NbMV0gPT09ICdmdW5jdGlvbicpIHtcbiAgICBbZXZlbnRUeXBlLCBsaXN0ZW5lciwgY2FwdHVyZV0gPSBhcmdzO1xuICAgIHRhcmdldFNlbGVjdG9yID0gdW5kZWZpbmVkO1xuICB9XG5cbiAgaWYgKCFjYXB0dXJlKSBjYXB0dXJlID0gZmFsc2U7XG4gIGNvbnN0IGV2ZW50cyA9IGV2ZW50VHlwZS5zcGxpdCgnICcpO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgZXZlbnRzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgY29uc3QgZXZlbnQgPSBldmVudHNbaV07XG5cbiAgICBmb3IgKGxldCBqID0gMDsgaiA8IHRoaXMubGVuZ3RoOyBqICs9IDEpIHtcbiAgICAgIGNvbnN0IGVsID0gdGhpc1tqXTtcbiAgICAgIGxldCBoYW5kbGVycztcblxuICAgICAgaWYgKCF0YXJnZXRTZWxlY3RvciAmJiBlbC5kb203TGlzdGVuZXJzKSB7XG4gICAgICAgIGhhbmRsZXJzID0gZWwuZG9tN0xpc3RlbmVyc1tldmVudF07XG4gICAgICB9IGVsc2UgaWYgKHRhcmdldFNlbGVjdG9yICYmIGVsLmRvbTdMaXZlTGlzdGVuZXJzKSB7XG4gICAgICAgIGhhbmRsZXJzID0gZWwuZG9tN0xpdmVMaXN0ZW5lcnNbZXZlbnRdO1xuICAgICAgfVxuXG4gICAgICBpZiAoaGFuZGxlcnMgJiYgaGFuZGxlcnMubGVuZ3RoKSB7XG4gICAgICAgIGZvciAobGV0IGsgPSBoYW5kbGVycy5sZW5ndGggLSAxOyBrID49IDA7IGsgLT0gMSkge1xuICAgICAgICAgIGNvbnN0IGhhbmRsZXIgPSBoYW5kbGVyc1trXTtcblxuICAgICAgICAgIGlmIChsaXN0ZW5lciAmJiBoYW5kbGVyLmxpc3RlbmVyID09PSBsaXN0ZW5lcikge1xuICAgICAgICAgICAgZWwucmVtb3ZlRXZlbnRMaXN0ZW5lcihldmVudCwgaGFuZGxlci5wcm94eUxpc3RlbmVyLCBjYXB0dXJlKTtcbiAgICAgICAgICAgIGhhbmRsZXJzLnNwbGljZShrLCAxKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKGxpc3RlbmVyICYmIGhhbmRsZXIubGlzdGVuZXIgJiYgaGFuZGxlci5saXN0ZW5lci5kb203cHJveHkgJiYgaGFuZGxlci5saXN0ZW5lci5kb203cHJveHkgPT09IGxpc3RlbmVyKSB7XG4gICAgICAgICAgICBlbC5yZW1vdmVFdmVudExpc3RlbmVyKGV2ZW50LCBoYW5kbGVyLnByb3h5TGlzdGVuZXIsIGNhcHR1cmUpO1xuICAgICAgICAgICAgaGFuZGxlcnMuc3BsaWNlKGssIDEpO1xuICAgICAgICAgIH0gZWxzZSBpZiAoIWxpc3RlbmVyKSB7XG4gICAgICAgICAgICBlbC5yZW1vdmVFdmVudExpc3RlbmVyKGV2ZW50LCBoYW5kbGVyLnByb3h5TGlzdGVuZXIsIGNhcHR1cmUpO1xuICAgICAgICAgICAgaGFuZGxlcnMuc3BsaWNlKGssIDEpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufVxuXG5mdW5jdGlvbiBvbmNlKC4uLmFyZ3MpIHtcbiAgY29uc3QgZG9tID0gdGhpcztcbiAgbGV0IFtldmVudE5hbWUsIHRhcmdldFNlbGVjdG9yLCBsaXN0ZW5lciwgY2FwdHVyZV0gPSBhcmdzO1xuXG4gIGlmICh0eXBlb2YgYXJnc1sxXSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgIFtldmVudE5hbWUsIGxpc3RlbmVyLCBjYXB0dXJlXSA9IGFyZ3M7XG4gICAgdGFyZ2V0U2VsZWN0b3IgPSB1bmRlZmluZWQ7XG4gIH1cblxuICBmdW5jdGlvbiBvbmNlSGFuZGxlciguLi5ldmVudEFyZ3MpIHtcbiAgICBsaXN0ZW5lci5hcHBseSh0aGlzLCBldmVudEFyZ3MpO1xuICAgIGRvbS5vZmYoZXZlbnROYW1lLCB0YXJnZXRTZWxlY3Rvciwgb25jZUhhbmRsZXIsIGNhcHR1cmUpO1xuXG4gICAgaWYgKG9uY2VIYW5kbGVyLmRvbTdwcm94eSkge1xuICAgICAgZGVsZXRlIG9uY2VIYW5kbGVyLmRvbTdwcm94eTtcbiAgICB9XG4gIH1cblxuICBvbmNlSGFuZGxlci5kb203cHJveHkgPSBsaXN0ZW5lcjtcbiAgcmV0dXJuIGRvbS5vbihldmVudE5hbWUsIHRhcmdldFNlbGVjdG9yLCBvbmNlSGFuZGxlciwgY2FwdHVyZSk7XG59XG5cbmZ1bmN0aW9uIHRyaWdnZXIoLi4uYXJncykge1xuICBjb25zdCB3aW5kb3cgPSBnZXRXaW5kb3coKTtcbiAgY29uc3QgZXZlbnRzID0gYXJnc1swXS5zcGxpdCgnICcpO1xuICBjb25zdCBldmVudERhdGEgPSBhcmdzWzFdO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgZXZlbnRzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgY29uc3QgZXZlbnQgPSBldmVudHNbaV07XG5cbiAgICBmb3IgKGxldCBqID0gMDsgaiA8IHRoaXMubGVuZ3RoOyBqICs9IDEpIHtcbiAgICAgIGNvbnN0IGVsID0gdGhpc1tqXTtcblxuICAgICAgaWYgKHdpbmRvdy5DdXN0b21FdmVudCkge1xuICAgICAgICBjb25zdCBldnQgPSBuZXcgd2luZG93LkN1c3RvbUV2ZW50KGV2ZW50LCB7XG4gICAgICAgICAgZGV0YWlsOiBldmVudERhdGEsXG4gICAgICAgICAgYnViYmxlczogdHJ1ZSxcbiAgICAgICAgICBjYW5jZWxhYmxlOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgICBlbC5kb203RXZlbnREYXRhID0gYXJncy5maWx0ZXIoKGRhdGEsIGRhdGFJbmRleCkgPT4gZGF0YUluZGV4ID4gMCk7XG4gICAgICAgIGVsLmRpc3BhdGNoRXZlbnQoZXZ0KTtcbiAgICAgICAgZWwuZG9tN0V2ZW50RGF0YSA9IFtdO1xuICAgICAgICBkZWxldGUgZWwuZG9tN0V2ZW50RGF0YTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn1cblxuZnVuY3Rpb24gdHJhbnNpdGlvblN0YXJ0KGNhbGxiYWNrKSB7XG4gIGNvbnN0IGRvbSA9IHRoaXM7XG5cbiAgZnVuY3Rpb24gZmlyZUNhbGxCYWNrKGUpIHtcbiAgICBpZiAoZS50YXJnZXQgIT09IHRoaXMpIHJldHVybjtcbiAgICBjYWxsYmFjay5jYWxsKHRoaXMsIGUpO1xuICAgIGRvbS5vZmYoJ3RyYW5zaXRpb25zdGFydCcsIGZpcmVDYWxsQmFjayk7XG4gIH1cblxuICBpZiAoY2FsbGJhY2spIHtcbiAgICBkb20ub24oJ3RyYW5zaXRpb25zdGFydCcsIGZpcmVDYWxsQmFjayk7XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn1cblxuZnVuY3Rpb24gdHJhbnNpdGlvbkVuZChjYWxsYmFjaykge1xuICBjb25zdCBkb20gPSB0aGlzO1xuXG4gIGZ1bmN0aW9uIGZpcmVDYWxsQmFjayhlKSB7XG4gICAgaWYgKGUudGFyZ2V0ICE9PSB0aGlzKSByZXR1cm47XG4gICAgY2FsbGJhY2suY2FsbCh0aGlzLCBlKTtcbiAgICBkb20ub2ZmKCd0cmFuc2l0aW9uZW5kJywgZmlyZUNhbGxCYWNrKTtcbiAgfVxuXG4gIGlmIChjYWxsYmFjaykge1xuICAgIGRvbS5vbigndHJhbnNpdGlvbmVuZCcsIGZpcmVDYWxsQmFjayk7XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn1cblxuZnVuY3Rpb24gYW5pbWF0aW9uRW5kKGNhbGxiYWNrKSB7XG4gIGNvbnN0IGRvbSA9IHRoaXM7XG5cbiAgZnVuY3Rpb24gZmlyZUNhbGxCYWNrKGUpIHtcbiAgICBpZiAoZS50YXJnZXQgIT09IHRoaXMpIHJldHVybjtcbiAgICBjYWxsYmFjay5jYWxsKHRoaXMsIGUpO1xuICAgIGRvbS5vZmYoJ2FuaW1hdGlvbmVuZCcsIGZpcmVDYWxsQmFjayk7XG4gIH1cblxuICBpZiAoY2FsbGJhY2spIHtcbiAgICBkb20ub24oJ2FuaW1hdGlvbmVuZCcsIGZpcmVDYWxsQmFjayk7XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn1cblxuZnVuY3Rpb24gd2lkdGgoKSB7XG4gIGNvbnN0IHdpbmRvdyA9IGdldFdpbmRvdygpO1xuXG4gIGlmICh0aGlzWzBdID09PSB3aW5kb3cpIHtcbiAgICByZXR1cm4gd2luZG93LmlubmVyV2lkdGg7XG4gIH1cblxuICBpZiAodGhpcy5sZW5ndGggPiAwKSB7XG4gICAgcmV0dXJuIHBhcnNlRmxvYXQodGhpcy5jc3MoJ3dpZHRoJykpO1xuICB9XG5cbiAgcmV0dXJuIG51bGw7XG59XG5cbmZ1bmN0aW9uIG91dGVyV2lkdGgoaW5jbHVkZU1hcmdpbnMpIHtcbiAgaWYgKHRoaXMubGVuZ3RoID4gMCkge1xuICAgIGlmIChpbmNsdWRlTWFyZ2lucykge1xuICAgICAgY29uc3Qgc3R5bGVzID0gdGhpcy5zdHlsZXMoKTtcbiAgICAgIHJldHVybiB0aGlzWzBdLm9mZnNldFdpZHRoICsgcGFyc2VGbG9hdChzdHlsZXMuZ2V0UHJvcGVydHlWYWx1ZSgnbWFyZ2luLXJpZ2h0JykpICsgcGFyc2VGbG9hdChzdHlsZXMuZ2V0UHJvcGVydHlWYWx1ZSgnbWFyZ2luLWxlZnQnKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXNbMF0ub2Zmc2V0V2lkdGg7XG4gIH1cblxuICByZXR1cm4gbnVsbDtcbn1cblxuZnVuY3Rpb24gaGVpZ2h0KCkge1xuICBjb25zdCB3aW5kb3cgPSBnZXRXaW5kb3coKTtcblxuICBpZiAodGhpc1swXSA9PT0gd2luZG93KSB7XG4gICAgcmV0dXJuIHdpbmRvdy5pbm5lckhlaWdodDtcbiAgfVxuXG4gIGlmICh0aGlzLmxlbmd0aCA+IDApIHtcbiAgICByZXR1cm4gcGFyc2VGbG9hdCh0aGlzLmNzcygnaGVpZ2h0JykpO1xuICB9XG5cbiAgcmV0dXJuIG51bGw7XG59XG5cbmZ1bmN0aW9uIG91dGVySGVpZ2h0KGluY2x1ZGVNYXJnaW5zKSB7XG4gIGlmICh0aGlzLmxlbmd0aCA+IDApIHtcbiAgICBpZiAoaW5jbHVkZU1hcmdpbnMpIHtcbiAgICAgIGNvbnN0IHN0eWxlcyA9IHRoaXMuc3R5bGVzKCk7XG4gICAgICByZXR1cm4gdGhpc1swXS5vZmZzZXRIZWlnaHQgKyBwYXJzZUZsb2F0KHN0eWxlcy5nZXRQcm9wZXJ0eVZhbHVlKCdtYXJnaW4tdG9wJykpICsgcGFyc2VGbG9hdChzdHlsZXMuZ2V0UHJvcGVydHlWYWx1ZSgnbWFyZ2luLWJvdHRvbScpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpc1swXS5vZmZzZXRIZWlnaHQ7XG4gIH1cblxuICByZXR1cm4gbnVsbDtcbn1cblxuZnVuY3Rpb24gb2Zmc2V0KCkge1xuICBpZiAodGhpcy5sZW5ndGggPiAwKSB7XG4gICAgY29uc3Qgd2luZG93ID0gZ2V0V2luZG93KCk7XG4gICAgY29uc3QgZG9jdW1lbnQgPSBnZXREb2N1bWVudCgpO1xuICAgIGNvbnN0IGVsID0gdGhpc1swXTtcbiAgICBjb25zdCBib3ggPSBlbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICBjb25zdCBib2R5ID0gZG9jdW1lbnQuYm9keTtcbiAgICBjb25zdCBjbGllbnRUb3AgPSBlbC5jbGllbnRUb3AgfHwgYm9keS5jbGllbnRUb3AgfHwgMDtcbiAgICBjb25zdCBjbGllbnRMZWZ0ID0gZWwuY2xpZW50TGVmdCB8fCBib2R5LmNsaWVudExlZnQgfHwgMDtcbiAgICBjb25zdCBzY3JvbGxUb3AgPSBlbCA9PT0gd2luZG93ID8gd2luZG93LnNjcm9sbFkgOiBlbC5zY3JvbGxUb3A7XG4gICAgY29uc3Qgc2Nyb2xsTGVmdCA9IGVsID09PSB3aW5kb3cgPyB3aW5kb3cuc2Nyb2xsWCA6IGVsLnNjcm9sbExlZnQ7XG4gICAgcmV0dXJuIHtcbiAgICAgIHRvcDogYm94LnRvcCArIHNjcm9sbFRvcCAtIGNsaWVudFRvcCxcbiAgICAgIGxlZnQ6IGJveC5sZWZ0ICsgc2Nyb2xsTGVmdCAtIGNsaWVudExlZnRcbiAgICB9O1xuICB9XG5cbiAgcmV0dXJuIG51bGw7XG59XG5cbmZ1bmN0aW9uIGhpZGUoKSB7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoaXNbaV0uc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufVxuXG5mdW5jdGlvbiBzaG93KCkge1xuICBjb25zdCB3aW5kb3cgPSBnZXRXaW5kb3coKTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICBjb25zdCBlbCA9IHRoaXNbaV07XG5cbiAgICBpZiAoZWwuc3R5bGUuZGlzcGxheSA9PT0gJ25vbmUnKSB7XG4gICAgICBlbC5zdHlsZS5kaXNwbGF5ID0gJyc7XG4gICAgfVxuXG4gICAgaWYgKHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGVsLCBudWxsKS5nZXRQcm9wZXJ0eVZhbHVlKCdkaXNwbGF5JykgPT09ICdub25lJykge1xuICAgICAgLy8gU3RpbGwgbm90IHZpc2libGVcbiAgICAgIGVsLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufVxuXG5mdW5jdGlvbiBzdHlsZXMoKSB7XG4gIGNvbnN0IHdpbmRvdyA9IGdldFdpbmRvdygpO1xuICBpZiAodGhpc1swXSkgcmV0dXJuIHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKHRoaXNbMF0sIG51bGwpO1xuICByZXR1cm4ge307XG59XG5cbmZ1bmN0aW9uIGNzcyhwcm9wcywgdmFsdWUpIHtcbiAgY29uc3Qgd2luZG93ID0gZ2V0V2luZG93KCk7XG4gIGxldCBpO1xuXG4gIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAxKSB7XG4gICAgaWYgKHR5cGVvZiBwcm9wcyA9PT0gJ3N0cmluZycpIHtcbiAgICAgIC8vIC5jc3MoJ3dpZHRoJylcbiAgICAgIGlmICh0aGlzWzBdKSByZXR1cm4gd2luZG93LmdldENvbXB1dGVkU3R5bGUodGhpc1swXSwgbnVsbCkuZ2V0UHJvcGVydHlWYWx1ZShwcm9wcyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIC5jc3MoeyB3aWR0aDogJzEwMHB4JyB9KVxuICAgICAgZm9yIChpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgZm9yIChjb25zdCBwcm9wIGluIHByb3BzKSB7XG4gICAgICAgICAgdGhpc1tpXS5zdHlsZVtwcm9wXSA9IHByb3BzW3Byb3BdO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgfVxuXG4gIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAyICYmIHR5cGVvZiBwcm9wcyA9PT0gJ3N0cmluZycpIHtcbiAgICAvLyAuY3NzKCd3aWR0aCcsICcxMDBweCcpXG4gICAgZm9yIChpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgIHRoaXNbaV0uc3R5bGVbcHJvcHNdID0gdmFsdWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn1cblxuZnVuY3Rpb24gZWFjaChjYWxsYmFjaykge1xuICBpZiAoIWNhbGxiYWNrKSByZXR1cm4gdGhpcztcbiAgdGhpcy5mb3JFYWNoKChlbCwgaW5kZXgpID0+IHtcbiAgICBjYWxsYmFjay5hcHBseShlbCwgW2VsLCBpbmRleF0pO1xuICB9KTtcbiAgcmV0dXJuIHRoaXM7XG59XG5cbmZ1bmN0aW9uIGZpbHRlcihjYWxsYmFjaykge1xuICBjb25zdCByZXN1bHQgPSBhcnJheUZpbHRlcih0aGlzLCBjYWxsYmFjayk7XG4gIHJldHVybiAkKHJlc3VsdCk7XG59XG5cbmZ1bmN0aW9uIGh0bWwoaHRtbCkge1xuICBpZiAodHlwZW9mIGh0bWwgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgcmV0dXJuIHRoaXNbMF0gPyB0aGlzWzBdLmlubmVySFRNTCA6IG51bGw7XG4gIH1cblxuICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGlzW2ldLmlubmVySFRNTCA9IGh0bWw7XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn1cblxuZnVuY3Rpb24gdGV4dCh0ZXh0KSB7XG4gIGlmICh0eXBlb2YgdGV4dCA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICByZXR1cm4gdGhpc1swXSA/IHRoaXNbMF0udGV4dENvbnRlbnQudHJpbSgpIDogbnVsbDtcbiAgfVxuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoaXNbaV0udGV4dENvbnRlbnQgPSB0ZXh0O1xuICB9XG5cbiAgcmV0dXJuIHRoaXM7XG59XG5cbmZ1bmN0aW9uIGlzKHNlbGVjdG9yKSB7XG4gIGNvbnN0IHdpbmRvdyA9IGdldFdpbmRvdygpO1xuICBjb25zdCBkb2N1bWVudCA9IGdldERvY3VtZW50KCk7XG4gIGNvbnN0IGVsID0gdGhpc1swXTtcbiAgbGV0IGNvbXBhcmVXaXRoO1xuICBsZXQgaTtcbiAgaWYgKCFlbCB8fCB0eXBlb2Ygc2VsZWN0b3IgPT09ICd1bmRlZmluZWQnKSByZXR1cm4gZmFsc2U7XG5cbiAgaWYgKHR5cGVvZiBzZWxlY3RvciA9PT0gJ3N0cmluZycpIHtcbiAgICBpZiAoZWwubWF0Y2hlcykgcmV0dXJuIGVsLm1hdGNoZXMoc2VsZWN0b3IpO1xuICAgIGlmIChlbC53ZWJraXRNYXRjaGVzU2VsZWN0b3IpIHJldHVybiBlbC53ZWJraXRNYXRjaGVzU2VsZWN0b3Ioc2VsZWN0b3IpO1xuICAgIGlmIChlbC5tc01hdGNoZXNTZWxlY3RvcikgcmV0dXJuIGVsLm1zTWF0Y2hlc1NlbGVjdG9yKHNlbGVjdG9yKTtcbiAgICBjb21wYXJlV2l0aCA9ICQoc2VsZWN0b3IpO1xuXG4gICAgZm9yIChpID0gMDsgaSA8IGNvbXBhcmVXaXRoLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICBpZiAoY29tcGFyZVdpdGhbaV0gPT09IGVsKSByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBpZiAoc2VsZWN0b3IgPT09IGRvY3VtZW50KSB7XG4gICAgcmV0dXJuIGVsID09PSBkb2N1bWVudDtcbiAgfVxuXG4gIGlmIChzZWxlY3RvciA9PT0gd2luZG93KSB7XG4gICAgcmV0dXJuIGVsID09PSB3aW5kb3c7XG4gIH1cblxuICBpZiAoc2VsZWN0b3Iubm9kZVR5cGUgfHwgc2VsZWN0b3IgaW5zdGFuY2VvZiBEb203KSB7XG4gICAgY29tcGFyZVdpdGggPSBzZWxlY3Rvci5ub2RlVHlwZSA/IFtzZWxlY3Rvcl0gOiBzZWxlY3RvcjtcblxuICAgIGZvciAoaSA9IDA7IGkgPCBjb21wYXJlV2l0aC5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgaWYgKGNvbXBhcmVXaXRoW2ldID09PSBlbCkgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgcmV0dXJuIGZhbHNlO1xufVxuXG5mdW5jdGlvbiBpbmRleCgpIHtcbiAgbGV0IGNoaWxkID0gdGhpc1swXTtcbiAgbGV0IGk7XG5cbiAgaWYgKGNoaWxkKSB7XG4gICAgaSA9IDA7IC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuXG4gICAgd2hpbGUgKChjaGlsZCA9IGNoaWxkLnByZXZpb3VzU2libGluZykgIT09IG51bGwpIHtcbiAgICAgIGlmIChjaGlsZC5ub2RlVHlwZSA9PT0gMSkgaSArPSAxO1xuICAgIH1cblxuICAgIHJldHVybiBpO1xuICB9XG5cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuZnVuY3Rpb24gZXEoaW5kZXgpIHtcbiAgaWYgKHR5cGVvZiBpbmRleCA9PT0gJ3VuZGVmaW5lZCcpIHJldHVybiB0aGlzO1xuICBjb25zdCBsZW5ndGggPSB0aGlzLmxlbmd0aDtcblxuICBpZiAoaW5kZXggPiBsZW5ndGggLSAxKSB7XG4gICAgcmV0dXJuICQoW10pO1xuICB9XG5cbiAgaWYgKGluZGV4IDwgMCkge1xuICAgIGNvbnN0IHJldHVybkluZGV4ID0gbGVuZ3RoICsgaW5kZXg7XG4gICAgaWYgKHJldHVybkluZGV4IDwgMCkgcmV0dXJuICQoW10pO1xuICAgIHJldHVybiAkKFt0aGlzW3JldHVybkluZGV4XV0pO1xuICB9XG5cbiAgcmV0dXJuICQoW3RoaXNbaW5kZXhdXSk7XG59XG5cbmZ1bmN0aW9uIGFwcGVuZCguLi5lbHMpIHtcbiAgbGV0IG5ld0NoaWxkO1xuICBjb25zdCBkb2N1bWVudCA9IGdldERvY3VtZW50KCk7XG5cbiAgZm9yIChsZXQgayA9IDA7IGsgPCBlbHMubGVuZ3RoOyBrICs9IDEpIHtcbiAgICBuZXdDaGlsZCA9IGVsc1trXTtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgaWYgKHR5cGVvZiBuZXdDaGlsZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgY29uc3QgdGVtcERpdiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgICAgICB0ZW1wRGl2LmlubmVySFRNTCA9IG5ld0NoaWxkO1xuXG4gICAgICAgIHdoaWxlICh0ZW1wRGl2LmZpcnN0Q2hpbGQpIHtcbiAgICAgICAgICB0aGlzW2ldLmFwcGVuZENoaWxkKHRlbXBEaXYuZmlyc3RDaGlsZCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAobmV3Q2hpbGQgaW5zdGFuY2VvZiBEb203KSB7XG4gICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgbmV3Q2hpbGQubGVuZ3RoOyBqICs9IDEpIHtcbiAgICAgICAgICB0aGlzW2ldLmFwcGVuZENoaWxkKG5ld0NoaWxkW2pdKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpc1tpXS5hcHBlbmRDaGlsZChuZXdDaGlsZCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXM7XG59XG5cbmZ1bmN0aW9uIGFwcGVuZFRvKHBhcmVudCkge1xuICAkKHBhcmVudCkuYXBwZW5kKHRoaXMpO1xuICByZXR1cm4gdGhpcztcbn1cblxuZnVuY3Rpb24gcHJlcGVuZChuZXdDaGlsZCkge1xuICBjb25zdCBkb2N1bWVudCA9IGdldERvY3VtZW50KCk7XG4gIGxldCBpO1xuICBsZXQgajtcblxuICBmb3IgKGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgIGlmICh0eXBlb2YgbmV3Q2hpbGQgPT09ICdzdHJpbmcnKSB7XG4gICAgICBjb25zdCB0ZW1wRGl2ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgICB0ZW1wRGl2LmlubmVySFRNTCA9IG5ld0NoaWxkO1xuXG4gICAgICBmb3IgKGogPSB0ZW1wRGl2LmNoaWxkTm9kZXMubGVuZ3RoIC0gMTsgaiA+PSAwOyBqIC09IDEpIHtcbiAgICAgICAgdGhpc1tpXS5pbnNlcnRCZWZvcmUodGVtcERpdi5jaGlsZE5vZGVzW2pdLCB0aGlzW2ldLmNoaWxkTm9kZXNbMF0pO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAobmV3Q2hpbGQgaW5zdGFuY2VvZiBEb203KSB7XG4gICAgICBmb3IgKGogPSAwOyBqIDwgbmV3Q2hpbGQubGVuZ3RoOyBqICs9IDEpIHtcbiAgICAgICAgdGhpc1tpXS5pbnNlcnRCZWZvcmUobmV3Q2hpbGRbal0sIHRoaXNbaV0uY2hpbGROb2Rlc1swXSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXNbaV0uaW5zZXJ0QmVmb3JlKG5ld0NoaWxkLCB0aGlzW2ldLmNoaWxkTm9kZXNbMF0pO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufVxuXG5mdW5jdGlvbiBwcmVwZW5kVG8ocGFyZW50KSB7XG4gICQocGFyZW50KS5wcmVwZW5kKHRoaXMpO1xuICByZXR1cm4gdGhpcztcbn1cblxuZnVuY3Rpb24gaW5zZXJ0QmVmb3JlKHNlbGVjdG9yKSB7XG4gIGNvbnN0IGJlZm9yZSA9ICQoc2VsZWN0b3IpO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgIGlmIChiZWZvcmUubGVuZ3RoID09PSAxKSB7XG4gICAgICBiZWZvcmVbMF0ucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUodGhpc1tpXSwgYmVmb3JlWzBdKTtcbiAgICB9IGVsc2UgaWYgKGJlZm9yZS5sZW5ndGggPiAxKSB7XG4gICAgICBmb3IgKGxldCBqID0gMDsgaiA8IGJlZm9yZS5sZW5ndGg7IGogKz0gMSkge1xuICAgICAgICBiZWZvcmVbal0ucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUodGhpc1tpXS5jbG9uZU5vZGUodHJ1ZSksIGJlZm9yZVtqXSk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIGluc2VydEFmdGVyKHNlbGVjdG9yKSB7XG4gIGNvbnN0IGFmdGVyID0gJChzZWxlY3Rvcik7XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgaWYgKGFmdGVyLmxlbmd0aCA9PT0gMSkge1xuICAgICAgYWZ0ZXJbMF0ucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUodGhpc1tpXSwgYWZ0ZXJbMF0ubmV4dFNpYmxpbmcpO1xuICAgIH0gZWxzZSBpZiAoYWZ0ZXIubGVuZ3RoID4gMSkge1xuICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBhZnRlci5sZW5ndGg7IGogKz0gMSkge1xuICAgICAgICBhZnRlcltqXS5wYXJlbnROb2RlLmluc2VydEJlZm9yZSh0aGlzW2ldLmNsb25lTm9kZSh0cnVlKSwgYWZ0ZXJbal0ubmV4dFNpYmxpbmcpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG5mdW5jdGlvbiBuZXh0KHNlbGVjdG9yKSB7XG4gIGlmICh0aGlzLmxlbmd0aCA+IDApIHtcbiAgICBpZiAoc2VsZWN0b3IpIHtcbiAgICAgIGlmICh0aGlzWzBdLm5leHRFbGVtZW50U2libGluZyAmJiAkKHRoaXNbMF0ubmV4dEVsZW1lbnRTaWJsaW5nKS5pcyhzZWxlY3RvcikpIHtcbiAgICAgICAgcmV0dXJuICQoW3RoaXNbMF0ubmV4dEVsZW1lbnRTaWJsaW5nXSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiAkKFtdKTtcbiAgICB9XG5cbiAgICBpZiAodGhpc1swXS5uZXh0RWxlbWVudFNpYmxpbmcpIHJldHVybiAkKFt0aGlzWzBdLm5leHRFbGVtZW50U2libGluZ10pO1xuICAgIHJldHVybiAkKFtdKTtcbiAgfVxuXG4gIHJldHVybiAkKFtdKTtcbn1cblxuZnVuY3Rpb24gbmV4dEFsbChzZWxlY3Rvcikge1xuICBjb25zdCBuZXh0RWxzID0gW107XG4gIGxldCBlbCA9IHRoaXNbMF07XG4gIGlmICghZWwpIHJldHVybiAkKFtdKTtcblxuICB3aGlsZSAoZWwubmV4dEVsZW1lbnRTaWJsaW5nKSB7XG4gICAgY29uc3QgbmV4dCA9IGVsLm5leHRFbGVtZW50U2libGluZzsgLy8gZXNsaW50LWRpc2FibGUtbGluZVxuXG4gICAgaWYgKHNlbGVjdG9yKSB7XG4gICAgICBpZiAoJChuZXh0KS5pcyhzZWxlY3RvcikpIG5leHRFbHMucHVzaChuZXh0KTtcbiAgICB9IGVsc2UgbmV4dEVscy5wdXNoKG5leHQpO1xuXG4gICAgZWwgPSBuZXh0O1xuICB9XG5cbiAgcmV0dXJuICQobmV4dEVscyk7XG59XG5cbmZ1bmN0aW9uIHByZXYoc2VsZWN0b3IpIHtcbiAgaWYgKHRoaXMubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IGVsID0gdGhpc1swXTtcblxuICAgIGlmIChzZWxlY3Rvcikge1xuICAgICAgaWYgKGVsLnByZXZpb3VzRWxlbWVudFNpYmxpbmcgJiYgJChlbC5wcmV2aW91c0VsZW1lbnRTaWJsaW5nKS5pcyhzZWxlY3RvcikpIHtcbiAgICAgICAgcmV0dXJuICQoW2VsLnByZXZpb3VzRWxlbWVudFNpYmxpbmddKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuICQoW10pO1xuICAgIH1cblxuICAgIGlmIChlbC5wcmV2aW91c0VsZW1lbnRTaWJsaW5nKSByZXR1cm4gJChbZWwucHJldmlvdXNFbGVtZW50U2libGluZ10pO1xuICAgIHJldHVybiAkKFtdKTtcbiAgfVxuXG4gIHJldHVybiAkKFtdKTtcbn1cblxuZnVuY3Rpb24gcHJldkFsbChzZWxlY3Rvcikge1xuICBjb25zdCBwcmV2RWxzID0gW107XG4gIGxldCBlbCA9IHRoaXNbMF07XG4gIGlmICghZWwpIHJldHVybiAkKFtdKTtcblxuICB3aGlsZSAoZWwucHJldmlvdXNFbGVtZW50U2libGluZykge1xuICAgIGNvbnN0IHByZXYgPSBlbC5wcmV2aW91c0VsZW1lbnRTaWJsaW5nOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lXG5cbiAgICBpZiAoc2VsZWN0b3IpIHtcbiAgICAgIGlmICgkKHByZXYpLmlzKHNlbGVjdG9yKSkgcHJldkVscy5wdXNoKHByZXYpO1xuICAgIH0gZWxzZSBwcmV2RWxzLnB1c2gocHJldik7XG5cbiAgICBlbCA9IHByZXY7XG4gIH1cblxuICByZXR1cm4gJChwcmV2RWxzKTtcbn1cblxuZnVuY3Rpb24gc2libGluZ3Moc2VsZWN0b3IpIHtcbiAgcmV0dXJuIHRoaXMubmV4dEFsbChzZWxlY3RvcikuYWRkKHRoaXMucHJldkFsbChzZWxlY3RvcikpO1xufVxuXG5mdW5jdGlvbiBwYXJlbnQoc2VsZWN0b3IpIHtcbiAgY29uc3QgcGFyZW50cyA9IFtdOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lXG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgaWYgKHRoaXNbaV0ucGFyZW50Tm9kZSAhPT0gbnVsbCkge1xuICAgICAgaWYgKHNlbGVjdG9yKSB7XG4gICAgICAgIGlmICgkKHRoaXNbaV0ucGFyZW50Tm9kZSkuaXMoc2VsZWN0b3IpKSBwYXJlbnRzLnB1c2godGhpc1tpXS5wYXJlbnROb2RlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBhcmVudHMucHVzaCh0aGlzW2ldLnBhcmVudE5vZGUpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiAkKHBhcmVudHMpO1xufVxuXG5mdW5jdGlvbiBwYXJlbnRzKHNlbGVjdG9yKSB7XG4gIGNvbnN0IHBhcmVudHMgPSBbXTsgLy8gZXNsaW50LWRpc2FibGUtbGluZVxuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgIGxldCBwYXJlbnQgPSB0aGlzW2ldLnBhcmVudE5vZGU7IC8vIGVzbGludC1kaXNhYmxlLWxpbmVcblxuICAgIHdoaWxlIChwYXJlbnQpIHtcbiAgICAgIGlmIChzZWxlY3Rvcikge1xuICAgICAgICBpZiAoJChwYXJlbnQpLmlzKHNlbGVjdG9yKSkgcGFyZW50cy5wdXNoKHBhcmVudCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwYXJlbnRzLnB1c2gocGFyZW50KTtcbiAgICAgIH1cblxuICAgICAgcGFyZW50ID0gcGFyZW50LnBhcmVudE5vZGU7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuICQocGFyZW50cyk7XG59XG5cbmZ1bmN0aW9uIGNsb3Nlc3Qoc2VsZWN0b3IpIHtcbiAgbGV0IGNsb3Nlc3QgPSB0aGlzOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lXG5cbiAgaWYgKHR5cGVvZiBzZWxlY3RvciA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICByZXR1cm4gJChbXSk7XG4gIH1cblxuICBpZiAoIWNsb3Nlc3QuaXMoc2VsZWN0b3IpKSB7XG4gICAgY2xvc2VzdCA9IGNsb3Nlc3QucGFyZW50cyhzZWxlY3RvcikuZXEoMCk7XG4gIH1cblxuICByZXR1cm4gY2xvc2VzdDtcbn1cblxuZnVuY3Rpb24gZmluZChzZWxlY3Rvcikge1xuICBjb25zdCBmb3VuZEVsZW1lbnRzID0gW107XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgY29uc3QgZm91bmQgPSB0aGlzW2ldLnF1ZXJ5U2VsZWN0b3JBbGwoc2VsZWN0b3IpO1xuXG4gICAgZm9yIChsZXQgaiA9IDA7IGogPCBmb3VuZC5sZW5ndGg7IGogKz0gMSkge1xuICAgICAgZm91bmRFbGVtZW50cy5wdXNoKGZvdW5kW2pdKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gJChmb3VuZEVsZW1lbnRzKTtcbn1cblxuZnVuY3Rpb24gY2hpbGRyZW4oc2VsZWN0b3IpIHtcbiAgY29uc3QgY2hpbGRyZW4gPSBbXTsgLy8gZXNsaW50LWRpc2FibGUtbGluZVxuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgIGNvbnN0IGNoaWxkTm9kZXMgPSB0aGlzW2ldLmNoaWxkcmVuO1xuXG4gICAgZm9yIChsZXQgaiA9IDA7IGogPCBjaGlsZE5vZGVzLmxlbmd0aDsgaiArPSAxKSB7XG4gICAgICBpZiAoIXNlbGVjdG9yIHx8ICQoY2hpbGROb2Rlc1tqXSkuaXMoc2VsZWN0b3IpKSB7XG4gICAgICAgIGNoaWxkcmVuLnB1c2goY2hpbGROb2Rlc1tqXSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuICQoY2hpbGRyZW4pO1xufVxuXG5mdW5jdGlvbiByZW1vdmUoKSB7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgIGlmICh0aGlzW2ldLnBhcmVudE5vZGUpIHRoaXNbaV0ucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh0aGlzW2ldKTtcbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufVxuXG5mdW5jdGlvbiBkZXRhY2goKSB7XG4gIHJldHVybiB0aGlzLnJlbW92ZSgpO1xufVxuXG5mdW5jdGlvbiBhZGQoLi4uZWxzKSB7XG4gIGNvbnN0IGRvbSA9IHRoaXM7XG4gIGxldCBpO1xuICBsZXQgajtcblxuICBmb3IgKGkgPSAwOyBpIDwgZWxzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgY29uc3QgdG9BZGQgPSAkKGVsc1tpXSk7XG5cbiAgICBmb3IgKGogPSAwOyBqIDwgdG9BZGQubGVuZ3RoOyBqICs9IDEpIHtcbiAgICAgIGRvbS5wdXNoKHRvQWRkW2pdKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gZG9tO1xufVxuXG5mdW5jdGlvbiBlbXB0eSgpIHtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgY29uc3QgZWwgPSB0aGlzW2ldO1xuXG4gICAgaWYgKGVsLm5vZGVUeXBlID09PSAxKSB7XG4gICAgICBmb3IgKGxldCBqID0gMDsgaiA8IGVsLmNoaWxkTm9kZXMubGVuZ3RoOyBqICs9IDEpIHtcbiAgICAgICAgaWYgKGVsLmNoaWxkTm9kZXNbal0ucGFyZW50Tm9kZSkge1xuICAgICAgICAgIGVsLmNoaWxkTm9kZXNbal0ucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChlbC5jaGlsZE5vZGVzW2pdKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBlbC50ZXh0Q29udGVudCA9ICcnO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufVxuXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmVcblxuZnVuY3Rpb24gc2Nyb2xsVG8oLi4uYXJncykge1xuICBjb25zdCB3aW5kb3cgPSBnZXRXaW5kb3coKTtcbiAgbGV0IFtsZWZ0LCB0b3AsIGR1cmF0aW9uLCBlYXNpbmcsIGNhbGxiYWNrXSA9IGFyZ3M7XG5cbiAgaWYgKGFyZ3MubGVuZ3RoID09PSA0ICYmIHR5cGVvZiBlYXNpbmcgPT09ICdmdW5jdGlvbicpIHtcbiAgICBjYWxsYmFjayA9IGVhc2luZztcbiAgICBbbGVmdCwgdG9wLCBkdXJhdGlvbiwgY2FsbGJhY2ssIGVhc2luZ10gPSBhcmdzO1xuICB9XG5cbiAgaWYgKHR5cGVvZiBlYXNpbmcgPT09ICd1bmRlZmluZWQnKSBlYXNpbmcgPSAnc3dpbmcnO1xuICByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uIGFuaW1hdGUoKSB7XG4gICAgY29uc3QgZWwgPSB0aGlzO1xuICAgIGxldCBjdXJyZW50VG9wO1xuICAgIGxldCBjdXJyZW50TGVmdDtcbiAgICBsZXQgbWF4VG9wO1xuICAgIGxldCBtYXhMZWZ0O1xuICAgIGxldCBuZXdUb3A7XG4gICAgbGV0IG5ld0xlZnQ7XG4gICAgbGV0IHNjcm9sbFRvcDsgLy8gZXNsaW50LWRpc2FibGUtbGluZVxuXG4gICAgbGV0IHNjcm9sbExlZnQ7IC8vIGVzbGludC1kaXNhYmxlLWxpbmVcblxuICAgIGxldCBhbmltYXRlVG9wID0gdG9wID4gMCB8fCB0b3AgPT09IDA7XG4gICAgbGV0IGFuaW1hdGVMZWZ0ID0gbGVmdCA+IDAgfHwgbGVmdCA9PT0gMDtcblxuICAgIGlmICh0eXBlb2YgZWFzaW5nID09PSAndW5kZWZpbmVkJykge1xuICAgICAgZWFzaW5nID0gJ3N3aW5nJztcbiAgICB9XG5cbiAgICBpZiAoYW5pbWF0ZVRvcCkge1xuICAgICAgY3VycmVudFRvcCA9IGVsLnNjcm9sbFRvcDtcblxuICAgICAgaWYgKCFkdXJhdGlvbikge1xuICAgICAgICBlbC5zY3JvbGxUb3AgPSB0b3A7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGFuaW1hdGVMZWZ0KSB7XG4gICAgICBjdXJyZW50TGVmdCA9IGVsLnNjcm9sbExlZnQ7XG5cbiAgICAgIGlmICghZHVyYXRpb24pIHtcbiAgICAgICAgZWwuc2Nyb2xsTGVmdCA9IGxlZnQ7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCFkdXJhdGlvbikgcmV0dXJuO1xuXG4gICAgaWYgKGFuaW1hdGVUb3ApIHtcbiAgICAgIG1heFRvcCA9IGVsLnNjcm9sbEhlaWdodCAtIGVsLm9mZnNldEhlaWdodDtcbiAgICAgIG5ld1RvcCA9IE1hdGgubWF4KE1hdGgubWluKHRvcCwgbWF4VG9wKSwgMCk7XG4gICAgfVxuXG4gICAgaWYgKGFuaW1hdGVMZWZ0KSB7XG4gICAgICBtYXhMZWZ0ID0gZWwuc2Nyb2xsV2lkdGggLSBlbC5vZmZzZXRXaWR0aDtcbiAgICAgIG5ld0xlZnQgPSBNYXRoLm1heChNYXRoLm1pbihsZWZ0LCBtYXhMZWZ0KSwgMCk7XG4gICAgfVxuXG4gICAgbGV0IHN0YXJ0VGltZSA9IG51bGw7XG4gICAgaWYgKGFuaW1hdGVUb3AgJiYgbmV3VG9wID09PSBjdXJyZW50VG9wKSBhbmltYXRlVG9wID0gZmFsc2U7XG4gICAgaWYgKGFuaW1hdGVMZWZ0ICYmIG5ld0xlZnQgPT09IGN1cnJlbnRMZWZ0KSBhbmltYXRlTGVmdCA9IGZhbHNlO1xuXG4gICAgZnVuY3Rpb24gcmVuZGVyKHRpbWUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKSkge1xuICAgICAgaWYgKHN0YXJ0VGltZSA9PT0gbnVsbCkge1xuICAgICAgICBzdGFydFRpbWUgPSB0aW1lO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBwcm9ncmVzcyA9IE1hdGgubWF4KE1hdGgubWluKCh0aW1lIC0gc3RhcnRUaW1lKSAvIGR1cmF0aW9uLCAxKSwgMCk7XG4gICAgICBjb25zdCBlYXNlUHJvZ3Jlc3MgPSBlYXNpbmcgPT09ICdsaW5lYXInID8gcHJvZ3Jlc3MgOiAwLjUgLSBNYXRoLmNvcyhwcm9ncmVzcyAqIE1hdGguUEkpIC8gMjtcbiAgICAgIGxldCBkb25lO1xuICAgICAgaWYgKGFuaW1hdGVUb3ApIHNjcm9sbFRvcCA9IGN1cnJlbnRUb3AgKyBlYXNlUHJvZ3Jlc3MgKiAobmV3VG9wIC0gY3VycmVudFRvcCk7XG4gICAgICBpZiAoYW5pbWF0ZUxlZnQpIHNjcm9sbExlZnQgPSBjdXJyZW50TGVmdCArIGVhc2VQcm9ncmVzcyAqIChuZXdMZWZ0IC0gY3VycmVudExlZnQpO1xuXG4gICAgICBpZiAoYW5pbWF0ZVRvcCAmJiBuZXdUb3AgPiBjdXJyZW50VG9wICYmIHNjcm9sbFRvcCA+PSBuZXdUb3ApIHtcbiAgICAgICAgZWwuc2Nyb2xsVG9wID0gbmV3VG9wO1xuICAgICAgICBkb25lID0gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKGFuaW1hdGVUb3AgJiYgbmV3VG9wIDwgY3VycmVudFRvcCAmJiBzY3JvbGxUb3AgPD0gbmV3VG9wKSB7XG4gICAgICAgIGVsLnNjcm9sbFRvcCA9IG5ld1RvcDtcbiAgICAgICAgZG9uZSA9IHRydWU7XG4gICAgICB9XG5cbiAgICAgIGlmIChhbmltYXRlTGVmdCAmJiBuZXdMZWZ0ID4gY3VycmVudExlZnQgJiYgc2Nyb2xsTGVmdCA+PSBuZXdMZWZ0KSB7XG4gICAgICAgIGVsLnNjcm9sbExlZnQgPSBuZXdMZWZ0O1xuICAgICAgICBkb25lID0gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKGFuaW1hdGVMZWZ0ICYmIG5ld0xlZnQgPCBjdXJyZW50TGVmdCAmJiBzY3JvbGxMZWZ0IDw9IG5ld0xlZnQpIHtcbiAgICAgICAgZWwuc2Nyb2xsTGVmdCA9IG5ld0xlZnQ7XG4gICAgICAgIGRvbmUgPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICBpZiAoZG9uZSkge1xuICAgICAgICBpZiAoY2FsbGJhY2spIGNhbGxiYWNrKCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGFuaW1hdGVUb3ApIGVsLnNjcm9sbFRvcCA9IHNjcm9sbFRvcDtcbiAgICAgIGlmIChhbmltYXRlTGVmdCkgZWwuc2Nyb2xsTGVmdCA9IHNjcm9sbExlZnQ7XG4gICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKHJlbmRlcik7XG4gICAgfVxuXG4gICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZShyZW5kZXIpO1xuICB9KTtcbn0gLy8gc2Nyb2xsVG9wKHRvcCwgZHVyYXRpb24sIGVhc2luZywgY2FsbGJhY2spIHtcblxuXG5mdW5jdGlvbiBzY3JvbGxUb3AoLi4uYXJncykge1xuICBsZXQgW3RvcCwgZHVyYXRpb24sIGVhc2luZywgY2FsbGJhY2tdID0gYXJncztcblxuICBpZiAoYXJncy5sZW5ndGggPT09IDMgJiYgdHlwZW9mIGVhc2luZyA9PT0gJ2Z1bmN0aW9uJykge1xuICAgIFt0b3AsIGR1cmF0aW9uLCBjYWxsYmFjaywgZWFzaW5nXSA9IGFyZ3M7XG4gIH1cblxuICBjb25zdCBkb20gPSB0aGlzO1xuXG4gIGlmICh0eXBlb2YgdG9wID09PSAndW5kZWZpbmVkJykge1xuICAgIGlmIChkb20ubGVuZ3RoID4gMCkgcmV0dXJuIGRvbVswXS5zY3JvbGxUb3A7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICByZXR1cm4gZG9tLnNjcm9sbFRvKHVuZGVmaW5lZCwgdG9wLCBkdXJhdGlvbiwgZWFzaW5nLCBjYWxsYmFjayk7XG59XG5cbmZ1bmN0aW9uIHNjcm9sbExlZnQoLi4uYXJncykge1xuICBsZXQgW2xlZnQsIGR1cmF0aW9uLCBlYXNpbmcsIGNhbGxiYWNrXSA9IGFyZ3M7XG5cbiAgaWYgKGFyZ3MubGVuZ3RoID09PSAzICYmIHR5cGVvZiBlYXNpbmcgPT09ICdmdW5jdGlvbicpIHtcbiAgICBbbGVmdCwgZHVyYXRpb24sIGNhbGxiYWNrLCBlYXNpbmddID0gYXJncztcbiAgfVxuXG4gIGNvbnN0IGRvbSA9IHRoaXM7XG5cbiAgaWYgKHR5cGVvZiBsZWZ0ID09PSAndW5kZWZpbmVkJykge1xuICAgIGlmIChkb20ubGVuZ3RoID4gMCkgcmV0dXJuIGRvbVswXS5zY3JvbGxMZWZ0O1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgcmV0dXJuIGRvbS5zY3JvbGxUbyhsZWZ0LCB1bmRlZmluZWQsIGR1cmF0aW9uLCBlYXNpbmcsIGNhbGxiYWNrKTtcbn1cblxuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG5cbmZ1bmN0aW9uIGFuaW1hdGUoaW5pdGlhbFByb3BzLCBpbml0aWFsUGFyYW1zKSB7XG4gIGNvbnN0IHdpbmRvdyA9IGdldFdpbmRvdygpO1xuICBjb25zdCBlbHMgPSB0aGlzO1xuICBjb25zdCBhID0ge1xuICAgIHByb3BzOiBPYmplY3QuYXNzaWduKHt9LCBpbml0aWFsUHJvcHMpLFxuICAgIHBhcmFtczogT2JqZWN0LmFzc2lnbih7XG4gICAgICBkdXJhdGlvbjogMzAwLFxuICAgICAgZWFzaW5nOiAnc3dpbmcnIC8vIG9yICdsaW5lYXInXG5cbiAgICAgIC8qIENhbGxiYWNrc1xuICAgICAgYmVnaW4oZWxlbWVudHMpXG4gICAgICBjb21wbGV0ZShlbGVtZW50cylcbiAgICAgIHByb2dyZXNzKGVsZW1lbnRzLCBjb21wbGV0ZSwgcmVtYWluaW5nLCBzdGFydCwgdHdlZW5WYWx1ZSlcbiAgICAgICovXG5cbiAgICB9LCBpbml0aWFsUGFyYW1zKSxcbiAgICBlbGVtZW50czogZWxzLFxuICAgIGFuaW1hdGluZzogZmFsc2UsXG4gICAgcXVlOiBbXSxcblxuICAgIGVhc2luZ1Byb2dyZXNzKGVhc2luZywgcHJvZ3Jlc3MpIHtcbiAgICAgIGlmIChlYXNpbmcgPT09ICdzd2luZycpIHtcbiAgICAgICAgcmV0dXJuIDAuNSAtIE1hdGguY29zKHByb2dyZXNzICogTWF0aC5QSSkgLyAyO1xuICAgICAgfVxuXG4gICAgICBpZiAodHlwZW9mIGVhc2luZyA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICByZXR1cm4gZWFzaW5nKHByb2dyZXNzKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHByb2dyZXNzO1xuICAgIH0sXG5cbiAgICBzdG9wKCkge1xuICAgICAgaWYgKGEuZnJhbWVJZCkge1xuICAgICAgICB3aW5kb3cuY2FuY2VsQW5pbWF0aW9uRnJhbWUoYS5mcmFtZUlkKTtcbiAgICAgIH1cblxuICAgICAgYS5hbmltYXRpbmcgPSBmYWxzZTtcbiAgICAgIGEuZWxlbWVudHMuZWFjaChlbCA9PiB7XG4gICAgICAgIGNvbnN0IGVsZW1lbnQgPSBlbDtcbiAgICAgICAgZGVsZXRlIGVsZW1lbnQuZG9tN0FuaW1hdGVJbnN0YW5jZTtcbiAgICAgIH0pO1xuICAgICAgYS5xdWUgPSBbXTtcbiAgICB9LFxuXG4gICAgZG9uZShjb21wbGV0ZSkge1xuICAgICAgYS5hbmltYXRpbmcgPSBmYWxzZTtcbiAgICAgIGEuZWxlbWVudHMuZWFjaChlbCA9PiB7XG4gICAgICAgIGNvbnN0IGVsZW1lbnQgPSBlbDtcbiAgICAgICAgZGVsZXRlIGVsZW1lbnQuZG9tN0FuaW1hdGVJbnN0YW5jZTtcbiAgICAgIH0pO1xuICAgICAgaWYgKGNvbXBsZXRlKSBjb21wbGV0ZShlbHMpO1xuXG4gICAgICBpZiAoYS5xdWUubGVuZ3RoID4gMCkge1xuICAgICAgICBjb25zdCBxdWUgPSBhLnF1ZS5zaGlmdCgpO1xuICAgICAgICBhLmFuaW1hdGUocXVlWzBdLCBxdWVbMV0pO1xuICAgICAgfVxuICAgIH0sXG5cbiAgICBhbmltYXRlKHByb3BzLCBwYXJhbXMpIHtcbiAgICAgIGlmIChhLmFuaW1hdGluZykge1xuICAgICAgICBhLnF1ZS5wdXNoKFtwcm9wcywgcGFyYW1zXSk7XG4gICAgICAgIHJldHVybiBhO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBlbGVtZW50cyA9IFtdOyAvLyBEZWZpbmUgJiBDYWNoZSBJbml0aWFscyAmIFVuaXRzXG5cbiAgICAgIGEuZWxlbWVudHMuZWFjaCgoZWwsIGluZGV4KSA9PiB7XG4gICAgICAgIGxldCBpbml0aWFsRnVsbFZhbHVlO1xuICAgICAgICBsZXQgaW5pdGlhbFZhbHVlO1xuICAgICAgICBsZXQgdW5pdDtcbiAgICAgICAgbGV0IGZpbmFsVmFsdWU7XG4gICAgICAgIGxldCBmaW5hbEZ1bGxWYWx1ZTtcbiAgICAgICAgaWYgKCFlbC5kb203QW5pbWF0ZUluc3RhbmNlKSBhLmVsZW1lbnRzW2luZGV4XS5kb203QW5pbWF0ZUluc3RhbmNlID0gYTtcbiAgICAgICAgZWxlbWVudHNbaW5kZXhdID0ge1xuICAgICAgICAgIGNvbnRhaW5lcjogZWxcbiAgICAgICAgfTtcbiAgICAgICAgT2JqZWN0LmtleXMocHJvcHMpLmZvckVhY2gocHJvcCA9PiB7XG4gICAgICAgICAgaW5pdGlhbEZ1bGxWYWx1ZSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGVsLCBudWxsKS5nZXRQcm9wZXJ0eVZhbHVlKHByb3ApLnJlcGxhY2UoJywnLCAnLicpO1xuICAgICAgICAgIGluaXRpYWxWYWx1ZSA9IHBhcnNlRmxvYXQoaW5pdGlhbEZ1bGxWYWx1ZSk7XG4gICAgICAgICAgdW5pdCA9IGluaXRpYWxGdWxsVmFsdWUucmVwbGFjZShpbml0aWFsVmFsdWUsICcnKTtcbiAgICAgICAgICBmaW5hbFZhbHVlID0gcGFyc2VGbG9hdChwcm9wc1twcm9wXSk7XG4gICAgICAgICAgZmluYWxGdWxsVmFsdWUgPSBwcm9wc1twcm9wXSArIHVuaXQ7XG4gICAgICAgICAgZWxlbWVudHNbaW5kZXhdW3Byb3BdID0ge1xuICAgICAgICAgICAgaW5pdGlhbEZ1bGxWYWx1ZSxcbiAgICAgICAgICAgIGluaXRpYWxWYWx1ZSxcbiAgICAgICAgICAgIHVuaXQsXG4gICAgICAgICAgICBmaW5hbFZhbHVlLFxuICAgICAgICAgICAgZmluYWxGdWxsVmFsdWUsXG4gICAgICAgICAgICBjdXJyZW50VmFsdWU6IGluaXRpYWxWYWx1ZVxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgICBsZXQgc3RhcnRUaW1lID0gbnVsbDtcbiAgICAgIGxldCB0aW1lO1xuICAgICAgbGV0IGVsZW1lbnRzRG9uZSA9IDA7XG4gICAgICBsZXQgcHJvcHNEb25lID0gMDtcbiAgICAgIGxldCBkb25lO1xuICAgICAgbGV0IGJlZ2FuID0gZmFsc2U7XG4gICAgICBhLmFuaW1hdGluZyA9IHRydWU7XG5cbiAgICAgIGZ1bmN0aW9uIHJlbmRlcigpIHtcbiAgICAgICAgdGltZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgICAgICBsZXQgcHJvZ3Jlc3M7XG4gICAgICAgIGxldCBlYXNlUHJvZ3Jlc3M7IC8vIGxldCBlbDtcblxuICAgICAgICBpZiAoIWJlZ2FuKSB7XG4gICAgICAgICAgYmVnYW4gPSB0cnVlO1xuICAgICAgICAgIGlmIChwYXJhbXMuYmVnaW4pIHBhcmFtcy5iZWdpbihlbHMpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHN0YXJ0VGltZSA9PT0gbnVsbCkge1xuICAgICAgICAgIHN0YXJ0VGltZSA9IHRpbWU7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocGFyYW1zLnByb2dyZXNzKSB7XG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG4gICAgICAgICAgcGFyYW1zLnByb2dyZXNzKGVscywgTWF0aC5tYXgoTWF0aC5taW4oKHRpbWUgLSBzdGFydFRpbWUpIC8gcGFyYW1zLmR1cmF0aW9uLCAxKSwgMCksIHN0YXJ0VGltZSArIHBhcmFtcy5kdXJhdGlvbiAtIHRpbWUgPCAwID8gMCA6IHN0YXJ0VGltZSArIHBhcmFtcy5kdXJhdGlvbiAtIHRpbWUsIHN0YXJ0VGltZSk7XG4gICAgICAgIH1cblxuICAgICAgICBlbGVtZW50cy5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgIGNvbnN0IGVsID0gZWxlbWVudDtcbiAgICAgICAgICBpZiAoZG9uZSB8fCBlbC5kb25lKSByZXR1cm47XG4gICAgICAgICAgT2JqZWN0LmtleXMocHJvcHMpLmZvckVhY2gocHJvcCA9PiB7XG4gICAgICAgICAgICBpZiAoZG9uZSB8fCBlbC5kb25lKSByZXR1cm47XG4gICAgICAgICAgICBwcm9ncmVzcyA9IE1hdGgubWF4KE1hdGgubWluKCh0aW1lIC0gc3RhcnRUaW1lKSAvIHBhcmFtcy5kdXJhdGlvbiwgMSksIDApO1xuICAgICAgICAgICAgZWFzZVByb2dyZXNzID0gYS5lYXNpbmdQcm9ncmVzcyhwYXJhbXMuZWFzaW5nLCBwcm9ncmVzcyk7XG4gICAgICAgICAgICBjb25zdCB7XG4gICAgICAgICAgICAgIGluaXRpYWxWYWx1ZSxcbiAgICAgICAgICAgICAgZmluYWxWYWx1ZSxcbiAgICAgICAgICAgICAgdW5pdFxuICAgICAgICAgICAgfSA9IGVsW3Byb3BdO1xuICAgICAgICAgICAgZWxbcHJvcF0uY3VycmVudFZhbHVlID0gaW5pdGlhbFZhbHVlICsgZWFzZVByb2dyZXNzICogKGZpbmFsVmFsdWUgLSBpbml0aWFsVmFsdWUpO1xuICAgICAgICAgICAgY29uc3QgY3VycmVudFZhbHVlID0gZWxbcHJvcF0uY3VycmVudFZhbHVlO1xuXG4gICAgICAgICAgICBpZiAoZmluYWxWYWx1ZSA+IGluaXRpYWxWYWx1ZSAmJiBjdXJyZW50VmFsdWUgPj0gZmluYWxWYWx1ZSB8fCBmaW5hbFZhbHVlIDwgaW5pdGlhbFZhbHVlICYmIGN1cnJlbnRWYWx1ZSA8PSBmaW5hbFZhbHVlKSB7XG4gICAgICAgICAgICAgIGVsLmNvbnRhaW5lci5zdHlsZVtwcm9wXSA9IGZpbmFsVmFsdWUgKyB1bml0O1xuICAgICAgICAgICAgICBwcm9wc0RvbmUgKz0gMTtcblxuICAgICAgICAgICAgICBpZiAocHJvcHNEb25lID09PSBPYmplY3Qua2V5cyhwcm9wcykubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgZWwuZG9uZSA9IHRydWU7XG4gICAgICAgICAgICAgICAgZWxlbWVudHNEb25lICs9IDE7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBpZiAoZWxlbWVudHNEb25lID09PSBlbGVtZW50cy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBkb25lID0gdHJ1ZTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoZG9uZSkge1xuICAgICAgICAgICAgICBhLmRvbmUocGFyYW1zLmNvbXBsZXRlKTtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBlbC5jb250YWluZXIuc3R5bGVbcHJvcF0gPSBjdXJyZW50VmFsdWUgKyB1bml0O1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgaWYgKGRvbmUpIHJldHVybjsgLy8gVGhlbiBjYWxsXG5cbiAgICAgICAgYS5mcmFtZUlkID0gd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZShyZW5kZXIpO1xuICAgICAgfVxuXG4gICAgICBhLmZyYW1lSWQgPSB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKHJlbmRlcik7XG4gICAgICByZXR1cm4gYTtcbiAgICB9XG5cbiAgfTtcblxuICBpZiAoYS5lbGVtZW50cy5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gZWxzO1xuICB9XG5cbiAgbGV0IGFuaW1hdGVJbnN0YW5jZTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IGEuZWxlbWVudHMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICBpZiAoYS5lbGVtZW50c1tpXS5kb203QW5pbWF0ZUluc3RhbmNlKSB7XG4gICAgICBhbmltYXRlSW5zdGFuY2UgPSBhLmVsZW1lbnRzW2ldLmRvbTdBbmltYXRlSW5zdGFuY2U7XG4gICAgfSBlbHNlIGEuZWxlbWVudHNbaV0uZG9tN0FuaW1hdGVJbnN0YW5jZSA9IGE7XG4gIH1cblxuICBpZiAoIWFuaW1hdGVJbnN0YW5jZSkge1xuICAgIGFuaW1hdGVJbnN0YW5jZSA9IGE7XG4gIH1cblxuICBpZiAoaW5pdGlhbFByb3BzID09PSAnc3RvcCcpIHtcbiAgICBhbmltYXRlSW5zdGFuY2Uuc3RvcCgpO1xuICB9IGVsc2Uge1xuICAgIGFuaW1hdGVJbnN0YW5jZS5hbmltYXRlKGEucHJvcHMsIGEucGFyYW1zKTtcbiAgfVxuXG4gIHJldHVybiBlbHM7XG59XG5cbmZ1bmN0aW9uIHN0b3AoKSB7XG4gIGNvbnN0IGVscyA9IHRoaXM7XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBlbHMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICBpZiAoZWxzW2ldLmRvbTdBbmltYXRlSW5zdGFuY2UpIHtcbiAgICAgIGVsc1tpXS5kb203QW5pbWF0ZUluc3RhbmNlLnN0b3AoKTtcbiAgICB9XG4gIH1cbn1cblxuY29uc3Qgbm9UcmlnZ2VyID0gJ3Jlc2l6ZSBzY3JvbGwnLnNwbGl0KCcgJyk7XG5cbmZ1bmN0aW9uIHNob3J0Y3V0KG5hbWUpIHtcbiAgZnVuY3Rpb24gZXZlbnRIYW5kbGVyKC4uLmFyZ3MpIHtcbiAgICBpZiAodHlwZW9mIGFyZ3NbMF0gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgaWYgKG5vVHJpZ2dlci5pbmRleE9mKG5hbWUpIDwgMCkge1xuICAgICAgICAgIGlmIChuYW1lIGluIHRoaXNbaV0pIHRoaXNbaV1bbmFtZV0oKTtlbHNlIHtcbiAgICAgICAgICAgICQodGhpc1tpXSkudHJpZ2dlcihuYW1lKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMub24obmFtZSwgLi4uYXJncyk7XG4gIH1cblxuICByZXR1cm4gZXZlbnRIYW5kbGVyO1xufVxuXG5jb25zdCBjbGljayA9IHNob3J0Y3V0KCdjbGljaycpO1xuY29uc3QgYmx1ciA9IHNob3J0Y3V0KCdibHVyJyk7XG5jb25zdCBmb2N1cyA9IHNob3J0Y3V0KCdmb2N1cycpO1xuY29uc3QgZm9jdXNpbiA9IHNob3J0Y3V0KCdmb2N1c2luJyk7XG5jb25zdCBmb2N1c291dCA9IHNob3J0Y3V0KCdmb2N1c291dCcpO1xuY29uc3Qga2V5dXAgPSBzaG9ydGN1dCgna2V5dXAnKTtcbmNvbnN0IGtleWRvd24gPSBzaG9ydGN1dCgna2V5ZG93bicpO1xuY29uc3Qga2V5cHJlc3MgPSBzaG9ydGN1dCgna2V5cHJlc3MnKTtcbmNvbnN0IHN1Ym1pdCA9IHNob3J0Y3V0KCdzdWJtaXQnKTtcbmNvbnN0IGNoYW5nZSA9IHNob3J0Y3V0KCdjaGFuZ2UnKTtcbmNvbnN0IG1vdXNlZG93biA9IHNob3J0Y3V0KCdtb3VzZWRvd24nKTtcbmNvbnN0IG1vdXNlbW92ZSA9IHNob3J0Y3V0KCdtb3VzZW1vdmUnKTtcbmNvbnN0IG1vdXNldXAgPSBzaG9ydGN1dCgnbW91c2V1cCcpO1xuY29uc3QgbW91c2VlbnRlciA9IHNob3J0Y3V0KCdtb3VzZWVudGVyJyk7XG5jb25zdCBtb3VzZWxlYXZlID0gc2hvcnRjdXQoJ21vdXNlbGVhdmUnKTtcbmNvbnN0IG1vdXNlb3V0ID0gc2hvcnRjdXQoJ21vdXNlb3V0Jyk7XG5jb25zdCBtb3VzZW92ZXIgPSBzaG9ydGN1dCgnbW91c2VvdmVyJyk7XG5jb25zdCB0b3VjaHN0YXJ0ID0gc2hvcnRjdXQoJ3RvdWNoc3RhcnQnKTtcbmNvbnN0IHRvdWNoZW5kID0gc2hvcnRjdXQoJ3RvdWNoZW5kJyk7XG5jb25zdCB0b3VjaG1vdmUgPSBzaG9ydGN1dCgndG91Y2htb3ZlJyk7XG5jb25zdCByZXNpemUgPSBzaG9ydGN1dCgncmVzaXplJyk7XG5jb25zdCBzY3JvbGwgPSBzaG9ydGN1dCgnc2Nyb2xsJyk7XG5cbmV4cG9ydCBkZWZhdWx0ICQ7XG5leHBvcnQgeyAkLCBhZGQsIGFkZENsYXNzLCBhbmltYXRlLCBhbmltYXRpb25FbmQsIGFwcGVuZCwgYXBwZW5kVG8sIGF0dHIsIGJsdXIsIGNoYW5nZSwgY2hpbGRyZW4sIGNsaWNrLCBjbG9zZXN0LCBjc3MsIGRhdGEsIGRhdGFzZXQsIGRldGFjaCwgZWFjaCwgZW1wdHksIGVxLCBmaWx0ZXIsIGZpbmQsIGZvY3VzLCBmb2N1c2luLCBmb2N1c291dCwgaGFzQ2xhc3MsIGhlaWdodCwgaGlkZSwgaHRtbCwgaW5kZXgsIGluc2VydEFmdGVyLCBpbnNlcnRCZWZvcmUsIGlzLCBrZXlkb3duLCBrZXlwcmVzcywga2V5dXAsIG1vdXNlZG93biwgbW91c2VlbnRlciwgbW91c2VsZWF2ZSwgbW91c2Vtb3ZlLCBtb3VzZW91dCwgbW91c2VvdmVyLCBtb3VzZXVwLCBuZXh0LCBuZXh0QWxsLCBvZmYsIG9mZnNldCwgb24sIG9uY2UsIG91dGVySGVpZ2h0LCBvdXRlcldpZHRoLCBwYXJlbnQsIHBhcmVudHMsIHByZXBlbmQsIHByZXBlbmRUbywgcHJldiwgcHJldkFsbCwgcHJvcCwgcmVtb3ZlLCByZW1vdmVBdHRyLCByZW1vdmVDbGFzcywgcmVtb3ZlRGF0YSwgcmVzaXplLCBzY3JvbGwsIHNjcm9sbExlZnQsIHNjcm9sbFRvLCBzY3JvbGxUb3AsIHNob3csIHNpYmxpbmdzLCBzdG9wLCBzdHlsZXMsIHN1Ym1pdCwgdGV4dCwgdG9nZ2xlQ2xhc3MsIHRvdWNoZW5kLCB0b3VjaG1vdmUsIHRvdWNoc3RhcnQsIHRyYW5zZm9ybSwgdHJhbnNpdGlvbiwgdHJhbnNpdGlvbkVuZCwgdHJhbnNpdGlvblN0YXJ0LCB0cmlnZ2VyLCB2YWwsIHZhbHVlLCB3aWR0aCB9O1xuIiwiaW1wb3J0IHsgJCwgYWRkQ2xhc3MsIHJlbW92ZUNsYXNzLCBoYXNDbGFzcywgdG9nZ2xlQ2xhc3MsIGF0dHIsIHJlbW92ZUF0dHIsIHRyYW5zZm9ybSwgdHJhbnNpdGlvbiwgb24sIG9mZiwgdHJpZ2dlciwgdHJhbnNpdGlvbkVuZCwgb3V0ZXJXaWR0aCwgb3V0ZXJIZWlnaHQsIHN0eWxlcywgb2Zmc2V0LCBjc3MsIGVhY2gsIGh0bWwsIHRleHQsIGlzLCBpbmRleCwgZXEsIGFwcGVuZCwgcHJlcGVuZCwgbmV4dCwgbmV4dEFsbCwgcHJldiwgcHJldkFsbCwgcGFyZW50LCBwYXJlbnRzLCBjbG9zZXN0LCBmaW5kLCBjaGlsZHJlbiwgZmlsdGVyLCByZW1vdmUgfSBmcm9tICdkb203JztcbmNvbnN0IE1ldGhvZHMgPSB7XG4gIGFkZENsYXNzLFxuICByZW1vdmVDbGFzcyxcbiAgaGFzQ2xhc3MsXG4gIHRvZ2dsZUNsYXNzLFxuICBhdHRyLFxuICByZW1vdmVBdHRyLFxuICB0cmFuc2Zvcm0sXG4gIHRyYW5zaXRpb24sXG4gIG9uLFxuICBvZmYsXG4gIHRyaWdnZXIsXG4gIHRyYW5zaXRpb25FbmQsXG4gIG91dGVyV2lkdGgsXG4gIG91dGVySGVpZ2h0LFxuICBzdHlsZXMsXG4gIG9mZnNldCxcbiAgY3NzLFxuICBlYWNoLFxuICBodG1sLFxuICB0ZXh0LFxuICBpcyxcbiAgaW5kZXgsXG4gIGVxLFxuICBhcHBlbmQsXG4gIHByZXBlbmQsXG4gIG5leHQsXG4gIG5leHRBbGwsXG4gIHByZXYsXG4gIHByZXZBbGwsXG4gIHBhcmVudCxcbiAgcGFyZW50cyxcbiAgY2xvc2VzdCxcbiAgZmluZCxcbiAgY2hpbGRyZW4sXG4gIGZpbHRlcixcbiAgcmVtb3ZlXG59O1xuT2JqZWN0LmtleXMoTWV0aG9kcykuZm9yRWFjaChtZXRob2ROYW1lID0+IHtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KCQuZm4sIG1ldGhvZE5hbWUsIHtcbiAgICB2YWx1ZTogTWV0aG9kc1ttZXRob2ROYW1lXSxcbiAgICB3cml0YWJsZTogdHJ1ZVxuICB9KTtcbn0pO1xuZXhwb3J0IGRlZmF1bHQgJDsiLCJpbXBvcnQgeyBnZXRXaW5kb3cgfSBmcm9tICdzc3Itd2luZG93JztcblxuZnVuY3Rpb24gZGVsZXRlUHJvcHMob2JqKSB7XG4gIGNvbnN0IG9iamVjdCA9IG9iajtcbiAgT2JqZWN0LmtleXMob2JqZWN0KS5mb3JFYWNoKGtleSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIG9iamVjdFtrZXldID0gbnVsbDtcbiAgICB9IGNhdGNoIChlKSB7Ly8gbm8gZ2V0dGVyIGZvciBvYmplY3RcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgZGVsZXRlIG9iamVjdFtrZXldO1xuICAgIH0gY2F0Y2ggKGUpIHsvLyBzb21ldGhpbmcgZ290IHdyb25nXG4gICAgfVxuICB9KTtcbn1cblxuZnVuY3Rpb24gbmV4dFRpY2soY2FsbGJhY2ssIGRlbGF5ID0gMCkge1xuICByZXR1cm4gc2V0VGltZW91dChjYWxsYmFjaywgZGVsYXkpO1xufVxuXG5mdW5jdGlvbiBub3coKSB7XG4gIHJldHVybiBEYXRlLm5vdygpO1xufVxuXG5mdW5jdGlvbiBnZXRDb21wdXRlZFN0eWxlKGVsKSB7XG4gIGNvbnN0IHdpbmRvdyA9IGdldFdpbmRvdygpO1xuICBsZXQgc3R5bGU7XG5cbiAgaWYgKHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKSB7XG4gICAgc3R5bGUgPSB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShlbCwgbnVsbCk7XG4gIH1cblxuICBpZiAoIXN0eWxlICYmIGVsLmN1cnJlbnRTdHlsZSkge1xuICAgIHN0eWxlID0gZWwuY3VycmVudFN0eWxlO1xuICB9XG5cbiAgaWYgKCFzdHlsZSkge1xuICAgIHN0eWxlID0gZWwuc3R5bGU7XG4gIH1cblxuICByZXR1cm4gc3R5bGU7XG59XG5cbmZ1bmN0aW9uIGdldFRyYW5zbGF0ZShlbCwgYXhpcyA9ICd4Jykge1xuICBjb25zdCB3aW5kb3cgPSBnZXRXaW5kb3coKTtcbiAgbGV0IG1hdHJpeDtcbiAgbGV0IGN1clRyYW5zZm9ybTtcbiAgbGV0IHRyYW5zZm9ybU1hdHJpeDtcbiAgY29uc3QgY3VyU3R5bGUgPSBnZXRDb21wdXRlZFN0eWxlKGVsLCBudWxsKTtcblxuICBpZiAod2luZG93LldlYktpdENTU01hdHJpeCkge1xuICAgIGN1clRyYW5zZm9ybSA9IGN1clN0eWxlLnRyYW5zZm9ybSB8fCBjdXJTdHlsZS53ZWJraXRUcmFuc2Zvcm07XG5cbiAgICBpZiAoY3VyVHJhbnNmb3JtLnNwbGl0KCcsJykubGVuZ3RoID4gNikge1xuICAgICAgY3VyVHJhbnNmb3JtID0gY3VyVHJhbnNmb3JtLnNwbGl0KCcsICcpLm1hcChhID0+IGEucmVwbGFjZSgnLCcsICcuJykpLmpvaW4oJywgJyk7XG4gICAgfSAvLyBTb21lIG9sZCB2ZXJzaW9ucyBvZiBXZWJraXQgY2hva2Ugd2hlbiAnbm9uZScgaXMgcGFzc2VkOyBwYXNzXG4gICAgLy8gZW1wdHkgc3RyaW5nIGluc3RlYWQgaW4gdGhpcyBjYXNlXG5cblxuICAgIHRyYW5zZm9ybU1hdHJpeCA9IG5ldyB3aW5kb3cuV2ViS2l0Q1NTTWF0cml4KGN1clRyYW5zZm9ybSA9PT0gJ25vbmUnID8gJycgOiBjdXJUcmFuc2Zvcm0pO1xuICB9IGVsc2Uge1xuICAgIHRyYW5zZm9ybU1hdHJpeCA9IGN1clN0eWxlLk1velRyYW5zZm9ybSB8fCBjdXJTdHlsZS5PVHJhbnNmb3JtIHx8IGN1clN0eWxlLk1zVHJhbnNmb3JtIHx8IGN1clN0eWxlLm1zVHJhbnNmb3JtIHx8IGN1clN0eWxlLnRyYW5zZm9ybSB8fCBjdXJTdHlsZS5nZXRQcm9wZXJ0eVZhbHVlKCd0cmFuc2Zvcm0nKS5yZXBsYWNlKCd0cmFuc2xhdGUoJywgJ21hdHJpeCgxLCAwLCAwLCAxLCcpO1xuICAgIG1hdHJpeCA9IHRyYW5zZm9ybU1hdHJpeC50b1N0cmluZygpLnNwbGl0KCcsJyk7XG4gIH1cblxuICBpZiAoYXhpcyA9PT0gJ3gnKSB7XG4gICAgLy8gTGF0ZXN0IENocm9tZSBhbmQgd2Via2l0cyBGaXhcbiAgICBpZiAod2luZG93LldlYktpdENTU01hdHJpeCkgY3VyVHJhbnNmb3JtID0gdHJhbnNmb3JtTWF0cml4Lm00MTsgLy8gQ3JhenkgSUUxMCBNYXRyaXhcbiAgICBlbHNlIGlmIChtYXRyaXgubGVuZ3RoID09PSAxNikgY3VyVHJhbnNmb3JtID0gcGFyc2VGbG9hdChtYXRyaXhbMTJdKTsgLy8gTm9ybWFsIEJyb3dzZXJzXG4gICAgZWxzZSBjdXJUcmFuc2Zvcm0gPSBwYXJzZUZsb2F0KG1hdHJpeFs0XSk7XG4gIH1cblxuICBpZiAoYXhpcyA9PT0gJ3knKSB7XG4gICAgLy8gTGF0ZXN0IENocm9tZSBhbmQgd2Via2l0cyBGaXhcbiAgICBpZiAod2luZG93LldlYktpdENTU01hdHJpeCkgY3VyVHJhbnNmb3JtID0gdHJhbnNmb3JtTWF0cml4Lm00MjsgLy8gQ3JhenkgSUUxMCBNYXRyaXhcbiAgICBlbHNlIGlmIChtYXRyaXgubGVuZ3RoID09PSAxNikgY3VyVHJhbnNmb3JtID0gcGFyc2VGbG9hdChtYXRyaXhbMTNdKTsgLy8gTm9ybWFsIEJyb3dzZXJzXG4gICAgZWxzZSBjdXJUcmFuc2Zvcm0gPSBwYXJzZUZsb2F0KG1hdHJpeFs1XSk7XG4gIH1cblxuICByZXR1cm4gY3VyVHJhbnNmb3JtIHx8IDA7XG59XG5cbmZ1bmN0aW9uIGlzT2JqZWN0KG8pIHtcbiAgcmV0dXJuIHR5cGVvZiBvID09PSAnb2JqZWN0JyAmJiBvICE9PSBudWxsICYmIG8uY29uc3RydWN0b3IgJiYgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG8pLnNsaWNlKDgsIC0xKSA9PT0gJ09iamVjdCc7XG59XG5cbmZ1bmN0aW9uIGlzTm9kZShub2RlKSB7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuICBpZiAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIHdpbmRvdy5IVE1MRWxlbWVudCAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICByZXR1cm4gbm9kZSBpbnN0YW5jZW9mIEhUTUxFbGVtZW50O1xuICB9XG5cbiAgcmV0dXJuIG5vZGUgJiYgKG5vZGUubm9kZVR5cGUgPT09IDEgfHwgbm9kZS5ub2RlVHlwZSA9PT0gMTEpO1xufVxuXG5mdW5jdGlvbiBleHRlbmQoLi4uYXJncykge1xuICBjb25zdCB0byA9IE9iamVjdChhcmdzWzBdKTtcbiAgY29uc3Qgbm9FeHRlbmQgPSBbJ19fcHJvdG9fXycsICdjb25zdHJ1Y3RvcicsICdwcm90b3R5cGUnXTtcblxuICBmb3IgKGxldCBpID0gMTsgaSA8IGFyZ3MubGVuZ3RoOyBpICs9IDEpIHtcbiAgICBjb25zdCBuZXh0U291cmNlID0gYXJnc1tpXTtcblxuICAgIGlmIChuZXh0U291cmNlICE9PSB1bmRlZmluZWQgJiYgbmV4dFNvdXJjZSAhPT0gbnVsbCAmJiAhaXNOb2RlKG5leHRTb3VyY2UpKSB7XG4gICAgICBjb25zdCBrZXlzQXJyYXkgPSBPYmplY3Qua2V5cyhPYmplY3QobmV4dFNvdXJjZSkpLmZpbHRlcihrZXkgPT4gbm9FeHRlbmQuaW5kZXhPZihrZXkpIDwgMCk7XG5cbiAgICAgIGZvciAobGV0IG5leHRJbmRleCA9IDAsIGxlbiA9IGtleXNBcnJheS5sZW5ndGg7IG5leHRJbmRleCA8IGxlbjsgbmV4dEluZGV4ICs9IDEpIHtcbiAgICAgICAgY29uc3QgbmV4dEtleSA9IGtleXNBcnJheVtuZXh0SW5kZXhdO1xuICAgICAgICBjb25zdCBkZXNjID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihuZXh0U291cmNlLCBuZXh0S2V5KTtcblxuICAgICAgICBpZiAoZGVzYyAhPT0gdW5kZWZpbmVkICYmIGRlc2MuZW51bWVyYWJsZSkge1xuICAgICAgICAgIGlmIChpc09iamVjdCh0b1tuZXh0S2V5XSkgJiYgaXNPYmplY3QobmV4dFNvdXJjZVtuZXh0S2V5XSkpIHtcbiAgICAgICAgICAgIGlmIChuZXh0U291cmNlW25leHRLZXldLl9fc3dpcGVyX18pIHtcbiAgICAgICAgICAgICAgdG9bbmV4dEtleV0gPSBuZXh0U291cmNlW25leHRLZXldO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgZXh0ZW5kKHRvW25leHRLZXldLCBuZXh0U291cmNlW25leHRLZXldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2UgaWYgKCFpc09iamVjdCh0b1tuZXh0S2V5XSkgJiYgaXNPYmplY3QobmV4dFNvdXJjZVtuZXh0S2V5XSkpIHtcbiAgICAgICAgICAgIHRvW25leHRLZXldID0ge307XG5cbiAgICAgICAgICAgIGlmIChuZXh0U291cmNlW25leHRLZXldLl9fc3dpcGVyX18pIHtcbiAgICAgICAgICAgICAgdG9bbmV4dEtleV0gPSBuZXh0U291cmNlW25leHRLZXldO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgZXh0ZW5kKHRvW25leHRLZXldLCBuZXh0U291cmNlW25leHRLZXldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdG9bbmV4dEtleV0gPSBuZXh0U291cmNlW25leHRLZXldO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0bztcbn1cblxuZnVuY3Rpb24gc2V0Q1NTUHJvcGVydHkoZWwsIHZhck5hbWUsIHZhclZhbHVlKSB7XG4gIGVsLnN0eWxlLnNldFByb3BlcnR5KHZhck5hbWUsIHZhclZhbHVlKTtcbn1cblxuZnVuY3Rpb24gYW5pbWF0ZUNTU01vZGVTY3JvbGwoe1xuICBzd2lwZXIsXG4gIHRhcmdldFBvc2l0aW9uLFxuICBzaWRlXG59KSB7XG4gIGNvbnN0IHdpbmRvdyA9IGdldFdpbmRvdygpO1xuICBjb25zdCBzdGFydFBvc2l0aW9uID0gLXN3aXBlci50cmFuc2xhdGU7XG4gIGxldCBzdGFydFRpbWUgPSBudWxsO1xuICBsZXQgdGltZTtcbiAgY29uc3QgZHVyYXRpb24gPSBzd2lwZXIucGFyYW1zLnNwZWVkO1xuICBzd2lwZXIud3JhcHBlckVsLnN0eWxlLnNjcm9sbFNuYXBUeXBlID0gJ25vbmUnO1xuICB3aW5kb3cuY2FuY2VsQW5pbWF0aW9uRnJhbWUoc3dpcGVyLmNzc01vZGVGcmFtZUlEKTtcbiAgY29uc3QgZGlyID0gdGFyZ2V0UG9zaXRpb24gPiBzdGFydFBvc2l0aW9uID8gJ25leHQnIDogJ3ByZXYnO1xuXG4gIGNvbnN0IGlzT3V0T2ZCb3VuZCA9IChjdXJyZW50LCB0YXJnZXQpID0+IHtcbiAgICByZXR1cm4gZGlyID09PSAnbmV4dCcgJiYgY3VycmVudCA+PSB0YXJnZXQgfHwgZGlyID09PSAncHJldicgJiYgY3VycmVudCA8PSB0YXJnZXQ7XG4gIH07XG5cbiAgY29uc3QgYW5pbWF0ZSA9ICgpID0+IHtcbiAgICB0aW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG5cbiAgICBpZiAoc3RhcnRUaW1lID09PSBudWxsKSB7XG4gICAgICBzdGFydFRpbWUgPSB0aW1lO1xuICAgIH1cblxuICAgIGNvbnN0IHByb2dyZXNzID0gTWF0aC5tYXgoTWF0aC5taW4oKHRpbWUgLSBzdGFydFRpbWUpIC8gZHVyYXRpb24sIDEpLCAwKTtcbiAgICBjb25zdCBlYXNlUHJvZ3Jlc3MgPSAwLjUgLSBNYXRoLmNvcyhwcm9ncmVzcyAqIE1hdGguUEkpIC8gMjtcbiAgICBsZXQgY3VycmVudFBvc2l0aW9uID0gc3RhcnRQb3NpdGlvbiArIGVhc2VQcm9ncmVzcyAqICh0YXJnZXRQb3NpdGlvbiAtIHN0YXJ0UG9zaXRpb24pO1xuXG4gICAgaWYgKGlzT3V0T2ZCb3VuZChjdXJyZW50UG9zaXRpb24sIHRhcmdldFBvc2l0aW9uKSkge1xuICAgICAgY3VycmVudFBvc2l0aW9uID0gdGFyZ2V0UG9zaXRpb247XG4gICAgfVxuXG4gICAgc3dpcGVyLndyYXBwZXJFbC5zY3JvbGxUbyh7XG4gICAgICBbc2lkZV06IGN1cnJlbnRQb3NpdGlvblxuICAgIH0pO1xuXG4gICAgaWYgKGlzT3V0T2ZCb3VuZChjdXJyZW50UG9zaXRpb24sIHRhcmdldFBvc2l0aW9uKSkge1xuICAgICAgc3dpcGVyLndyYXBwZXJFbC5zdHlsZS5vdmVyZmxvdyA9ICdoaWRkZW4nO1xuICAgICAgc3dpcGVyLndyYXBwZXJFbC5zdHlsZS5zY3JvbGxTbmFwVHlwZSA9ICcnO1xuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHN3aXBlci53cmFwcGVyRWwuc3R5bGUub3ZlcmZsb3cgPSAnJztcbiAgICAgICAgc3dpcGVyLndyYXBwZXJFbC5zY3JvbGxUbyh7XG4gICAgICAgICAgW3NpZGVdOiBjdXJyZW50UG9zaXRpb25cbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICAgIHdpbmRvdy5jYW5jZWxBbmltYXRpb25GcmFtZShzd2lwZXIuY3NzTW9kZUZyYW1lSUQpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHN3aXBlci5jc3NNb2RlRnJhbWVJRCA9IHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoYW5pbWF0ZSk7XG4gIH07XG5cbiAgYW5pbWF0ZSgpO1xufVxuXG5leHBvcnQgeyBhbmltYXRlQ1NTTW9kZVNjcm9sbCwgZGVsZXRlUHJvcHMsIG5leHRUaWNrLCBub3csIGdldFRyYW5zbGF0ZSwgaXNPYmplY3QsIGV4dGVuZCwgZ2V0Q29tcHV0ZWRTdHlsZSwgc2V0Q1NTUHJvcGVydHkgfTsiLCJpbXBvcnQgeyBnZXRXaW5kb3csIGdldERvY3VtZW50IH0gZnJvbSAnc3NyLXdpbmRvdyc7XG5sZXQgc3VwcG9ydDtcblxuZnVuY3Rpb24gY2FsY1N1cHBvcnQoKSB7XG4gIGNvbnN0IHdpbmRvdyA9IGdldFdpbmRvdygpO1xuICBjb25zdCBkb2N1bWVudCA9IGdldERvY3VtZW50KCk7XG4gIHJldHVybiB7XG4gICAgc21vb3RoU2Nyb2xsOiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQgJiYgJ3Njcm9sbEJlaGF2aW9yJyBpbiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc3R5bGUsXG4gICAgdG91Y2g6ICEhKCdvbnRvdWNoc3RhcnQnIGluIHdpbmRvdyB8fCB3aW5kb3cuRG9jdW1lbnRUb3VjaCAmJiBkb2N1bWVudCBpbnN0YW5jZW9mIHdpbmRvdy5Eb2N1bWVudFRvdWNoKSxcbiAgICBwYXNzaXZlTGlzdGVuZXI6IGZ1bmN0aW9uIGNoZWNrUGFzc2l2ZUxpc3RlbmVyKCkge1xuICAgICAgbGV0IHN1cHBvcnRzUGFzc2l2ZSA9IGZhbHNlO1xuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBvcHRzID0gT2JqZWN0LmRlZmluZVByb3BlcnR5KHt9LCAncGFzc2l2ZScsIHtcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmVcbiAgICAgICAgICBnZXQoKSB7XG4gICAgICAgICAgICBzdXBwb3J0c1Bhc3NpdmUgPSB0cnVlO1xuICAgICAgICAgIH1cblxuICAgICAgICB9KTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Rlc3RQYXNzaXZlTGlzdGVuZXInLCBudWxsLCBvcHRzKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHsvLyBObyBzdXBwb3J0XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBzdXBwb3J0c1Bhc3NpdmU7XG4gICAgfSgpLFxuICAgIGdlc3R1cmVzOiBmdW5jdGlvbiBjaGVja0dlc3R1cmVzKCkge1xuICAgICAgcmV0dXJuICdvbmdlc3R1cmVzdGFydCcgaW4gd2luZG93O1xuICAgIH0oKVxuICB9O1xufVxuXG5mdW5jdGlvbiBnZXRTdXBwb3J0KCkge1xuICBpZiAoIXN1cHBvcnQpIHtcbiAgICBzdXBwb3J0ID0gY2FsY1N1cHBvcnQoKTtcbiAgfVxuXG4gIHJldHVybiBzdXBwb3J0O1xufVxuXG5leHBvcnQgeyBnZXRTdXBwb3J0IH07IiwiaW1wb3J0IHsgZ2V0V2luZG93IH0gZnJvbSAnc3NyLXdpbmRvdyc7XG5pbXBvcnQgeyBnZXRTdXBwb3J0IH0gZnJvbSAnLi9nZXQtc3VwcG9ydC5qcyc7XG5sZXQgZGV2aWNlQ2FjaGVkO1xuXG5mdW5jdGlvbiBjYWxjRGV2aWNlKHtcbiAgdXNlckFnZW50XG59ID0ge30pIHtcbiAgY29uc3Qgc3VwcG9ydCA9IGdldFN1cHBvcnQoKTtcbiAgY29uc3Qgd2luZG93ID0gZ2V0V2luZG93KCk7XG4gIGNvbnN0IHBsYXRmb3JtID0gd2luZG93Lm5hdmlnYXRvci5wbGF0Zm9ybTtcbiAgY29uc3QgdWEgPSB1c2VyQWdlbnQgfHwgd2luZG93Lm5hdmlnYXRvci51c2VyQWdlbnQ7XG4gIGNvbnN0IGRldmljZSA9IHtcbiAgICBpb3M6IGZhbHNlLFxuICAgIGFuZHJvaWQ6IGZhbHNlXG4gIH07XG4gIGNvbnN0IHNjcmVlbldpZHRoID0gd2luZG93LnNjcmVlbi53aWR0aDtcbiAgY29uc3Qgc2NyZWVuSGVpZ2h0ID0gd2luZG93LnNjcmVlbi5oZWlnaHQ7XG4gIGNvbnN0IGFuZHJvaWQgPSB1YS5tYXRjaCgvKEFuZHJvaWQpOz9bXFxzXFwvXSsoW1xcZC5dKyk/Lyk7IC8vIGVzbGludC1kaXNhYmxlLWxpbmVcblxuICBsZXQgaXBhZCA9IHVhLm1hdGNoKC8oaVBhZCkuKk9TXFxzKFtcXGRfXSspLyk7XG4gIGNvbnN0IGlwb2QgPSB1YS5tYXRjaCgvKGlQb2QpKC4qT1NcXHMoW1xcZF9dKykpPy8pO1xuICBjb25zdCBpcGhvbmUgPSAhaXBhZCAmJiB1YS5tYXRjaCgvKGlQaG9uZVxcc09TfGlPUylcXHMoW1xcZF9dKykvKTtcbiAgY29uc3Qgd2luZG93cyA9IHBsYXRmb3JtID09PSAnV2luMzInO1xuICBsZXQgbWFjb3MgPSBwbGF0Zm9ybSA9PT0gJ01hY0ludGVsJzsgLy8gaVBhZE9zIDEzIGZpeFxuXG4gIGNvbnN0IGlQYWRTY3JlZW5zID0gWycxMDI0eDEzNjYnLCAnMTM2NngxMDI0JywgJzgzNHgxMTk0JywgJzExOTR4ODM0JywgJzgzNHgxMTEyJywgJzExMTJ4ODM0JywgJzc2OHgxMDI0JywgJzEwMjR4NzY4JywgJzgyMHgxMTgwJywgJzExODB4ODIwJywgJzgxMHgxMDgwJywgJzEwODB4ODEwJ107XG5cbiAgaWYgKCFpcGFkICYmIG1hY29zICYmIHN1cHBvcnQudG91Y2ggJiYgaVBhZFNjcmVlbnMuaW5kZXhPZihgJHtzY3JlZW5XaWR0aH14JHtzY3JlZW5IZWlnaHR9YCkgPj0gMCkge1xuICAgIGlwYWQgPSB1YS5tYXRjaCgvKFZlcnNpb24pXFwvKFtcXGQuXSspLyk7XG4gICAgaWYgKCFpcGFkKSBpcGFkID0gWzAsIDEsICcxM18wXzAnXTtcbiAgICBtYWNvcyA9IGZhbHNlO1xuICB9IC8vIEFuZHJvaWRcblxuXG4gIGlmIChhbmRyb2lkICYmICF3aW5kb3dzKSB7XG4gICAgZGV2aWNlLm9zID0gJ2FuZHJvaWQnO1xuICAgIGRldmljZS5hbmRyb2lkID0gdHJ1ZTtcbiAgfVxuXG4gIGlmIChpcGFkIHx8IGlwaG9uZSB8fCBpcG9kKSB7XG4gICAgZGV2aWNlLm9zID0gJ2lvcyc7XG4gICAgZGV2aWNlLmlvcyA9IHRydWU7XG4gIH0gLy8gRXhwb3J0IG9iamVjdFxuXG5cbiAgcmV0dXJuIGRldmljZTtcbn1cblxuZnVuY3Rpb24gZ2V0RGV2aWNlKG92ZXJyaWRlcyA9IHt9KSB7XG4gIGlmICghZGV2aWNlQ2FjaGVkKSB7XG4gICAgZGV2aWNlQ2FjaGVkID0gY2FsY0RldmljZShvdmVycmlkZXMpO1xuICB9XG5cbiAgcmV0dXJuIGRldmljZUNhY2hlZDtcbn1cblxuZXhwb3J0IHsgZ2V0RGV2aWNlIH07IiwiaW1wb3J0IHsgZ2V0V2luZG93IH0gZnJvbSAnc3NyLXdpbmRvdyc7XG5sZXQgYnJvd3NlcjtcblxuZnVuY3Rpb24gY2FsY0Jyb3dzZXIoKSB7XG4gIGNvbnN0IHdpbmRvdyA9IGdldFdpbmRvdygpO1xuXG4gIGZ1bmN0aW9uIGlzU2FmYXJpKCkge1xuICAgIGNvbnN0IHVhID0gd2luZG93Lm5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKTtcbiAgICByZXR1cm4gdWEuaW5kZXhPZignc2FmYXJpJykgPj0gMCAmJiB1YS5pbmRleE9mKCdjaHJvbWUnKSA8IDAgJiYgdWEuaW5kZXhPZignYW5kcm9pZCcpIDwgMDtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgaXNTYWZhcmk6IGlzU2FmYXJpKCksXG4gICAgaXNXZWJWaWV3OiAvKGlQaG9uZXxpUG9kfGlQYWQpLipBcHBsZVdlYktpdCg/IS4qU2FmYXJpKS9pLnRlc3Qod2luZG93Lm5hdmlnYXRvci51c2VyQWdlbnQpXG4gIH07XG59XG5cbmZ1bmN0aW9uIGdldEJyb3dzZXIoKSB7XG4gIGlmICghYnJvd3Nlcikge1xuICAgIGJyb3dzZXIgPSBjYWxjQnJvd3NlcigpO1xuICB9XG5cbiAgcmV0dXJuIGJyb3dzZXI7XG59XG5cbmV4cG9ydCB7IGdldEJyb3dzZXIgfTsiLCJpbXBvcnQgeyBnZXRXaW5kb3cgfSBmcm9tICdzc3Itd2luZG93JztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIFJlc2l6ZSh7XG4gIHN3aXBlcixcbiAgb24sXG4gIGVtaXRcbn0pIHtcbiAgY29uc3Qgd2luZG93ID0gZ2V0V2luZG93KCk7XG4gIGxldCBvYnNlcnZlciA9IG51bGw7XG4gIGxldCBhbmltYXRpb25GcmFtZSA9IG51bGw7XG5cbiAgY29uc3QgcmVzaXplSGFuZGxlciA9ICgpID0+IHtcbiAgICBpZiAoIXN3aXBlciB8fCBzd2lwZXIuZGVzdHJveWVkIHx8ICFzd2lwZXIuaW5pdGlhbGl6ZWQpIHJldHVybjtcbiAgICBlbWl0KCdiZWZvcmVSZXNpemUnKTtcbiAgICBlbWl0KCdyZXNpemUnKTtcbiAgfTtcblxuICBjb25zdCBjcmVhdGVPYnNlcnZlciA9ICgpID0+IHtcbiAgICBpZiAoIXN3aXBlciB8fCBzd2lwZXIuZGVzdHJveWVkIHx8ICFzd2lwZXIuaW5pdGlhbGl6ZWQpIHJldHVybjtcbiAgICBvYnNlcnZlciA9IG5ldyBSZXNpemVPYnNlcnZlcihlbnRyaWVzID0+IHtcbiAgICAgIGFuaW1hdGlvbkZyYW1lID0gd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICB3aWR0aCxcbiAgICAgICAgICBoZWlnaHRcbiAgICAgICAgfSA9IHN3aXBlcjtcbiAgICAgICAgbGV0IG5ld1dpZHRoID0gd2lkdGg7XG4gICAgICAgIGxldCBuZXdIZWlnaHQgPSBoZWlnaHQ7XG4gICAgICAgIGVudHJpZXMuZm9yRWFjaCgoe1xuICAgICAgICAgIGNvbnRlbnRCb3hTaXplLFxuICAgICAgICAgIGNvbnRlbnRSZWN0LFxuICAgICAgICAgIHRhcmdldFxuICAgICAgICB9KSA9PiB7XG4gICAgICAgICAgaWYgKHRhcmdldCAmJiB0YXJnZXQgIT09IHN3aXBlci5lbCkgcmV0dXJuO1xuICAgICAgICAgIG5ld1dpZHRoID0gY29udGVudFJlY3QgPyBjb250ZW50UmVjdC53aWR0aCA6IChjb250ZW50Qm94U2l6ZVswXSB8fCBjb250ZW50Qm94U2l6ZSkuaW5saW5lU2l6ZTtcbiAgICAgICAgICBuZXdIZWlnaHQgPSBjb250ZW50UmVjdCA/IGNvbnRlbnRSZWN0LmhlaWdodCA6IChjb250ZW50Qm94U2l6ZVswXSB8fCBjb250ZW50Qm94U2l6ZSkuYmxvY2tTaXplO1xuICAgICAgICB9KTtcblxuICAgICAgICBpZiAobmV3V2lkdGggIT09IHdpZHRoIHx8IG5ld0hlaWdodCAhPT0gaGVpZ2h0KSB7XG4gICAgICAgICAgcmVzaXplSGFuZGxlcigpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBvYnNlcnZlci5vYnNlcnZlKHN3aXBlci5lbCk7XG4gIH07XG5cbiAgY29uc3QgcmVtb3ZlT2JzZXJ2ZXIgPSAoKSA9PiB7XG4gICAgaWYgKGFuaW1hdGlvbkZyYW1lKSB7XG4gICAgICB3aW5kb3cuY2FuY2VsQW5pbWF0aW9uRnJhbWUoYW5pbWF0aW9uRnJhbWUpO1xuICAgIH1cblxuICAgIGlmIChvYnNlcnZlciAmJiBvYnNlcnZlci51bm9ic2VydmUgJiYgc3dpcGVyLmVsKSB7XG4gICAgICBvYnNlcnZlci51bm9ic2VydmUoc3dpcGVyLmVsKTtcbiAgICAgIG9ic2VydmVyID0gbnVsbDtcbiAgICB9XG4gIH07XG5cbiAgY29uc3Qgb3JpZW50YXRpb25DaGFuZ2VIYW5kbGVyID0gKCkgPT4ge1xuICAgIGlmICghc3dpcGVyIHx8IHN3aXBlci5kZXN0cm95ZWQgfHwgIXN3aXBlci5pbml0aWFsaXplZCkgcmV0dXJuO1xuICAgIGVtaXQoJ29yaWVudGF0aW9uY2hhbmdlJyk7XG4gIH07XG5cbiAgb24oJ2luaXQnLCAoKSA9PiB7XG4gICAgaWYgKHN3aXBlci5wYXJhbXMucmVzaXplT2JzZXJ2ZXIgJiYgdHlwZW9mIHdpbmRvdy5SZXNpemVPYnNlcnZlciAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIGNyZWF0ZU9ic2VydmVyKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIHJlc2l6ZUhhbmRsZXIpO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdvcmllbnRhdGlvbmNoYW5nZScsIG9yaWVudGF0aW9uQ2hhbmdlSGFuZGxlcik7XG4gIH0pO1xuICBvbignZGVzdHJveScsICgpID0+IHtcbiAgICByZW1vdmVPYnNlcnZlcigpO1xuICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdyZXNpemUnLCByZXNpemVIYW5kbGVyKTtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignb3JpZW50YXRpb25jaGFuZ2UnLCBvcmllbnRhdGlvbkNoYW5nZUhhbmRsZXIpO1xuICB9KTtcbn0iLCJpbXBvcnQgeyBnZXRXaW5kb3cgfSBmcm9tICdzc3Itd2luZG93JztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIE9ic2VydmVyKHtcbiAgc3dpcGVyLFxuICBleHRlbmRQYXJhbXMsXG4gIG9uLFxuICBlbWl0XG59KSB7XG4gIGNvbnN0IG9ic2VydmVycyA9IFtdO1xuICBjb25zdCB3aW5kb3cgPSBnZXRXaW5kb3coKTtcblxuICBjb25zdCBhdHRhY2ggPSAodGFyZ2V0LCBvcHRpb25zID0ge30pID0+IHtcbiAgICBjb25zdCBPYnNlcnZlckZ1bmMgPSB3aW5kb3cuTXV0YXRpb25PYnNlcnZlciB8fCB3aW5kb3cuV2Via2l0TXV0YXRpb25PYnNlcnZlcjtcbiAgICBjb25zdCBvYnNlcnZlciA9IG5ldyBPYnNlcnZlckZ1bmMobXV0YXRpb25zID0+IHtcbiAgICAgIC8vIFRoZSBvYnNlcnZlclVwZGF0ZSBldmVudCBzaG91bGQgb25seSBiZSB0cmlnZ2VyZWRcbiAgICAgIC8vIG9uY2UgZGVzcGl0ZSB0aGUgbnVtYmVyIG9mIG11dGF0aW9ucy4gIEFkZGl0aW9uYWxcbiAgICAgIC8vIHRyaWdnZXJzIGFyZSByZWR1bmRhbnQgYW5kIGFyZSB2ZXJ5IGNvc3RseVxuICAgICAgaWYgKG11dGF0aW9ucy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgZW1pdCgnb2JzZXJ2ZXJVcGRhdGUnLCBtdXRhdGlvbnNbMF0pO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG9ic2VydmVyVXBkYXRlID0gZnVuY3Rpb24gb2JzZXJ2ZXJVcGRhdGUoKSB7XG4gICAgICAgIGVtaXQoJ29ic2VydmVyVXBkYXRlJywgbXV0YXRpb25zWzBdKTtcbiAgICAgIH07XG5cbiAgICAgIGlmICh3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKSB7XG4gICAgICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUob2JzZXJ2ZXJVcGRhdGUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgd2luZG93LnNldFRpbWVvdXQob2JzZXJ2ZXJVcGRhdGUsIDApO1xuICAgICAgfVxuICAgIH0pO1xuICAgIG9ic2VydmVyLm9ic2VydmUodGFyZ2V0LCB7XG4gICAgICBhdHRyaWJ1dGVzOiB0eXBlb2Ygb3B0aW9ucy5hdHRyaWJ1dGVzID09PSAndW5kZWZpbmVkJyA/IHRydWUgOiBvcHRpb25zLmF0dHJpYnV0ZXMsXG4gICAgICBjaGlsZExpc3Q6IHR5cGVvZiBvcHRpb25zLmNoaWxkTGlzdCA9PT0gJ3VuZGVmaW5lZCcgPyB0cnVlIDogb3B0aW9ucy5jaGlsZExpc3QsXG4gICAgICBjaGFyYWN0ZXJEYXRhOiB0eXBlb2Ygb3B0aW9ucy5jaGFyYWN0ZXJEYXRhID09PSAndW5kZWZpbmVkJyA/IHRydWUgOiBvcHRpb25zLmNoYXJhY3RlckRhdGFcbiAgICB9KTtcbiAgICBvYnNlcnZlcnMucHVzaChvYnNlcnZlcik7XG4gIH07XG5cbiAgY29uc3QgaW5pdCA9ICgpID0+IHtcbiAgICBpZiAoIXN3aXBlci5wYXJhbXMub2JzZXJ2ZXIpIHJldHVybjtcblxuICAgIGlmIChzd2lwZXIucGFyYW1zLm9ic2VydmVQYXJlbnRzKSB7XG4gICAgICBjb25zdCBjb250YWluZXJQYXJlbnRzID0gc3dpcGVyLiRlbC5wYXJlbnRzKCk7XG5cbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY29udGFpbmVyUGFyZW50cy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICBhdHRhY2goY29udGFpbmVyUGFyZW50c1tpXSk7XG4gICAgICB9XG4gICAgfSAvLyBPYnNlcnZlIGNvbnRhaW5lclxuXG5cbiAgICBhdHRhY2goc3dpcGVyLiRlbFswXSwge1xuICAgICAgY2hpbGRMaXN0OiBzd2lwZXIucGFyYW1zLm9ic2VydmVTbGlkZUNoaWxkcmVuXG4gICAgfSk7IC8vIE9ic2VydmUgd3JhcHBlclxuXG4gICAgYXR0YWNoKHN3aXBlci4kd3JhcHBlckVsWzBdLCB7XG4gICAgICBhdHRyaWJ1dGVzOiBmYWxzZVxuICAgIH0pO1xuICB9O1xuXG4gIGNvbnN0IGRlc3Ryb3kgPSAoKSA9PiB7XG4gICAgb2JzZXJ2ZXJzLmZvckVhY2gob2JzZXJ2ZXIgPT4ge1xuICAgICAgb2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xuICAgIH0pO1xuICAgIG9ic2VydmVycy5zcGxpY2UoMCwgb2JzZXJ2ZXJzLmxlbmd0aCk7XG4gIH07XG5cbiAgZXh0ZW5kUGFyYW1zKHtcbiAgICBvYnNlcnZlcjogZmFsc2UsXG4gICAgb2JzZXJ2ZVBhcmVudHM6IGZhbHNlLFxuICAgIG9ic2VydmVTbGlkZUNoaWxkcmVuOiBmYWxzZVxuICB9KTtcbiAgb24oJ2luaXQnLCBpbml0KTtcbiAgb24oJ2Rlc3Ryb3knLCBkZXN0cm95KTtcbn0iLCIvKiBlc2xpbnQtZGlzYWJsZSBuby11bmRlcnNjb3JlLWRhbmdsZSAqL1xuZXhwb3J0IGRlZmF1bHQge1xuICBvbihldmVudHMsIGhhbmRsZXIsIHByaW9yaXR5KSB7XG4gICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgaWYgKCFzZWxmLmV2ZW50c0xpc3RlbmVycyB8fCBzZWxmLmRlc3Ryb3llZCkgcmV0dXJuIHNlbGY7XG4gICAgaWYgKHR5cGVvZiBoYW5kbGVyICE9PSAnZnVuY3Rpb24nKSByZXR1cm4gc2VsZjtcbiAgICBjb25zdCBtZXRob2QgPSBwcmlvcml0eSA/ICd1bnNoaWZ0JyA6ICdwdXNoJztcbiAgICBldmVudHMuc3BsaXQoJyAnKS5mb3JFYWNoKGV2ZW50ID0+IHtcbiAgICAgIGlmICghc2VsZi5ldmVudHNMaXN0ZW5lcnNbZXZlbnRdKSBzZWxmLmV2ZW50c0xpc3RlbmVyc1tldmVudF0gPSBbXTtcbiAgICAgIHNlbGYuZXZlbnRzTGlzdGVuZXJzW2V2ZW50XVttZXRob2RdKGhhbmRsZXIpO1xuICAgIH0pO1xuICAgIHJldHVybiBzZWxmO1xuICB9LFxuXG4gIG9uY2UoZXZlbnRzLCBoYW5kbGVyLCBwcmlvcml0eSkge1xuICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgIGlmICghc2VsZi5ldmVudHNMaXN0ZW5lcnMgfHwgc2VsZi5kZXN0cm95ZWQpIHJldHVybiBzZWxmO1xuICAgIGlmICh0eXBlb2YgaGFuZGxlciAhPT0gJ2Z1bmN0aW9uJykgcmV0dXJuIHNlbGY7XG5cbiAgICBmdW5jdGlvbiBvbmNlSGFuZGxlciguLi5hcmdzKSB7XG4gICAgICBzZWxmLm9mZihldmVudHMsIG9uY2VIYW5kbGVyKTtcblxuICAgICAgaWYgKG9uY2VIYW5kbGVyLl9fZW1pdHRlclByb3h5KSB7XG4gICAgICAgIGRlbGV0ZSBvbmNlSGFuZGxlci5fX2VtaXR0ZXJQcm94eTtcbiAgICAgIH1cblxuICAgICAgaGFuZGxlci5hcHBseShzZWxmLCBhcmdzKTtcbiAgICB9XG5cbiAgICBvbmNlSGFuZGxlci5fX2VtaXR0ZXJQcm94eSA9IGhhbmRsZXI7XG4gICAgcmV0dXJuIHNlbGYub24oZXZlbnRzLCBvbmNlSGFuZGxlciwgcHJpb3JpdHkpO1xuICB9LFxuXG4gIG9uQW55KGhhbmRsZXIsIHByaW9yaXR5KSB7XG4gICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgaWYgKCFzZWxmLmV2ZW50c0xpc3RlbmVycyB8fCBzZWxmLmRlc3Ryb3llZCkgcmV0dXJuIHNlbGY7XG4gICAgaWYgKHR5cGVvZiBoYW5kbGVyICE9PSAnZnVuY3Rpb24nKSByZXR1cm4gc2VsZjtcbiAgICBjb25zdCBtZXRob2QgPSBwcmlvcml0eSA/ICd1bnNoaWZ0JyA6ICdwdXNoJztcblxuICAgIGlmIChzZWxmLmV2ZW50c0FueUxpc3RlbmVycy5pbmRleE9mKGhhbmRsZXIpIDwgMCkge1xuICAgICAgc2VsZi5ldmVudHNBbnlMaXN0ZW5lcnNbbWV0aG9kXShoYW5kbGVyKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc2VsZjtcbiAgfSxcblxuICBvZmZBbnkoaGFuZGxlcikge1xuICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgIGlmICghc2VsZi5ldmVudHNMaXN0ZW5lcnMgfHwgc2VsZi5kZXN0cm95ZWQpIHJldHVybiBzZWxmO1xuICAgIGlmICghc2VsZi5ldmVudHNBbnlMaXN0ZW5lcnMpIHJldHVybiBzZWxmO1xuICAgIGNvbnN0IGluZGV4ID0gc2VsZi5ldmVudHNBbnlMaXN0ZW5lcnMuaW5kZXhPZihoYW5kbGVyKTtcblxuICAgIGlmIChpbmRleCA+PSAwKSB7XG4gICAgICBzZWxmLmV2ZW50c0FueUxpc3RlbmVycy5zcGxpY2UoaW5kZXgsIDEpO1xuICAgIH1cblxuICAgIHJldHVybiBzZWxmO1xuICB9LFxuXG4gIG9mZihldmVudHMsIGhhbmRsZXIpIHtcbiAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICBpZiAoIXNlbGYuZXZlbnRzTGlzdGVuZXJzIHx8IHNlbGYuZGVzdHJveWVkKSByZXR1cm4gc2VsZjtcbiAgICBpZiAoIXNlbGYuZXZlbnRzTGlzdGVuZXJzKSByZXR1cm4gc2VsZjtcbiAgICBldmVudHMuc3BsaXQoJyAnKS5mb3JFYWNoKGV2ZW50ID0+IHtcbiAgICAgIGlmICh0eXBlb2YgaGFuZGxlciA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgc2VsZi5ldmVudHNMaXN0ZW5lcnNbZXZlbnRdID0gW107XG4gICAgICB9IGVsc2UgaWYgKHNlbGYuZXZlbnRzTGlzdGVuZXJzW2V2ZW50XSkge1xuICAgICAgICBzZWxmLmV2ZW50c0xpc3RlbmVyc1tldmVudF0uZm9yRWFjaCgoZXZlbnRIYW5kbGVyLCBpbmRleCkgPT4ge1xuICAgICAgICAgIGlmIChldmVudEhhbmRsZXIgPT09IGhhbmRsZXIgfHwgZXZlbnRIYW5kbGVyLl9fZW1pdHRlclByb3h5ICYmIGV2ZW50SGFuZGxlci5fX2VtaXR0ZXJQcm94eSA9PT0gaGFuZGxlcikge1xuICAgICAgICAgICAgc2VsZi5ldmVudHNMaXN0ZW5lcnNbZXZlbnRdLnNwbGljZShpbmRleCwgMSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gc2VsZjtcbiAgfSxcblxuICBlbWl0KC4uLmFyZ3MpIHtcbiAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICBpZiAoIXNlbGYuZXZlbnRzTGlzdGVuZXJzIHx8IHNlbGYuZGVzdHJveWVkKSByZXR1cm4gc2VsZjtcbiAgICBpZiAoIXNlbGYuZXZlbnRzTGlzdGVuZXJzKSByZXR1cm4gc2VsZjtcbiAgICBsZXQgZXZlbnRzO1xuICAgIGxldCBkYXRhO1xuICAgIGxldCBjb250ZXh0O1xuXG4gICAgaWYgKHR5cGVvZiBhcmdzWzBdID09PSAnc3RyaW5nJyB8fCBBcnJheS5pc0FycmF5KGFyZ3NbMF0pKSB7XG4gICAgICBldmVudHMgPSBhcmdzWzBdO1xuICAgICAgZGF0YSA9IGFyZ3Muc2xpY2UoMSwgYXJncy5sZW5ndGgpO1xuICAgICAgY29udGV4dCA9IHNlbGY7XG4gICAgfSBlbHNlIHtcbiAgICAgIGV2ZW50cyA9IGFyZ3NbMF0uZXZlbnRzO1xuICAgICAgZGF0YSA9IGFyZ3NbMF0uZGF0YTtcbiAgICAgIGNvbnRleHQgPSBhcmdzWzBdLmNvbnRleHQgfHwgc2VsZjtcbiAgICB9XG5cbiAgICBkYXRhLnVuc2hpZnQoY29udGV4dCk7XG4gICAgY29uc3QgZXZlbnRzQXJyYXkgPSBBcnJheS5pc0FycmF5KGV2ZW50cykgPyBldmVudHMgOiBldmVudHMuc3BsaXQoJyAnKTtcbiAgICBldmVudHNBcnJheS5mb3JFYWNoKGV2ZW50ID0+IHtcbiAgICAgIGlmIChzZWxmLmV2ZW50c0FueUxpc3RlbmVycyAmJiBzZWxmLmV2ZW50c0FueUxpc3RlbmVycy5sZW5ndGgpIHtcbiAgICAgICAgc2VsZi5ldmVudHNBbnlMaXN0ZW5lcnMuZm9yRWFjaChldmVudEhhbmRsZXIgPT4ge1xuICAgICAgICAgIGV2ZW50SGFuZGxlci5hcHBseShjb250ZXh0LCBbZXZlbnQsIC4uLmRhdGFdKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzZWxmLmV2ZW50c0xpc3RlbmVycyAmJiBzZWxmLmV2ZW50c0xpc3RlbmVyc1tldmVudF0pIHtcbiAgICAgICAgc2VsZi5ldmVudHNMaXN0ZW5lcnNbZXZlbnRdLmZvckVhY2goZXZlbnRIYW5kbGVyID0+IHtcbiAgICAgICAgICBldmVudEhhbmRsZXIuYXBwbHkoY29udGV4dCwgZGF0YSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBzZWxmO1xuICB9XG5cbn07IiwiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdXBkYXRlU2l6ZSgpIHtcbiAgY29uc3Qgc3dpcGVyID0gdGhpcztcbiAgbGV0IHdpZHRoO1xuICBsZXQgaGVpZ2h0O1xuICBjb25zdCAkZWwgPSBzd2lwZXIuJGVsO1xuXG4gIGlmICh0eXBlb2Ygc3dpcGVyLnBhcmFtcy53aWR0aCAhPT0gJ3VuZGVmaW5lZCcgJiYgc3dpcGVyLnBhcmFtcy53aWR0aCAhPT0gbnVsbCkge1xuICAgIHdpZHRoID0gc3dpcGVyLnBhcmFtcy53aWR0aDtcbiAgfSBlbHNlIHtcbiAgICB3aWR0aCA9ICRlbFswXS5jbGllbnRXaWR0aDtcbiAgfVxuXG4gIGlmICh0eXBlb2Ygc3dpcGVyLnBhcmFtcy5oZWlnaHQgIT09ICd1bmRlZmluZWQnICYmIHN3aXBlci5wYXJhbXMuaGVpZ2h0ICE9PSBudWxsKSB7XG4gICAgaGVpZ2h0ID0gc3dpcGVyLnBhcmFtcy5oZWlnaHQ7XG4gIH0gZWxzZSB7XG4gICAgaGVpZ2h0ID0gJGVsWzBdLmNsaWVudEhlaWdodDtcbiAgfVxuXG4gIGlmICh3aWR0aCA9PT0gMCAmJiBzd2lwZXIuaXNIb3Jpem9udGFsKCkgfHwgaGVpZ2h0ID09PSAwICYmIHN3aXBlci5pc1ZlcnRpY2FsKCkpIHtcbiAgICByZXR1cm47XG4gIH0gLy8gU3VidHJhY3QgcGFkZGluZ3NcblxuXG4gIHdpZHRoID0gd2lkdGggLSBwYXJzZUludCgkZWwuY3NzKCdwYWRkaW5nLWxlZnQnKSB8fCAwLCAxMCkgLSBwYXJzZUludCgkZWwuY3NzKCdwYWRkaW5nLXJpZ2h0JykgfHwgMCwgMTApO1xuICBoZWlnaHQgPSBoZWlnaHQgLSBwYXJzZUludCgkZWwuY3NzKCdwYWRkaW5nLXRvcCcpIHx8IDAsIDEwKSAtIHBhcnNlSW50KCRlbC5jc3MoJ3BhZGRpbmctYm90dG9tJykgfHwgMCwgMTApO1xuICBpZiAoTnVtYmVyLmlzTmFOKHdpZHRoKSkgd2lkdGggPSAwO1xuICBpZiAoTnVtYmVyLmlzTmFOKGhlaWdodCkpIGhlaWdodCA9IDA7XG4gIE9iamVjdC5hc3NpZ24oc3dpcGVyLCB7XG4gICAgd2lkdGgsXG4gICAgaGVpZ2h0LFxuICAgIHNpemU6IHN3aXBlci5pc0hvcml6b250YWwoKSA/IHdpZHRoIDogaGVpZ2h0XG4gIH0pO1xufSIsImltcG9ydCB7IHNldENTU1Byb3BlcnR5IH0gZnJvbSAnLi4vLi4vc2hhcmVkL3V0aWxzLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHVwZGF0ZVNsaWRlcygpIHtcbiAgY29uc3Qgc3dpcGVyID0gdGhpcztcblxuICBmdW5jdGlvbiBnZXREaXJlY3Rpb25MYWJlbChwcm9wZXJ0eSkge1xuICAgIGlmIChzd2lwZXIuaXNIb3Jpem9udGFsKCkpIHtcbiAgICAgIHJldHVybiBwcm9wZXJ0eTtcbiAgICB9IC8vIHByZXR0aWVyLWlnbm9yZVxuXG5cbiAgICByZXR1cm4ge1xuICAgICAgJ3dpZHRoJzogJ2hlaWdodCcsXG4gICAgICAnbWFyZ2luLXRvcCc6ICdtYXJnaW4tbGVmdCcsXG4gICAgICAnbWFyZ2luLWJvdHRvbSAnOiAnbWFyZ2luLXJpZ2h0JyxcbiAgICAgICdtYXJnaW4tbGVmdCc6ICdtYXJnaW4tdG9wJyxcbiAgICAgICdtYXJnaW4tcmlnaHQnOiAnbWFyZ2luLWJvdHRvbScsXG4gICAgICAncGFkZGluZy1sZWZ0JzogJ3BhZGRpbmctdG9wJyxcbiAgICAgICdwYWRkaW5nLXJpZ2h0JzogJ3BhZGRpbmctYm90dG9tJyxcbiAgICAgICdtYXJnaW5SaWdodCc6ICdtYXJnaW5Cb3R0b20nXG4gICAgfVtwcm9wZXJ0eV07XG4gIH1cblxuICBmdW5jdGlvbiBnZXREaXJlY3Rpb25Qcm9wZXJ0eVZhbHVlKG5vZGUsIGxhYmVsKSB7XG4gICAgcmV0dXJuIHBhcnNlRmxvYXQobm9kZS5nZXRQcm9wZXJ0eVZhbHVlKGdldERpcmVjdGlvbkxhYmVsKGxhYmVsKSkgfHwgMCk7XG4gIH1cblxuICBjb25zdCBwYXJhbXMgPSBzd2lwZXIucGFyYW1zO1xuICBjb25zdCB7XG4gICAgJHdyYXBwZXJFbCxcbiAgICBzaXplOiBzd2lwZXJTaXplLFxuICAgIHJ0bFRyYW5zbGF0ZTogcnRsLFxuICAgIHdyb25nUlRMXG4gIH0gPSBzd2lwZXI7XG4gIGNvbnN0IGlzVmlydHVhbCA9IHN3aXBlci52aXJ0dWFsICYmIHBhcmFtcy52aXJ0dWFsLmVuYWJsZWQ7XG4gIGNvbnN0IHByZXZpb3VzU2xpZGVzTGVuZ3RoID0gaXNWaXJ0dWFsID8gc3dpcGVyLnZpcnR1YWwuc2xpZGVzLmxlbmd0aCA6IHN3aXBlci5zbGlkZXMubGVuZ3RoO1xuICBjb25zdCBzbGlkZXMgPSAkd3JhcHBlckVsLmNoaWxkcmVuKGAuJHtzd2lwZXIucGFyYW1zLnNsaWRlQ2xhc3N9YCk7XG4gIGNvbnN0IHNsaWRlc0xlbmd0aCA9IGlzVmlydHVhbCA/IHN3aXBlci52aXJ0dWFsLnNsaWRlcy5sZW5ndGggOiBzbGlkZXMubGVuZ3RoO1xuICBsZXQgc25hcEdyaWQgPSBbXTtcbiAgY29uc3Qgc2xpZGVzR3JpZCA9IFtdO1xuICBjb25zdCBzbGlkZXNTaXplc0dyaWQgPSBbXTtcbiAgbGV0IG9mZnNldEJlZm9yZSA9IHBhcmFtcy5zbGlkZXNPZmZzZXRCZWZvcmU7XG5cbiAgaWYgKHR5cGVvZiBvZmZzZXRCZWZvcmUgPT09ICdmdW5jdGlvbicpIHtcbiAgICBvZmZzZXRCZWZvcmUgPSBwYXJhbXMuc2xpZGVzT2Zmc2V0QmVmb3JlLmNhbGwoc3dpcGVyKTtcbiAgfVxuXG4gIGxldCBvZmZzZXRBZnRlciA9IHBhcmFtcy5zbGlkZXNPZmZzZXRBZnRlcjtcblxuICBpZiAodHlwZW9mIG9mZnNldEFmdGVyID09PSAnZnVuY3Rpb24nKSB7XG4gICAgb2Zmc2V0QWZ0ZXIgPSBwYXJhbXMuc2xpZGVzT2Zmc2V0QWZ0ZXIuY2FsbChzd2lwZXIpO1xuICB9XG5cbiAgY29uc3QgcHJldmlvdXNTbmFwR3JpZExlbmd0aCA9IHN3aXBlci5zbmFwR3JpZC5sZW5ndGg7XG4gIGNvbnN0IHByZXZpb3VzU2xpZGVzR3JpZExlbmd0aCA9IHN3aXBlci5zbGlkZXNHcmlkLmxlbmd0aDtcbiAgbGV0IHNwYWNlQmV0d2VlbiA9IHBhcmFtcy5zcGFjZUJldHdlZW47XG4gIGxldCBzbGlkZVBvc2l0aW9uID0gLW9mZnNldEJlZm9yZTtcbiAgbGV0IHByZXZTbGlkZVNpemUgPSAwO1xuICBsZXQgaW5kZXggPSAwO1xuXG4gIGlmICh0eXBlb2Ygc3dpcGVyU2l6ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAodHlwZW9mIHNwYWNlQmV0d2VlbiA9PT0gJ3N0cmluZycgJiYgc3BhY2VCZXR3ZWVuLmluZGV4T2YoJyUnKSA+PSAwKSB7XG4gICAgc3BhY2VCZXR3ZWVuID0gcGFyc2VGbG9hdChzcGFjZUJldHdlZW4ucmVwbGFjZSgnJScsICcnKSkgLyAxMDAgKiBzd2lwZXJTaXplO1xuICB9XG5cbiAgc3dpcGVyLnZpcnR1YWxTaXplID0gLXNwYWNlQmV0d2VlbjsgLy8gcmVzZXQgbWFyZ2luc1xuXG4gIGlmIChydGwpIHNsaWRlcy5jc3Moe1xuICAgIG1hcmdpbkxlZnQ6ICcnLFxuICAgIG1hcmdpbkJvdHRvbTogJycsXG4gICAgbWFyZ2luVG9wOiAnJ1xuICB9KTtlbHNlIHNsaWRlcy5jc3Moe1xuICAgIG1hcmdpblJpZ2h0OiAnJyxcbiAgICBtYXJnaW5Cb3R0b206ICcnLFxuICAgIG1hcmdpblRvcDogJydcbiAgfSk7IC8vIHJlc2V0IGNzc01vZGUgb2Zmc2V0c1xuXG4gIGlmIChwYXJhbXMuY2VudGVyZWRTbGlkZXMgJiYgcGFyYW1zLmNzc01vZGUpIHtcbiAgICBzZXRDU1NQcm9wZXJ0eShzd2lwZXIud3JhcHBlckVsLCAnLS1zd2lwZXItY2VudGVyZWQtb2Zmc2V0LWJlZm9yZScsICcnKTtcbiAgICBzZXRDU1NQcm9wZXJ0eShzd2lwZXIud3JhcHBlckVsLCAnLS1zd2lwZXItY2VudGVyZWQtb2Zmc2V0LWFmdGVyJywgJycpO1xuICB9XG5cbiAgY29uc3QgZ3JpZEVuYWJsZWQgPSBwYXJhbXMuZ3JpZCAmJiBwYXJhbXMuZ3JpZC5yb3dzID4gMSAmJiBzd2lwZXIuZ3JpZDtcblxuICBpZiAoZ3JpZEVuYWJsZWQpIHtcbiAgICBzd2lwZXIuZ3JpZC5pbml0U2xpZGVzKHNsaWRlc0xlbmd0aCk7XG4gIH0gLy8gQ2FsYyBzbGlkZXNcblxuXG4gIGxldCBzbGlkZVNpemU7XG4gIGNvbnN0IHNob3VsZFJlc2V0U2xpZGVTaXplID0gcGFyYW1zLnNsaWRlc1BlclZpZXcgPT09ICdhdXRvJyAmJiBwYXJhbXMuYnJlYWtwb2ludHMgJiYgT2JqZWN0LmtleXMocGFyYW1zLmJyZWFrcG9pbnRzKS5maWx0ZXIoa2V5ID0+IHtcbiAgICByZXR1cm4gdHlwZW9mIHBhcmFtcy5icmVha3BvaW50c1trZXldLnNsaWRlc1BlclZpZXcgIT09ICd1bmRlZmluZWQnO1xuICB9KS5sZW5ndGggPiAwO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgc2xpZGVzTGVuZ3RoOyBpICs9IDEpIHtcbiAgICBzbGlkZVNpemUgPSAwO1xuICAgIGNvbnN0IHNsaWRlID0gc2xpZGVzLmVxKGkpO1xuXG4gICAgaWYgKGdyaWRFbmFibGVkKSB7XG4gICAgICBzd2lwZXIuZ3JpZC51cGRhdGVTbGlkZShpLCBzbGlkZSwgc2xpZGVzTGVuZ3RoLCBnZXREaXJlY3Rpb25MYWJlbCk7XG4gICAgfVxuXG4gICAgaWYgKHNsaWRlLmNzcygnZGlzcGxheScpID09PSAnbm9uZScpIGNvbnRpbnVlOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lXG5cbiAgICBpZiAocGFyYW1zLnNsaWRlc1BlclZpZXcgPT09ICdhdXRvJykge1xuICAgICAgaWYgKHNob3VsZFJlc2V0U2xpZGVTaXplKSB7XG4gICAgICAgIHNsaWRlc1tpXS5zdHlsZVtnZXREaXJlY3Rpb25MYWJlbCgnd2lkdGgnKV0gPSBgYDtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2xpZGVTdHlsZXMgPSBnZXRDb21wdXRlZFN0eWxlKHNsaWRlWzBdKTtcbiAgICAgIGNvbnN0IGN1cnJlbnRUcmFuc2Zvcm0gPSBzbGlkZVswXS5zdHlsZS50cmFuc2Zvcm07XG4gICAgICBjb25zdCBjdXJyZW50V2ViS2l0VHJhbnNmb3JtID0gc2xpZGVbMF0uc3R5bGUud2Via2l0VHJhbnNmb3JtO1xuXG4gICAgICBpZiAoY3VycmVudFRyYW5zZm9ybSkge1xuICAgICAgICBzbGlkZVswXS5zdHlsZS50cmFuc2Zvcm0gPSAnbm9uZSc7XG4gICAgICB9XG5cbiAgICAgIGlmIChjdXJyZW50V2ViS2l0VHJhbnNmb3JtKSB7XG4gICAgICAgIHNsaWRlWzBdLnN0eWxlLndlYmtpdFRyYW5zZm9ybSA9ICdub25lJztcbiAgICAgIH1cblxuICAgICAgaWYgKHBhcmFtcy5yb3VuZExlbmd0aHMpIHtcbiAgICAgICAgc2xpZGVTaXplID0gc3dpcGVyLmlzSG9yaXpvbnRhbCgpID8gc2xpZGUub3V0ZXJXaWR0aCh0cnVlKSA6IHNsaWRlLm91dGVySGVpZ2h0KHRydWUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG4gICAgICAgIGNvbnN0IHdpZHRoID0gZ2V0RGlyZWN0aW9uUHJvcGVydHlWYWx1ZShzbGlkZVN0eWxlcywgJ3dpZHRoJyk7XG4gICAgICAgIGNvbnN0IHBhZGRpbmdMZWZ0ID0gZ2V0RGlyZWN0aW9uUHJvcGVydHlWYWx1ZShzbGlkZVN0eWxlcywgJ3BhZGRpbmctbGVmdCcpO1xuICAgICAgICBjb25zdCBwYWRkaW5nUmlnaHQgPSBnZXREaXJlY3Rpb25Qcm9wZXJ0eVZhbHVlKHNsaWRlU3R5bGVzLCAncGFkZGluZy1yaWdodCcpO1xuICAgICAgICBjb25zdCBtYXJnaW5MZWZ0ID0gZ2V0RGlyZWN0aW9uUHJvcGVydHlWYWx1ZShzbGlkZVN0eWxlcywgJ21hcmdpbi1sZWZ0Jyk7XG4gICAgICAgIGNvbnN0IG1hcmdpblJpZ2h0ID0gZ2V0RGlyZWN0aW9uUHJvcGVydHlWYWx1ZShzbGlkZVN0eWxlcywgJ21hcmdpbi1yaWdodCcpO1xuICAgICAgICBjb25zdCBib3hTaXppbmcgPSBzbGlkZVN0eWxlcy5nZXRQcm9wZXJ0eVZhbHVlKCdib3gtc2l6aW5nJyk7XG5cbiAgICAgICAgaWYgKGJveFNpemluZyAmJiBib3hTaXppbmcgPT09ICdib3JkZXItYm94Jykge1xuICAgICAgICAgIHNsaWRlU2l6ZSA9IHdpZHRoICsgbWFyZ2luTGVmdCArIG1hcmdpblJpZ2h0O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnN0IHtcbiAgICAgICAgICAgIGNsaWVudFdpZHRoLFxuICAgICAgICAgICAgb2Zmc2V0V2lkdGhcbiAgICAgICAgICB9ID0gc2xpZGVbMF07XG4gICAgICAgICAgc2xpZGVTaXplID0gd2lkdGggKyBwYWRkaW5nTGVmdCArIHBhZGRpbmdSaWdodCArIG1hcmdpbkxlZnQgKyBtYXJnaW5SaWdodCArIChvZmZzZXRXaWR0aCAtIGNsaWVudFdpZHRoKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoY3VycmVudFRyYW5zZm9ybSkge1xuICAgICAgICBzbGlkZVswXS5zdHlsZS50cmFuc2Zvcm0gPSBjdXJyZW50VHJhbnNmb3JtO1xuICAgICAgfVxuXG4gICAgICBpZiAoY3VycmVudFdlYktpdFRyYW5zZm9ybSkge1xuICAgICAgICBzbGlkZVswXS5zdHlsZS53ZWJraXRUcmFuc2Zvcm0gPSBjdXJyZW50V2ViS2l0VHJhbnNmb3JtO1xuICAgICAgfVxuXG4gICAgICBpZiAocGFyYW1zLnJvdW5kTGVuZ3Rocykgc2xpZGVTaXplID0gTWF0aC5mbG9vcihzbGlkZVNpemUpO1xuICAgIH0gZWxzZSB7XG4gICAgICBzbGlkZVNpemUgPSAoc3dpcGVyU2l6ZSAtIChwYXJhbXMuc2xpZGVzUGVyVmlldyAtIDEpICogc3BhY2VCZXR3ZWVuKSAvIHBhcmFtcy5zbGlkZXNQZXJWaWV3O1xuICAgICAgaWYgKHBhcmFtcy5yb3VuZExlbmd0aHMpIHNsaWRlU2l6ZSA9IE1hdGguZmxvb3Ioc2xpZGVTaXplKTtcblxuICAgICAgaWYgKHNsaWRlc1tpXSkge1xuICAgICAgICBzbGlkZXNbaV0uc3R5bGVbZ2V0RGlyZWN0aW9uTGFiZWwoJ3dpZHRoJyldID0gYCR7c2xpZGVTaXplfXB4YDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoc2xpZGVzW2ldKSB7XG4gICAgICBzbGlkZXNbaV0uc3dpcGVyU2xpZGVTaXplID0gc2xpZGVTaXplO1xuICAgIH1cblxuICAgIHNsaWRlc1NpemVzR3JpZC5wdXNoKHNsaWRlU2l6ZSk7XG5cbiAgICBpZiAocGFyYW1zLmNlbnRlcmVkU2xpZGVzKSB7XG4gICAgICBzbGlkZVBvc2l0aW9uID0gc2xpZGVQb3NpdGlvbiArIHNsaWRlU2l6ZSAvIDIgKyBwcmV2U2xpZGVTaXplIC8gMiArIHNwYWNlQmV0d2VlbjtcbiAgICAgIGlmIChwcmV2U2xpZGVTaXplID09PSAwICYmIGkgIT09IDApIHNsaWRlUG9zaXRpb24gPSBzbGlkZVBvc2l0aW9uIC0gc3dpcGVyU2l6ZSAvIDIgLSBzcGFjZUJldHdlZW47XG4gICAgICBpZiAoaSA9PT0gMCkgc2xpZGVQb3NpdGlvbiA9IHNsaWRlUG9zaXRpb24gLSBzd2lwZXJTaXplIC8gMiAtIHNwYWNlQmV0d2VlbjtcbiAgICAgIGlmIChNYXRoLmFicyhzbGlkZVBvc2l0aW9uKSA8IDEgLyAxMDAwKSBzbGlkZVBvc2l0aW9uID0gMDtcbiAgICAgIGlmIChwYXJhbXMucm91bmRMZW5ndGhzKSBzbGlkZVBvc2l0aW9uID0gTWF0aC5mbG9vcihzbGlkZVBvc2l0aW9uKTtcbiAgICAgIGlmIChpbmRleCAlIHBhcmFtcy5zbGlkZXNQZXJHcm91cCA9PT0gMCkgc25hcEdyaWQucHVzaChzbGlkZVBvc2l0aW9uKTtcbiAgICAgIHNsaWRlc0dyaWQucHVzaChzbGlkZVBvc2l0aW9uKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKHBhcmFtcy5yb3VuZExlbmd0aHMpIHNsaWRlUG9zaXRpb24gPSBNYXRoLmZsb29yKHNsaWRlUG9zaXRpb24pO1xuICAgICAgaWYgKChpbmRleCAtIE1hdGgubWluKHN3aXBlci5wYXJhbXMuc2xpZGVzUGVyR3JvdXBTa2lwLCBpbmRleCkpICUgc3dpcGVyLnBhcmFtcy5zbGlkZXNQZXJHcm91cCA9PT0gMCkgc25hcEdyaWQucHVzaChzbGlkZVBvc2l0aW9uKTtcbiAgICAgIHNsaWRlc0dyaWQucHVzaChzbGlkZVBvc2l0aW9uKTtcbiAgICAgIHNsaWRlUG9zaXRpb24gPSBzbGlkZVBvc2l0aW9uICsgc2xpZGVTaXplICsgc3BhY2VCZXR3ZWVuO1xuICAgIH1cblxuICAgIHN3aXBlci52aXJ0dWFsU2l6ZSArPSBzbGlkZVNpemUgKyBzcGFjZUJldHdlZW47XG4gICAgcHJldlNsaWRlU2l6ZSA9IHNsaWRlU2l6ZTtcbiAgICBpbmRleCArPSAxO1xuICB9XG5cbiAgc3dpcGVyLnZpcnR1YWxTaXplID0gTWF0aC5tYXgoc3dpcGVyLnZpcnR1YWxTaXplLCBzd2lwZXJTaXplKSArIG9mZnNldEFmdGVyO1xuXG4gIGlmIChydGwgJiYgd3JvbmdSVEwgJiYgKHBhcmFtcy5lZmZlY3QgPT09ICdzbGlkZScgfHwgcGFyYW1zLmVmZmVjdCA9PT0gJ2NvdmVyZmxvdycpKSB7XG4gICAgJHdyYXBwZXJFbC5jc3Moe1xuICAgICAgd2lkdGg6IGAke3N3aXBlci52aXJ0dWFsU2l6ZSArIHBhcmFtcy5zcGFjZUJldHdlZW59cHhgXG4gICAgfSk7XG4gIH1cblxuICBpZiAocGFyYW1zLnNldFdyYXBwZXJTaXplKSB7XG4gICAgJHdyYXBwZXJFbC5jc3Moe1xuICAgICAgW2dldERpcmVjdGlvbkxhYmVsKCd3aWR0aCcpXTogYCR7c3dpcGVyLnZpcnR1YWxTaXplICsgcGFyYW1zLnNwYWNlQmV0d2Vlbn1weGBcbiAgICB9KTtcbiAgfVxuXG4gIGlmIChncmlkRW5hYmxlZCkge1xuICAgIHN3aXBlci5ncmlkLnVwZGF0ZVdyYXBwZXJTaXplKHNsaWRlU2l6ZSwgc25hcEdyaWQsIGdldERpcmVjdGlvbkxhYmVsKTtcbiAgfSAvLyBSZW1vdmUgbGFzdCBncmlkIGVsZW1lbnRzIGRlcGVuZGluZyBvbiB3aWR0aFxuXG5cbiAgaWYgKCFwYXJhbXMuY2VudGVyZWRTbGlkZXMpIHtcbiAgICBjb25zdCBuZXdTbGlkZXNHcmlkID0gW107XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNuYXBHcmlkLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICBsZXQgc2xpZGVzR3JpZEl0ZW0gPSBzbmFwR3JpZFtpXTtcbiAgICAgIGlmIChwYXJhbXMucm91bmRMZW5ndGhzKSBzbGlkZXNHcmlkSXRlbSA9IE1hdGguZmxvb3Ioc2xpZGVzR3JpZEl0ZW0pO1xuXG4gICAgICBpZiAoc25hcEdyaWRbaV0gPD0gc3dpcGVyLnZpcnR1YWxTaXplIC0gc3dpcGVyU2l6ZSkge1xuICAgICAgICBuZXdTbGlkZXNHcmlkLnB1c2goc2xpZGVzR3JpZEl0ZW0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHNuYXBHcmlkID0gbmV3U2xpZGVzR3JpZDtcblxuICAgIGlmIChNYXRoLmZsb29yKHN3aXBlci52aXJ0dWFsU2l6ZSAtIHN3aXBlclNpemUpIC0gTWF0aC5mbG9vcihzbmFwR3JpZFtzbmFwR3JpZC5sZW5ndGggLSAxXSkgPiAxKSB7XG4gICAgICBzbmFwR3JpZC5wdXNoKHN3aXBlci52aXJ0dWFsU2l6ZSAtIHN3aXBlclNpemUpO1xuICAgIH1cbiAgfVxuXG4gIGlmIChzbmFwR3JpZC5sZW5ndGggPT09IDApIHNuYXBHcmlkID0gWzBdO1xuXG4gIGlmIChwYXJhbXMuc3BhY2VCZXR3ZWVuICE9PSAwKSB7XG4gICAgY29uc3Qga2V5ID0gc3dpcGVyLmlzSG9yaXpvbnRhbCgpICYmIHJ0bCA/ICdtYXJnaW5MZWZ0JyA6IGdldERpcmVjdGlvbkxhYmVsKCdtYXJnaW5SaWdodCcpO1xuICAgIHNsaWRlcy5maWx0ZXIoKF8sIHNsaWRlSW5kZXgpID0+IHtcbiAgICAgIGlmICghcGFyYW1zLmNzc01vZGUpIHJldHVybiB0cnVlO1xuXG4gICAgICBpZiAoc2xpZGVJbmRleCA9PT0gc2xpZGVzLmxlbmd0aCAtIDEpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9KS5jc3Moe1xuICAgICAgW2tleV06IGAke3NwYWNlQmV0d2Vlbn1weGBcbiAgICB9KTtcbiAgfVxuXG4gIGlmIChwYXJhbXMuY2VudGVyZWRTbGlkZXMgJiYgcGFyYW1zLmNlbnRlcmVkU2xpZGVzQm91bmRzKSB7XG4gICAgbGV0IGFsbFNsaWRlc1NpemUgPSAwO1xuICAgIHNsaWRlc1NpemVzR3JpZC5mb3JFYWNoKHNsaWRlU2l6ZVZhbHVlID0+IHtcbiAgICAgIGFsbFNsaWRlc1NpemUgKz0gc2xpZGVTaXplVmFsdWUgKyAocGFyYW1zLnNwYWNlQmV0d2VlbiA/IHBhcmFtcy5zcGFjZUJldHdlZW4gOiAwKTtcbiAgICB9KTtcbiAgICBhbGxTbGlkZXNTaXplIC09IHBhcmFtcy5zcGFjZUJldHdlZW47XG4gICAgY29uc3QgbWF4U25hcCA9IGFsbFNsaWRlc1NpemUgLSBzd2lwZXJTaXplO1xuICAgIHNuYXBHcmlkID0gc25hcEdyaWQubWFwKHNuYXAgPT4ge1xuICAgICAgaWYgKHNuYXAgPCAwKSByZXR1cm4gLW9mZnNldEJlZm9yZTtcbiAgICAgIGlmIChzbmFwID4gbWF4U25hcCkgcmV0dXJuIG1heFNuYXAgKyBvZmZzZXRBZnRlcjtcbiAgICAgIHJldHVybiBzbmFwO1xuICAgIH0pO1xuICB9XG5cbiAgaWYgKHBhcmFtcy5jZW50ZXJJbnN1ZmZpY2llbnRTbGlkZXMpIHtcbiAgICBsZXQgYWxsU2xpZGVzU2l6ZSA9IDA7XG4gICAgc2xpZGVzU2l6ZXNHcmlkLmZvckVhY2goc2xpZGVTaXplVmFsdWUgPT4ge1xuICAgICAgYWxsU2xpZGVzU2l6ZSArPSBzbGlkZVNpemVWYWx1ZSArIChwYXJhbXMuc3BhY2VCZXR3ZWVuID8gcGFyYW1zLnNwYWNlQmV0d2VlbiA6IDApO1xuICAgIH0pO1xuICAgIGFsbFNsaWRlc1NpemUgLT0gcGFyYW1zLnNwYWNlQmV0d2VlbjtcblxuICAgIGlmIChhbGxTbGlkZXNTaXplIDwgc3dpcGVyU2l6ZSkge1xuICAgICAgY29uc3QgYWxsU2xpZGVzT2Zmc2V0ID0gKHN3aXBlclNpemUgLSBhbGxTbGlkZXNTaXplKSAvIDI7XG4gICAgICBzbmFwR3JpZC5mb3JFYWNoKChzbmFwLCBzbmFwSW5kZXgpID0+IHtcbiAgICAgICAgc25hcEdyaWRbc25hcEluZGV4XSA9IHNuYXAgLSBhbGxTbGlkZXNPZmZzZXQ7XG4gICAgICB9KTtcbiAgICAgIHNsaWRlc0dyaWQuZm9yRWFjaCgoc25hcCwgc25hcEluZGV4KSA9PiB7XG4gICAgICAgIHNsaWRlc0dyaWRbc25hcEluZGV4XSA9IHNuYXAgKyBhbGxTbGlkZXNPZmZzZXQ7XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBPYmplY3QuYXNzaWduKHN3aXBlciwge1xuICAgIHNsaWRlcyxcbiAgICBzbmFwR3JpZCxcbiAgICBzbGlkZXNHcmlkLFxuICAgIHNsaWRlc1NpemVzR3JpZFxuICB9KTtcblxuICBpZiAocGFyYW1zLmNlbnRlcmVkU2xpZGVzICYmIHBhcmFtcy5jc3NNb2RlICYmICFwYXJhbXMuY2VudGVyZWRTbGlkZXNCb3VuZHMpIHtcbiAgICBzZXRDU1NQcm9wZXJ0eShzd2lwZXIud3JhcHBlckVsLCAnLS1zd2lwZXItY2VudGVyZWQtb2Zmc2V0LWJlZm9yZScsIGAkey1zbmFwR3JpZFswXX1weGApO1xuICAgIHNldENTU1Byb3BlcnR5KHN3aXBlci53cmFwcGVyRWwsICctLXN3aXBlci1jZW50ZXJlZC1vZmZzZXQtYWZ0ZXInLCBgJHtzd2lwZXIuc2l6ZSAvIDIgLSBzbGlkZXNTaXplc0dyaWRbc2xpZGVzU2l6ZXNHcmlkLmxlbmd0aCAtIDFdIC8gMn1weGApO1xuICAgIGNvbnN0IGFkZFRvU25hcEdyaWQgPSAtc3dpcGVyLnNuYXBHcmlkWzBdO1xuICAgIGNvbnN0IGFkZFRvU2xpZGVzR3JpZCA9IC1zd2lwZXIuc2xpZGVzR3JpZFswXTtcbiAgICBzd2lwZXIuc25hcEdyaWQgPSBzd2lwZXIuc25hcEdyaWQubWFwKHYgPT4gdiArIGFkZFRvU25hcEdyaWQpO1xuICAgIHN3aXBlci5zbGlkZXNHcmlkID0gc3dpcGVyLnNsaWRlc0dyaWQubWFwKHYgPT4gdiArIGFkZFRvU2xpZGVzR3JpZCk7XG4gIH1cblxuICBpZiAoc2xpZGVzTGVuZ3RoICE9PSBwcmV2aW91c1NsaWRlc0xlbmd0aCkge1xuICAgIHN3aXBlci5lbWl0KCdzbGlkZXNMZW5ndGhDaGFuZ2UnKTtcbiAgfVxuXG4gIGlmIChzbmFwR3JpZC5sZW5ndGggIT09IHByZXZpb3VzU25hcEdyaWRMZW5ndGgpIHtcbiAgICBpZiAoc3dpcGVyLnBhcmFtcy53YXRjaE92ZXJmbG93KSBzd2lwZXIuY2hlY2tPdmVyZmxvdygpO1xuICAgIHN3aXBlci5lbWl0KCdzbmFwR3JpZExlbmd0aENoYW5nZScpO1xuICB9XG5cbiAgaWYgKHNsaWRlc0dyaWQubGVuZ3RoICE9PSBwcmV2aW91c1NsaWRlc0dyaWRMZW5ndGgpIHtcbiAgICBzd2lwZXIuZW1pdCgnc2xpZGVzR3JpZExlbmd0aENoYW5nZScpO1xuICB9XG5cbiAgaWYgKHBhcmFtcy53YXRjaFNsaWRlc1Byb2dyZXNzKSB7XG4gICAgc3dpcGVyLnVwZGF0ZVNsaWRlc09mZnNldCgpO1xuICB9XG5cbiAgaWYgKCFpc1ZpcnR1YWwgJiYgIXBhcmFtcy5jc3NNb2RlICYmIChwYXJhbXMuZWZmZWN0ID09PSAnc2xpZGUnIHx8IHBhcmFtcy5lZmZlY3QgPT09ICdmYWRlJykpIHtcbiAgICBjb25zdCBiYWNrRmFjZUhpZGRlbkNsYXNzID0gYCR7cGFyYW1zLmNvbnRhaW5lck1vZGlmaWVyQ2xhc3N9YmFja2ZhY2UtaGlkZGVuYDtcbiAgICBjb25zdCBoYXNDbGFzc0JhY2tmYWNlQ2xhc3NBZGRlZCA9IHN3aXBlci4kZWwuaGFzQ2xhc3MoYmFja0ZhY2VIaWRkZW5DbGFzcyk7XG5cbiAgICBpZiAoc2xpZGVzTGVuZ3RoIDw9IHBhcmFtcy5tYXhCYWNrZmFjZUhpZGRlblNsaWRlcykge1xuICAgICAgaWYgKCFoYXNDbGFzc0JhY2tmYWNlQ2xhc3NBZGRlZCkgc3dpcGVyLiRlbC5hZGRDbGFzcyhiYWNrRmFjZUhpZGRlbkNsYXNzKTtcbiAgICB9IGVsc2UgaWYgKGhhc0NsYXNzQmFja2ZhY2VDbGFzc0FkZGVkKSB7XG4gICAgICBzd2lwZXIuJGVsLnJlbW92ZUNsYXNzKGJhY2tGYWNlSGlkZGVuQ2xhc3MpO1xuICAgIH1cbiAgfVxufSIsImltcG9ydCAkIGZyb20gJy4uLy4uL3NoYXJlZC9kb20uanMnO1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdXBkYXRlQXV0b0hlaWdodChzcGVlZCkge1xuICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICBjb25zdCBhY3RpdmVTbGlkZXMgPSBbXTtcbiAgY29uc3QgaXNWaXJ0dWFsID0gc3dpcGVyLnZpcnR1YWwgJiYgc3dpcGVyLnBhcmFtcy52aXJ0dWFsLmVuYWJsZWQ7XG4gIGxldCBuZXdIZWlnaHQgPSAwO1xuICBsZXQgaTtcblxuICBpZiAodHlwZW9mIHNwZWVkID09PSAnbnVtYmVyJykge1xuICAgIHN3aXBlci5zZXRUcmFuc2l0aW9uKHNwZWVkKTtcbiAgfSBlbHNlIGlmIChzcGVlZCA9PT0gdHJ1ZSkge1xuICAgIHN3aXBlci5zZXRUcmFuc2l0aW9uKHN3aXBlci5wYXJhbXMuc3BlZWQpO1xuICB9XG5cbiAgY29uc3QgZ2V0U2xpZGVCeUluZGV4ID0gaW5kZXggPT4ge1xuICAgIGlmIChpc1ZpcnR1YWwpIHtcbiAgICAgIHJldHVybiBzd2lwZXIuc2xpZGVzLmZpbHRlcihlbCA9PiBwYXJzZUludChlbC5nZXRBdHRyaWJ1dGUoJ2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4JyksIDEwKSA9PT0gaW5kZXgpWzBdO1xuICAgIH1cblxuICAgIHJldHVybiBzd2lwZXIuc2xpZGVzLmVxKGluZGV4KVswXTtcbiAgfTsgLy8gRmluZCBzbGlkZXMgY3VycmVudGx5IGluIHZpZXdcblxuXG4gIGlmIChzd2lwZXIucGFyYW1zLnNsaWRlc1BlclZpZXcgIT09ICdhdXRvJyAmJiBzd2lwZXIucGFyYW1zLnNsaWRlc1BlclZpZXcgPiAxKSB7XG4gICAgaWYgKHN3aXBlci5wYXJhbXMuY2VudGVyZWRTbGlkZXMpIHtcbiAgICAgIChzd2lwZXIudmlzaWJsZVNsaWRlcyB8fCAkKFtdKSkuZWFjaChzbGlkZSA9PiB7XG4gICAgICAgIGFjdGl2ZVNsaWRlcy5wdXNoKHNsaWRlKTtcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBmb3IgKGkgPSAwOyBpIDwgTWF0aC5jZWlsKHN3aXBlci5wYXJhbXMuc2xpZGVzUGVyVmlldyk7IGkgKz0gMSkge1xuICAgICAgICBjb25zdCBpbmRleCA9IHN3aXBlci5hY3RpdmVJbmRleCArIGk7XG4gICAgICAgIGlmIChpbmRleCA+IHN3aXBlci5zbGlkZXMubGVuZ3RoICYmICFpc1ZpcnR1YWwpIGJyZWFrO1xuICAgICAgICBhY3RpdmVTbGlkZXMucHVzaChnZXRTbGlkZUJ5SW5kZXgoaW5kZXgpKTtcbiAgICAgIH1cbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgYWN0aXZlU2xpZGVzLnB1c2goZ2V0U2xpZGVCeUluZGV4KHN3aXBlci5hY3RpdmVJbmRleCkpO1xuICB9IC8vIEZpbmQgbmV3IGhlaWdodCBmcm9tIGhpZ2hlc3Qgc2xpZGUgaW4gdmlld1xuXG5cbiAgZm9yIChpID0gMDsgaSA8IGFjdGl2ZVNsaWRlcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgIGlmICh0eXBlb2YgYWN0aXZlU2xpZGVzW2ldICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgY29uc3QgaGVpZ2h0ID0gYWN0aXZlU2xpZGVzW2ldLm9mZnNldEhlaWdodDtcbiAgICAgIG5ld0hlaWdodCA9IGhlaWdodCA+IG5ld0hlaWdodCA/IGhlaWdodCA6IG5ld0hlaWdodDtcbiAgICB9XG4gIH0gLy8gVXBkYXRlIEhlaWdodFxuXG5cbiAgaWYgKG5ld0hlaWdodCB8fCBuZXdIZWlnaHQgPT09IDApIHN3aXBlci4kd3JhcHBlckVsLmNzcygnaGVpZ2h0JywgYCR7bmV3SGVpZ2h0fXB4YCk7XG59IiwiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdXBkYXRlU2xpZGVzT2Zmc2V0KCkge1xuICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICBjb25zdCBzbGlkZXMgPSBzd2lwZXIuc2xpZGVzO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgc2xpZGVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgc2xpZGVzW2ldLnN3aXBlclNsaWRlT2Zmc2V0ID0gc3dpcGVyLmlzSG9yaXpvbnRhbCgpID8gc2xpZGVzW2ldLm9mZnNldExlZnQgOiBzbGlkZXNbaV0ub2Zmc2V0VG9wO1xuICB9XG59IiwiaW1wb3J0ICQgZnJvbSAnLi4vLi4vc2hhcmVkL2RvbS5qcyc7XG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB1cGRhdGVTbGlkZXNQcm9ncmVzcyh0cmFuc2xhdGUgPSB0aGlzICYmIHRoaXMudHJhbnNsYXRlIHx8IDApIHtcbiAgY29uc3Qgc3dpcGVyID0gdGhpcztcbiAgY29uc3QgcGFyYW1zID0gc3dpcGVyLnBhcmFtcztcbiAgY29uc3Qge1xuICAgIHNsaWRlcyxcbiAgICBydGxUcmFuc2xhdGU6IHJ0bCxcbiAgICBzbmFwR3JpZFxuICB9ID0gc3dpcGVyO1xuICBpZiAoc2xpZGVzLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICBpZiAodHlwZW9mIHNsaWRlc1swXS5zd2lwZXJTbGlkZU9mZnNldCA9PT0gJ3VuZGVmaW5lZCcpIHN3aXBlci51cGRhdGVTbGlkZXNPZmZzZXQoKTtcbiAgbGV0IG9mZnNldENlbnRlciA9IC10cmFuc2xhdGU7XG4gIGlmIChydGwpIG9mZnNldENlbnRlciA9IHRyYW5zbGF0ZTsgLy8gVmlzaWJsZSBTbGlkZXNcblxuICBzbGlkZXMucmVtb3ZlQ2xhc3MocGFyYW1zLnNsaWRlVmlzaWJsZUNsYXNzKTtcbiAgc3dpcGVyLnZpc2libGVTbGlkZXNJbmRleGVzID0gW107XG4gIHN3aXBlci52aXNpYmxlU2xpZGVzID0gW107XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBzbGlkZXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICBjb25zdCBzbGlkZSA9IHNsaWRlc1tpXTtcbiAgICBsZXQgc2xpZGVPZmZzZXQgPSBzbGlkZS5zd2lwZXJTbGlkZU9mZnNldDtcblxuICAgIGlmIChwYXJhbXMuY3NzTW9kZSAmJiBwYXJhbXMuY2VudGVyZWRTbGlkZXMpIHtcbiAgICAgIHNsaWRlT2Zmc2V0IC09IHNsaWRlc1swXS5zd2lwZXJTbGlkZU9mZnNldDtcbiAgICB9XG5cbiAgICBjb25zdCBzbGlkZVByb2dyZXNzID0gKG9mZnNldENlbnRlciArIChwYXJhbXMuY2VudGVyZWRTbGlkZXMgPyBzd2lwZXIubWluVHJhbnNsYXRlKCkgOiAwKSAtIHNsaWRlT2Zmc2V0KSAvIChzbGlkZS5zd2lwZXJTbGlkZVNpemUgKyBwYXJhbXMuc3BhY2VCZXR3ZWVuKTtcbiAgICBjb25zdCBvcmlnaW5hbFNsaWRlUHJvZ3Jlc3MgPSAob2Zmc2V0Q2VudGVyIC0gc25hcEdyaWRbMF0gKyAocGFyYW1zLmNlbnRlcmVkU2xpZGVzID8gc3dpcGVyLm1pblRyYW5zbGF0ZSgpIDogMCkgLSBzbGlkZU9mZnNldCkgLyAoc2xpZGUuc3dpcGVyU2xpZGVTaXplICsgcGFyYW1zLnNwYWNlQmV0d2Vlbik7XG4gICAgY29uc3Qgc2xpZGVCZWZvcmUgPSAtKG9mZnNldENlbnRlciAtIHNsaWRlT2Zmc2V0KTtcbiAgICBjb25zdCBzbGlkZUFmdGVyID0gc2xpZGVCZWZvcmUgKyBzd2lwZXIuc2xpZGVzU2l6ZXNHcmlkW2ldO1xuICAgIGNvbnN0IGlzVmlzaWJsZSA9IHNsaWRlQmVmb3JlID49IDAgJiYgc2xpZGVCZWZvcmUgPCBzd2lwZXIuc2l6ZSAtIDEgfHwgc2xpZGVBZnRlciA+IDEgJiYgc2xpZGVBZnRlciA8PSBzd2lwZXIuc2l6ZSB8fCBzbGlkZUJlZm9yZSA8PSAwICYmIHNsaWRlQWZ0ZXIgPj0gc3dpcGVyLnNpemU7XG5cbiAgICBpZiAoaXNWaXNpYmxlKSB7XG4gICAgICBzd2lwZXIudmlzaWJsZVNsaWRlcy5wdXNoKHNsaWRlKTtcbiAgICAgIHN3aXBlci52aXNpYmxlU2xpZGVzSW5kZXhlcy5wdXNoKGkpO1xuICAgICAgc2xpZGVzLmVxKGkpLmFkZENsYXNzKHBhcmFtcy5zbGlkZVZpc2libGVDbGFzcyk7XG4gICAgfVxuXG4gICAgc2xpZGUucHJvZ3Jlc3MgPSBydGwgPyAtc2xpZGVQcm9ncmVzcyA6IHNsaWRlUHJvZ3Jlc3M7XG4gICAgc2xpZGUub3JpZ2luYWxQcm9ncmVzcyA9IHJ0bCA/IC1vcmlnaW5hbFNsaWRlUHJvZ3Jlc3MgOiBvcmlnaW5hbFNsaWRlUHJvZ3Jlc3M7XG4gIH1cblxuICBzd2lwZXIudmlzaWJsZVNsaWRlcyA9ICQoc3dpcGVyLnZpc2libGVTbGlkZXMpO1xufSIsImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHVwZGF0ZVByb2dyZXNzKHRyYW5zbGF0ZSkge1xuICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuXG4gIGlmICh0eXBlb2YgdHJhbnNsYXRlID09PSAndW5kZWZpbmVkJykge1xuICAgIGNvbnN0IG11bHRpcGxpZXIgPSBzd2lwZXIucnRsVHJhbnNsYXRlID8gLTEgOiAxOyAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmVcblxuICAgIHRyYW5zbGF0ZSA9IHN3aXBlciAmJiBzd2lwZXIudHJhbnNsYXRlICYmIHN3aXBlci50cmFuc2xhdGUgKiBtdWx0aXBsaWVyIHx8IDA7XG4gIH1cblxuICBjb25zdCBwYXJhbXMgPSBzd2lwZXIucGFyYW1zO1xuICBjb25zdCB0cmFuc2xhdGVzRGlmZiA9IHN3aXBlci5tYXhUcmFuc2xhdGUoKSAtIHN3aXBlci5taW5UcmFuc2xhdGUoKTtcbiAgbGV0IHtcbiAgICBwcm9ncmVzcyxcbiAgICBpc0JlZ2lubmluZyxcbiAgICBpc0VuZFxuICB9ID0gc3dpcGVyO1xuICBjb25zdCB3YXNCZWdpbm5pbmcgPSBpc0JlZ2lubmluZztcbiAgY29uc3Qgd2FzRW5kID0gaXNFbmQ7XG5cbiAgaWYgKHRyYW5zbGF0ZXNEaWZmID09PSAwKSB7XG4gICAgcHJvZ3Jlc3MgPSAwO1xuICAgIGlzQmVnaW5uaW5nID0gdHJ1ZTtcbiAgICBpc0VuZCA9IHRydWU7XG4gIH0gZWxzZSB7XG4gICAgcHJvZ3Jlc3MgPSAodHJhbnNsYXRlIC0gc3dpcGVyLm1pblRyYW5zbGF0ZSgpKSAvIHRyYW5zbGF0ZXNEaWZmO1xuICAgIGlzQmVnaW5uaW5nID0gcHJvZ3Jlc3MgPD0gMDtcbiAgICBpc0VuZCA9IHByb2dyZXNzID49IDE7XG4gIH1cblxuICBPYmplY3QuYXNzaWduKHN3aXBlciwge1xuICAgIHByb2dyZXNzLFxuICAgIGlzQmVnaW5uaW5nLFxuICAgIGlzRW5kXG4gIH0pO1xuICBpZiAocGFyYW1zLndhdGNoU2xpZGVzUHJvZ3Jlc3MgfHwgcGFyYW1zLmNlbnRlcmVkU2xpZGVzICYmIHBhcmFtcy5hdXRvSGVpZ2h0KSBzd2lwZXIudXBkYXRlU2xpZGVzUHJvZ3Jlc3ModHJhbnNsYXRlKTtcblxuICBpZiAoaXNCZWdpbm5pbmcgJiYgIXdhc0JlZ2lubmluZykge1xuICAgIHN3aXBlci5lbWl0KCdyZWFjaEJlZ2lubmluZyB0b0VkZ2UnKTtcbiAgfVxuXG4gIGlmIChpc0VuZCAmJiAhd2FzRW5kKSB7XG4gICAgc3dpcGVyLmVtaXQoJ3JlYWNoRW5kIHRvRWRnZScpO1xuICB9XG5cbiAgaWYgKHdhc0JlZ2lubmluZyAmJiAhaXNCZWdpbm5pbmcgfHwgd2FzRW5kICYmICFpc0VuZCkge1xuICAgIHN3aXBlci5lbWl0KCdmcm9tRWRnZScpO1xuICB9XG5cbiAgc3dpcGVyLmVtaXQoJ3Byb2dyZXNzJywgcHJvZ3Jlc3MpO1xufSIsImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHVwZGF0ZVNsaWRlc0NsYXNzZXMoKSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gIGNvbnN0IHtcbiAgICBzbGlkZXMsXG4gICAgcGFyYW1zLFxuICAgICR3cmFwcGVyRWwsXG4gICAgYWN0aXZlSW5kZXgsXG4gICAgcmVhbEluZGV4XG4gIH0gPSBzd2lwZXI7XG4gIGNvbnN0IGlzVmlydHVhbCA9IHN3aXBlci52aXJ0dWFsICYmIHBhcmFtcy52aXJ0dWFsLmVuYWJsZWQ7XG4gIHNsaWRlcy5yZW1vdmVDbGFzcyhgJHtwYXJhbXMuc2xpZGVBY3RpdmVDbGFzc30gJHtwYXJhbXMuc2xpZGVOZXh0Q2xhc3N9ICR7cGFyYW1zLnNsaWRlUHJldkNsYXNzfSAke3BhcmFtcy5zbGlkZUR1cGxpY2F0ZUFjdGl2ZUNsYXNzfSAke3BhcmFtcy5zbGlkZUR1cGxpY2F0ZU5leHRDbGFzc30gJHtwYXJhbXMuc2xpZGVEdXBsaWNhdGVQcmV2Q2xhc3N9YCk7XG4gIGxldCBhY3RpdmVTbGlkZTtcblxuICBpZiAoaXNWaXJ0dWFsKSB7XG4gICAgYWN0aXZlU2xpZGUgPSBzd2lwZXIuJHdyYXBwZXJFbC5maW5kKGAuJHtwYXJhbXMuc2xpZGVDbGFzc31bZGF0YS1zd2lwZXItc2xpZGUtaW5kZXg9XCIke2FjdGl2ZUluZGV4fVwiXWApO1xuICB9IGVsc2Uge1xuICAgIGFjdGl2ZVNsaWRlID0gc2xpZGVzLmVxKGFjdGl2ZUluZGV4KTtcbiAgfSAvLyBBY3RpdmUgY2xhc3Nlc1xuXG5cbiAgYWN0aXZlU2xpZGUuYWRkQ2xhc3MocGFyYW1zLnNsaWRlQWN0aXZlQ2xhc3MpO1xuXG4gIGlmIChwYXJhbXMubG9vcCkge1xuICAgIC8vIER1cGxpY2F0ZSB0byBhbGwgbG9vcGVkIHNsaWRlc1xuICAgIGlmIChhY3RpdmVTbGlkZS5oYXNDbGFzcyhwYXJhbXMuc2xpZGVEdXBsaWNhdGVDbGFzcykpIHtcbiAgICAgICR3cmFwcGVyRWwuY2hpbGRyZW4oYC4ke3BhcmFtcy5zbGlkZUNsYXNzfTpub3QoLiR7cGFyYW1zLnNsaWRlRHVwbGljYXRlQ2xhc3N9KVtkYXRhLXN3aXBlci1zbGlkZS1pbmRleD1cIiR7cmVhbEluZGV4fVwiXWApLmFkZENsYXNzKHBhcmFtcy5zbGlkZUR1cGxpY2F0ZUFjdGl2ZUNsYXNzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgJHdyYXBwZXJFbC5jaGlsZHJlbihgLiR7cGFyYW1zLnNsaWRlQ2xhc3N9LiR7cGFyYW1zLnNsaWRlRHVwbGljYXRlQ2xhc3N9W2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4PVwiJHtyZWFsSW5kZXh9XCJdYCkuYWRkQ2xhc3MocGFyYW1zLnNsaWRlRHVwbGljYXRlQWN0aXZlQ2xhc3MpO1xuICAgIH1cbiAgfSAvLyBOZXh0IFNsaWRlXG5cblxuICBsZXQgbmV4dFNsaWRlID0gYWN0aXZlU2xpZGUubmV4dEFsbChgLiR7cGFyYW1zLnNsaWRlQ2xhc3N9YCkuZXEoMCkuYWRkQ2xhc3MocGFyYW1zLnNsaWRlTmV4dENsYXNzKTtcblxuICBpZiAocGFyYW1zLmxvb3AgJiYgbmV4dFNsaWRlLmxlbmd0aCA9PT0gMCkge1xuICAgIG5leHRTbGlkZSA9IHNsaWRlcy5lcSgwKTtcbiAgICBuZXh0U2xpZGUuYWRkQ2xhc3MocGFyYW1zLnNsaWRlTmV4dENsYXNzKTtcbiAgfSAvLyBQcmV2IFNsaWRlXG5cblxuICBsZXQgcHJldlNsaWRlID0gYWN0aXZlU2xpZGUucHJldkFsbChgLiR7cGFyYW1zLnNsaWRlQ2xhc3N9YCkuZXEoMCkuYWRkQ2xhc3MocGFyYW1zLnNsaWRlUHJldkNsYXNzKTtcblxuICBpZiAocGFyYW1zLmxvb3AgJiYgcHJldlNsaWRlLmxlbmd0aCA9PT0gMCkge1xuICAgIHByZXZTbGlkZSA9IHNsaWRlcy5lcSgtMSk7XG4gICAgcHJldlNsaWRlLmFkZENsYXNzKHBhcmFtcy5zbGlkZVByZXZDbGFzcyk7XG4gIH1cblxuICBpZiAocGFyYW1zLmxvb3ApIHtcbiAgICAvLyBEdXBsaWNhdGUgdG8gYWxsIGxvb3BlZCBzbGlkZXNcbiAgICBpZiAobmV4dFNsaWRlLmhhc0NsYXNzKHBhcmFtcy5zbGlkZUR1cGxpY2F0ZUNsYXNzKSkge1xuICAgICAgJHdyYXBwZXJFbC5jaGlsZHJlbihgLiR7cGFyYW1zLnNsaWRlQ2xhc3N9Om5vdCguJHtwYXJhbXMuc2xpZGVEdXBsaWNhdGVDbGFzc30pW2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4PVwiJHtuZXh0U2xpZGUuYXR0cignZGF0YS1zd2lwZXItc2xpZGUtaW5kZXgnKX1cIl1gKS5hZGRDbGFzcyhwYXJhbXMuc2xpZGVEdXBsaWNhdGVOZXh0Q2xhc3MpO1xuICAgIH0gZWxzZSB7XG4gICAgICAkd3JhcHBlckVsLmNoaWxkcmVuKGAuJHtwYXJhbXMuc2xpZGVDbGFzc30uJHtwYXJhbXMuc2xpZGVEdXBsaWNhdGVDbGFzc31bZGF0YS1zd2lwZXItc2xpZGUtaW5kZXg9XCIke25leHRTbGlkZS5hdHRyKCdkYXRhLXN3aXBlci1zbGlkZS1pbmRleCcpfVwiXWApLmFkZENsYXNzKHBhcmFtcy5zbGlkZUR1cGxpY2F0ZU5leHRDbGFzcyk7XG4gICAgfVxuXG4gICAgaWYgKHByZXZTbGlkZS5oYXNDbGFzcyhwYXJhbXMuc2xpZGVEdXBsaWNhdGVDbGFzcykpIHtcbiAgICAgICR3cmFwcGVyRWwuY2hpbGRyZW4oYC4ke3BhcmFtcy5zbGlkZUNsYXNzfTpub3QoLiR7cGFyYW1zLnNsaWRlRHVwbGljYXRlQ2xhc3N9KVtkYXRhLXN3aXBlci1zbGlkZS1pbmRleD1cIiR7cHJldlNsaWRlLmF0dHIoJ2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4Jyl9XCJdYCkuYWRkQ2xhc3MocGFyYW1zLnNsaWRlRHVwbGljYXRlUHJldkNsYXNzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgJHdyYXBwZXJFbC5jaGlsZHJlbihgLiR7cGFyYW1zLnNsaWRlQ2xhc3N9LiR7cGFyYW1zLnNsaWRlRHVwbGljYXRlQ2xhc3N9W2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4PVwiJHtwcmV2U2xpZGUuYXR0cignZGF0YS1zd2lwZXItc2xpZGUtaW5kZXgnKX1cIl1gKS5hZGRDbGFzcyhwYXJhbXMuc2xpZGVEdXBsaWNhdGVQcmV2Q2xhc3MpO1xuICAgIH1cbiAgfVxuXG4gIHN3aXBlci5lbWl0U2xpZGVzQ2xhc3NlcygpO1xufSIsImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHVwZGF0ZUFjdGl2ZUluZGV4KG5ld0FjdGl2ZUluZGV4KSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gIGNvbnN0IHRyYW5zbGF0ZSA9IHN3aXBlci5ydGxUcmFuc2xhdGUgPyBzd2lwZXIudHJhbnNsYXRlIDogLXN3aXBlci50cmFuc2xhdGU7XG4gIGNvbnN0IHtcbiAgICBzbGlkZXNHcmlkLFxuICAgIHNuYXBHcmlkLFxuICAgIHBhcmFtcyxcbiAgICBhY3RpdmVJbmRleDogcHJldmlvdXNJbmRleCxcbiAgICByZWFsSW5kZXg6IHByZXZpb3VzUmVhbEluZGV4LFxuICAgIHNuYXBJbmRleDogcHJldmlvdXNTbmFwSW5kZXhcbiAgfSA9IHN3aXBlcjtcbiAgbGV0IGFjdGl2ZUluZGV4ID0gbmV3QWN0aXZlSW5kZXg7XG4gIGxldCBzbmFwSW5kZXg7XG5cbiAgaWYgKHR5cGVvZiBhY3RpdmVJbmRleCA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNsaWRlc0dyaWQubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgIGlmICh0eXBlb2Ygc2xpZGVzR3JpZFtpICsgMV0gIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIGlmICh0cmFuc2xhdGUgPj0gc2xpZGVzR3JpZFtpXSAmJiB0cmFuc2xhdGUgPCBzbGlkZXNHcmlkW2kgKyAxXSAtIChzbGlkZXNHcmlkW2kgKyAxXSAtIHNsaWRlc0dyaWRbaV0pIC8gMikge1xuICAgICAgICAgIGFjdGl2ZUluZGV4ID0gaTtcbiAgICAgICAgfSBlbHNlIGlmICh0cmFuc2xhdGUgPj0gc2xpZGVzR3JpZFtpXSAmJiB0cmFuc2xhdGUgPCBzbGlkZXNHcmlkW2kgKyAxXSkge1xuICAgICAgICAgIGFjdGl2ZUluZGV4ID0gaSArIDE7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAodHJhbnNsYXRlID49IHNsaWRlc0dyaWRbaV0pIHtcbiAgICAgICAgYWN0aXZlSW5kZXggPSBpO1xuICAgICAgfVxuICAgIH0gLy8gTm9ybWFsaXplIHNsaWRlSW5kZXhcblxuXG4gICAgaWYgKHBhcmFtcy5ub3JtYWxpemVTbGlkZUluZGV4KSB7XG4gICAgICBpZiAoYWN0aXZlSW5kZXggPCAwIHx8IHR5cGVvZiBhY3RpdmVJbmRleCA9PT0gJ3VuZGVmaW5lZCcpIGFjdGl2ZUluZGV4ID0gMDtcbiAgICB9XG4gIH1cblxuICBpZiAoc25hcEdyaWQuaW5kZXhPZih0cmFuc2xhdGUpID49IDApIHtcbiAgICBzbmFwSW5kZXggPSBzbmFwR3JpZC5pbmRleE9mKHRyYW5zbGF0ZSk7XG4gIH0gZWxzZSB7XG4gICAgY29uc3Qgc2tpcCA9IE1hdGgubWluKHBhcmFtcy5zbGlkZXNQZXJHcm91cFNraXAsIGFjdGl2ZUluZGV4KTtcbiAgICBzbmFwSW5kZXggPSBza2lwICsgTWF0aC5mbG9vcigoYWN0aXZlSW5kZXggLSBza2lwKSAvIHBhcmFtcy5zbGlkZXNQZXJHcm91cCk7XG4gIH1cblxuICBpZiAoc25hcEluZGV4ID49IHNuYXBHcmlkLmxlbmd0aCkgc25hcEluZGV4ID0gc25hcEdyaWQubGVuZ3RoIC0gMTtcblxuICBpZiAoYWN0aXZlSW5kZXggPT09IHByZXZpb3VzSW5kZXgpIHtcbiAgICBpZiAoc25hcEluZGV4ICE9PSBwcmV2aW91c1NuYXBJbmRleCkge1xuICAgICAgc3dpcGVyLnNuYXBJbmRleCA9IHNuYXBJbmRleDtcbiAgICAgIHN3aXBlci5lbWl0KCdzbmFwSW5kZXhDaGFuZ2UnKTtcbiAgICB9XG5cbiAgICByZXR1cm47XG4gIH0gLy8gR2V0IHJlYWwgaW5kZXhcblxuXG4gIGNvbnN0IHJlYWxJbmRleCA9IHBhcnNlSW50KHN3aXBlci5zbGlkZXMuZXEoYWN0aXZlSW5kZXgpLmF0dHIoJ2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4JykgfHwgYWN0aXZlSW5kZXgsIDEwKTtcbiAgT2JqZWN0LmFzc2lnbihzd2lwZXIsIHtcbiAgICBzbmFwSW5kZXgsXG4gICAgcmVhbEluZGV4LFxuICAgIHByZXZpb3VzSW5kZXgsXG4gICAgYWN0aXZlSW5kZXhcbiAgfSk7XG4gIHN3aXBlci5lbWl0KCdhY3RpdmVJbmRleENoYW5nZScpO1xuICBzd2lwZXIuZW1pdCgnc25hcEluZGV4Q2hhbmdlJyk7XG5cbiAgaWYgKHByZXZpb3VzUmVhbEluZGV4ICE9PSByZWFsSW5kZXgpIHtcbiAgICBzd2lwZXIuZW1pdCgncmVhbEluZGV4Q2hhbmdlJyk7XG4gIH1cblxuICBpZiAoc3dpcGVyLmluaXRpYWxpemVkIHx8IHN3aXBlci5wYXJhbXMucnVuQ2FsbGJhY2tzT25Jbml0KSB7XG4gICAgc3dpcGVyLmVtaXQoJ3NsaWRlQ2hhbmdlJyk7XG4gIH1cbn0iLCJpbXBvcnQgJCBmcm9tICcuLi8uLi9zaGFyZWQvZG9tLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHVwZGF0ZUNsaWNrZWRTbGlkZShlKSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gIGNvbnN0IHBhcmFtcyA9IHN3aXBlci5wYXJhbXM7XG4gIGNvbnN0IHNsaWRlID0gJChlKS5jbG9zZXN0KGAuJHtwYXJhbXMuc2xpZGVDbGFzc31gKVswXTtcbiAgbGV0IHNsaWRlRm91bmQgPSBmYWxzZTtcbiAgbGV0IHNsaWRlSW5kZXg7XG5cbiAgaWYgKHNsaWRlKSB7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzd2lwZXIuc2xpZGVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICBpZiAoc3dpcGVyLnNsaWRlc1tpXSA9PT0gc2xpZGUpIHtcbiAgICAgICAgc2xpZGVGb3VuZCA9IHRydWU7XG4gICAgICAgIHNsaWRlSW5kZXggPSBpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBpZiAoc2xpZGUgJiYgc2xpZGVGb3VuZCkge1xuICAgIHN3aXBlci5jbGlja2VkU2xpZGUgPSBzbGlkZTtcblxuICAgIGlmIChzd2lwZXIudmlydHVhbCAmJiBzd2lwZXIucGFyYW1zLnZpcnR1YWwuZW5hYmxlZCkge1xuICAgICAgc3dpcGVyLmNsaWNrZWRJbmRleCA9IHBhcnNlSW50KCQoc2xpZGUpLmF0dHIoJ2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4JyksIDEwKTtcbiAgICB9IGVsc2Uge1xuICAgICAgc3dpcGVyLmNsaWNrZWRJbmRleCA9IHNsaWRlSW5kZXg7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHN3aXBlci5jbGlja2VkU2xpZGUgPSB1bmRlZmluZWQ7XG4gICAgc3dpcGVyLmNsaWNrZWRJbmRleCA9IHVuZGVmaW5lZDtcbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAocGFyYW1zLnNsaWRlVG9DbGlja2VkU2xpZGUgJiYgc3dpcGVyLmNsaWNrZWRJbmRleCAhPT0gdW5kZWZpbmVkICYmIHN3aXBlci5jbGlja2VkSW5kZXggIT09IHN3aXBlci5hY3RpdmVJbmRleCkge1xuICAgIHN3aXBlci5zbGlkZVRvQ2xpY2tlZFNsaWRlKCk7XG4gIH1cbn0iLCJpbXBvcnQgdXBkYXRlU2l6ZSBmcm9tICcuL3VwZGF0ZVNpemUuanMnO1xuaW1wb3J0IHVwZGF0ZVNsaWRlcyBmcm9tICcuL3VwZGF0ZVNsaWRlcy5qcyc7XG5pbXBvcnQgdXBkYXRlQXV0b0hlaWdodCBmcm9tICcuL3VwZGF0ZUF1dG9IZWlnaHQuanMnO1xuaW1wb3J0IHVwZGF0ZVNsaWRlc09mZnNldCBmcm9tICcuL3VwZGF0ZVNsaWRlc09mZnNldC5qcyc7XG5pbXBvcnQgdXBkYXRlU2xpZGVzUHJvZ3Jlc3MgZnJvbSAnLi91cGRhdGVTbGlkZXNQcm9ncmVzcy5qcyc7XG5pbXBvcnQgdXBkYXRlUHJvZ3Jlc3MgZnJvbSAnLi91cGRhdGVQcm9ncmVzcy5qcyc7XG5pbXBvcnQgdXBkYXRlU2xpZGVzQ2xhc3NlcyBmcm9tICcuL3VwZGF0ZVNsaWRlc0NsYXNzZXMuanMnO1xuaW1wb3J0IHVwZGF0ZUFjdGl2ZUluZGV4IGZyb20gJy4vdXBkYXRlQWN0aXZlSW5kZXguanMnO1xuaW1wb3J0IHVwZGF0ZUNsaWNrZWRTbGlkZSBmcm9tICcuL3VwZGF0ZUNsaWNrZWRTbGlkZS5qcyc7XG5leHBvcnQgZGVmYXVsdCB7XG4gIHVwZGF0ZVNpemUsXG4gIHVwZGF0ZVNsaWRlcyxcbiAgdXBkYXRlQXV0b0hlaWdodCxcbiAgdXBkYXRlU2xpZGVzT2Zmc2V0LFxuICB1cGRhdGVTbGlkZXNQcm9ncmVzcyxcbiAgdXBkYXRlUHJvZ3Jlc3MsXG4gIHVwZGF0ZVNsaWRlc0NsYXNzZXMsXG4gIHVwZGF0ZUFjdGl2ZUluZGV4LFxuICB1cGRhdGVDbGlja2VkU2xpZGVcbn07IiwiaW1wb3J0IHsgZ2V0VHJhbnNsYXRlIH0gZnJvbSAnLi4vLi4vc2hhcmVkL3V0aWxzLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGdldFN3aXBlclRyYW5zbGF0ZShheGlzID0gdGhpcy5pc0hvcml6b250YWwoKSA/ICd4JyA6ICd5Jykge1xuICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICBjb25zdCB7XG4gICAgcGFyYW1zLFxuICAgIHJ0bFRyYW5zbGF0ZTogcnRsLFxuICAgIHRyYW5zbGF0ZSxcbiAgICAkd3JhcHBlckVsXG4gIH0gPSBzd2lwZXI7XG5cbiAgaWYgKHBhcmFtcy52aXJ0dWFsVHJhbnNsYXRlKSB7XG4gICAgcmV0dXJuIHJ0bCA/IC10cmFuc2xhdGUgOiB0cmFuc2xhdGU7XG4gIH1cblxuICBpZiAocGFyYW1zLmNzc01vZGUpIHtcbiAgICByZXR1cm4gdHJhbnNsYXRlO1xuICB9XG5cbiAgbGV0IGN1cnJlbnRUcmFuc2xhdGUgPSBnZXRUcmFuc2xhdGUoJHdyYXBwZXJFbFswXSwgYXhpcyk7XG4gIGlmIChydGwpIGN1cnJlbnRUcmFuc2xhdGUgPSAtY3VycmVudFRyYW5zbGF0ZTtcbiAgcmV0dXJuIGN1cnJlbnRUcmFuc2xhdGUgfHwgMDtcbn0iLCJleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBzZXRUcmFuc2xhdGUodHJhbnNsYXRlLCBieUNvbnRyb2xsZXIpIHtcbiAgY29uc3Qgc3dpcGVyID0gdGhpcztcbiAgY29uc3Qge1xuICAgIHJ0bFRyYW5zbGF0ZTogcnRsLFxuICAgIHBhcmFtcyxcbiAgICAkd3JhcHBlckVsLFxuICAgIHdyYXBwZXJFbCxcbiAgICBwcm9ncmVzc1xuICB9ID0gc3dpcGVyO1xuICBsZXQgeCA9IDA7XG4gIGxldCB5ID0gMDtcbiAgY29uc3QgeiA9IDA7XG5cbiAgaWYgKHN3aXBlci5pc0hvcml6b250YWwoKSkge1xuICAgIHggPSBydGwgPyAtdHJhbnNsYXRlIDogdHJhbnNsYXRlO1xuICB9IGVsc2Uge1xuICAgIHkgPSB0cmFuc2xhdGU7XG4gIH1cblxuICBpZiAocGFyYW1zLnJvdW5kTGVuZ3Rocykge1xuICAgIHggPSBNYXRoLmZsb29yKHgpO1xuICAgIHkgPSBNYXRoLmZsb29yKHkpO1xuICB9XG5cbiAgaWYgKHBhcmFtcy5jc3NNb2RlKSB7XG4gICAgd3JhcHBlckVsW3N3aXBlci5pc0hvcml6b250YWwoKSA/ICdzY3JvbGxMZWZ0JyA6ICdzY3JvbGxUb3AnXSA9IHN3aXBlci5pc0hvcml6b250YWwoKSA/IC14IDogLXk7XG4gIH0gZWxzZSBpZiAoIXBhcmFtcy52aXJ0dWFsVHJhbnNsYXRlKSB7XG4gICAgJHdyYXBwZXJFbC50cmFuc2Zvcm0oYHRyYW5zbGF0ZTNkKCR7eH1weCwgJHt5fXB4LCAke3p9cHgpYCk7XG4gIH1cblxuICBzd2lwZXIucHJldmlvdXNUcmFuc2xhdGUgPSBzd2lwZXIudHJhbnNsYXRlO1xuICBzd2lwZXIudHJhbnNsYXRlID0gc3dpcGVyLmlzSG9yaXpvbnRhbCgpID8geCA6IHk7IC8vIENoZWNrIGlmIHdlIG5lZWQgdG8gdXBkYXRlIHByb2dyZXNzXG5cbiAgbGV0IG5ld1Byb2dyZXNzO1xuICBjb25zdCB0cmFuc2xhdGVzRGlmZiA9IHN3aXBlci5tYXhUcmFuc2xhdGUoKSAtIHN3aXBlci5taW5UcmFuc2xhdGUoKTtcblxuICBpZiAodHJhbnNsYXRlc0RpZmYgPT09IDApIHtcbiAgICBuZXdQcm9ncmVzcyA9IDA7XG4gIH0gZWxzZSB7XG4gICAgbmV3UHJvZ3Jlc3MgPSAodHJhbnNsYXRlIC0gc3dpcGVyLm1pblRyYW5zbGF0ZSgpKSAvIHRyYW5zbGF0ZXNEaWZmO1xuICB9XG5cbiAgaWYgKG5ld1Byb2dyZXNzICE9PSBwcm9ncmVzcykge1xuICAgIHN3aXBlci51cGRhdGVQcm9ncmVzcyh0cmFuc2xhdGUpO1xuICB9XG5cbiAgc3dpcGVyLmVtaXQoJ3NldFRyYW5zbGF0ZScsIHN3aXBlci50cmFuc2xhdGUsIGJ5Q29udHJvbGxlcik7XG59IiwiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gbWluVHJhbnNsYXRlKCkge1xuICByZXR1cm4gLXRoaXMuc25hcEdyaWRbMF07XG59IiwiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gbWF4VHJhbnNsYXRlKCkge1xuICByZXR1cm4gLXRoaXMuc25hcEdyaWRbdGhpcy5zbmFwR3JpZC5sZW5ndGggLSAxXTtcbn0iLCJpbXBvcnQgeyBhbmltYXRlQ1NTTW9kZVNjcm9sbCB9IGZyb20gJy4uLy4uL3NoYXJlZC91dGlscy5qcyc7XG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB0cmFuc2xhdGVUbyh0cmFuc2xhdGUgPSAwLCBzcGVlZCA9IHRoaXMucGFyYW1zLnNwZWVkLCBydW5DYWxsYmFja3MgPSB0cnVlLCB0cmFuc2xhdGVCb3VuZHMgPSB0cnVlLCBpbnRlcm5hbCkge1xuICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICBjb25zdCB7XG4gICAgcGFyYW1zLFxuICAgIHdyYXBwZXJFbFxuICB9ID0gc3dpcGVyO1xuXG4gIGlmIChzd2lwZXIuYW5pbWF0aW5nICYmIHBhcmFtcy5wcmV2ZW50SW50ZXJhY3Rpb25PblRyYW5zaXRpb24pIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBjb25zdCBtaW5UcmFuc2xhdGUgPSBzd2lwZXIubWluVHJhbnNsYXRlKCk7XG4gIGNvbnN0IG1heFRyYW5zbGF0ZSA9IHN3aXBlci5tYXhUcmFuc2xhdGUoKTtcbiAgbGV0IG5ld1RyYW5zbGF0ZTtcbiAgaWYgKHRyYW5zbGF0ZUJvdW5kcyAmJiB0cmFuc2xhdGUgPiBtaW5UcmFuc2xhdGUpIG5ld1RyYW5zbGF0ZSA9IG1pblRyYW5zbGF0ZTtlbHNlIGlmICh0cmFuc2xhdGVCb3VuZHMgJiYgdHJhbnNsYXRlIDwgbWF4VHJhbnNsYXRlKSBuZXdUcmFuc2xhdGUgPSBtYXhUcmFuc2xhdGU7ZWxzZSBuZXdUcmFuc2xhdGUgPSB0cmFuc2xhdGU7IC8vIFVwZGF0ZSBwcm9ncmVzc1xuXG4gIHN3aXBlci51cGRhdGVQcm9ncmVzcyhuZXdUcmFuc2xhdGUpO1xuXG4gIGlmIChwYXJhbXMuY3NzTW9kZSkge1xuICAgIGNvbnN0IGlzSCA9IHN3aXBlci5pc0hvcml6b250YWwoKTtcblxuICAgIGlmIChzcGVlZCA9PT0gMCkge1xuICAgICAgd3JhcHBlckVsW2lzSCA/ICdzY3JvbGxMZWZ0JyA6ICdzY3JvbGxUb3AnXSA9IC1uZXdUcmFuc2xhdGU7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICghc3dpcGVyLnN1cHBvcnQuc21vb3RoU2Nyb2xsKSB7XG4gICAgICAgIGFuaW1hdGVDU1NNb2RlU2Nyb2xsKHtcbiAgICAgICAgICBzd2lwZXIsXG4gICAgICAgICAgdGFyZ2V0UG9zaXRpb246IC1uZXdUcmFuc2xhdGUsXG4gICAgICAgICAgc2lkZTogaXNIID8gJ2xlZnQnIDogJ3RvcCdcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuXG4gICAgICB3cmFwcGVyRWwuc2Nyb2xsVG8oe1xuICAgICAgICBbaXNIID8gJ2xlZnQnIDogJ3RvcCddOiAtbmV3VHJhbnNsYXRlLFxuICAgICAgICBiZWhhdmlvcjogJ3Ntb290aCdcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgaWYgKHNwZWVkID09PSAwKSB7XG4gICAgc3dpcGVyLnNldFRyYW5zaXRpb24oMCk7XG4gICAgc3dpcGVyLnNldFRyYW5zbGF0ZShuZXdUcmFuc2xhdGUpO1xuXG4gICAgaWYgKHJ1bkNhbGxiYWNrcykge1xuICAgICAgc3dpcGVyLmVtaXQoJ2JlZm9yZVRyYW5zaXRpb25TdGFydCcsIHNwZWVkLCBpbnRlcm5hbCk7XG4gICAgICBzd2lwZXIuZW1pdCgndHJhbnNpdGlvbkVuZCcpO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBzd2lwZXIuc2V0VHJhbnNpdGlvbihzcGVlZCk7XG4gICAgc3dpcGVyLnNldFRyYW5zbGF0ZShuZXdUcmFuc2xhdGUpO1xuXG4gICAgaWYgKHJ1bkNhbGxiYWNrcykge1xuICAgICAgc3dpcGVyLmVtaXQoJ2JlZm9yZVRyYW5zaXRpb25TdGFydCcsIHNwZWVkLCBpbnRlcm5hbCk7XG4gICAgICBzd2lwZXIuZW1pdCgndHJhbnNpdGlvblN0YXJ0Jyk7XG4gICAgfVxuXG4gICAgaWYgKCFzd2lwZXIuYW5pbWF0aW5nKSB7XG4gICAgICBzd2lwZXIuYW5pbWF0aW5nID0gdHJ1ZTtcblxuICAgICAgaWYgKCFzd2lwZXIub25UcmFuc2xhdGVUb1dyYXBwZXJUcmFuc2l0aW9uRW5kKSB7XG4gICAgICAgIHN3aXBlci5vblRyYW5zbGF0ZVRvV3JhcHBlclRyYW5zaXRpb25FbmQgPSBmdW5jdGlvbiB0cmFuc2l0aW9uRW5kKGUpIHtcbiAgICAgICAgICBpZiAoIXN3aXBlciB8fCBzd2lwZXIuZGVzdHJveWVkKSByZXR1cm47XG4gICAgICAgICAgaWYgKGUudGFyZ2V0ICE9PSB0aGlzKSByZXR1cm47XG4gICAgICAgICAgc3dpcGVyLiR3cmFwcGVyRWxbMF0ucmVtb3ZlRXZlbnRMaXN0ZW5lcigndHJhbnNpdGlvbmVuZCcsIHN3aXBlci5vblRyYW5zbGF0ZVRvV3JhcHBlclRyYW5zaXRpb25FbmQpO1xuICAgICAgICAgIHN3aXBlci4kd3JhcHBlckVsWzBdLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3dlYmtpdFRyYW5zaXRpb25FbmQnLCBzd2lwZXIub25UcmFuc2xhdGVUb1dyYXBwZXJUcmFuc2l0aW9uRW5kKTtcbiAgICAgICAgICBzd2lwZXIub25UcmFuc2xhdGVUb1dyYXBwZXJUcmFuc2l0aW9uRW5kID0gbnVsbDtcbiAgICAgICAgICBkZWxldGUgc3dpcGVyLm9uVHJhbnNsYXRlVG9XcmFwcGVyVHJhbnNpdGlvbkVuZDtcblxuICAgICAgICAgIGlmIChydW5DYWxsYmFja3MpIHtcbiAgICAgICAgICAgIHN3aXBlci5lbWl0KCd0cmFuc2l0aW9uRW5kJyk7XG4gICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBzd2lwZXIuJHdyYXBwZXJFbFswXS5hZGRFdmVudExpc3RlbmVyKCd0cmFuc2l0aW9uZW5kJywgc3dpcGVyLm9uVHJhbnNsYXRlVG9XcmFwcGVyVHJhbnNpdGlvbkVuZCk7XG4gICAgICBzd2lwZXIuJHdyYXBwZXJFbFswXS5hZGRFdmVudExpc3RlbmVyKCd3ZWJraXRUcmFuc2l0aW9uRW5kJywgc3dpcGVyLm9uVHJhbnNsYXRlVG9XcmFwcGVyVHJhbnNpdGlvbkVuZCk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRydWU7XG59IiwiaW1wb3J0IGdldFRyYW5zbGF0ZSBmcm9tICcuL2dldFRyYW5zbGF0ZS5qcyc7XG5pbXBvcnQgc2V0VHJhbnNsYXRlIGZyb20gJy4vc2V0VHJhbnNsYXRlLmpzJztcbmltcG9ydCBtaW5UcmFuc2xhdGUgZnJvbSAnLi9taW5UcmFuc2xhdGUuanMnO1xuaW1wb3J0IG1heFRyYW5zbGF0ZSBmcm9tICcuL21heFRyYW5zbGF0ZS5qcyc7XG5pbXBvcnQgdHJhbnNsYXRlVG8gZnJvbSAnLi90cmFuc2xhdGVUby5qcyc7XG5leHBvcnQgZGVmYXVsdCB7XG4gIGdldFRyYW5zbGF0ZSxcbiAgc2V0VHJhbnNsYXRlLFxuICBtaW5UcmFuc2xhdGUsXG4gIG1heFRyYW5zbGF0ZSxcbiAgdHJhbnNsYXRlVG9cbn07IiwiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gc2V0VHJhbnNpdGlvbihkdXJhdGlvbiwgYnlDb250cm9sbGVyKSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG5cbiAgaWYgKCFzd2lwZXIucGFyYW1zLmNzc01vZGUpIHtcbiAgICBzd2lwZXIuJHdyYXBwZXJFbC50cmFuc2l0aW9uKGR1cmF0aW9uKTtcbiAgfVxuXG4gIHN3aXBlci5lbWl0KCdzZXRUcmFuc2l0aW9uJywgZHVyYXRpb24sIGJ5Q29udHJvbGxlcik7XG59IiwiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdHJhbnNpdGlvbkVtaXQoe1xuICBzd2lwZXIsXG4gIHJ1bkNhbGxiYWNrcyxcbiAgZGlyZWN0aW9uLFxuICBzdGVwXG59KSB7XG4gIGNvbnN0IHtcbiAgICBhY3RpdmVJbmRleCxcbiAgICBwcmV2aW91c0luZGV4XG4gIH0gPSBzd2lwZXI7XG4gIGxldCBkaXIgPSBkaXJlY3Rpb247XG5cbiAgaWYgKCFkaXIpIHtcbiAgICBpZiAoYWN0aXZlSW5kZXggPiBwcmV2aW91c0luZGV4KSBkaXIgPSAnbmV4dCc7ZWxzZSBpZiAoYWN0aXZlSW5kZXggPCBwcmV2aW91c0luZGV4KSBkaXIgPSAncHJldic7ZWxzZSBkaXIgPSAncmVzZXQnO1xuICB9XG5cbiAgc3dpcGVyLmVtaXQoYHRyYW5zaXRpb24ke3N0ZXB9YCk7XG5cbiAgaWYgKHJ1bkNhbGxiYWNrcyAmJiBhY3RpdmVJbmRleCAhPT0gcHJldmlvdXNJbmRleCkge1xuICAgIGlmIChkaXIgPT09ICdyZXNldCcpIHtcbiAgICAgIHN3aXBlci5lbWl0KGBzbGlkZVJlc2V0VHJhbnNpdGlvbiR7c3RlcH1gKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBzd2lwZXIuZW1pdChgc2xpZGVDaGFuZ2VUcmFuc2l0aW9uJHtzdGVwfWApO1xuXG4gICAgaWYgKGRpciA9PT0gJ25leHQnKSB7XG4gICAgICBzd2lwZXIuZW1pdChgc2xpZGVOZXh0VHJhbnNpdGlvbiR7c3RlcH1gKTtcbiAgICB9IGVsc2Uge1xuICAgICAgc3dpcGVyLmVtaXQoYHNsaWRlUHJldlRyYW5zaXRpb24ke3N0ZXB9YCk7XG4gICAgfVxuICB9XG59IiwiaW1wb3J0IHRyYW5zaXRpb25FbWl0IGZyb20gJy4vdHJhbnNpdGlvbkVtaXQuanMnO1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdHJhbnNpdGlvblN0YXJ0KHJ1bkNhbGxiYWNrcyA9IHRydWUsIGRpcmVjdGlvbikge1xuICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICBjb25zdCB7XG4gICAgcGFyYW1zXG4gIH0gPSBzd2lwZXI7XG4gIGlmIChwYXJhbXMuY3NzTW9kZSkgcmV0dXJuO1xuXG4gIGlmIChwYXJhbXMuYXV0b0hlaWdodCkge1xuICAgIHN3aXBlci51cGRhdGVBdXRvSGVpZ2h0KCk7XG4gIH1cblxuICB0cmFuc2l0aW9uRW1pdCh7XG4gICAgc3dpcGVyLFxuICAgIHJ1bkNhbGxiYWNrcyxcbiAgICBkaXJlY3Rpb24sXG4gICAgc3RlcDogJ1N0YXJ0J1xuICB9KTtcbn0iLCJpbXBvcnQgdHJhbnNpdGlvbkVtaXQgZnJvbSAnLi90cmFuc2l0aW9uRW1pdC5qcyc7XG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB0cmFuc2l0aW9uRW5kKHJ1bkNhbGxiYWNrcyA9IHRydWUsIGRpcmVjdGlvbikge1xuICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICBjb25zdCB7XG4gICAgcGFyYW1zXG4gIH0gPSBzd2lwZXI7XG4gIHN3aXBlci5hbmltYXRpbmcgPSBmYWxzZTtcbiAgaWYgKHBhcmFtcy5jc3NNb2RlKSByZXR1cm47XG4gIHN3aXBlci5zZXRUcmFuc2l0aW9uKDApO1xuICB0cmFuc2l0aW9uRW1pdCh7XG4gICAgc3dpcGVyLFxuICAgIHJ1bkNhbGxiYWNrcyxcbiAgICBkaXJlY3Rpb24sXG4gICAgc3RlcDogJ0VuZCdcbiAgfSk7XG59IiwiaW1wb3J0IHNldFRyYW5zaXRpb24gZnJvbSAnLi9zZXRUcmFuc2l0aW9uLmpzJztcbmltcG9ydCB0cmFuc2l0aW9uU3RhcnQgZnJvbSAnLi90cmFuc2l0aW9uU3RhcnQuanMnO1xuaW1wb3J0IHRyYW5zaXRpb25FbmQgZnJvbSAnLi90cmFuc2l0aW9uRW5kLmpzJztcbmV4cG9ydCBkZWZhdWx0IHtcbiAgc2V0VHJhbnNpdGlvbixcbiAgdHJhbnNpdGlvblN0YXJ0LFxuICB0cmFuc2l0aW9uRW5kXG59OyIsImltcG9ydCB7IGFuaW1hdGVDU1NNb2RlU2Nyb2xsIH0gZnJvbSAnLi4vLi4vc2hhcmVkL3V0aWxzLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHNsaWRlVG8oaW5kZXggPSAwLCBzcGVlZCA9IHRoaXMucGFyYW1zLnNwZWVkLCBydW5DYWxsYmFja3MgPSB0cnVlLCBpbnRlcm5hbCwgaW5pdGlhbCkge1xuICBpZiAodHlwZW9mIGluZGV4ICE9PSAnbnVtYmVyJyAmJiB0eXBlb2YgaW5kZXggIT09ICdzdHJpbmcnKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBUaGUgJ2luZGV4JyBhcmd1bWVudCBjYW5ub3QgaGF2ZSB0eXBlIG90aGVyIHRoYW4gJ251bWJlcicgb3IgJ3N0cmluZycuIFske3R5cGVvZiBpbmRleH1dIGdpdmVuLmApO1xuICB9XG5cbiAgaWYgKHR5cGVvZiBpbmRleCA9PT0gJ3N0cmluZycpIHtcbiAgICAvKipcbiAgICAgKiBUaGUgYGluZGV4YCBhcmd1bWVudCBjb252ZXJ0ZWQgZnJvbSBgc3RyaW5nYCB0byBgbnVtYmVyYC5cbiAgICAgKiBAdHlwZSB7bnVtYmVyfVxuICAgICAqL1xuICAgIGNvbnN0IGluZGV4QXNOdW1iZXIgPSBwYXJzZUludChpbmRleCwgMTApO1xuICAgIC8qKlxuICAgICAqIERldGVybWluZXMgd2hldGhlciB0aGUgYGluZGV4YCBhcmd1bWVudCBpcyBhIHZhbGlkIGBudW1iZXJgXG4gICAgICogYWZ0ZXIgYmVpbmcgY29udmVydGVkIGZyb20gdGhlIGBzdHJpbmdgIHR5cGUuXG4gICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICovXG5cbiAgICBjb25zdCBpc1ZhbGlkTnVtYmVyID0gaXNGaW5pdGUoaW5kZXhBc051bWJlcik7XG5cbiAgICBpZiAoIWlzVmFsaWROdW1iZXIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgVGhlIHBhc3NlZC1pbiAnaW5kZXgnIChzdHJpbmcpIGNvdWxkbid0IGJlIGNvbnZlcnRlZCB0byAnbnVtYmVyJy4gWyR7aW5kZXh9XSBnaXZlbi5gKTtcbiAgICB9IC8vIEtub3dpbmcgdGhhdCB0aGUgY29udmVydGVkIGBpbmRleGAgaXMgYSB2YWxpZCBudW1iZXIsXG4gICAgLy8gd2UgY2FuIHVwZGF0ZSB0aGUgb3JpZ2luYWwgYXJndW1lbnQncyB2YWx1ZS5cblxuXG4gICAgaW5kZXggPSBpbmRleEFzTnVtYmVyO1xuICB9XG5cbiAgY29uc3Qgc3dpcGVyID0gdGhpcztcbiAgbGV0IHNsaWRlSW5kZXggPSBpbmRleDtcbiAgaWYgKHNsaWRlSW5kZXggPCAwKSBzbGlkZUluZGV4ID0gMDtcbiAgY29uc3Qge1xuICAgIHBhcmFtcyxcbiAgICBzbmFwR3JpZCxcbiAgICBzbGlkZXNHcmlkLFxuICAgIHByZXZpb3VzSW5kZXgsXG4gICAgYWN0aXZlSW5kZXgsXG4gICAgcnRsVHJhbnNsYXRlOiBydGwsXG4gICAgd3JhcHBlckVsLFxuICAgIGVuYWJsZWRcbiAgfSA9IHN3aXBlcjtcblxuICBpZiAoc3dpcGVyLmFuaW1hdGluZyAmJiBwYXJhbXMucHJldmVudEludGVyYWN0aW9uT25UcmFuc2l0aW9uIHx8ICFlbmFibGVkICYmICFpbnRlcm5hbCAmJiAhaW5pdGlhbCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGNvbnN0IHNraXAgPSBNYXRoLm1pbihzd2lwZXIucGFyYW1zLnNsaWRlc1Blckdyb3VwU2tpcCwgc2xpZGVJbmRleCk7XG4gIGxldCBzbmFwSW5kZXggPSBza2lwICsgTWF0aC5mbG9vcigoc2xpZGVJbmRleCAtIHNraXApIC8gc3dpcGVyLnBhcmFtcy5zbGlkZXNQZXJHcm91cCk7XG4gIGlmIChzbmFwSW5kZXggPj0gc25hcEdyaWQubGVuZ3RoKSBzbmFwSW5kZXggPSBzbmFwR3JpZC5sZW5ndGggLSAxO1xuICBjb25zdCB0cmFuc2xhdGUgPSAtc25hcEdyaWRbc25hcEluZGV4XTsgLy8gTm9ybWFsaXplIHNsaWRlSW5kZXhcblxuICBpZiAocGFyYW1zLm5vcm1hbGl6ZVNsaWRlSW5kZXgpIHtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNsaWRlc0dyaWQubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWRUcmFuc2xhdGUgPSAtTWF0aC5mbG9vcih0cmFuc2xhdGUgKiAxMDApO1xuICAgICAgY29uc3Qgbm9ybWFsaXplZEdyaWQgPSBNYXRoLmZsb29yKHNsaWRlc0dyaWRbaV0gKiAxMDApO1xuICAgICAgY29uc3Qgbm9ybWFsaXplZEdyaWROZXh0ID0gTWF0aC5mbG9vcihzbGlkZXNHcmlkW2kgKyAxXSAqIDEwMCk7XG5cbiAgICAgIGlmICh0eXBlb2Ygc2xpZGVzR3JpZFtpICsgMV0gIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIGlmIChub3JtYWxpemVkVHJhbnNsYXRlID49IG5vcm1hbGl6ZWRHcmlkICYmIG5vcm1hbGl6ZWRUcmFuc2xhdGUgPCBub3JtYWxpemVkR3JpZE5leHQgLSAobm9ybWFsaXplZEdyaWROZXh0IC0gbm9ybWFsaXplZEdyaWQpIC8gMikge1xuICAgICAgICAgIHNsaWRlSW5kZXggPSBpO1xuICAgICAgICB9IGVsc2UgaWYgKG5vcm1hbGl6ZWRUcmFuc2xhdGUgPj0gbm9ybWFsaXplZEdyaWQgJiYgbm9ybWFsaXplZFRyYW5zbGF0ZSA8IG5vcm1hbGl6ZWRHcmlkTmV4dCkge1xuICAgICAgICAgIHNsaWRlSW5kZXggPSBpICsgMTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChub3JtYWxpemVkVHJhbnNsYXRlID49IG5vcm1hbGl6ZWRHcmlkKSB7XG4gICAgICAgIHNsaWRlSW5kZXggPSBpO1xuICAgICAgfVxuICAgIH1cbiAgfSAvLyBEaXJlY3Rpb25zIGxvY2tzXG5cblxuICBpZiAoc3dpcGVyLmluaXRpYWxpemVkICYmIHNsaWRlSW5kZXggIT09IGFjdGl2ZUluZGV4KSB7XG4gICAgaWYgKCFzd2lwZXIuYWxsb3dTbGlkZU5leHQgJiYgdHJhbnNsYXRlIDwgc3dpcGVyLnRyYW5zbGF0ZSAmJiB0cmFuc2xhdGUgPCBzd2lwZXIubWluVHJhbnNsYXRlKCkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAoIXN3aXBlci5hbGxvd1NsaWRlUHJldiAmJiB0cmFuc2xhdGUgPiBzd2lwZXIudHJhbnNsYXRlICYmIHRyYW5zbGF0ZSA+IHN3aXBlci5tYXhUcmFuc2xhdGUoKSkge1xuICAgICAgaWYgKChhY3RpdmVJbmRleCB8fCAwKSAhPT0gc2xpZGVJbmRleCkgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIGlmIChzbGlkZUluZGV4ICE9PSAocHJldmlvdXNJbmRleCB8fCAwKSAmJiBydW5DYWxsYmFja3MpIHtcbiAgICBzd2lwZXIuZW1pdCgnYmVmb3JlU2xpZGVDaGFuZ2VTdGFydCcpO1xuICB9IC8vIFVwZGF0ZSBwcm9ncmVzc1xuXG5cbiAgc3dpcGVyLnVwZGF0ZVByb2dyZXNzKHRyYW5zbGF0ZSk7XG4gIGxldCBkaXJlY3Rpb247XG4gIGlmIChzbGlkZUluZGV4ID4gYWN0aXZlSW5kZXgpIGRpcmVjdGlvbiA9ICduZXh0JztlbHNlIGlmIChzbGlkZUluZGV4IDwgYWN0aXZlSW5kZXgpIGRpcmVjdGlvbiA9ICdwcmV2JztlbHNlIGRpcmVjdGlvbiA9ICdyZXNldCc7IC8vIFVwZGF0ZSBJbmRleFxuXG4gIGlmIChydGwgJiYgLXRyYW5zbGF0ZSA9PT0gc3dpcGVyLnRyYW5zbGF0ZSB8fCAhcnRsICYmIHRyYW5zbGF0ZSA9PT0gc3dpcGVyLnRyYW5zbGF0ZSkge1xuICAgIHN3aXBlci51cGRhdGVBY3RpdmVJbmRleChzbGlkZUluZGV4KTsgLy8gVXBkYXRlIEhlaWdodFxuXG4gICAgaWYgKHBhcmFtcy5hdXRvSGVpZ2h0KSB7XG4gICAgICBzd2lwZXIudXBkYXRlQXV0b0hlaWdodCgpO1xuICAgIH1cblxuICAgIHN3aXBlci51cGRhdGVTbGlkZXNDbGFzc2VzKCk7XG5cbiAgICBpZiAocGFyYW1zLmVmZmVjdCAhPT0gJ3NsaWRlJykge1xuICAgICAgc3dpcGVyLnNldFRyYW5zbGF0ZSh0cmFuc2xhdGUpO1xuICAgIH1cblxuICAgIGlmIChkaXJlY3Rpb24gIT09ICdyZXNldCcpIHtcbiAgICAgIHN3aXBlci50cmFuc2l0aW9uU3RhcnQocnVuQ2FsbGJhY2tzLCBkaXJlY3Rpb24pO1xuICAgICAgc3dpcGVyLnRyYW5zaXRpb25FbmQocnVuQ2FsbGJhY2tzLCBkaXJlY3Rpb24pO1xuICAgIH1cblxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGlmIChwYXJhbXMuY3NzTW9kZSkge1xuICAgIGNvbnN0IGlzSCA9IHN3aXBlci5pc0hvcml6b250YWwoKTtcbiAgICBjb25zdCB0ID0gcnRsID8gdHJhbnNsYXRlIDogLXRyYW5zbGF0ZTtcblxuICAgIGlmIChzcGVlZCA9PT0gMCkge1xuICAgICAgY29uc3QgaXNWaXJ0dWFsID0gc3dpcGVyLnZpcnR1YWwgJiYgc3dpcGVyLnBhcmFtcy52aXJ0dWFsLmVuYWJsZWQ7XG5cbiAgICAgIGlmIChpc1ZpcnR1YWwpIHtcbiAgICAgICAgc3dpcGVyLndyYXBwZXJFbC5zdHlsZS5zY3JvbGxTbmFwVHlwZSA9ICdub25lJztcbiAgICAgICAgc3dpcGVyLl9pbW1lZGlhdGVWaXJ0dWFsID0gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgd3JhcHBlckVsW2lzSCA/ICdzY3JvbGxMZWZ0JyA6ICdzY3JvbGxUb3AnXSA9IHQ7XG5cbiAgICAgIGlmIChpc1ZpcnR1YWwpIHtcbiAgICAgICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgICAgICBzd2lwZXIud3JhcHBlckVsLnN0eWxlLnNjcm9sbFNuYXBUeXBlID0gJyc7XG4gICAgICAgICAgc3dpcGVyLl9zd2lwZXJJbW1lZGlhdGVWaXJ0dWFsID0gZmFsc2U7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoIXN3aXBlci5zdXBwb3J0LnNtb290aFNjcm9sbCkge1xuICAgICAgICBhbmltYXRlQ1NTTW9kZVNjcm9sbCh7XG4gICAgICAgICAgc3dpcGVyLFxuICAgICAgICAgIHRhcmdldFBvc2l0aW9uOiB0LFxuICAgICAgICAgIHNpZGU6IGlzSCA/ICdsZWZ0JyA6ICd0b3AnXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgd3JhcHBlckVsLnNjcm9sbFRvKHtcbiAgICAgICAgW2lzSCA/ICdsZWZ0JyA6ICd0b3AnXTogdCxcbiAgICAgICAgYmVoYXZpb3I6ICdzbW9vdGgnXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHN3aXBlci5zZXRUcmFuc2l0aW9uKHNwZWVkKTtcbiAgc3dpcGVyLnNldFRyYW5zbGF0ZSh0cmFuc2xhdGUpO1xuICBzd2lwZXIudXBkYXRlQWN0aXZlSW5kZXgoc2xpZGVJbmRleCk7XG4gIHN3aXBlci51cGRhdGVTbGlkZXNDbGFzc2VzKCk7XG4gIHN3aXBlci5lbWl0KCdiZWZvcmVUcmFuc2l0aW9uU3RhcnQnLCBzcGVlZCwgaW50ZXJuYWwpO1xuICBzd2lwZXIudHJhbnNpdGlvblN0YXJ0KHJ1bkNhbGxiYWNrcywgZGlyZWN0aW9uKTtcblxuICBpZiAoc3BlZWQgPT09IDApIHtcbiAgICBzd2lwZXIudHJhbnNpdGlvbkVuZChydW5DYWxsYmFja3MsIGRpcmVjdGlvbik7XG4gIH0gZWxzZSBpZiAoIXN3aXBlci5hbmltYXRpbmcpIHtcbiAgICBzd2lwZXIuYW5pbWF0aW5nID0gdHJ1ZTtcblxuICAgIGlmICghc3dpcGVyLm9uU2xpZGVUb1dyYXBwZXJUcmFuc2l0aW9uRW5kKSB7XG4gICAgICBzd2lwZXIub25TbGlkZVRvV3JhcHBlclRyYW5zaXRpb25FbmQgPSBmdW5jdGlvbiB0cmFuc2l0aW9uRW5kKGUpIHtcbiAgICAgICAgaWYgKCFzd2lwZXIgfHwgc3dpcGVyLmRlc3Ryb3llZCkgcmV0dXJuO1xuICAgICAgICBpZiAoZS50YXJnZXQgIT09IHRoaXMpIHJldHVybjtcbiAgICAgICAgc3dpcGVyLiR3cmFwcGVyRWxbMF0ucmVtb3ZlRXZlbnRMaXN0ZW5lcigndHJhbnNpdGlvbmVuZCcsIHN3aXBlci5vblNsaWRlVG9XcmFwcGVyVHJhbnNpdGlvbkVuZCk7XG4gICAgICAgIHN3aXBlci4kd3JhcHBlckVsWzBdLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3dlYmtpdFRyYW5zaXRpb25FbmQnLCBzd2lwZXIub25TbGlkZVRvV3JhcHBlclRyYW5zaXRpb25FbmQpO1xuICAgICAgICBzd2lwZXIub25TbGlkZVRvV3JhcHBlclRyYW5zaXRpb25FbmQgPSBudWxsO1xuICAgICAgICBkZWxldGUgc3dpcGVyLm9uU2xpZGVUb1dyYXBwZXJUcmFuc2l0aW9uRW5kO1xuICAgICAgICBzd2lwZXIudHJhbnNpdGlvbkVuZChydW5DYWxsYmFja3MsIGRpcmVjdGlvbik7XG4gICAgICB9O1xuICAgIH1cblxuICAgIHN3aXBlci4kd3JhcHBlckVsWzBdLmFkZEV2ZW50TGlzdGVuZXIoJ3RyYW5zaXRpb25lbmQnLCBzd2lwZXIub25TbGlkZVRvV3JhcHBlclRyYW5zaXRpb25FbmQpO1xuICAgIHN3aXBlci4kd3JhcHBlckVsWzBdLmFkZEV2ZW50TGlzdGVuZXIoJ3dlYmtpdFRyYW5zaXRpb25FbmQnLCBzd2lwZXIub25TbGlkZVRvV3JhcHBlclRyYW5zaXRpb25FbmQpO1xuICB9XG5cbiAgcmV0dXJuIHRydWU7XG59IiwiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gc2xpZGVUb0xvb3AoaW5kZXggPSAwLCBzcGVlZCA9IHRoaXMucGFyYW1zLnNwZWVkLCBydW5DYWxsYmFja3MgPSB0cnVlLCBpbnRlcm5hbCkge1xuICBpZiAodHlwZW9mIGluZGV4ID09PSAnc3RyaW5nJykge1xuICAgIC8qKlxuICAgICAqIFRoZSBgaW5kZXhgIGFyZ3VtZW50IGNvbnZlcnRlZCBmcm9tIGBzdHJpbmdgIHRvIGBudW1iZXJgLlxuICAgICAqIEB0eXBlIHtudW1iZXJ9XG4gICAgICovXG4gICAgY29uc3QgaW5kZXhBc051bWJlciA9IHBhcnNlSW50KGluZGV4LCAxMCk7XG4gICAgLyoqXG4gICAgICogRGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSBgaW5kZXhgIGFyZ3VtZW50IGlzIGEgdmFsaWQgYG51bWJlcmBcbiAgICAgKiBhZnRlciBiZWluZyBjb252ZXJ0ZWQgZnJvbSB0aGUgYHN0cmluZ2AgdHlwZS5cbiAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgKi9cblxuICAgIGNvbnN0IGlzVmFsaWROdW1iZXIgPSBpc0Zpbml0ZShpbmRleEFzTnVtYmVyKTtcblxuICAgIGlmICghaXNWYWxpZE51bWJlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBUaGUgcGFzc2VkLWluICdpbmRleCcgKHN0cmluZykgY291bGRuJ3QgYmUgY29udmVydGVkIHRvICdudW1iZXInLiBbJHtpbmRleH1dIGdpdmVuLmApO1xuICAgIH0gLy8gS25vd2luZyB0aGF0IHRoZSBjb252ZXJ0ZWQgYGluZGV4YCBpcyBhIHZhbGlkIG51bWJlcixcbiAgICAvLyB3ZSBjYW4gdXBkYXRlIHRoZSBvcmlnaW5hbCBhcmd1bWVudCdzIHZhbHVlLlxuXG5cbiAgICBpbmRleCA9IGluZGV4QXNOdW1iZXI7XG4gIH1cblxuICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICBsZXQgbmV3SW5kZXggPSBpbmRleDtcblxuICBpZiAoc3dpcGVyLnBhcmFtcy5sb29wKSB7XG4gICAgbmV3SW5kZXggKz0gc3dpcGVyLmxvb3BlZFNsaWRlcztcbiAgfVxuXG4gIHJldHVybiBzd2lwZXIuc2xpZGVUbyhuZXdJbmRleCwgc3BlZWQsIHJ1bkNhbGxiYWNrcywgaW50ZXJuYWwpO1xufSIsIi8qIGVzbGludCBuby11bnVzZWQtdmFyczogXCJvZmZcIiAqL1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gc2xpZGVOZXh0KHNwZWVkID0gdGhpcy5wYXJhbXMuc3BlZWQsIHJ1bkNhbGxiYWNrcyA9IHRydWUsIGludGVybmFsKSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gIGNvbnN0IHtcbiAgICBhbmltYXRpbmcsXG4gICAgZW5hYmxlZCxcbiAgICBwYXJhbXNcbiAgfSA9IHN3aXBlcjtcbiAgaWYgKCFlbmFibGVkKSByZXR1cm4gc3dpcGVyO1xuICBsZXQgcGVyR3JvdXAgPSBwYXJhbXMuc2xpZGVzUGVyR3JvdXA7XG5cbiAgaWYgKHBhcmFtcy5zbGlkZXNQZXJWaWV3ID09PSAnYXV0bycgJiYgcGFyYW1zLnNsaWRlc1Blckdyb3VwID09PSAxICYmIHBhcmFtcy5zbGlkZXNQZXJHcm91cEF1dG8pIHtcbiAgICBwZXJHcm91cCA9IE1hdGgubWF4KHN3aXBlci5zbGlkZXNQZXJWaWV3RHluYW1pYygnY3VycmVudCcsIHRydWUpLCAxKTtcbiAgfVxuXG4gIGNvbnN0IGluY3JlbWVudCA9IHN3aXBlci5hY3RpdmVJbmRleCA8IHBhcmFtcy5zbGlkZXNQZXJHcm91cFNraXAgPyAxIDogcGVyR3JvdXA7XG5cbiAgaWYgKHBhcmFtcy5sb29wKSB7XG4gICAgaWYgKGFuaW1hdGluZyAmJiBwYXJhbXMubG9vcFByZXZlbnRzU2xpZGUpIHJldHVybiBmYWxzZTtcbiAgICBzd2lwZXIubG9vcEZpeCgpOyAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmVcblxuICAgIHN3aXBlci5fY2xpZW50TGVmdCA9IHN3aXBlci4kd3JhcHBlckVsWzBdLmNsaWVudExlZnQ7XG4gIH1cblxuICBpZiAocGFyYW1zLnJld2luZCAmJiBzd2lwZXIuaXNFbmQpIHtcbiAgICByZXR1cm4gc3dpcGVyLnNsaWRlVG8oMCwgc3BlZWQsIHJ1bkNhbGxiYWNrcywgaW50ZXJuYWwpO1xuICB9XG5cbiAgcmV0dXJuIHN3aXBlci5zbGlkZVRvKHN3aXBlci5hY3RpdmVJbmRleCArIGluY3JlbWVudCwgc3BlZWQsIHJ1bkNhbGxiYWNrcywgaW50ZXJuYWwpO1xufSIsIi8qIGVzbGludCBuby11bnVzZWQtdmFyczogXCJvZmZcIiAqL1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gc2xpZGVQcmV2KHNwZWVkID0gdGhpcy5wYXJhbXMuc3BlZWQsIHJ1bkNhbGxiYWNrcyA9IHRydWUsIGludGVybmFsKSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gIGNvbnN0IHtcbiAgICBwYXJhbXMsXG4gICAgYW5pbWF0aW5nLFxuICAgIHNuYXBHcmlkLFxuICAgIHNsaWRlc0dyaWQsXG4gICAgcnRsVHJhbnNsYXRlLFxuICAgIGVuYWJsZWRcbiAgfSA9IHN3aXBlcjtcbiAgaWYgKCFlbmFibGVkKSByZXR1cm4gc3dpcGVyO1xuXG4gIGlmIChwYXJhbXMubG9vcCkge1xuICAgIGlmIChhbmltYXRpbmcgJiYgcGFyYW1zLmxvb3BQcmV2ZW50c1NsaWRlKSByZXR1cm4gZmFsc2U7XG4gICAgc3dpcGVyLmxvb3BGaXgoKTsgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG5cbiAgICBzd2lwZXIuX2NsaWVudExlZnQgPSBzd2lwZXIuJHdyYXBwZXJFbFswXS5jbGllbnRMZWZ0O1xuICB9XG5cbiAgY29uc3QgdHJhbnNsYXRlID0gcnRsVHJhbnNsYXRlID8gc3dpcGVyLnRyYW5zbGF0ZSA6IC1zd2lwZXIudHJhbnNsYXRlO1xuXG4gIGZ1bmN0aW9uIG5vcm1hbGl6ZSh2YWwpIHtcbiAgICBpZiAodmFsIDwgMCkgcmV0dXJuIC1NYXRoLmZsb29yKE1hdGguYWJzKHZhbCkpO1xuICAgIHJldHVybiBNYXRoLmZsb29yKHZhbCk7XG4gIH1cblxuICBjb25zdCBub3JtYWxpemVkVHJhbnNsYXRlID0gbm9ybWFsaXplKHRyYW5zbGF0ZSk7XG4gIGNvbnN0IG5vcm1hbGl6ZWRTbmFwR3JpZCA9IHNuYXBHcmlkLm1hcCh2YWwgPT4gbm9ybWFsaXplKHZhbCkpO1xuICBsZXQgcHJldlNuYXAgPSBzbmFwR3JpZFtub3JtYWxpemVkU25hcEdyaWQuaW5kZXhPZihub3JtYWxpemVkVHJhbnNsYXRlKSAtIDFdO1xuXG4gIGlmICh0eXBlb2YgcHJldlNuYXAgPT09ICd1bmRlZmluZWQnICYmIHBhcmFtcy5jc3NNb2RlKSB7XG4gICAgbGV0IHByZXZTbmFwSW5kZXg7XG4gICAgc25hcEdyaWQuZm9yRWFjaCgoc25hcCwgc25hcEluZGV4KSA9PiB7XG4gICAgICBpZiAobm9ybWFsaXplZFRyYW5zbGF0ZSA+PSBzbmFwKSB7XG4gICAgICAgIC8vIHByZXZTbmFwID0gc25hcDtcbiAgICAgICAgcHJldlNuYXBJbmRleCA9IHNuYXBJbmRleDtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGlmICh0eXBlb2YgcHJldlNuYXBJbmRleCAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIHByZXZTbmFwID0gc25hcEdyaWRbcHJldlNuYXBJbmRleCA+IDAgPyBwcmV2U25hcEluZGV4IC0gMSA6IHByZXZTbmFwSW5kZXhdO1xuICAgIH1cbiAgfVxuXG4gIGxldCBwcmV2SW5kZXggPSAwO1xuXG4gIGlmICh0eXBlb2YgcHJldlNuYXAgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgcHJldkluZGV4ID0gc2xpZGVzR3JpZC5pbmRleE9mKHByZXZTbmFwKTtcbiAgICBpZiAocHJldkluZGV4IDwgMCkgcHJldkluZGV4ID0gc3dpcGVyLmFjdGl2ZUluZGV4IC0gMTtcblxuICAgIGlmIChwYXJhbXMuc2xpZGVzUGVyVmlldyA9PT0gJ2F1dG8nICYmIHBhcmFtcy5zbGlkZXNQZXJHcm91cCA9PT0gMSAmJiBwYXJhbXMuc2xpZGVzUGVyR3JvdXBBdXRvKSB7XG4gICAgICBwcmV2SW5kZXggPSBwcmV2SW5kZXggLSBzd2lwZXIuc2xpZGVzUGVyVmlld0R5bmFtaWMoJ3ByZXZpb3VzJywgdHJ1ZSkgKyAxO1xuICAgICAgcHJldkluZGV4ID0gTWF0aC5tYXgocHJldkluZGV4LCAwKTtcbiAgICB9XG4gIH1cblxuICBpZiAocGFyYW1zLnJld2luZCAmJiBzd2lwZXIuaXNCZWdpbm5pbmcpIHtcbiAgICBjb25zdCBsYXN0SW5kZXggPSBzd2lwZXIucGFyYW1zLnZpcnR1YWwgJiYgc3dpcGVyLnBhcmFtcy52aXJ0dWFsLmVuYWJsZWQgJiYgc3dpcGVyLnZpcnR1YWwgPyBzd2lwZXIudmlydHVhbC5zbGlkZXMubGVuZ3RoIC0gMSA6IHN3aXBlci5zbGlkZXMubGVuZ3RoIC0gMTtcbiAgICByZXR1cm4gc3dpcGVyLnNsaWRlVG8obGFzdEluZGV4LCBzcGVlZCwgcnVuQ2FsbGJhY2tzLCBpbnRlcm5hbCk7XG4gIH1cblxuICByZXR1cm4gc3dpcGVyLnNsaWRlVG8ocHJldkluZGV4LCBzcGVlZCwgcnVuQ2FsbGJhY2tzLCBpbnRlcm5hbCk7XG59IiwiLyogZXNsaW50IG5vLXVudXNlZC12YXJzOiBcIm9mZlwiICovXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBzbGlkZVJlc2V0KHNwZWVkID0gdGhpcy5wYXJhbXMuc3BlZWQsIHJ1bkNhbGxiYWNrcyA9IHRydWUsIGludGVybmFsKSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gIHJldHVybiBzd2lwZXIuc2xpZGVUbyhzd2lwZXIuYWN0aXZlSW5kZXgsIHNwZWVkLCBydW5DYWxsYmFja3MsIGludGVybmFsKTtcbn0iLCIvKiBlc2xpbnQgbm8tdW51c2VkLXZhcnM6IFwib2ZmXCIgKi9cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHNsaWRlVG9DbG9zZXN0KHNwZWVkID0gdGhpcy5wYXJhbXMuc3BlZWQsIHJ1bkNhbGxiYWNrcyA9IHRydWUsIGludGVybmFsLCB0aHJlc2hvbGQgPSAwLjUpIHtcbiAgY29uc3Qgc3dpcGVyID0gdGhpcztcbiAgbGV0IGluZGV4ID0gc3dpcGVyLmFjdGl2ZUluZGV4O1xuICBjb25zdCBza2lwID0gTWF0aC5taW4oc3dpcGVyLnBhcmFtcy5zbGlkZXNQZXJHcm91cFNraXAsIGluZGV4KTtcbiAgY29uc3Qgc25hcEluZGV4ID0gc2tpcCArIE1hdGguZmxvb3IoKGluZGV4IC0gc2tpcCkgLyBzd2lwZXIucGFyYW1zLnNsaWRlc1Blckdyb3VwKTtcbiAgY29uc3QgdHJhbnNsYXRlID0gc3dpcGVyLnJ0bFRyYW5zbGF0ZSA/IHN3aXBlci50cmFuc2xhdGUgOiAtc3dpcGVyLnRyYW5zbGF0ZTtcblxuICBpZiAodHJhbnNsYXRlID49IHN3aXBlci5zbmFwR3JpZFtzbmFwSW5kZXhdKSB7XG4gICAgLy8gVGhlIGN1cnJlbnQgdHJhbnNsYXRlIGlzIG9uIG9yIGFmdGVyIHRoZSBjdXJyZW50IHNuYXAgaW5kZXgsIHNvIHRoZSBjaG9pY2VcbiAgICAvLyBpcyBiZXR3ZWVuIHRoZSBjdXJyZW50IGluZGV4IGFuZCB0aGUgb25lIGFmdGVyIGl0LlxuICAgIGNvbnN0IGN1cnJlbnRTbmFwID0gc3dpcGVyLnNuYXBHcmlkW3NuYXBJbmRleF07XG4gICAgY29uc3QgbmV4dFNuYXAgPSBzd2lwZXIuc25hcEdyaWRbc25hcEluZGV4ICsgMV07XG5cbiAgICBpZiAodHJhbnNsYXRlIC0gY3VycmVudFNuYXAgPiAobmV4dFNuYXAgLSBjdXJyZW50U25hcCkgKiB0aHJlc2hvbGQpIHtcbiAgICAgIGluZGV4ICs9IHN3aXBlci5wYXJhbXMuc2xpZGVzUGVyR3JvdXA7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIC8vIFRoZSBjdXJyZW50IHRyYW5zbGF0ZSBpcyBiZWZvcmUgdGhlIGN1cnJlbnQgc25hcCBpbmRleCwgc28gdGhlIGNob2ljZVxuICAgIC8vIGlzIGJldHdlZW4gdGhlIGN1cnJlbnQgaW5kZXggYW5kIHRoZSBvbmUgYmVmb3JlIGl0LlxuICAgIGNvbnN0IHByZXZTbmFwID0gc3dpcGVyLnNuYXBHcmlkW3NuYXBJbmRleCAtIDFdO1xuICAgIGNvbnN0IGN1cnJlbnRTbmFwID0gc3dpcGVyLnNuYXBHcmlkW3NuYXBJbmRleF07XG5cbiAgICBpZiAodHJhbnNsYXRlIC0gcHJldlNuYXAgPD0gKGN1cnJlbnRTbmFwIC0gcHJldlNuYXApICogdGhyZXNob2xkKSB7XG4gICAgICBpbmRleCAtPSBzd2lwZXIucGFyYW1zLnNsaWRlc1Blckdyb3VwO1xuICAgIH1cbiAgfVxuXG4gIGluZGV4ID0gTWF0aC5tYXgoaW5kZXgsIDApO1xuICBpbmRleCA9IE1hdGgubWluKGluZGV4LCBzd2lwZXIuc2xpZGVzR3JpZC5sZW5ndGggLSAxKTtcbiAgcmV0dXJuIHN3aXBlci5zbGlkZVRvKGluZGV4LCBzcGVlZCwgcnVuQ2FsbGJhY2tzLCBpbnRlcm5hbCk7XG59IiwiaW1wb3J0ICQgZnJvbSAnLi4vLi4vc2hhcmVkL2RvbS5qcyc7XG5pbXBvcnQgeyBuZXh0VGljayB9IGZyb20gJy4uLy4uL3NoYXJlZC91dGlscy5qcyc7XG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBzbGlkZVRvQ2xpY2tlZFNsaWRlKCkge1xuICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICBjb25zdCB7XG4gICAgcGFyYW1zLFxuICAgICR3cmFwcGVyRWxcbiAgfSA9IHN3aXBlcjtcbiAgY29uc3Qgc2xpZGVzUGVyVmlldyA9IHBhcmFtcy5zbGlkZXNQZXJWaWV3ID09PSAnYXV0bycgPyBzd2lwZXIuc2xpZGVzUGVyVmlld0R5bmFtaWMoKSA6IHBhcmFtcy5zbGlkZXNQZXJWaWV3O1xuICBsZXQgc2xpZGVUb0luZGV4ID0gc3dpcGVyLmNsaWNrZWRJbmRleDtcbiAgbGV0IHJlYWxJbmRleDtcblxuICBpZiAocGFyYW1zLmxvb3ApIHtcbiAgICBpZiAoc3dpcGVyLmFuaW1hdGluZykgcmV0dXJuO1xuICAgIHJlYWxJbmRleCA9IHBhcnNlSW50KCQoc3dpcGVyLmNsaWNrZWRTbGlkZSkuYXR0cignZGF0YS1zd2lwZXItc2xpZGUtaW5kZXgnKSwgMTApO1xuXG4gICAgaWYgKHBhcmFtcy5jZW50ZXJlZFNsaWRlcykge1xuICAgICAgaWYgKHNsaWRlVG9JbmRleCA8IHN3aXBlci5sb29wZWRTbGlkZXMgLSBzbGlkZXNQZXJWaWV3IC8gMiB8fCBzbGlkZVRvSW5kZXggPiBzd2lwZXIuc2xpZGVzLmxlbmd0aCAtIHN3aXBlci5sb29wZWRTbGlkZXMgKyBzbGlkZXNQZXJWaWV3IC8gMikge1xuICAgICAgICBzd2lwZXIubG9vcEZpeCgpO1xuICAgICAgICBzbGlkZVRvSW5kZXggPSAkd3JhcHBlckVsLmNoaWxkcmVuKGAuJHtwYXJhbXMuc2xpZGVDbGFzc31bZGF0YS1zd2lwZXItc2xpZGUtaW5kZXg9XCIke3JlYWxJbmRleH1cIl06bm90KC4ke3BhcmFtcy5zbGlkZUR1cGxpY2F0ZUNsYXNzfSlgKS5lcSgwKS5pbmRleCgpO1xuICAgICAgICBuZXh0VGljaygoKSA9PiB7XG4gICAgICAgICAgc3dpcGVyLnNsaWRlVG8oc2xpZGVUb0luZGV4KTtcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzd2lwZXIuc2xpZGVUbyhzbGlkZVRvSW5kZXgpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoc2xpZGVUb0luZGV4ID4gc3dpcGVyLnNsaWRlcy5sZW5ndGggLSBzbGlkZXNQZXJWaWV3KSB7XG4gICAgICBzd2lwZXIubG9vcEZpeCgpO1xuICAgICAgc2xpZGVUb0luZGV4ID0gJHdyYXBwZXJFbC5jaGlsZHJlbihgLiR7cGFyYW1zLnNsaWRlQ2xhc3N9W2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4PVwiJHtyZWFsSW5kZXh9XCJdOm5vdCguJHtwYXJhbXMuc2xpZGVEdXBsaWNhdGVDbGFzc30pYCkuZXEoMCkuaW5kZXgoKTtcbiAgICAgIG5leHRUaWNrKCgpID0+IHtcbiAgICAgICAgc3dpcGVyLnNsaWRlVG8oc2xpZGVUb0luZGV4KTtcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBzd2lwZXIuc2xpZGVUbyhzbGlkZVRvSW5kZXgpO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBzd2lwZXIuc2xpZGVUbyhzbGlkZVRvSW5kZXgpO1xuICB9XG59IiwiaW1wb3J0IHNsaWRlVG8gZnJvbSAnLi9zbGlkZVRvLmpzJztcbmltcG9ydCBzbGlkZVRvTG9vcCBmcm9tICcuL3NsaWRlVG9Mb29wLmpzJztcbmltcG9ydCBzbGlkZU5leHQgZnJvbSAnLi9zbGlkZU5leHQuanMnO1xuaW1wb3J0IHNsaWRlUHJldiBmcm9tICcuL3NsaWRlUHJldi5qcyc7XG5pbXBvcnQgc2xpZGVSZXNldCBmcm9tICcuL3NsaWRlUmVzZXQuanMnO1xuaW1wb3J0IHNsaWRlVG9DbG9zZXN0IGZyb20gJy4vc2xpZGVUb0Nsb3Nlc3QuanMnO1xuaW1wb3J0IHNsaWRlVG9DbGlja2VkU2xpZGUgZnJvbSAnLi9zbGlkZVRvQ2xpY2tlZFNsaWRlLmpzJztcbmV4cG9ydCBkZWZhdWx0IHtcbiAgc2xpZGVUbyxcbiAgc2xpZGVUb0xvb3AsXG4gIHNsaWRlTmV4dCxcbiAgc2xpZGVQcmV2LFxuICBzbGlkZVJlc2V0LFxuICBzbGlkZVRvQ2xvc2VzdCxcbiAgc2xpZGVUb0NsaWNrZWRTbGlkZVxufTsiLCJpbXBvcnQgeyBnZXREb2N1bWVudCB9IGZyb20gJ3Nzci13aW5kb3cnO1xuaW1wb3J0ICQgZnJvbSAnLi4vLi4vc2hhcmVkL2RvbS5qcyc7XG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBsb29wQ3JlYXRlKCkge1xuICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICBjb25zdCBkb2N1bWVudCA9IGdldERvY3VtZW50KCk7XG4gIGNvbnN0IHtcbiAgICBwYXJhbXMsXG4gICAgJHdyYXBwZXJFbFxuICB9ID0gc3dpcGVyOyAvLyBSZW1vdmUgZHVwbGljYXRlZCBzbGlkZXNcblxuICBjb25zdCAkc2VsZWN0b3IgPSAkd3JhcHBlckVsLmNoaWxkcmVuKCkubGVuZ3RoID4gMCA/ICQoJHdyYXBwZXJFbC5jaGlsZHJlbigpWzBdLnBhcmVudE5vZGUpIDogJHdyYXBwZXJFbDtcbiAgJHNlbGVjdG9yLmNoaWxkcmVuKGAuJHtwYXJhbXMuc2xpZGVDbGFzc30uJHtwYXJhbXMuc2xpZGVEdXBsaWNhdGVDbGFzc31gKS5yZW1vdmUoKTtcbiAgbGV0IHNsaWRlcyA9ICRzZWxlY3Rvci5jaGlsZHJlbihgLiR7cGFyYW1zLnNsaWRlQ2xhc3N9YCk7XG5cbiAgaWYgKHBhcmFtcy5sb29wRmlsbEdyb3VwV2l0aEJsYW5rKSB7XG4gICAgY29uc3QgYmxhbmtTbGlkZXNOdW0gPSBwYXJhbXMuc2xpZGVzUGVyR3JvdXAgLSBzbGlkZXMubGVuZ3RoICUgcGFyYW1zLnNsaWRlc1Blckdyb3VwO1xuXG4gICAgaWYgKGJsYW5rU2xpZGVzTnVtICE9PSBwYXJhbXMuc2xpZGVzUGVyR3JvdXApIHtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYmxhbmtTbGlkZXNOdW07IGkgKz0gMSkge1xuICAgICAgICBjb25zdCBibGFua05vZGUgPSAkKGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpKS5hZGRDbGFzcyhgJHtwYXJhbXMuc2xpZGVDbGFzc30gJHtwYXJhbXMuc2xpZGVCbGFua0NsYXNzfWApO1xuICAgICAgICAkc2VsZWN0b3IuYXBwZW5kKGJsYW5rTm9kZSk7XG4gICAgICB9XG5cbiAgICAgIHNsaWRlcyA9ICRzZWxlY3Rvci5jaGlsZHJlbihgLiR7cGFyYW1zLnNsaWRlQ2xhc3N9YCk7XG4gICAgfVxuICB9XG5cbiAgaWYgKHBhcmFtcy5zbGlkZXNQZXJWaWV3ID09PSAnYXV0bycgJiYgIXBhcmFtcy5sb29wZWRTbGlkZXMpIHBhcmFtcy5sb29wZWRTbGlkZXMgPSBzbGlkZXMubGVuZ3RoO1xuICBzd2lwZXIubG9vcGVkU2xpZGVzID0gTWF0aC5jZWlsKHBhcnNlRmxvYXQocGFyYW1zLmxvb3BlZFNsaWRlcyB8fCBwYXJhbXMuc2xpZGVzUGVyVmlldywgMTApKTtcbiAgc3dpcGVyLmxvb3BlZFNsaWRlcyArPSBwYXJhbXMubG9vcEFkZGl0aW9uYWxTbGlkZXM7XG5cbiAgaWYgKHN3aXBlci5sb29wZWRTbGlkZXMgPiBzbGlkZXMubGVuZ3RoICYmIHN3aXBlci5wYXJhbXMubG9vcGVkU2xpZGVzTGltaXQpIHtcbiAgICBzd2lwZXIubG9vcGVkU2xpZGVzID0gc2xpZGVzLmxlbmd0aDtcbiAgfVxuXG4gIGNvbnN0IHByZXBlbmRTbGlkZXMgPSBbXTtcbiAgY29uc3QgYXBwZW5kU2xpZGVzID0gW107XG4gIHNsaWRlcy5lYWNoKChlbCwgaW5kZXgpID0+IHtcbiAgICBjb25zdCBzbGlkZSA9ICQoZWwpO1xuICAgIHNsaWRlLmF0dHIoJ2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4JywgaW5kZXgpO1xuICB9KTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IHN3aXBlci5sb29wZWRTbGlkZXM7IGkgKz0gMSkge1xuICAgIGNvbnN0IGluZGV4ID0gaSAtIE1hdGguZmxvb3IoaSAvIHNsaWRlcy5sZW5ndGgpICogc2xpZGVzLmxlbmd0aDtcbiAgICBhcHBlbmRTbGlkZXMucHVzaChzbGlkZXMuZXEoaW5kZXgpWzBdKTtcbiAgICBwcmVwZW5kU2xpZGVzLnVuc2hpZnQoc2xpZGVzLmVxKHNsaWRlcy5sZW5ndGggLSBpbmRleCAtIDEpWzBdKTtcbiAgfVxuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXBwZW5kU2xpZGVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgJHNlbGVjdG9yLmFwcGVuZCgkKGFwcGVuZFNsaWRlc1tpXS5jbG9uZU5vZGUodHJ1ZSkpLmFkZENsYXNzKHBhcmFtcy5zbGlkZUR1cGxpY2F0ZUNsYXNzKSk7XG4gIH1cblxuICBmb3IgKGxldCBpID0gcHJlcGVuZFNsaWRlcy5sZW5ndGggLSAxOyBpID49IDA7IGkgLT0gMSkge1xuICAgICRzZWxlY3Rvci5wcmVwZW5kKCQocHJlcGVuZFNsaWRlc1tpXS5jbG9uZU5vZGUodHJ1ZSkpLmFkZENsYXNzKHBhcmFtcy5zbGlkZUR1cGxpY2F0ZUNsYXNzKSk7XG4gIH1cbn0iLCJleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBsb29wRml4KCkge1xuICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICBzd2lwZXIuZW1pdCgnYmVmb3JlTG9vcEZpeCcpO1xuICBjb25zdCB7XG4gICAgYWN0aXZlSW5kZXgsXG4gICAgc2xpZGVzLFxuICAgIGxvb3BlZFNsaWRlcyxcbiAgICBhbGxvd1NsaWRlUHJldixcbiAgICBhbGxvd1NsaWRlTmV4dCxcbiAgICBzbmFwR3JpZCxcbiAgICBydGxUcmFuc2xhdGU6IHJ0bFxuICB9ID0gc3dpcGVyO1xuICBsZXQgbmV3SW5kZXg7XG4gIHN3aXBlci5hbGxvd1NsaWRlUHJldiA9IHRydWU7XG4gIHN3aXBlci5hbGxvd1NsaWRlTmV4dCA9IHRydWU7XG4gIGNvbnN0IHNuYXBUcmFuc2xhdGUgPSAtc25hcEdyaWRbYWN0aXZlSW5kZXhdO1xuICBjb25zdCBkaWZmID0gc25hcFRyYW5zbGF0ZSAtIHN3aXBlci5nZXRUcmFuc2xhdGUoKTsgLy8gRml4IEZvciBOZWdhdGl2ZSBPdmVyc2xpZGluZ1xuXG4gIGlmIChhY3RpdmVJbmRleCA8IGxvb3BlZFNsaWRlcykge1xuICAgIG5ld0luZGV4ID0gc2xpZGVzLmxlbmd0aCAtIGxvb3BlZFNsaWRlcyAqIDMgKyBhY3RpdmVJbmRleDtcbiAgICBuZXdJbmRleCArPSBsb29wZWRTbGlkZXM7XG4gICAgY29uc3Qgc2xpZGVDaGFuZ2VkID0gc3dpcGVyLnNsaWRlVG8obmV3SW5kZXgsIDAsIGZhbHNlLCB0cnVlKTtcblxuICAgIGlmIChzbGlkZUNoYW5nZWQgJiYgZGlmZiAhPT0gMCkge1xuICAgICAgc3dpcGVyLnNldFRyYW5zbGF0ZSgocnRsID8gLXN3aXBlci50cmFuc2xhdGUgOiBzd2lwZXIudHJhbnNsYXRlKSAtIGRpZmYpO1xuICAgIH1cbiAgfSBlbHNlIGlmIChhY3RpdmVJbmRleCA+PSBzbGlkZXMubGVuZ3RoIC0gbG9vcGVkU2xpZGVzKSB7XG4gICAgLy8gRml4IEZvciBQb3NpdGl2ZSBPdmVyc2xpZGluZ1xuICAgIG5ld0luZGV4ID0gLXNsaWRlcy5sZW5ndGggKyBhY3RpdmVJbmRleCArIGxvb3BlZFNsaWRlcztcbiAgICBuZXdJbmRleCArPSBsb29wZWRTbGlkZXM7XG4gICAgY29uc3Qgc2xpZGVDaGFuZ2VkID0gc3dpcGVyLnNsaWRlVG8obmV3SW5kZXgsIDAsIGZhbHNlLCB0cnVlKTtcblxuICAgIGlmIChzbGlkZUNoYW5nZWQgJiYgZGlmZiAhPT0gMCkge1xuICAgICAgc3dpcGVyLnNldFRyYW5zbGF0ZSgocnRsID8gLXN3aXBlci50cmFuc2xhdGUgOiBzd2lwZXIudHJhbnNsYXRlKSAtIGRpZmYpO1xuICAgIH1cbiAgfVxuXG4gIHN3aXBlci5hbGxvd1NsaWRlUHJldiA9IGFsbG93U2xpZGVQcmV2O1xuICBzd2lwZXIuYWxsb3dTbGlkZU5leHQgPSBhbGxvd1NsaWRlTmV4dDtcbiAgc3dpcGVyLmVtaXQoJ2xvb3BGaXgnKTtcbn0iLCJleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBsb29wRGVzdHJveSgpIHtcbiAgY29uc3Qgc3dpcGVyID0gdGhpcztcbiAgY29uc3Qge1xuICAgICR3cmFwcGVyRWwsXG4gICAgcGFyYW1zLFxuICAgIHNsaWRlc1xuICB9ID0gc3dpcGVyO1xuICAkd3JhcHBlckVsLmNoaWxkcmVuKGAuJHtwYXJhbXMuc2xpZGVDbGFzc30uJHtwYXJhbXMuc2xpZGVEdXBsaWNhdGVDbGFzc30sLiR7cGFyYW1zLnNsaWRlQ2xhc3N9LiR7cGFyYW1zLnNsaWRlQmxhbmtDbGFzc31gKS5yZW1vdmUoKTtcbiAgc2xpZGVzLnJlbW92ZUF0dHIoJ2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4Jyk7XG59IiwiaW1wb3J0IGxvb3BDcmVhdGUgZnJvbSAnLi9sb29wQ3JlYXRlLmpzJztcbmltcG9ydCBsb29wRml4IGZyb20gJy4vbG9vcEZpeC5qcyc7XG5pbXBvcnQgbG9vcERlc3Ryb3kgZnJvbSAnLi9sb29wRGVzdHJveS5qcyc7XG5leHBvcnQgZGVmYXVsdCB7XG4gIGxvb3BDcmVhdGUsXG4gIGxvb3BGaXgsXG4gIGxvb3BEZXN0cm95XG59OyIsImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHNldEdyYWJDdXJzb3IobW92aW5nKSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gIGlmIChzd2lwZXIuc3VwcG9ydC50b3VjaCB8fCAhc3dpcGVyLnBhcmFtcy5zaW11bGF0ZVRvdWNoIHx8IHN3aXBlci5wYXJhbXMud2F0Y2hPdmVyZmxvdyAmJiBzd2lwZXIuaXNMb2NrZWQgfHwgc3dpcGVyLnBhcmFtcy5jc3NNb2RlKSByZXR1cm47XG4gIGNvbnN0IGVsID0gc3dpcGVyLnBhcmFtcy50b3VjaEV2ZW50c1RhcmdldCA9PT0gJ2NvbnRhaW5lcicgPyBzd2lwZXIuZWwgOiBzd2lwZXIud3JhcHBlckVsO1xuICBlbC5zdHlsZS5jdXJzb3IgPSAnbW92ZSc7XG4gIGVsLnN0eWxlLmN1cnNvciA9IG1vdmluZyA/ICdncmFiYmluZycgOiAnZ3JhYic7XG59IiwiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdW5zZXRHcmFiQ3Vyc29yKCkge1xuICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuXG4gIGlmIChzd2lwZXIuc3VwcG9ydC50b3VjaCB8fCBzd2lwZXIucGFyYW1zLndhdGNoT3ZlcmZsb3cgJiYgc3dpcGVyLmlzTG9ja2VkIHx8IHN3aXBlci5wYXJhbXMuY3NzTW9kZSkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIHN3aXBlcltzd2lwZXIucGFyYW1zLnRvdWNoRXZlbnRzVGFyZ2V0ID09PSAnY29udGFpbmVyJyA/ICdlbCcgOiAnd3JhcHBlckVsJ10uc3R5bGUuY3Vyc29yID0gJyc7XG59IiwiaW1wb3J0IHNldEdyYWJDdXJzb3IgZnJvbSAnLi9zZXRHcmFiQ3Vyc29yLmpzJztcbmltcG9ydCB1bnNldEdyYWJDdXJzb3IgZnJvbSAnLi91bnNldEdyYWJDdXJzb3IuanMnO1xuZXhwb3J0IGRlZmF1bHQge1xuICBzZXRHcmFiQ3Vyc29yLFxuICB1bnNldEdyYWJDdXJzb3Jcbn07IiwiaW1wb3J0IHsgZ2V0V2luZG93LCBnZXREb2N1bWVudCB9IGZyb20gJ3Nzci13aW5kb3cnO1xuaW1wb3J0ICQgZnJvbSAnLi4vLi4vc2hhcmVkL2RvbS5qcyc7XG5pbXBvcnQgeyBub3cgfSBmcm9tICcuLi8uLi9zaGFyZWQvdXRpbHMuanMnOyAvLyBNb2RpZmllZCBmcm9tIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzU0NTIwNTU0L2N1c3RvbS1lbGVtZW50LWdldHJvb3Rub2RlLWNsb3Nlc3QtZnVuY3Rpb24tY3Jvc3NpbmctbXVsdGlwbGUtcGFyZW50LXNoYWRvd2RcblxuZnVuY3Rpb24gY2xvc2VzdEVsZW1lbnQoc2VsZWN0b3IsIGJhc2UgPSB0aGlzKSB7XG4gIGZ1bmN0aW9uIF9fY2xvc2VzdEZyb20oZWwpIHtcbiAgICBpZiAoIWVsIHx8IGVsID09PSBnZXREb2N1bWVudCgpIHx8IGVsID09PSBnZXRXaW5kb3coKSkgcmV0dXJuIG51bGw7XG4gICAgaWYgKGVsLmFzc2lnbmVkU2xvdCkgZWwgPSBlbC5hc3NpZ25lZFNsb3Q7XG4gICAgY29uc3QgZm91bmQgPSBlbC5jbG9zZXN0KHNlbGVjdG9yKTtcblxuICAgIGlmICghZm91bmQgJiYgIWVsLmdldFJvb3ROb2RlKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICByZXR1cm4gZm91bmQgfHwgX19jbG9zZXN0RnJvbShlbC5nZXRSb290Tm9kZSgpLmhvc3QpO1xuICB9XG5cbiAgcmV0dXJuIF9fY2xvc2VzdEZyb20oYmFzZSk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIG9uVG91Y2hTdGFydChldmVudCkge1xuICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICBjb25zdCBkb2N1bWVudCA9IGdldERvY3VtZW50KCk7XG4gIGNvbnN0IHdpbmRvdyA9IGdldFdpbmRvdygpO1xuICBjb25zdCBkYXRhID0gc3dpcGVyLnRvdWNoRXZlbnRzRGF0YTtcbiAgY29uc3Qge1xuICAgIHBhcmFtcyxcbiAgICB0b3VjaGVzLFxuICAgIGVuYWJsZWRcbiAgfSA9IHN3aXBlcjtcbiAgaWYgKCFlbmFibGVkKSByZXR1cm47XG5cbiAgaWYgKHN3aXBlci5hbmltYXRpbmcgJiYgcGFyYW1zLnByZXZlbnRJbnRlcmFjdGlvbk9uVHJhbnNpdGlvbikge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGlmICghc3dpcGVyLmFuaW1hdGluZyAmJiBwYXJhbXMuY3NzTW9kZSAmJiBwYXJhbXMubG9vcCkge1xuICAgIHN3aXBlci5sb29wRml4KCk7XG4gIH1cblxuICBsZXQgZSA9IGV2ZW50O1xuICBpZiAoZS5vcmlnaW5hbEV2ZW50KSBlID0gZS5vcmlnaW5hbEV2ZW50O1xuICBsZXQgJHRhcmdldEVsID0gJChlLnRhcmdldCk7XG5cbiAgaWYgKHBhcmFtcy50b3VjaEV2ZW50c1RhcmdldCA9PT0gJ3dyYXBwZXInKSB7XG4gICAgaWYgKCEkdGFyZ2V0RWwuY2xvc2VzdChzd2lwZXIud3JhcHBlckVsKS5sZW5ndGgpIHJldHVybjtcbiAgfVxuXG4gIGRhdGEuaXNUb3VjaEV2ZW50ID0gZS50eXBlID09PSAndG91Y2hzdGFydCc7XG4gIGlmICghZGF0YS5pc1RvdWNoRXZlbnQgJiYgJ3doaWNoJyBpbiBlICYmIGUud2hpY2ggPT09IDMpIHJldHVybjtcbiAgaWYgKCFkYXRhLmlzVG91Y2hFdmVudCAmJiAnYnV0dG9uJyBpbiBlICYmIGUuYnV0dG9uID4gMCkgcmV0dXJuO1xuICBpZiAoZGF0YS5pc1RvdWNoZWQgJiYgZGF0YS5pc01vdmVkKSByZXR1cm47IC8vIGNoYW5nZSB0YXJnZXQgZWwgZm9yIHNoYWRvdyByb290IGNvbXBvbmVudFxuXG4gIGNvbnN0IHN3aXBpbmdDbGFzc0hhc1ZhbHVlID0gISFwYXJhbXMubm9Td2lwaW5nQ2xhc3MgJiYgcGFyYW1zLm5vU3dpcGluZ0NsYXNzICE9PSAnJzsgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG5cbiAgY29uc3QgZXZlbnRQYXRoID0gZXZlbnQuY29tcG9zZWRQYXRoID8gZXZlbnQuY29tcG9zZWRQYXRoKCkgOiBldmVudC5wYXRoO1xuXG4gIGlmIChzd2lwaW5nQ2xhc3NIYXNWYWx1ZSAmJiBlLnRhcmdldCAmJiBlLnRhcmdldC5zaGFkb3dSb290ICYmIGV2ZW50UGF0aCkge1xuICAgICR0YXJnZXRFbCA9ICQoZXZlbnRQYXRoWzBdKTtcbiAgfVxuXG4gIGNvbnN0IG5vU3dpcGluZ1NlbGVjdG9yID0gcGFyYW1zLm5vU3dpcGluZ1NlbGVjdG9yID8gcGFyYW1zLm5vU3dpcGluZ1NlbGVjdG9yIDogYC4ke3BhcmFtcy5ub1N3aXBpbmdDbGFzc31gO1xuICBjb25zdCBpc1RhcmdldFNoYWRvdyA9ICEhKGUudGFyZ2V0ICYmIGUudGFyZ2V0LnNoYWRvd1Jvb3QpOyAvLyB1c2UgY2xvc2VzdEVsZW1lbnQgZm9yIHNoYWRvdyByb290IGVsZW1lbnQgdG8gZ2V0IHRoZSBhY3R1YWwgY2xvc2VzdCBmb3IgbmVzdGVkIHNoYWRvdyByb290IGVsZW1lbnRcblxuICBpZiAocGFyYW1zLm5vU3dpcGluZyAmJiAoaXNUYXJnZXRTaGFkb3cgPyBjbG9zZXN0RWxlbWVudChub1N3aXBpbmdTZWxlY3RvciwgJHRhcmdldEVsWzBdKSA6ICR0YXJnZXRFbC5jbG9zZXN0KG5vU3dpcGluZ1NlbGVjdG9yKVswXSkpIHtcbiAgICBzd2lwZXIuYWxsb3dDbGljayA9IHRydWU7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKHBhcmFtcy5zd2lwZUhhbmRsZXIpIHtcbiAgICBpZiAoISR0YXJnZXRFbC5jbG9zZXN0KHBhcmFtcy5zd2lwZUhhbmRsZXIpWzBdKSByZXR1cm47XG4gIH1cblxuICB0b3VjaGVzLmN1cnJlbnRYID0gZS50eXBlID09PSAndG91Y2hzdGFydCcgPyBlLnRhcmdldFRvdWNoZXNbMF0ucGFnZVggOiBlLnBhZ2VYO1xuICB0b3VjaGVzLmN1cnJlbnRZID0gZS50eXBlID09PSAndG91Y2hzdGFydCcgPyBlLnRhcmdldFRvdWNoZXNbMF0ucGFnZVkgOiBlLnBhZ2VZO1xuICBjb25zdCBzdGFydFggPSB0b3VjaGVzLmN1cnJlbnRYO1xuICBjb25zdCBzdGFydFkgPSB0b3VjaGVzLmN1cnJlbnRZOyAvLyBEbyBOT1Qgc3RhcnQgaWYgaU9TIGVkZ2Ugc3dpcGUgaXMgZGV0ZWN0ZWQuIE90aGVyd2lzZSBpT1MgYXBwIGNhbm5vdCBzd2lwZS10by1nby1iYWNrIGFueW1vcmVcblxuICBjb25zdCBlZGdlU3dpcGVEZXRlY3Rpb24gPSBwYXJhbXMuZWRnZVN3aXBlRGV0ZWN0aW9uIHx8IHBhcmFtcy5pT1NFZGdlU3dpcGVEZXRlY3Rpb247XG4gIGNvbnN0IGVkZ2VTd2lwZVRocmVzaG9sZCA9IHBhcmFtcy5lZGdlU3dpcGVUaHJlc2hvbGQgfHwgcGFyYW1zLmlPU0VkZ2VTd2lwZVRocmVzaG9sZDtcblxuICBpZiAoZWRnZVN3aXBlRGV0ZWN0aW9uICYmIChzdGFydFggPD0gZWRnZVN3aXBlVGhyZXNob2xkIHx8IHN0YXJ0WCA+PSB3aW5kb3cuaW5uZXJXaWR0aCAtIGVkZ2VTd2lwZVRocmVzaG9sZCkpIHtcbiAgICBpZiAoZWRnZVN3aXBlRGV0ZWN0aW9uID09PSAncHJldmVudCcpIHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gIH1cblxuICBPYmplY3QuYXNzaWduKGRhdGEsIHtcbiAgICBpc1RvdWNoZWQ6IHRydWUsXG4gICAgaXNNb3ZlZDogZmFsc2UsXG4gICAgYWxsb3dUb3VjaENhbGxiYWNrczogdHJ1ZSxcbiAgICBpc1Njcm9sbGluZzogdW5kZWZpbmVkLFxuICAgIHN0YXJ0TW92aW5nOiB1bmRlZmluZWRcbiAgfSk7XG4gIHRvdWNoZXMuc3RhcnRYID0gc3RhcnRYO1xuICB0b3VjaGVzLnN0YXJ0WSA9IHN0YXJ0WTtcbiAgZGF0YS50b3VjaFN0YXJ0VGltZSA9IG5vdygpO1xuICBzd2lwZXIuYWxsb3dDbGljayA9IHRydWU7XG4gIHN3aXBlci51cGRhdGVTaXplKCk7XG4gIHN3aXBlci5zd2lwZURpcmVjdGlvbiA9IHVuZGVmaW5lZDtcbiAgaWYgKHBhcmFtcy50aHJlc2hvbGQgPiAwKSBkYXRhLmFsbG93VGhyZXNob2xkTW92ZSA9IGZhbHNlO1xuXG4gIGlmIChlLnR5cGUgIT09ICd0b3VjaHN0YXJ0Jykge1xuICAgIGxldCBwcmV2ZW50RGVmYXVsdCA9IHRydWU7XG5cbiAgICBpZiAoJHRhcmdldEVsLmlzKGRhdGEuZm9jdXNhYmxlRWxlbWVudHMpKSB7XG4gICAgICBwcmV2ZW50RGVmYXVsdCA9IGZhbHNlO1xuXG4gICAgICBpZiAoJHRhcmdldEVsWzBdLm5vZGVOYW1lID09PSAnU0VMRUNUJykge1xuICAgICAgICBkYXRhLmlzVG91Y2hlZCA9IGZhbHNlO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChkb2N1bWVudC5hY3RpdmVFbGVtZW50ICYmICQoZG9jdW1lbnQuYWN0aXZlRWxlbWVudCkuaXMoZGF0YS5mb2N1c2FibGVFbGVtZW50cykgJiYgZG9jdW1lbnQuYWN0aXZlRWxlbWVudCAhPT0gJHRhcmdldEVsWzBdKSB7XG4gICAgICBkb2N1bWVudC5hY3RpdmVFbGVtZW50LmJsdXIoKTtcbiAgICB9XG5cbiAgICBjb25zdCBzaG91bGRQcmV2ZW50RGVmYXVsdCA9IHByZXZlbnREZWZhdWx0ICYmIHN3aXBlci5hbGxvd1RvdWNoTW92ZSAmJiBwYXJhbXMudG91Y2hTdGFydFByZXZlbnREZWZhdWx0O1xuXG4gICAgaWYgKChwYXJhbXMudG91Y2hTdGFydEZvcmNlUHJldmVudERlZmF1bHQgfHwgc2hvdWxkUHJldmVudERlZmF1bHQpICYmICEkdGFyZ2V0RWxbMF0uaXNDb250ZW50RWRpdGFibGUpIHtcbiAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG4gIH1cblxuICBpZiAoc3dpcGVyLnBhcmFtcy5mcmVlTW9kZSAmJiBzd2lwZXIucGFyYW1zLmZyZWVNb2RlLmVuYWJsZWQgJiYgc3dpcGVyLmZyZWVNb2RlICYmIHN3aXBlci5hbmltYXRpbmcgJiYgIXBhcmFtcy5jc3NNb2RlKSB7XG4gICAgc3dpcGVyLmZyZWVNb2RlLm9uVG91Y2hTdGFydCgpO1xuICB9XG5cbiAgc3dpcGVyLmVtaXQoJ3RvdWNoU3RhcnQnLCBlKTtcbn0iLCJpbXBvcnQgeyBnZXREb2N1bWVudCB9IGZyb20gJ3Nzci13aW5kb3cnO1xuaW1wb3J0ICQgZnJvbSAnLi4vLi4vc2hhcmVkL2RvbS5qcyc7XG5pbXBvcnQgeyBub3cgfSBmcm9tICcuLi8uLi9zaGFyZWQvdXRpbHMuanMnO1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gb25Ub3VjaE1vdmUoZXZlbnQpIHtcbiAgY29uc3QgZG9jdW1lbnQgPSBnZXREb2N1bWVudCgpO1xuICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICBjb25zdCBkYXRhID0gc3dpcGVyLnRvdWNoRXZlbnRzRGF0YTtcbiAgY29uc3Qge1xuICAgIHBhcmFtcyxcbiAgICB0b3VjaGVzLFxuICAgIHJ0bFRyYW5zbGF0ZTogcnRsLFxuICAgIGVuYWJsZWRcbiAgfSA9IHN3aXBlcjtcbiAgaWYgKCFlbmFibGVkKSByZXR1cm47XG4gIGxldCBlID0gZXZlbnQ7XG4gIGlmIChlLm9yaWdpbmFsRXZlbnQpIGUgPSBlLm9yaWdpbmFsRXZlbnQ7XG5cbiAgaWYgKCFkYXRhLmlzVG91Y2hlZCkge1xuICAgIGlmIChkYXRhLnN0YXJ0TW92aW5nICYmIGRhdGEuaXNTY3JvbGxpbmcpIHtcbiAgICAgIHN3aXBlci5lbWl0KCd0b3VjaE1vdmVPcHBvc2l0ZScsIGUpO1xuICAgIH1cblxuICAgIHJldHVybjtcbiAgfVxuXG4gIGlmIChkYXRhLmlzVG91Y2hFdmVudCAmJiBlLnR5cGUgIT09ICd0b3VjaG1vdmUnKSByZXR1cm47XG4gIGNvbnN0IHRhcmdldFRvdWNoID0gZS50eXBlID09PSAndG91Y2htb3ZlJyAmJiBlLnRhcmdldFRvdWNoZXMgJiYgKGUudGFyZ2V0VG91Y2hlc1swXSB8fCBlLmNoYW5nZWRUb3VjaGVzWzBdKTtcbiAgY29uc3QgcGFnZVggPSBlLnR5cGUgPT09ICd0b3VjaG1vdmUnID8gdGFyZ2V0VG91Y2gucGFnZVggOiBlLnBhZ2VYO1xuICBjb25zdCBwYWdlWSA9IGUudHlwZSA9PT0gJ3RvdWNobW92ZScgPyB0YXJnZXRUb3VjaC5wYWdlWSA6IGUucGFnZVk7XG5cbiAgaWYgKGUucHJldmVudGVkQnlOZXN0ZWRTd2lwZXIpIHtcbiAgICB0b3VjaGVzLnN0YXJ0WCA9IHBhZ2VYO1xuICAgIHRvdWNoZXMuc3RhcnRZID0gcGFnZVk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKCFzd2lwZXIuYWxsb3dUb3VjaE1vdmUpIHtcbiAgICBpZiAoISQoZS50YXJnZXQpLmlzKGRhdGEuZm9jdXNhYmxlRWxlbWVudHMpKSB7XG4gICAgICBzd2lwZXIuYWxsb3dDbGljayA9IGZhbHNlO1xuICAgIH1cblxuICAgIGlmIChkYXRhLmlzVG91Y2hlZCkge1xuICAgICAgT2JqZWN0LmFzc2lnbih0b3VjaGVzLCB7XG4gICAgICAgIHN0YXJ0WDogcGFnZVgsXG4gICAgICAgIHN0YXJ0WTogcGFnZVksXG4gICAgICAgIGN1cnJlbnRYOiBwYWdlWCxcbiAgICAgICAgY3VycmVudFk6IHBhZ2VZXG4gICAgICB9KTtcbiAgICAgIGRhdGEudG91Y2hTdGFydFRpbWUgPSBub3coKTtcbiAgICB9XG5cbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAoZGF0YS5pc1RvdWNoRXZlbnQgJiYgcGFyYW1zLnRvdWNoUmVsZWFzZU9uRWRnZXMgJiYgIXBhcmFtcy5sb29wKSB7XG4gICAgaWYgKHN3aXBlci5pc1ZlcnRpY2FsKCkpIHtcbiAgICAgIC8vIFZlcnRpY2FsXG4gICAgICBpZiAocGFnZVkgPCB0b3VjaGVzLnN0YXJ0WSAmJiBzd2lwZXIudHJhbnNsYXRlIDw9IHN3aXBlci5tYXhUcmFuc2xhdGUoKSB8fCBwYWdlWSA+IHRvdWNoZXMuc3RhcnRZICYmIHN3aXBlci50cmFuc2xhdGUgPj0gc3dpcGVyLm1pblRyYW5zbGF0ZSgpKSB7XG4gICAgICAgIGRhdGEuaXNUb3VjaGVkID0gZmFsc2U7XG4gICAgICAgIGRhdGEuaXNNb3ZlZCA9IGZhbHNlO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChwYWdlWCA8IHRvdWNoZXMuc3RhcnRYICYmIHN3aXBlci50cmFuc2xhdGUgPD0gc3dpcGVyLm1heFRyYW5zbGF0ZSgpIHx8IHBhZ2VYID4gdG91Y2hlcy5zdGFydFggJiYgc3dpcGVyLnRyYW5zbGF0ZSA+PSBzd2lwZXIubWluVHJhbnNsYXRlKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gIH1cblxuICBpZiAoZGF0YS5pc1RvdWNoRXZlbnQgJiYgZG9jdW1lbnQuYWN0aXZlRWxlbWVudCkge1xuICAgIGlmIChlLnRhcmdldCA9PT0gZG9jdW1lbnQuYWN0aXZlRWxlbWVudCAmJiAkKGUudGFyZ2V0KS5pcyhkYXRhLmZvY3VzYWJsZUVsZW1lbnRzKSkge1xuICAgICAgZGF0YS5pc01vdmVkID0gdHJ1ZTtcbiAgICAgIHN3aXBlci5hbGxvd0NsaWNrID0gZmFsc2U7XG4gICAgICByZXR1cm47XG4gICAgfVxuICB9XG5cbiAgaWYgKGRhdGEuYWxsb3dUb3VjaENhbGxiYWNrcykge1xuICAgIHN3aXBlci5lbWl0KCd0b3VjaE1vdmUnLCBlKTtcbiAgfVxuXG4gIGlmIChlLnRhcmdldFRvdWNoZXMgJiYgZS50YXJnZXRUb3VjaGVzLmxlbmd0aCA+IDEpIHJldHVybjtcbiAgdG91Y2hlcy5jdXJyZW50WCA9IHBhZ2VYO1xuICB0b3VjaGVzLmN1cnJlbnRZID0gcGFnZVk7XG4gIGNvbnN0IGRpZmZYID0gdG91Y2hlcy5jdXJyZW50WCAtIHRvdWNoZXMuc3RhcnRYO1xuICBjb25zdCBkaWZmWSA9IHRvdWNoZXMuY3VycmVudFkgLSB0b3VjaGVzLnN0YXJ0WTtcbiAgaWYgKHN3aXBlci5wYXJhbXMudGhyZXNob2xkICYmIE1hdGguc3FydChkaWZmWCAqKiAyICsgZGlmZlkgKiogMikgPCBzd2lwZXIucGFyYW1zLnRocmVzaG9sZCkgcmV0dXJuO1xuXG4gIGlmICh0eXBlb2YgZGF0YS5pc1Njcm9sbGluZyA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBsZXQgdG91Y2hBbmdsZTtcblxuICAgIGlmIChzd2lwZXIuaXNIb3Jpem9udGFsKCkgJiYgdG91Y2hlcy5jdXJyZW50WSA9PT0gdG91Y2hlcy5zdGFydFkgfHwgc3dpcGVyLmlzVmVydGljYWwoKSAmJiB0b3VjaGVzLmN1cnJlbnRYID09PSB0b3VjaGVzLnN0YXJ0WCkge1xuICAgICAgZGF0YS5pc1Njcm9sbGluZyA9IGZhbHNlO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmVcbiAgICAgIGlmIChkaWZmWCAqIGRpZmZYICsgZGlmZlkgKiBkaWZmWSA+PSAyNSkge1xuICAgICAgICB0b3VjaEFuZ2xlID0gTWF0aC5hdGFuMihNYXRoLmFicyhkaWZmWSksIE1hdGguYWJzKGRpZmZYKSkgKiAxODAgLyBNYXRoLlBJO1xuICAgICAgICBkYXRhLmlzU2Nyb2xsaW5nID0gc3dpcGVyLmlzSG9yaXpvbnRhbCgpID8gdG91Y2hBbmdsZSA+IHBhcmFtcy50b3VjaEFuZ2xlIDogOTAgLSB0b3VjaEFuZ2xlID4gcGFyYW1zLnRvdWNoQW5nbGU7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgaWYgKGRhdGEuaXNTY3JvbGxpbmcpIHtcbiAgICBzd2lwZXIuZW1pdCgndG91Y2hNb3ZlT3Bwb3NpdGUnLCBlKTtcbiAgfVxuXG4gIGlmICh0eXBlb2YgZGF0YS5zdGFydE1vdmluZyA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAodG91Y2hlcy5jdXJyZW50WCAhPT0gdG91Y2hlcy5zdGFydFggfHwgdG91Y2hlcy5jdXJyZW50WSAhPT0gdG91Y2hlcy5zdGFydFkpIHtcbiAgICAgIGRhdGEuc3RhcnRNb3ZpbmcgPSB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIGlmIChkYXRhLmlzU2Nyb2xsaW5nKSB7XG4gICAgZGF0YS5pc1RvdWNoZWQgPSBmYWxzZTtcbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAoIWRhdGEuc3RhcnRNb3ZpbmcpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBzd2lwZXIuYWxsb3dDbGljayA9IGZhbHNlO1xuXG4gIGlmICghcGFyYW1zLmNzc01vZGUgJiYgZS5jYW5jZWxhYmxlKSB7XG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICB9XG5cbiAgaWYgKHBhcmFtcy50b3VjaE1vdmVTdG9wUHJvcGFnYXRpb24gJiYgIXBhcmFtcy5uZXN0ZWQpIHtcbiAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xuICB9XG5cbiAgaWYgKCFkYXRhLmlzTW92ZWQpIHtcbiAgICBpZiAocGFyYW1zLmxvb3AgJiYgIXBhcmFtcy5jc3NNb2RlKSB7XG4gICAgICBzd2lwZXIubG9vcEZpeCgpO1xuICAgIH1cblxuICAgIGRhdGEuc3RhcnRUcmFuc2xhdGUgPSBzd2lwZXIuZ2V0VHJhbnNsYXRlKCk7XG4gICAgc3dpcGVyLnNldFRyYW5zaXRpb24oMCk7XG5cbiAgICBpZiAoc3dpcGVyLmFuaW1hdGluZykge1xuICAgICAgc3dpcGVyLiR3cmFwcGVyRWwudHJpZ2dlcignd2Via2l0VHJhbnNpdGlvbkVuZCB0cmFuc2l0aW9uZW5kJyk7XG4gICAgfVxuXG4gICAgZGF0YS5hbGxvd01vbWVudHVtQm91bmNlID0gZmFsc2U7IC8vIEdyYWIgQ3Vyc29yXG5cbiAgICBpZiAocGFyYW1zLmdyYWJDdXJzb3IgJiYgKHN3aXBlci5hbGxvd1NsaWRlTmV4dCA9PT0gdHJ1ZSB8fCBzd2lwZXIuYWxsb3dTbGlkZVByZXYgPT09IHRydWUpKSB7XG4gICAgICBzd2lwZXIuc2V0R3JhYkN1cnNvcih0cnVlKTtcbiAgICB9XG5cbiAgICBzd2lwZXIuZW1pdCgnc2xpZGVyRmlyc3RNb3ZlJywgZSk7XG4gIH1cblxuICBzd2lwZXIuZW1pdCgnc2xpZGVyTW92ZScsIGUpO1xuICBkYXRhLmlzTW92ZWQgPSB0cnVlO1xuICBsZXQgZGlmZiA9IHN3aXBlci5pc0hvcml6b250YWwoKSA/IGRpZmZYIDogZGlmZlk7XG4gIHRvdWNoZXMuZGlmZiA9IGRpZmY7XG4gIGRpZmYgKj0gcGFyYW1zLnRvdWNoUmF0aW87XG4gIGlmIChydGwpIGRpZmYgPSAtZGlmZjtcbiAgc3dpcGVyLnN3aXBlRGlyZWN0aW9uID0gZGlmZiA+IDAgPyAncHJldicgOiAnbmV4dCc7XG4gIGRhdGEuY3VycmVudFRyYW5zbGF0ZSA9IGRpZmYgKyBkYXRhLnN0YXJ0VHJhbnNsYXRlO1xuICBsZXQgZGlzYWJsZVBhcmVudFN3aXBlciA9IHRydWU7XG4gIGxldCByZXNpc3RhbmNlUmF0aW8gPSBwYXJhbXMucmVzaXN0YW5jZVJhdGlvO1xuXG4gIGlmIChwYXJhbXMudG91Y2hSZWxlYXNlT25FZGdlcykge1xuICAgIHJlc2lzdGFuY2VSYXRpbyA9IDA7XG4gIH1cblxuICBpZiAoZGlmZiA+IDAgJiYgZGF0YS5jdXJyZW50VHJhbnNsYXRlID4gc3dpcGVyLm1pblRyYW5zbGF0ZSgpKSB7XG4gICAgZGlzYWJsZVBhcmVudFN3aXBlciA9IGZhbHNlO1xuICAgIGlmIChwYXJhbXMucmVzaXN0YW5jZSkgZGF0YS5jdXJyZW50VHJhbnNsYXRlID0gc3dpcGVyLm1pblRyYW5zbGF0ZSgpIC0gMSArICgtc3dpcGVyLm1pblRyYW5zbGF0ZSgpICsgZGF0YS5zdGFydFRyYW5zbGF0ZSArIGRpZmYpICoqIHJlc2lzdGFuY2VSYXRpbztcbiAgfSBlbHNlIGlmIChkaWZmIDwgMCAmJiBkYXRhLmN1cnJlbnRUcmFuc2xhdGUgPCBzd2lwZXIubWF4VHJhbnNsYXRlKCkpIHtcbiAgICBkaXNhYmxlUGFyZW50U3dpcGVyID0gZmFsc2U7XG4gICAgaWYgKHBhcmFtcy5yZXNpc3RhbmNlKSBkYXRhLmN1cnJlbnRUcmFuc2xhdGUgPSBzd2lwZXIubWF4VHJhbnNsYXRlKCkgKyAxIC0gKHN3aXBlci5tYXhUcmFuc2xhdGUoKSAtIGRhdGEuc3RhcnRUcmFuc2xhdGUgLSBkaWZmKSAqKiByZXNpc3RhbmNlUmF0aW87XG4gIH1cblxuICBpZiAoZGlzYWJsZVBhcmVudFN3aXBlcikge1xuICAgIGUucHJldmVudGVkQnlOZXN0ZWRTd2lwZXIgPSB0cnVlO1xuICB9IC8vIERpcmVjdGlvbnMgbG9ja3NcblxuXG4gIGlmICghc3dpcGVyLmFsbG93U2xpZGVOZXh0ICYmIHN3aXBlci5zd2lwZURpcmVjdGlvbiA9PT0gJ25leHQnICYmIGRhdGEuY3VycmVudFRyYW5zbGF0ZSA8IGRhdGEuc3RhcnRUcmFuc2xhdGUpIHtcbiAgICBkYXRhLmN1cnJlbnRUcmFuc2xhdGUgPSBkYXRhLnN0YXJ0VHJhbnNsYXRlO1xuICB9XG5cbiAgaWYgKCFzd2lwZXIuYWxsb3dTbGlkZVByZXYgJiYgc3dpcGVyLnN3aXBlRGlyZWN0aW9uID09PSAncHJldicgJiYgZGF0YS5jdXJyZW50VHJhbnNsYXRlID4gZGF0YS5zdGFydFRyYW5zbGF0ZSkge1xuICAgIGRhdGEuY3VycmVudFRyYW5zbGF0ZSA9IGRhdGEuc3RhcnRUcmFuc2xhdGU7XG4gIH1cblxuICBpZiAoIXN3aXBlci5hbGxvd1NsaWRlUHJldiAmJiAhc3dpcGVyLmFsbG93U2xpZGVOZXh0KSB7XG4gICAgZGF0YS5jdXJyZW50VHJhbnNsYXRlID0gZGF0YS5zdGFydFRyYW5zbGF0ZTtcbiAgfSAvLyBUaHJlc2hvbGRcblxuXG4gIGlmIChwYXJhbXMudGhyZXNob2xkID4gMCkge1xuICAgIGlmIChNYXRoLmFicyhkaWZmKSA+IHBhcmFtcy50aHJlc2hvbGQgfHwgZGF0YS5hbGxvd1RocmVzaG9sZE1vdmUpIHtcbiAgICAgIGlmICghZGF0YS5hbGxvd1RocmVzaG9sZE1vdmUpIHtcbiAgICAgICAgZGF0YS5hbGxvd1RocmVzaG9sZE1vdmUgPSB0cnVlO1xuICAgICAgICB0b3VjaGVzLnN0YXJ0WCA9IHRvdWNoZXMuY3VycmVudFg7XG4gICAgICAgIHRvdWNoZXMuc3RhcnRZID0gdG91Y2hlcy5jdXJyZW50WTtcbiAgICAgICAgZGF0YS5jdXJyZW50VHJhbnNsYXRlID0gZGF0YS5zdGFydFRyYW5zbGF0ZTtcbiAgICAgICAgdG91Y2hlcy5kaWZmID0gc3dpcGVyLmlzSG9yaXpvbnRhbCgpID8gdG91Y2hlcy5jdXJyZW50WCAtIHRvdWNoZXMuc3RhcnRYIDogdG91Y2hlcy5jdXJyZW50WSAtIHRvdWNoZXMuc3RhcnRZO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGRhdGEuY3VycmVudFRyYW5zbGF0ZSA9IGRhdGEuc3RhcnRUcmFuc2xhdGU7XG4gICAgICByZXR1cm47XG4gICAgfVxuICB9XG5cbiAgaWYgKCFwYXJhbXMuZm9sbG93RmluZ2VyIHx8IHBhcmFtcy5jc3NNb2RlKSByZXR1cm47IC8vIFVwZGF0ZSBhY3RpdmUgaW5kZXggaW4gZnJlZSBtb2RlXG5cbiAgaWYgKHBhcmFtcy5mcmVlTW9kZSAmJiBwYXJhbXMuZnJlZU1vZGUuZW5hYmxlZCAmJiBzd2lwZXIuZnJlZU1vZGUgfHwgcGFyYW1zLndhdGNoU2xpZGVzUHJvZ3Jlc3MpIHtcbiAgICBzd2lwZXIudXBkYXRlQWN0aXZlSW5kZXgoKTtcbiAgICBzd2lwZXIudXBkYXRlU2xpZGVzQ2xhc3NlcygpO1xuICB9XG5cbiAgaWYgKHN3aXBlci5wYXJhbXMuZnJlZU1vZGUgJiYgcGFyYW1zLmZyZWVNb2RlLmVuYWJsZWQgJiYgc3dpcGVyLmZyZWVNb2RlKSB7XG4gICAgc3dpcGVyLmZyZWVNb2RlLm9uVG91Y2hNb3ZlKCk7XG4gIH0gLy8gVXBkYXRlIHByb2dyZXNzXG5cblxuICBzd2lwZXIudXBkYXRlUHJvZ3Jlc3MoZGF0YS5jdXJyZW50VHJhbnNsYXRlKTsgLy8gVXBkYXRlIHRyYW5zbGF0ZVxuXG4gIHN3aXBlci5zZXRUcmFuc2xhdGUoZGF0YS5jdXJyZW50VHJhbnNsYXRlKTtcbn0iLCJpbXBvcnQgeyBub3csIG5leHRUaWNrIH0gZnJvbSAnLi4vLi4vc2hhcmVkL3V0aWxzLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIG9uVG91Y2hFbmQoZXZlbnQpIHtcbiAgY29uc3Qgc3dpcGVyID0gdGhpcztcbiAgY29uc3QgZGF0YSA9IHN3aXBlci50b3VjaEV2ZW50c0RhdGE7XG4gIGNvbnN0IHtcbiAgICBwYXJhbXMsXG4gICAgdG91Y2hlcyxcbiAgICBydGxUcmFuc2xhdGU6IHJ0bCxcbiAgICBzbGlkZXNHcmlkLFxuICAgIGVuYWJsZWRcbiAgfSA9IHN3aXBlcjtcbiAgaWYgKCFlbmFibGVkKSByZXR1cm47XG4gIGxldCBlID0gZXZlbnQ7XG4gIGlmIChlLm9yaWdpbmFsRXZlbnQpIGUgPSBlLm9yaWdpbmFsRXZlbnQ7XG5cbiAgaWYgKGRhdGEuYWxsb3dUb3VjaENhbGxiYWNrcykge1xuICAgIHN3aXBlci5lbWl0KCd0b3VjaEVuZCcsIGUpO1xuICB9XG5cbiAgZGF0YS5hbGxvd1RvdWNoQ2FsbGJhY2tzID0gZmFsc2U7XG5cbiAgaWYgKCFkYXRhLmlzVG91Y2hlZCkge1xuICAgIGlmIChkYXRhLmlzTW92ZWQgJiYgcGFyYW1zLmdyYWJDdXJzb3IpIHtcbiAgICAgIHN3aXBlci5zZXRHcmFiQ3Vyc29yKGZhbHNlKTtcbiAgICB9XG5cbiAgICBkYXRhLmlzTW92ZWQgPSBmYWxzZTtcbiAgICBkYXRhLnN0YXJ0TW92aW5nID0gZmFsc2U7XG4gICAgcmV0dXJuO1xuICB9IC8vIFJldHVybiBHcmFiIEN1cnNvclxuXG5cbiAgaWYgKHBhcmFtcy5ncmFiQ3Vyc29yICYmIGRhdGEuaXNNb3ZlZCAmJiBkYXRhLmlzVG91Y2hlZCAmJiAoc3dpcGVyLmFsbG93U2xpZGVOZXh0ID09PSB0cnVlIHx8IHN3aXBlci5hbGxvd1NsaWRlUHJldiA9PT0gdHJ1ZSkpIHtcbiAgICBzd2lwZXIuc2V0R3JhYkN1cnNvcihmYWxzZSk7XG4gIH0gLy8gVGltZSBkaWZmXG5cblxuICBjb25zdCB0b3VjaEVuZFRpbWUgPSBub3coKTtcbiAgY29uc3QgdGltZURpZmYgPSB0b3VjaEVuZFRpbWUgLSBkYXRhLnRvdWNoU3RhcnRUaW1lOyAvLyBUYXAsIGRvdWJsZVRhcCwgQ2xpY2tcblxuICBpZiAoc3dpcGVyLmFsbG93Q2xpY2spIHtcbiAgICBjb25zdCBwYXRoVHJlZSA9IGUucGF0aCB8fCBlLmNvbXBvc2VkUGF0aCAmJiBlLmNvbXBvc2VkUGF0aCgpO1xuICAgIHN3aXBlci51cGRhdGVDbGlja2VkU2xpZGUocGF0aFRyZWUgJiYgcGF0aFRyZWVbMF0gfHwgZS50YXJnZXQpO1xuICAgIHN3aXBlci5lbWl0KCd0YXAgY2xpY2snLCBlKTtcblxuICAgIGlmICh0aW1lRGlmZiA8IDMwMCAmJiB0b3VjaEVuZFRpbWUgLSBkYXRhLmxhc3RDbGlja1RpbWUgPCAzMDApIHtcbiAgICAgIHN3aXBlci5lbWl0KCdkb3VibGVUYXAgZG91YmxlQ2xpY2snLCBlKTtcbiAgICB9XG4gIH1cblxuICBkYXRhLmxhc3RDbGlja1RpbWUgPSBub3coKTtcbiAgbmV4dFRpY2soKCkgPT4ge1xuICAgIGlmICghc3dpcGVyLmRlc3Ryb3llZCkgc3dpcGVyLmFsbG93Q2xpY2sgPSB0cnVlO1xuICB9KTtcblxuICBpZiAoIWRhdGEuaXNUb3VjaGVkIHx8ICFkYXRhLmlzTW92ZWQgfHwgIXN3aXBlci5zd2lwZURpcmVjdGlvbiB8fCB0b3VjaGVzLmRpZmYgPT09IDAgfHwgZGF0YS5jdXJyZW50VHJhbnNsYXRlID09PSBkYXRhLnN0YXJ0VHJhbnNsYXRlKSB7XG4gICAgZGF0YS5pc1RvdWNoZWQgPSBmYWxzZTtcbiAgICBkYXRhLmlzTW92ZWQgPSBmYWxzZTtcbiAgICBkYXRhLnN0YXJ0TW92aW5nID0gZmFsc2U7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgZGF0YS5pc1RvdWNoZWQgPSBmYWxzZTtcbiAgZGF0YS5pc01vdmVkID0gZmFsc2U7XG4gIGRhdGEuc3RhcnRNb3ZpbmcgPSBmYWxzZTtcbiAgbGV0IGN1cnJlbnRQb3M7XG5cbiAgaWYgKHBhcmFtcy5mb2xsb3dGaW5nZXIpIHtcbiAgICBjdXJyZW50UG9zID0gcnRsID8gc3dpcGVyLnRyYW5zbGF0ZSA6IC1zd2lwZXIudHJhbnNsYXRlO1xuICB9IGVsc2Uge1xuICAgIGN1cnJlbnRQb3MgPSAtZGF0YS5jdXJyZW50VHJhbnNsYXRlO1xuICB9XG5cbiAgaWYgKHBhcmFtcy5jc3NNb2RlKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKHN3aXBlci5wYXJhbXMuZnJlZU1vZGUgJiYgcGFyYW1zLmZyZWVNb2RlLmVuYWJsZWQpIHtcbiAgICBzd2lwZXIuZnJlZU1vZGUub25Ub3VjaEVuZCh7XG4gICAgICBjdXJyZW50UG9zXG4gICAgfSk7XG4gICAgcmV0dXJuO1xuICB9IC8vIEZpbmQgY3VycmVudCBzbGlkZVxuXG5cbiAgbGV0IHN0b3BJbmRleCA9IDA7XG4gIGxldCBncm91cFNpemUgPSBzd2lwZXIuc2xpZGVzU2l6ZXNHcmlkWzBdO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgc2xpZGVzR3JpZC5sZW5ndGg7IGkgKz0gaSA8IHBhcmFtcy5zbGlkZXNQZXJHcm91cFNraXAgPyAxIDogcGFyYW1zLnNsaWRlc1Blckdyb3VwKSB7XG4gICAgY29uc3QgaW5jcmVtZW50ID0gaSA8IHBhcmFtcy5zbGlkZXNQZXJHcm91cFNraXAgLSAxID8gMSA6IHBhcmFtcy5zbGlkZXNQZXJHcm91cDtcblxuICAgIGlmICh0eXBlb2Ygc2xpZGVzR3JpZFtpICsgaW5jcmVtZW50XSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIGlmIChjdXJyZW50UG9zID49IHNsaWRlc0dyaWRbaV0gJiYgY3VycmVudFBvcyA8IHNsaWRlc0dyaWRbaSArIGluY3JlbWVudF0pIHtcbiAgICAgICAgc3RvcEluZGV4ID0gaTtcbiAgICAgICAgZ3JvdXBTaXplID0gc2xpZGVzR3JpZFtpICsgaW5jcmVtZW50XSAtIHNsaWRlc0dyaWRbaV07XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChjdXJyZW50UG9zID49IHNsaWRlc0dyaWRbaV0pIHtcbiAgICAgIHN0b3BJbmRleCA9IGk7XG4gICAgICBncm91cFNpemUgPSBzbGlkZXNHcmlkW3NsaWRlc0dyaWQubGVuZ3RoIC0gMV0gLSBzbGlkZXNHcmlkW3NsaWRlc0dyaWQubGVuZ3RoIC0gMl07XG4gICAgfVxuICB9XG5cbiAgbGV0IHJld2luZEZpcnN0SW5kZXggPSBudWxsO1xuICBsZXQgcmV3aW5kTGFzdEluZGV4ID0gbnVsbDtcblxuICBpZiAocGFyYW1zLnJld2luZCkge1xuICAgIGlmIChzd2lwZXIuaXNCZWdpbm5pbmcpIHtcbiAgICAgIHJld2luZExhc3RJbmRleCA9IHN3aXBlci5wYXJhbXMudmlydHVhbCAmJiBzd2lwZXIucGFyYW1zLnZpcnR1YWwuZW5hYmxlZCAmJiBzd2lwZXIudmlydHVhbCA/IHN3aXBlci52aXJ0dWFsLnNsaWRlcy5sZW5ndGggLSAxIDogc3dpcGVyLnNsaWRlcy5sZW5ndGggLSAxO1xuICAgIH0gZWxzZSBpZiAoc3dpcGVyLmlzRW5kKSB7XG4gICAgICByZXdpbmRGaXJzdEluZGV4ID0gMDtcbiAgICB9XG4gIH0gLy8gRmluZCBjdXJyZW50IHNsaWRlIHNpemVcblxuXG4gIGNvbnN0IHJhdGlvID0gKGN1cnJlbnRQb3MgLSBzbGlkZXNHcmlkW3N0b3BJbmRleF0pIC8gZ3JvdXBTaXplO1xuICBjb25zdCBpbmNyZW1lbnQgPSBzdG9wSW5kZXggPCBwYXJhbXMuc2xpZGVzUGVyR3JvdXBTa2lwIC0gMSA/IDEgOiBwYXJhbXMuc2xpZGVzUGVyR3JvdXA7XG5cbiAgaWYgKHRpbWVEaWZmID4gcGFyYW1zLmxvbmdTd2lwZXNNcykge1xuICAgIC8vIExvbmcgdG91Y2hlc1xuICAgIGlmICghcGFyYW1zLmxvbmdTd2lwZXMpIHtcbiAgICAgIHN3aXBlci5zbGlkZVRvKHN3aXBlci5hY3RpdmVJbmRleCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHN3aXBlci5zd2lwZURpcmVjdGlvbiA9PT0gJ25leHQnKSB7XG4gICAgICBpZiAocmF0aW8gPj0gcGFyYW1zLmxvbmdTd2lwZXNSYXRpbykgc3dpcGVyLnNsaWRlVG8ocGFyYW1zLnJld2luZCAmJiBzd2lwZXIuaXNFbmQgPyByZXdpbmRGaXJzdEluZGV4IDogc3RvcEluZGV4ICsgaW5jcmVtZW50KTtlbHNlIHN3aXBlci5zbGlkZVRvKHN0b3BJbmRleCk7XG4gICAgfVxuXG4gICAgaWYgKHN3aXBlci5zd2lwZURpcmVjdGlvbiA9PT0gJ3ByZXYnKSB7XG4gICAgICBpZiAocmF0aW8gPiAxIC0gcGFyYW1zLmxvbmdTd2lwZXNSYXRpbykge1xuICAgICAgICBzd2lwZXIuc2xpZGVUbyhzdG9wSW5kZXggKyBpbmNyZW1lbnQpO1xuICAgICAgfSBlbHNlIGlmIChyZXdpbmRMYXN0SW5kZXggIT09IG51bGwgJiYgcmF0aW8gPCAwICYmIE1hdGguYWJzKHJhdGlvKSA+IHBhcmFtcy5sb25nU3dpcGVzUmF0aW8pIHtcbiAgICAgICAgc3dpcGVyLnNsaWRlVG8ocmV3aW5kTGFzdEluZGV4KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHN3aXBlci5zbGlkZVRvKHN0b3BJbmRleCk7XG4gICAgICB9XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIC8vIFNob3J0IHN3aXBlc1xuICAgIGlmICghcGFyYW1zLnNob3J0U3dpcGVzKSB7XG4gICAgICBzd2lwZXIuc2xpZGVUbyhzd2lwZXIuYWN0aXZlSW5kZXgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGlzTmF2QnV0dG9uVGFyZ2V0ID0gc3dpcGVyLm5hdmlnYXRpb24gJiYgKGUudGFyZ2V0ID09PSBzd2lwZXIubmF2aWdhdGlvbi5uZXh0RWwgfHwgZS50YXJnZXQgPT09IHN3aXBlci5uYXZpZ2F0aW9uLnByZXZFbCk7XG5cbiAgICBpZiAoIWlzTmF2QnV0dG9uVGFyZ2V0KSB7XG4gICAgICBpZiAoc3dpcGVyLnN3aXBlRGlyZWN0aW9uID09PSAnbmV4dCcpIHtcbiAgICAgICAgc3dpcGVyLnNsaWRlVG8ocmV3aW5kRmlyc3RJbmRleCAhPT0gbnVsbCA/IHJld2luZEZpcnN0SW5kZXggOiBzdG9wSW5kZXggKyBpbmNyZW1lbnQpO1xuICAgICAgfVxuXG4gICAgICBpZiAoc3dpcGVyLnN3aXBlRGlyZWN0aW9uID09PSAncHJldicpIHtcbiAgICAgICAgc3dpcGVyLnNsaWRlVG8ocmV3aW5kTGFzdEluZGV4ICE9PSBudWxsID8gcmV3aW5kTGFzdEluZGV4IDogc3RvcEluZGV4KTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGUudGFyZ2V0ID09PSBzd2lwZXIubmF2aWdhdGlvbi5uZXh0RWwpIHtcbiAgICAgIHN3aXBlci5zbGlkZVRvKHN0b3BJbmRleCArIGluY3JlbWVudCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN3aXBlci5zbGlkZVRvKHN0b3BJbmRleCk7XG4gICAgfVxuICB9XG59IiwiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gb25SZXNpemUoKSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gIGNvbnN0IHtcbiAgICBwYXJhbXMsXG4gICAgZWxcbiAgfSA9IHN3aXBlcjtcbiAgaWYgKGVsICYmIGVsLm9mZnNldFdpZHRoID09PSAwKSByZXR1cm47IC8vIEJyZWFrcG9pbnRzXG5cbiAgaWYgKHBhcmFtcy5icmVha3BvaW50cykge1xuICAgIHN3aXBlci5zZXRCcmVha3BvaW50KCk7XG4gIH0gLy8gU2F2ZSBsb2Nrc1xuXG5cbiAgY29uc3Qge1xuICAgIGFsbG93U2xpZGVOZXh0LFxuICAgIGFsbG93U2xpZGVQcmV2LFxuICAgIHNuYXBHcmlkXG4gIH0gPSBzd2lwZXI7IC8vIERpc2FibGUgbG9ja3Mgb24gcmVzaXplXG5cbiAgc3dpcGVyLmFsbG93U2xpZGVOZXh0ID0gdHJ1ZTtcbiAgc3dpcGVyLmFsbG93U2xpZGVQcmV2ID0gdHJ1ZTtcbiAgc3dpcGVyLnVwZGF0ZVNpemUoKTtcbiAgc3dpcGVyLnVwZGF0ZVNsaWRlcygpO1xuICBzd2lwZXIudXBkYXRlU2xpZGVzQ2xhc3NlcygpO1xuXG4gIGlmICgocGFyYW1zLnNsaWRlc1BlclZpZXcgPT09ICdhdXRvJyB8fCBwYXJhbXMuc2xpZGVzUGVyVmlldyA+IDEpICYmIHN3aXBlci5pc0VuZCAmJiAhc3dpcGVyLmlzQmVnaW5uaW5nICYmICFzd2lwZXIucGFyYW1zLmNlbnRlcmVkU2xpZGVzKSB7XG4gICAgc3dpcGVyLnNsaWRlVG8oc3dpcGVyLnNsaWRlcy5sZW5ndGggLSAxLCAwLCBmYWxzZSwgdHJ1ZSk7XG4gIH0gZWxzZSB7XG4gICAgc3dpcGVyLnNsaWRlVG8oc3dpcGVyLmFjdGl2ZUluZGV4LCAwLCBmYWxzZSwgdHJ1ZSk7XG4gIH1cblxuICBpZiAoc3dpcGVyLmF1dG9wbGF5ICYmIHN3aXBlci5hdXRvcGxheS5ydW5uaW5nICYmIHN3aXBlci5hdXRvcGxheS5wYXVzZWQpIHtcbiAgICBzd2lwZXIuYXV0b3BsYXkucnVuKCk7XG4gIH0gLy8gUmV0dXJuIGxvY2tzIGFmdGVyIHJlc2l6ZVxuXG5cbiAgc3dpcGVyLmFsbG93U2xpZGVQcmV2ID0gYWxsb3dTbGlkZVByZXY7XG4gIHN3aXBlci5hbGxvd1NsaWRlTmV4dCA9IGFsbG93U2xpZGVOZXh0O1xuXG4gIGlmIChzd2lwZXIucGFyYW1zLndhdGNoT3ZlcmZsb3cgJiYgc25hcEdyaWQgIT09IHN3aXBlci5zbmFwR3JpZCkge1xuICAgIHN3aXBlci5jaGVja092ZXJmbG93KCk7XG4gIH1cbn0iLCJleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBvbkNsaWNrKGUpIHtcbiAgY29uc3Qgc3dpcGVyID0gdGhpcztcbiAgaWYgKCFzd2lwZXIuZW5hYmxlZCkgcmV0dXJuO1xuXG4gIGlmICghc3dpcGVyLmFsbG93Q2xpY2spIHtcbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5wcmV2ZW50Q2xpY2tzKSBlLnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5wcmV2ZW50Q2xpY2tzUHJvcGFnYXRpb24gJiYgc3dpcGVyLmFuaW1hdGluZykge1xuICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgIGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7XG4gICAgfVxuICB9XG59IiwiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gb25TY3JvbGwoKSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gIGNvbnN0IHtcbiAgICB3cmFwcGVyRWwsXG4gICAgcnRsVHJhbnNsYXRlLFxuICAgIGVuYWJsZWRcbiAgfSA9IHN3aXBlcjtcbiAgaWYgKCFlbmFibGVkKSByZXR1cm47XG4gIHN3aXBlci5wcmV2aW91c1RyYW5zbGF0ZSA9IHN3aXBlci50cmFuc2xhdGU7XG5cbiAgaWYgKHN3aXBlci5pc0hvcml6b250YWwoKSkge1xuICAgIHN3aXBlci50cmFuc2xhdGUgPSAtd3JhcHBlckVsLnNjcm9sbExlZnQ7XG4gIH0gZWxzZSB7XG4gICAgc3dpcGVyLnRyYW5zbGF0ZSA9IC13cmFwcGVyRWwuc2Nyb2xsVG9wO1xuICB9IC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuXG5cbiAgaWYgKHN3aXBlci50cmFuc2xhdGUgPT09IDApIHN3aXBlci50cmFuc2xhdGUgPSAwO1xuICBzd2lwZXIudXBkYXRlQWN0aXZlSW5kZXgoKTtcbiAgc3dpcGVyLnVwZGF0ZVNsaWRlc0NsYXNzZXMoKTtcbiAgbGV0IG5ld1Byb2dyZXNzO1xuICBjb25zdCB0cmFuc2xhdGVzRGlmZiA9IHN3aXBlci5tYXhUcmFuc2xhdGUoKSAtIHN3aXBlci5taW5UcmFuc2xhdGUoKTtcblxuICBpZiAodHJhbnNsYXRlc0RpZmYgPT09IDApIHtcbiAgICBuZXdQcm9ncmVzcyA9IDA7XG4gIH0gZWxzZSB7XG4gICAgbmV3UHJvZ3Jlc3MgPSAoc3dpcGVyLnRyYW5zbGF0ZSAtIHN3aXBlci5taW5UcmFuc2xhdGUoKSkgLyB0cmFuc2xhdGVzRGlmZjtcbiAgfVxuXG4gIGlmIChuZXdQcm9ncmVzcyAhPT0gc3dpcGVyLnByb2dyZXNzKSB7XG4gICAgc3dpcGVyLnVwZGF0ZVByb2dyZXNzKHJ0bFRyYW5zbGF0ZSA/IC1zd2lwZXIudHJhbnNsYXRlIDogc3dpcGVyLnRyYW5zbGF0ZSk7XG4gIH1cblxuICBzd2lwZXIuZW1pdCgnc2V0VHJhbnNsYXRlJywgc3dpcGVyLnRyYW5zbGF0ZSwgZmFsc2UpO1xufSIsImltcG9ydCB7IGdldERvY3VtZW50IH0gZnJvbSAnc3NyLXdpbmRvdyc7XG5pbXBvcnQgb25Ub3VjaFN0YXJ0IGZyb20gJy4vb25Ub3VjaFN0YXJ0LmpzJztcbmltcG9ydCBvblRvdWNoTW92ZSBmcm9tICcuL29uVG91Y2hNb3ZlLmpzJztcbmltcG9ydCBvblRvdWNoRW5kIGZyb20gJy4vb25Ub3VjaEVuZC5qcyc7XG5pbXBvcnQgb25SZXNpemUgZnJvbSAnLi9vblJlc2l6ZS5qcyc7XG5pbXBvcnQgb25DbGljayBmcm9tICcuL29uQ2xpY2suanMnO1xuaW1wb3J0IG9uU2Nyb2xsIGZyb20gJy4vb25TY3JvbGwuanMnO1xubGV0IGR1bW15RXZlbnRBdHRhY2hlZCA9IGZhbHNlO1xuXG5mdW5jdGlvbiBkdW1teUV2ZW50TGlzdGVuZXIoKSB7fVxuXG5jb25zdCBldmVudHMgPSAoc3dpcGVyLCBtZXRob2QpID0+IHtcbiAgY29uc3QgZG9jdW1lbnQgPSBnZXREb2N1bWVudCgpO1xuICBjb25zdCB7XG4gICAgcGFyYW1zLFxuICAgIHRvdWNoRXZlbnRzLFxuICAgIGVsLFxuICAgIHdyYXBwZXJFbCxcbiAgICBkZXZpY2UsXG4gICAgc3VwcG9ydFxuICB9ID0gc3dpcGVyO1xuICBjb25zdCBjYXB0dXJlID0gISFwYXJhbXMubmVzdGVkO1xuICBjb25zdCBkb21NZXRob2QgPSBtZXRob2QgPT09ICdvbicgPyAnYWRkRXZlbnRMaXN0ZW5lcicgOiAncmVtb3ZlRXZlbnRMaXN0ZW5lcic7XG4gIGNvbnN0IHN3aXBlck1ldGhvZCA9IG1ldGhvZDsgLy8gVG91Y2ggRXZlbnRzXG5cbiAgaWYgKCFzdXBwb3J0LnRvdWNoKSB7XG4gICAgZWxbZG9tTWV0aG9kXSh0b3VjaEV2ZW50cy5zdGFydCwgc3dpcGVyLm9uVG91Y2hTdGFydCwgZmFsc2UpO1xuICAgIGRvY3VtZW50W2RvbU1ldGhvZF0odG91Y2hFdmVudHMubW92ZSwgc3dpcGVyLm9uVG91Y2hNb3ZlLCBjYXB0dXJlKTtcbiAgICBkb2N1bWVudFtkb21NZXRob2RdKHRvdWNoRXZlbnRzLmVuZCwgc3dpcGVyLm9uVG91Y2hFbmQsIGZhbHNlKTtcbiAgfSBlbHNlIHtcbiAgICBjb25zdCBwYXNzaXZlTGlzdGVuZXIgPSB0b3VjaEV2ZW50cy5zdGFydCA9PT0gJ3RvdWNoc3RhcnQnICYmIHN1cHBvcnQucGFzc2l2ZUxpc3RlbmVyICYmIHBhcmFtcy5wYXNzaXZlTGlzdGVuZXJzID8ge1xuICAgICAgcGFzc2l2ZTogdHJ1ZSxcbiAgICAgIGNhcHR1cmU6IGZhbHNlXG4gICAgfSA6IGZhbHNlO1xuICAgIGVsW2RvbU1ldGhvZF0odG91Y2hFdmVudHMuc3RhcnQsIHN3aXBlci5vblRvdWNoU3RhcnQsIHBhc3NpdmVMaXN0ZW5lcik7XG4gICAgZWxbZG9tTWV0aG9kXSh0b3VjaEV2ZW50cy5tb3ZlLCBzd2lwZXIub25Ub3VjaE1vdmUsIHN1cHBvcnQucGFzc2l2ZUxpc3RlbmVyID8ge1xuICAgICAgcGFzc2l2ZTogZmFsc2UsXG4gICAgICBjYXB0dXJlXG4gICAgfSA6IGNhcHR1cmUpO1xuICAgIGVsW2RvbU1ldGhvZF0odG91Y2hFdmVudHMuZW5kLCBzd2lwZXIub25Ub3VjaEVuZCwgcGFzc2l2ZUxpc3RlbmVyKTtcblxuICAgIGlmICh0b3VjaEV2ZW50cy5jYW5jZWwpIHtcbiAgICAgIGVsW2RvbU1ldGhvZF0odG91Y2hFdmVudHMuY2FuY2VsLCBzd2lwZXIub25Ub3VjaEVuZCwgcGFzc2l2ZUxpc3RlbmVyKTtcbiAgICB9XG4gIH0gLy8gUHJldmVudCBMaW5rcyBDbGlja3NcblxuXG4gIGlmIChwYXJhbXMucHJldmVudENsaWNrcyB8fCBwYXJhbXMucHJldmVudENsaWNrc1Byb3BhZ2F0aW9uKSB7XG4gICAgZWxbZG9tTWV0aG9kXSgnY2xpY2snLCBzd2lwZXIub25DbGljaywgdHJ1ZSk7XG4gIH1cblxuICBpZiAocGFyYW1zLmNzc01vZGUpIHtcbiAgICB3cmFwcGVyRWxbZG9tTWV0aG9kXSgnc2Nyb2xsJywgc3dpcGVyLm9uU2Nyb2xsKTtcbiAgfSAvLyBSZXNpemUgaGFuZGxlclxuXG5cbiAgaWYgKHBhcmFtcy51cGRhdGVPbldpbmRvd1Jlc2l6ZSkge1xuICAgIHN3aXBlcltzd2lwZXJNZXRob2RdKGRldmljZS5pb3MgfHwgZGV2aWNlLmFuZHJvaWQgPyAncmVzaXplIG9yaWVudGF0aW9uY2hhbmdlIG9ic2VydmVyVXBkYXRlJyA6ICdyZXNpemUgb2JzZXJ2ZXJVcGRhdGUnLCBvblJlc2l6ZSwgdHJ1ZSk7XG4gIH0gZWxzZSB7XG4gICAgc3dpcGVyW3N3aXBlck1ldGhvZF0oJ29ic2VydmVyVXBkYXRlJywgb25SZXNpemUsIHRydWUpO1xuICB9XG59O1xuXG5mdW5jdGlvbiBhdHRhY2hFdmVudHMoKSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gIGNvbnN0IGRvY3VtZW50ID0gZ2V0RG9jdW1lbnQoKTtcbiAgY29uc3Qge1xuICAgIHBhcmFtcyxcbiAgICBzdXBwb3J0XG4gIH0gPSBzd2lwZXI7XG4gIHN3aXBlci5vblRvdWNoU3RhcnQgPSBvblRvdWNoU3RhcnQuYmluZChzd2lwZXIpO1xuICBzd2lwZXIub25Ub3VjaE1vdmUgPSBvblRvdWNoTW92ZS5iaW5kKHN3aXBlcik7XG4gIHN3aXBlci5vblRvdWNoRW5kID0gb25Ub3VjaEVuZC5iaW5kKHN3aXBlcik7XG5cbiAgaWYgKHBhcmFtcy5jc3NNb2RlKSB7XG4gICAgc3dpcGVyLm9uU2Nyb2xsID0gb25TY3JvbGwuYmluZChzd2lwZXIpO1xuICB9XG5cbiAgc3dpcGVyLm9uQ2xpY2sgPSBvbkNsaWNrLmJpbmQoc3dpcGVyKTtcblxuICBpZiAoc3VwcG9ydC50b3VjaCAmJiAhZHVtbXlFdmVudEF0dGFjaGVkKSB7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigndG91Y2hzdGFydCcsIGR1bW15RXZlbnRMaXN0ZW5lcik7XG4gICAgZHVtbXlFdmVudEF0dGFjaGVkID0gdHJ1ZTtcbiAgfVxuXG4gIGV2ZW50cyhzd2lwZXIsICdvbicpO1xufVxuXG5mdW5jdGlvbiBkZXRhY2hFdmVudHMoKSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gIGV2ZW50cyhzd2lwZXIsICdvZmYnKTtcbn1cblxuZXhwb3J0IGRlZmF1bHQge1xuICBhdHRhY2hFdmVudHMsXG4gIGRldGFjaEV2ZW50c1xufTsiLCJpbXBvcnQgeyBleHRlbmQgfSBmcm9tICcuLi8uLi9zaGFyZWQvdXRpbHMuanMnO1xuXG5jb25zdCBpc0dyaWRFbmFibGVkID0gKHN3aXBlciwgcGFyYW1zKSA9PiB7XG4gIHJldHVybiBzd2lwZXIuZ3JpZCAmJiBwYXJhbXMuZ3JpZCAmJiBwYXJhbXMuZ3JpZC5yb3dzID4gMTtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHNldEJyZWFrcG9pbnQoKSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gIGNvbnN0IHtcbiAgICBhY3RpdmVJbmRleCxcbiAgICBpbml0aWFsaXplZCxcbiAgICBsb29wZWRTbGlkZXMgPSAwLFxuICAgIHBhcmFtcyxcbiAgICAkZWxcbiAgfSA9IHN3aXBlcjtcbiAgY29uc3QgYnJlYWtwb2ludHMgPSBwYXJhbXMuYnJlYWtwb2ludHM7XG4gIGlmICghYnJlYWtwb2ludHMgfHwgYnJlYWtwb2ludHMgJiYgT2JqZWN0LmtleXMoYnJlYWtwb2ludHMpLmxlbmd0aCA9PT0gMCkgcmV0dXJuOyAvLyBHZXQgYnJlYWtwb2ludCBmb3Igd2luZG93IHdpZHRoIGFuZCB1cGRhdGUgcGFyYW1ldGVyc1xuXG4gIGNvbnN0IGJyZWFrcG9pbnQgPSBzd2lwZXIuZ2V0QnJlYWtwb2ludChicmVha3BvaW50cywgc3dpcGVyLnBhcmFtcy5icmVha3BvaW50c0Jhc2UsIHN3aXBlci5lbCk7XG4gIGlmICghYnJlYWtwb2ludCB8fCBzd2lwZXIuY3VycmVudEJyZWFrcG9pbnQgPT09IGJyZWFrcG9pbnQpIHJldHVybjtcbiAgY29uc3QgYnJlYWtwb2ludE9ubHlQYXJhbXMgPSBicmVha3BvaW50IGluIGJyZWFrcG9pbnRzID8gYnJlYWtwb2ludHNbYnJlYWtwb2ludF0gOiB1bmRlZmluZWQ7XG4gIGNvbnN0IGJyZWFrcG9pbnRQYXJhbXMgPSBicmVha3BvaW50T25seVBhcmFtcyB8fCBzd2lwZXIub3JpZ2luYWxQYXJhbXM7XG4gIGNvbnN0IHdhc011bHRpUm93ID0gaXNHcmlkRW5hYmxlZChzd2lwZXIsIHBhcmFtcyk7XG4gIGNvbnN0IGlzTXVsdGlSb3cgPSBpc0dyaWRFbmFibGVkKHN3aXBlciwgYnJlYWtwb2ludFBhcmFtcyk7XG4gIGNvbnN0IHdhc0VuYWJsZWQgPSBwYXJhbXMuZW5hYmxlZDtcblxuICBpZiAod2FzTXVsdGlSb3cgJiYgIWlzTXVsdGlSb3cpIHtcbiAgICAkZWwucmVtb3ZlQ2xhc3MoYCR7cGFyYW1zLmNvbnRhaW5lck1vZGlmaWVyQ2xhc3N9Z3JpZCAke3BhcmFtcy5jb250YWluZXJNb2RpZmllckNsYXNzfWdyaWQtY29sdW1uYCk7XG4gICAgc3dpcGVyLmVtaXRDb250YWluZXJDbGFzc2VzKCk7XG4gIH0gZWxzZSBpZiAoIXdhc011bHRpUm93ICYmIGlzTXVsdGlSb3cpIHtcbiAgICAkZWwuYWRkQ2xhc3MoYCR7cGFyYW1zLmNvbnRhaW5lck1vZGlmaWVyQ2xhc3N9Z3JpZGApO1xuXG4gICAgaWYgKGJyZWFrcG9pbnRQYXJhbXMuZ3JpZC5maWxsICYmIGJyZWFrcG9pbnRQYXJhbXMuZ3JpZC5maWxsID09PSAnY29sdW1uJyB8fCAhYnJlYWtwb2ludFBhcmFtcy5ncmlkLmZpbGwgJiYgcGFyYW1zLmdyaWQuZmlsbCA9PT0gJ2NvbHVtbicpIHtcbiAgICAgICRlbC5hZGRDbGFzcyhgJHtwYXJhbXMuY29udGFpbmVyTW9kaWZpZXJDbGFzc31ncmlkLWNvbHVtbmApO1xuICAgIH1cblxuICAgIHN3aXBlci5lbWl0Q29udGFpbmVyQ2xhc3NlcygpO1xuICB9IC8vIFRvZ2dsZSBuYXZpZ2F0aW9uLCBwYWdpbmF0aW9uLCBzY3JvbGxiYXJcblxuXG4gIFsnbmF2aWdhdGlvbicsICdwYWdpbmF0aW9uJywgJ3Njcm9sbGJhciddLmZvckVhY2gocHJvcCA9PiB7XG4gICAgY29uc3Qgd2FzTW9kdWxlRW5hYmxlZCA9IHBhcmFtc1twcm9wXSAmJiBwYXJhbXNbcHJvcF0uZW5hYmxlZDtcbiAgICBjb25zdCBpc01vZHVsZUVuYWJsZWQgPSBicmVha3BvaW50UGFyYW1zW3Byb3BdICYmIGJyZWFrcG9pbnRQYXJhbXNbcHJvcF0uZW5hYmxlZDtcblxuICAgIGlmICh3YXNNb2R1bGVFbmFibGVkICYmICFpc01vZHVsZUVuYWJsZWQpIHtcbiAgICAgIHN3aXBlcltwcm9wXS5kaXNhYmxlKCk7XG4gICAgfVxuXG4gICAgaWYgKCF3YXNNb2R1bGVFbmFibGVkICYmIGlzTW9kdWxlRW5hYmxlZCkge1xuICAgICAgc3dpcGVyW3Byb3BdLmVuYWJsZSgpO1xuICAgIH1cbiAgfSk7XG4gIGNvbnN0IGRpcmVjdGlvbkNoYW5nZWQgPSBicmVha3BvaW50UGFyYW1zLmRpcmVjdGlvbiAmJiBicmVha3BvaW50UGFyYW1zLmRpcmVjdGlvbiAhPT0gcGFyYW1zLmRpcmVjdGlvbjtcbiAgY29uc3QgbmVlZHNSZUxvb3AgPSBwYXJhbXMubG9vcCAmJiAoYnJlYWtwb2ludFBhcmFtcy5zbGlkZXNQZXJWaWV3ICE9PSBwYXJhbXMuc2xpZGVzUGVyVmlldyB8fCBkaXJlY3Rpb25DaGFuZ2VkKTtcblxuICBpZiAoZGlyZWN0aW9uQ2hhbmdlZCAmJiBpbml0aWFsaXplZCkge1xuICAgIHN3aXBlci5jaGFuZ2VEaXJlY3Rpb24oKTtcbiAgfVxuXG4gIGV4dGVuZChzd2lwZXIucGFyYW1zLCBicmVha3BvaW50UGFyYW1zKTtcbiAgY29uc3QgaXNFbmFibGVkID0gc3dpcGVyLnBhcmFtcy5lbmFibGVkO1xuICBPYmplY3QuYXNzaWduKHN3aXBlciwge1xuICAgIGFsbG93VG91Y2hNb3ZlOiBzd2lwZXIucGFyYW1zLmFsbG93VG91Y2hNb3ZlLFxuICAgIGFsbG93U2xpZGVOZXh0OiBzd2lwZXIucGFyYW1zLmFsbG93U2xpZGVOZXh0LFxuICAgIGFsbG93U2xpZGVQcmV2OiBzd2lwZXIucGFyYW1zLmFsbG93U2xpZGVQcmV2XG4gIH0pO1xuXG4gIGlmICh3YXNFbmFibGVkICYmICFpc0VuYWJsZWQpIHtcbiAgICBzd2lwZXIuZGlzYWJsZSgpO1xuICB9IGVsc2UgaWYgKCF3YXNFbmFibGVkICYmIGlzRW5hYmxlZCkge1xuICAgIHN3aXBlci5lbmFibGUoKTtcbiAgfVxuXG4gIHN3aXBlci5jdXJyZW50QnJlYWtwb2ludCA9IGJyZWFrcG9pbnQ7XG4gIHN3aXBlci5lbWl0KCdfYmVmb3JlQnJlYWtwb2ludCcsIGJyZWFrcG9pbnRQYXJhbXMpO1xuXG4gIGlmIChuZWVkc1JlTG9vcCAmJiBpbml0aWFsaXplZCkge1xuICAgIHN3aXBlci5sb29wRGVzdHJveSgpO1xuICAgIHN3aXBlci5sb29wQ3JlYXRlKCk7XG4gICAgc3dpcGVyLnVwZGF0ZVNsaWRlcygpO1xuICAgIHN3aXBlci5zbGlkZVRvKGFjdGl2ZUluZGV4IC0gbG9vcGVkU2xpZGVzICsgc3dpcGVyLmxvb3BlZFNsaWRlcywgMCwgZmFsc2UpO1xuICB9XG5cbiAgc3dpcGVyLmVtaXQoJ2JyZWFrcG9pbnQnLCBicmVha3BvaW50UGFyYW1zKTtcbn0iLCJpbXBvcnQgeyBnZXRXaW5kb3cgfSBmcm9tICdzc3Itd2luZG93JztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGdldEJyZWFrcG9pbnQoYnJlYWtwb2ludHMsIGJhc2UgPSAnd2luZG93JywgY29udGFpbmVyRWwpIHtcbiAgaWYgKCFicmVha3BvaW50cyB8fCBiYXNlID09PSAnY29udGFpbmVyJyAmJiAhY29udGFpbmVyRWwpIHJldHVybiB1bmRlZmluZWQ7XG4gIGxldCBicmVha3BvaW50ID0gZmFsc2U7XG4gIGNvbnN0IHdpbmRvdyA9IGdldFdpbmRvdygpO1xuICBjb25zdCBjdXJyZW50SGVpZ2h0ID0gYmFzZSA9PT0gJ3dpbmRvdycgPyB3aW5kb3cuaW5uZXJIZWlnaHQgOiBjb250YWluZXJFbC5jbGllbnRIZWlnaHQ7XG4gIGNvbnN0IHBvaW50cyA9IE9iamVjdC5rZXlzKGJyZWFrcG9pbnRzKS5tYXAocG9pbnQgPT4ge1xuICAgIGlmICh0eXBlb2YgcG9pbnQgPT09ICdzdHJpbmcnICYmIHBvaW50LmluZGV4T2YoJ0AnKSA9PT0gMCkge1xuICAgICAgY29uc3QgbWluUmF0aW8gPSBwYXJzZUZsb2F0KHBvaW50LnN1YnN0cigxKSk7XG4gICAgICBjb25zdCB2YWx1ZSA9IGN1cnJlbnRIZWlnaHQgKiBtaW5SYXRpbztcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHZhbHVlLFxuICAgICAgICBwb2ludFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgdmFsdWU6IHBvaW50LFxuICAgICAgcG9pbnRcbiAgICB9O1xuICB9KTtcbiAgcG9pbnRzLnNvcnQoKGEsIGIpID0+IHBhcnNlSW50KGEudmFsdWUsIDEwKSAtIHBhcnNlSW50KGIudmFsdWUsIDEwKSk7XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBwb2ludHMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICBjb25zdCB7XG4gICAgICBwb2ludCxcbiAgICAgIHZhbHVlXG4gICAgfSA9IHBvaW50c1tpXTtcblxuICAgIGlmIChiYXNlID09PSAnd2luZG93Jykge1xuICAgICAgaWYgKHdpbmRvdy5tYXRjaE1lZGlhKGAobWluLXdpZHRoOiAke3ZhbHVlfXB4KWApLm1hdGNoZXMpIHtcbiAgICAgICAgYnJlYWtwb2ludCA9IHBvaW50O1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAodmFsdWUgPD0gY29udGFpbmVyRWwuY2xpZW50V2lkdGgpIHtcbiAgICAgIGJyZWFrcG9pbnQgPSBwb2ludDtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gYnJlYWtwb2ludCB8fCAnbWF4Jztcbn0iLCJpbXBvcnQgc2V0QnJlYWtwb2ludCBmcm9tICcuL3NldEJyZWFrcG9pbnQuanMnO1xuaW1wb3J0IGdldEJyZWFrcG9pbnQgZnJvbSAnLi9nZXRCcmVha3BvaW50LmpzJztcbmV4cG9ydCBkZWZhdWx0IHtcbiAgc2V0QnJlYWtwb2ludCxcbiAgZ2V0QnJlYWtwb2ludFxufTsiLCJmdW5jdGlvbiBwcmVwYXJlQ2xhc3NlcyhlbnRyaWVzLCBwcmVmaXgpIHtcbiAgY29uc3QgcmVzdWx0Q2xhc3NlcyA9IFtdO1xuICBlbnRyaWVzLmZvckVhY2goaXRlbSA9PiB7XG4gICAgaWYgKHR5cGVvZiBpdGVtID09PSAnb2JqZWN0Jykge1xuICAgICAgT2JqZWN0LmtleXMoaXRlbSkuZm9yRWFjaChjbGFzc05hbWVzID0+IHtcbiAgICAgICAgaWYgKGl0ZW1bY2xhc3NOYW1lc10pIHtcbiAgICAgICAgICByZXN1bHRDbGFzc2VzLnB1c2gocHJlZml4ICsgY2xhc3NOYW1lcyk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIGl0ZW0gPT09ICdzdHJpbmcnKSB7XG4gICAgICByZXN1bHRDbGFzc2VzLnB1c2gocHJlZml4ICsgaXRlbSk7XG4gICAgfVxuICB9KTtcbiAgcmV0dXJuIHJlc3VsdENsYXNzZXM7XG59XG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGFkZENsYXNzZXMoKSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gIGNvbnN0IHtcbiAgICBjbGFzc05hbWVzLFxuICAgIHBhcmFtcyxcbiAgICBydGwsXG4gICAgJGVsLFxuICAgIGRldmljZSxcbiAgICBzdXBwb3J0XG4gIH0gPSBzd2lwZXI7IC8vIHByZXR0aWVyLWlnbm9yZVxuXG4gIGNvbnN0IHN1ZmZpeGVzID0gcHJlcGFyZUNsYXNzZXMoWydpbml0aWFsaXplZCcsIHBhcmFtcy5kaXJlY3Rpb24sIHtcbiAgICAncG9pbnRlci1ldmVudHMnOiAhc3VwcG9ydC50b3VjaFxuICB9LCB7XG4gICAgJ2ZyZWUtbW9kZSc6IHN3aXBlci5wYXJhbXMuZnJlZU1vZGUgJiYgcGFyYW1zLmZyZWVNb2RlLmVuYWJsZWRcbiAgfSwge1xuICAgICdhdXRvaGVpZ2h0JzogcGFyYW1zLmF1dG9IZWlnaHRcbiAgfSwge1xuICAgICdydGwnOiBydGxcbiAgfSwge1xuICAgICdncmlkJzogcGFyYW1zLmdyaWQgJiYgcGFyYW1zLmdyaWQucm93cyA+IDFcbiAgfSwge1xuICAgICdncmlkLWNvbHVtbic6IHBhcmFtcy5ncmlkICYmIHBhcmFtcy5ncmlkLnJvd3MgPiAxICYmIHBhcmFtcy5ncmlkLmZpbGwgPT09ICdjb2x1bW4nXG4gIH0sIHtcbiAgICAnYW5kcm9pZCc6IGRldmljZS5hbmRyb2lkXG4gIH0sIHtcbiAgICAnaW9zJzogZGV2aWNlLmlvc1xuICB9LCB7XG4gICAgJ2Nzcy1tb2RlJzogcGFyYW1zLmNzc01vZGVcbiAgfSwge1xuICAgICdjZW50ZXJlZCc6IHBhcmFtcy5jc3NNb2RlICYmIHBhcmFtcy5jZW50ZXJlZFNsaWRlc1xuICB9LCB7XG4gICAgJ3dhdGNoLXByb2dyZXNzJzogcGFyYW1zLndhdGNoU2xpZGVzUHJvZ3Jlc3NcbiAgfV0sIHBhcmFtcy5jb250YWluZXJNb2RpZmllckNsYXNzKTtcbiAgY2xhc3NOYW1lcy5wdXNoKC4uLnN1ZmZpeGVzKTtcbiAgJGVsLmFkZENsYXNzKFsuLi5jbGFzc05hbWVzXS5qb2luKCcgJykpO1xuICBzd2lwZXIuZW1pdENvbnRhaW5lckNsYXNzZXMoKTtcbn0iLCJleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiByZW1vdmVDbGFzc2VzKCkge1xuICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICBjb25zdCB7XG4gICAgJGVsLFxuICAgIGNsYXNzTmFtZXNcbiAgfSA9IHN3aXBlcjtcbiAgJGVsLnJlbW92ZUNsYXNzKGNsYXNzTmFtZXMuam9pbignICcpKTtcbiAgc3dpcGVyLmVtaXRDb250YWluZXJDbGFzc2VzKCk7XG59IiwiaW1wb3J0IGFkZENsYXNzZXMgZnJvbSAnLi9hZGRDbGFzc2VzLmpzJztcbmltcG9ydCByZW1vdmVDbGFzc2VzIGZyb20gJy4vcmVtb3ZlQ2xhc3Nlcy5qcyc7XG5leHBvcnQgZGVmYXVsdCB7XG4gIGFkZENsYXNzZXMsXG4gIHJlbW92ZUNsYXNzZXNcbn07IiwiaW1wb3J0IHsgZ2V0V2luZG93IH0gZnJvbSAnc3NyLXdpbmRvdyc7XG5pbXBvcnQgJCBmcm9tICcuLi8uLi9zaGFyZWQvZG9tLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGxvYWRJbWFnZShpbWFnZUVsLCBzcmMsIHNyY3NldCwgc2l6ZXMsIGNoZWNrRm9yQ29tcGxldGUsIGNhbGxiYWNrKSB7XG4gIGNvbnN0IHdpbmRvdyA9IGdldFdpbmRvdygpO1xuICBsZXQgaW1hZ2U7XG5cbiAgZnVuY3Rpb24gb25SZWFkeSgpIHtcbiAgICBpZiAoY2FsbGJhY2spIGNhbGxiYWNrKCk7XG4gIH1cblxuICBjb25zdCBpc1BpY3R1cmUgPSAkKGltYWdlRWwpLnBhcmVudCgncGljdHVyZScpWzBdO1xuXG4gIGlmICghaXNQaWN0dXJlICYmICghaW1hZ2VFbC5jb21wbGV0ZSB8fCAhY2hlY2tGb3JDb21wbGV0ZSkpIHtcbiAgICBpZiAoc3JjKSB7XG4gICAgICBpbWFnZSA9IG5ldyB3aW5kb3cuSW1hZ2UoKTtcbiAgICAgIGltYWdlLm9ubG9hZCA9IG9uUmVhZHk7XG4gICAgICBpbWFnZS5vbmVycm9yID0gb25SZWFkeTtcblxuICAgICAgaWYgKHNpemVzKSB7XG4gICAgICAgIGltYWdlLnNpemVzID0gc2l6ZXM7XG4gICAgICB9XG5cbiAgICAgIGlmIChzcmNzZXQpIHtcbiAgICAgICAgaW1hZ2Uuc3Jjc2V0ID0gc3Jjc2V0O1xuICAgICAgfVxuXG4gICAgICBpZiAoc3JjKSB7XG4gICAgICAgIGltYWdlLnNyYyA9IHNyYztcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgb25SZWFkeSgpO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICAvLyBpbWFnZSBhbHJlYWR5IGxvYWRlZC4uLlxuICAgIG9uUmVhZHkoKTtcbiAgfVxufSIsImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHByZWxvYWRJbWFnZXMoKSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gIHN3aXBlci5pbWFnZXNUb0xvYWQgPSBzd2lwZXIuJGVsLmZpbmQoJ2ltZycpO1xuXG4gIGZ1bmN0aW9uIG9uUmVhZHkoKSB7XG4gICAgaWYgKHR5cGVvZiBzd2lwZXIgPT09ICd1bmRlZmluZWQnIHx8IHN3aXBlciA9PT0gbnVsbCB8fCAhc3dpcGVyIHx8IHN3aXBlci5kZXN0cm95ZWQpIHJldHVybjtcbiAgICBpZiAoc3dpcGVyLmltYWdlc0xvYWRlZCAhPT0gdW5kZWZpbmVkKSBzd2lwZXIuaW1hZ2VzTG9hZGVkICs9IDE7XG5cbiAgICBpZiAoc3dpcGVyLmltYWdlc0xvYWRlZCA9PT0gc3dpcGVyLmltYWdlc1RvTG9hZC5sZW5ndGgpIHtcbiAgICAgIGlmIChzd2lwZXIucGFyYW1zLnVwZGF0ZU9uSW1hZ2VzUmVhZHkpIHN3aXBlci51cGRhdGUoKTtcbiAgICAgIHN3aXBlci5lbWl0KCdpbWFnZXNSZWFkeScpO1xuICAgIH1cbiAgfVxuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgc3dpcGVyLmltYWdlc1RvTG9hZC5sZW5ndGg7IGkgKz0gMSkge1xuICAgIGNvbnN0IGltYWdlRWwgPSBzd2lwZXIuaW1hZ2VzVG9Mb2FkW2ldO1xuICAgIHN3aXBlci5sb2FkSW1hZ2UoaW1hZ2VFbCwgaW1hZ2VFbC5jdXJyZW50U3JjIHx8IGltYWdlRWwuZ2V0QXR0cmlidXRlKCdzcmMnKSwgaW1hZ2VFbC5zcmNzZXQgfHwgaW1hZ2VFbC5nZXRBdHRyaWJ1dGUoJ3NyY3NldCcpLCBpbWFnZUVsLnNpemVzIHx8IGltYWdlRWwuZ2V0QXR0cmlidXRlKCdzaXplcycpLCB0cnVlLCBvblJlYWR5KTtcbiAgfVxufSIsImltcG9ydCBsb2FkSW1hZ2UgZnJvbSAnLi9sb2FkSW1hZ2UuanMnO1xuaW1wb3J0IHByZWxvYWRJbWFnZXMgZnJvbSAnLi9wcmVsb2FkSW1hZ2VzLmpzJztcbmV4cG9ydCBkZWZhdWx0IHtcbiAgbG9hZEltYWdlLFxuICBwcmVsb2FkSW1hZ2VzXG59OyIsImZ1bmN0aW9uIGNoZWNrT3ZlcmZsb3coKSB7XG4gIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gIGNvbnN0IHtcbiAgICBpc0xvY2tlZDogd2FzTG9ja2VkLFxuICAgIHBhcmFtc1xuICB9ID0gc3dpcGVyO1xuICBjb25zdCB7XG4gICAgc2xpZGVzT2Zmc2V0QmVmb3JlXG4gIH0gPSBwYXJhbXM7XG5cbiAgaWYgKHNsaWRlc09mZnNldEJlZm9yZSkge1xuICAgIGNvbnN0IGxhc3RTbGlkZUluZGV4ID0gc3dpcGVyLnNsaWRlcy5sZW5ndGggLSAxO1xuICAgIGNvbnN0IGxhc3RTbGlkZVJpZ2h0RWRnZSA9IHN3aXBlci5zbGlkZXNHcmlkW2xhc3RTbGlkZUluZGV4XSArIHN3aXBlci5zbGlkZXNTaXplc0dyaWRbbGFzdFNsaWRlSW5kZXhdICsgc2xpZGVzT2Zmc2V0QmVmb3JlICogMjtcbiAgICBzd2lwZXIuaXNMb2NrZWQgPSBzd2lwZXIuc2l6ZSA+IGxhc3RTbGlkZVJpZ2h0RWRnZTtcbiAgfSBlbHNlIHtcbiAgICBzd2lwZXIuaXNMb2NrZWQgPSBzd2lwZXIuc25hcEdyaWQubGVuZ3RoID09PSAxO1xuICB9XG5cbiAgaWYgKHBhcmFtcy5hbGxvd1NsaWRlTmV4dCA9PT0gdHJ1ZSkge1xuICAgIHN3aXBlci5hbGxvd1NsaWRlTmV4dCA9ICFzd2lwZXIuaXNMb2NrZWQ7XG4gIH1cblxuICBpZiAocGFyYW1zLmFsbG93U2xpZGVQcmV2ID09PSB0cnVlKSB7XG4gICAgc3dpcGVyLmFsbG93U2xpZGVQcmV2ID0gIXN3aXBlci5pc0xvY2tlZDtcbiAgfVxuXG4gIGlmICh3YXNMb2NrZWQgJiYgd2FzTG9ja2VkICE9PSBzd2lwZXIuaXNMb2NrZWQpIHtcbiAgICBzd2lwZXIuaXNFbmQgPSBmYWxzZTtcbiAgfVxuXG4gIGlmICh3YXNMb2NrZWQgIT09IHN3aXBlci5pc0xvY2tlZCkge1xuICAgIHN3aXBlci5lbWl0KHN3aXBlci5pc0xvY2tlZCA/ICdsb2NrJyA6ICd1bmxvY2snKTtcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGNoZWNrT3ZlcmZsb3dcbn07IiwiZXhwb3J0IGRlZmF1bHQge1xuICBpbml0OiB0cnVlLFxuICBkaXJlY3Rpb246ICdob3Jpem9udGFsJyxcbiAgdG91Y2hFdmVudHNUYXJnZXQ6ICd3cmFwcGVyJyxcbiAgaW5pdGlhbFNsaWRlOiAwLFxuICBzcGVlZDogMzAwLFxuICBjc3NNb2RlOiBmYWxzZSxcbiAgdXBkYXRlT25XaW5kb3dSZXNpemU6IHRydWUsXG4gIHJlc2l6ZU9ic2VydmVyOiB0cnVlLFxuICBuZXN0ZWQ6IGZhbHNlLFxuICBjcmVhdGVFbGVtZW50czogZmFsc2UsXG4gIGVuYWJsZWQ6IHRydWUsXG4gIGZvY3VzYWJsZUVsZW1lbnRzOiAnaW5wdXQsIHNlbGVjdCwgb3B0aW9uLCB0ZXh0YXJlYSwgYnV0dG9uLCB2aWRlbywgbGFiZWwnLFxuICAvLyBPdmVycmlkZXNcbiAgd2lkdGg6IG51bGwsXG4gIGhlaWdodDogbnVsbCxcbiAgLy9cbiAgcHJldmVudEludGVyYWN0aW9uT25UcmFuc2l0aW9uOiBmYWxzZSxcbiAgLy8gc3NyXG4gIHVzZXJBZ2VudDogbnVsbCxcbiAgdXJsOiBudWxsLFxuICAvLyBUbyBzdXBwb3J0IGlPUydzIHN3aXBlLXRvLWdvLWJhY2sgZ2VzdHVyZSAod2hlbiBiZWluZyB1c2VkIGluLWFwcCkuXG4gIGVkZ2VTd2lwZURldGVjdGlvbjogZmFsc2UsXG4gIGVkZ2VTd2lwZVRocmVzaG9sZDogMjAsXG4gIC8vIEF1dG9oZWlnaHRcbiAgYXV0b0hlaWdodDogZmFsc2UsXG4gIC8vIFNldCB3cmFwcGVyIHdpZHRoXG4gIHNldFdyYXBwZXJTaXplOiBmYWxzZSxcbiAgLy8gVmlydHVhbCBUcmFuc2xhdGVcbiAgdmlydHVhbFRyYW5zbGF0ZTogZmFsc2UsXG4gIC8vIEVmZmVjdHNcbiAgZWZmZWN0OiAnc2xpZGUnLFxuICAvLyAnc2xpZGUnIG9yICdmYWRlJyBvciAnY3ViZScgb3IgJ2NvdmVyZmxvdycgb3IgJ2ZsaXAnXG4gIC8vIEJyZWFrcG9pbnRzXG4gIGJyZWFrcG9pbnRzOiB1bmRlZmluZWQsXG4gIGJyZWFrcG9pbnRzQmFzZTogJ3dpbmRvdycsXG4gIC8vIFNsaWRlcyBncmlkXG4gIHNwYWNlQmV0d2VlbjogMCxcbiAgc2xpZGVzUGVyVmlldzogMSxcbiAgc2xpZGVzUGVyR3JvdXA6IDEsXG4gIHNsaWRlc1Blckdyb3VwU2tpcDogMCxcbiAgc2xpZGVzUGVyR3JvdXBBdXRvOiBmYWxzZSxcbiAgY2VudGVyZWRTbGlkZXM6IGZhbHNlLFxuICBjZW50ZXJlZFNsaWRlc0JvdW5kczogZmFsc2UsXG4gIHNsaWRlc09mZnNldEJlZm9yZTogMCxcbiAgLy8gaW4gcHhcbiAgc2xpZGVzT2Zmc2V0QWZ0ZXI6IDAsXG4gIC8vIGluIHB4XG4gIG5vcm1hbGl6ZVNsaWRlSW5kZXg6IHRydWUsXG4gIGNlbnRlckluc3VmZmljaWVudFNsaWRlczogZmFsc2UsXG4gIC8vIERpc2FibGUgc3dpcGVyIGFuZCBoaWRlIG5hdmlnYXRpb24gd2hlbiBjb250YWluZXIgbm90IG92ZXJmbG93XG4gIHdhdGNoT3ZlcmZsb3c6IHRydWUsXG4gIC8vIFJvdW5kIGxlbmd0aFxuICByb3VuZExlbmd0aHM6IGZhbHNlLFxuICAvLyBUb3VjaGVzXG4gIHRvdWNoUmF0aW86IDEsXG4gIHRvdWNoQW5nbGU6IDQ1LFxuICBzaW11bGF0ZVRvdWNoOiB0cnVlLFxuICBzaG9ydFN3aXBlczogdHJ1ZSxcbiAgbG9uZ1N3aXBlczogdHJ1ZSxcbiAgbG9uZ1N3aXBlc1JhdGlvOiAwLjUsXG4gIGxvbmdTd2lwZXNNczogMzAwLFxuICBmb2xsb3dGaW5nZXI6IHRydWUsXG4gIGFsbG93VG91Y2hNb3ZlOiB0cnVlLFxuICB0aHJlc2hvbGQ6IDAsXG4gIHRvdWNoTW92ZVN0b3BQcm9wYWdhdGlvbjogZmFsc2UsXG4gIHRvdWNoU3RhcnRQcmV2ZW50RGVmYXVsdDogdHJ1ZSxcbiAgdG91Y2hTdGFydEZvcmNlUHJldmVudERlZmF1bHQ6IGZhbHNlLFxuICB0b3VjaFJlbGVhc2VPbkVkZ2VzOiBmYWxzZSxcbiAgLy8gVW5pcXVlIE5hdmlnYXRpb24gRWxlbWVudHNcbiAgdW5pcXVlTmF2RWxlbWVudHM6IHRydWUsXG4gIC8vIFJlc2lzdGFuY2VcbiAgcmVzaXN0YW5jZTogdHJ1ZSxcbiAgcmVzaXN0YW5jZVJhdGlvOiAwLjg1LFxuICAvLyBQcm9ncmVzc1xuICB3YXRjaFNsaWRlc1Byb2dyZXNzOiBmYWxzZSxcbiAgLy8gQ3Vyc29yXG4gIGdyYWJDdXJzb3I6IGZhbHNlLFxuICAvLyBDbGlja3NcbiAgcHJldmVudENsaWNrczogdHJ1ZSxcbiAgcHJldmVudENsaWNrc1Byb3BhZ2F0aW9uOiB0cnVlLFxuICBzbGlkZVRvQ2xpY2tlZFNsaWRlOiBmYWxzZSxcbiAgLy8gSW1hZ2VzXG4gIHByZWxvYWRJbWFnZXM6IHRydWUsXG4gIHVwZGF0ZU9uSW1hZ2VzUmVhZHk6IHRydWUsXG4gIC8vIGxvb3BcbiAgbG9vcDogZmFsc2UsXG4gIGxvb3BBZGRpdGlvbmFsU2xpZGVzOiAwLFxuICBsb29wZWRTbGlkZXM6IG51bGwsXG4gIGxvb3BlZFNsaWRlc0xpbWl0OiB0cnVlLFxuICBsb29wRmlsbEdyb3VwV2l0aEJsYW5rOiBmYWxzZSxcbiAgbG9vcFByZXZlbnRzU2xpZGU6IHRydWUsXG4gIC8vIHJld2luZFxuICByZXdpbmQ6IGZhbHNlLFxuICAvLyBTd2lwaW5nL25vIHN3aXBpbmdcbiAgYWxsb3dTbGlkZVByZXY6IHRydWUsXG4gIGFsbG93U2xpZGVOZXh0OiB0cnVlLFxuICBzd2lwZUhhbmRsZXI6IG51bGwsXG4gIC8vICcuc3dpcGUtaGFuZGxlcicsXG4gIG5vU3dpcGluZzogdHJ1ZSxcbiAgbm9Td2lwaW5nQ2xhc3M6ICdzd2lwZXItbm8tc3dpcGluZycsXG4gIG5vU3dpcGluZ1NlbGVjdG9yOiBudWxsLFxuICAvLyBQYXNzaXZlIExpc3RlbmVyc1xuICBwYXNzaXZlTGlzdGVuZXJzOiB0cnVlLFxuICBtYXhCYWNrZmFjZUhpZGRlblNsaWRlczogMTAsXG4gIC8vIE5TXG4gIGNvbnRhaW5lck1vZGlmaWVyQ2xhc3M6ICdzd2lwZXItJyxcbiAgLy8gTkVXXG4gIHNsaWRlQ2xhc3M6ICdzd2lwZXItc2xpZGUnLFxuICBzbGlkZUJsYW5rQ2xhc3M6ICdzd2lwZXItc2xpZGUtaW52aXNpYmxlLWJsYW5rJyxcbiAgc2xpZGVBY3RpdmVDbGFzczogJ3N3aXBlci1zbGlkZS1hY3RpdmUnLFxuICBzbGlkZUR1cGxpY2F0ZUFjdGl2ZUNsYXNzOiAnc3dpcGVyLXNsaWRlLWR1cGxpY2F0ZS1hY3RpdmUnLFxuICBzbGlkZVZpc2libGVDbGFzczogJ3N3aXBlci1zbGlkZS12aXNpYmxlJyxcbiAgc2xpZGVEdXBsaWNhdGVDbGFzczogJ3N3aXBlci1zbGlkZS1kdXBsaWNhdGUnLFxuICBzbGlkZU5leHRDbGFzczogJ3N3aXBlci1zbGlkZS1uZXh0JyxcbiAgc2xpZGVEdXBsaWNhdGVOZXh0Q2xhc3M6ICdzd2lwZXItc2xpZGUtZHVwbGljYXRlLW5leHQnLFxuICBzbGlkZVByZXZDbGFzczogJ3N3aXBlci1zbGlkZS1wcmV2JyxcbiAgc2xpZGVEdXBsaWNhdGVQcmV2Q2xhc3M6ICdzd2lwZXItc2xpZGUtZHVwbGljYXRlLXByZXYnLFxuICB3cmFwcGVyQ2xhc3M6ICdzd2lwZXItd3JhcHBlcicsXG4gIC8vIENhbGxiYWNrc1xuICBydW5DYWxsYmFja3NPbkluaXQ6IHRydWUsXG4gIC8vIEludGVybmFsc1xuICBfZW1pdENsYXNzZXM6IGZhbHNlXG59OyIsImltcG9ydCB7IGV4dGVuZCB9IGZyb20gJy4uL3NoYXJlZC91dGlscy5qcyc7XG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBtb2R1bGVFeHRlbmRQYXJhbXMocGFyYW1zLCBhbGxNb2R1bGVzUGFyYW1zKSB7XG4gIHJldHVybiBmdW5jdGlvbiBleHRlbmRQYXJhbXMob2JqID0ge30pIHtcbiAgICBjb25zdCBtb2R1bGVQYXJhbU5hbWUgPSBPYmplY3Qua2V5cyhvYmopWzBdO1xuICAgIGNvbnN0IG1vZHVsZVBhcmFtcyA9IG9ialttb2R1bGVQYXJhbU5hbWVdO1xuXG4gICAgaWYgKHR5cGVvZiBtb2R1bGVQYXJhbXMgIT09ICdvYmplY3QnIHx8IG1vZHVsZVBhcmFtcyA9PT0gbnVsbCkge1xuICAgICAgZXh0ZW5kKGFsbE1vZHVsZXNQYXJhbXMsIG9iaik7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKFsnbmF2aWdhdGlvbicsICdwYWdpbmF0aW9uJywgJ3Njcm9sbGJhciddLmluZGV4T2YobW9kdWxlUGFyYW1OYW1lKSA+PSAwICYmIHBhcmFtc1ttb2R1bGVQYXJhbU5hbWVdID09PSB0cnVlKSB7XG4gICAgICBwYXJhbXNbbW9kdWxlUGFyYW1OYW1lXSA9IHtcbiAgICAgICAgYXV0bzogdHJ1ZVxuICAgICAgfTtcbiAgICB9XG5cbiAgICBpZiAoIShtb2R1bGVQYXJhbU5hbWUgaW4gcGFyYW1zICYmICdlbmFibGVkJyBpbiBtb2R1bGVQYXJhbXMpKSB7XG4gICAgICBleHRlbmQoYWxsTW9kdWxlc1BhcmFtcywgb2JqKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAocGFyYW1zW21vZHVsZVBhcmFtTmFtZV0gPT09IHRydWUpIHtcbiAgICAgIHBhcmFtc1ttb2R1bGVQYXJhbU5hbWVdID0ge1xuICAgICAgICBlbmFibGVkOiB0cnVlXG4gICAgICB9O1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgcGFyYW1zW21vZHVsZVBhcmFtTmFtZV0gPT09ICdvYmplY3QnICYmICEoJ2VuYWJsZWQnIGluIHBhcmFtc1ttb2R1bGVQYXJhbU5hbWVdKSkge1xuICAgICAgcGFyYW1zW21vZHVsZVBhcmFtTmFtZV0uZW5hYmxlZCA9IHRydWU7XG4gICAgfVxuXG4gICAgaWYgKCFwYXJhbXNbbW9kdWxlUGFyYW1OYW1lXSkgcGFyYW1zW21vZHVsZVBhcmFtTmFtZV0gPSB7XG4gICAgICBlbmFibGVkOiBmYWxzZVxuICAgIH07XG4gICAgZXh0ZW5kKGFsbE1vZHVsZXNQYXJhbXMsIG9iaik7XG4gIH07XG59IiwiLyogZXNsaW50IG5vLXBhcmFtLXJlYXNzaWduOiBcIm9mZlwiICovXG5pbXBvcnQgeyBnZXREb2N1bWVudCB9IGZyb20gJ3Nzci13aW5kb3cnO1xuaW1wb3J0ICQgZnJvbSAnLi4vc2hhcmVkL2RvbS5qcyc7XG5pbXBvcnQgeyBleHRlbmQsIG5vdywgZGVsZXRlUHJvcHMgfSBmcm9tICcuLi9zaGFyZWQvdXRpbHMuanMnO1xuaW1wb3J0IHsgZ2V0U3VwcG9ydCB9IGZyb20gJy4uL3NoYXJlZC9nZXQtc3VwcG9ydC5qcyc7XG5pbXBvcnQgeyBnZXREZXZpY2UgfSBmcm9tICcuLi9zaGFyZWQvZ2V0LWRldmljZS5qcyc7XG5pbXBvcnQgeyBnZXRCcm93c2VyIH0gZnJvbSAnLi4vc2hhcmVkL2dldC1icm93c2VyLmpzJztcbmltcG9ydCBSZXNpemUgZnJvbSAnLi9tb2R1bGVzL3Jlc2l6ZS9yZXNpemUuanMnO1xuaW1wb3J0IE9ic2VydmVyIGZyb20gJy4vbW9kdWxlcy9vYnNlcnZlci9vYnNlcnZlci5qcyc7XG5pbXBvcnQgZXZlbnRzRW1pdHRlciBmcm9tICcuL2V2ZW50cy1lbWl0dGVyLmpzJztcbmltcG9ydCB1cGRhdGUgZnJvbSAnLi91cGRhdGUvaW5kZXguanMnO1xuaW1wb3J0IHRyYW5zbGF0ZSBmcm9tICcuL3RyYW5zbGF0ZS9pbmRleC5qcyc7XG5pbXBvcnQgdHJhbnNpdGlvbiBmcm9tICcuL3RyYW5zaXRpb24vaW5kZXguanMnO1xuaW1wb3J0IHNsaWRlIGZyb20gJy4vc2xpZGUvaW5kZXguanMnO1xuaW1wb3J0IGxvb3AgZnJvbSAnLi9sb29wL2luZGV4LmpzJztcbmltcG9ydCBncmFiQ3Vyc29yIGZyb20gJy4vZ3JhYi1jdXJzb3IvaW5kZXguanMnO1xuaW1wb3J0IGV2ZW50cyBmcm9tICcuL2V2ZW50cy9pbmRleC5qcyc7XG5pbXBvcnQgYnJlYWtwb2ludHMgZnJvbSAnLi9icmVha3BvaW50cy9pbmRleC5qcyc7XG5pbXBvcnQgY2xhc3NlcyBmcm9tICcuL2NsYXNzZXMvaW5kZXguanMnO1xuaW1wb3J0IGltYWdlcyBmcm9tICcuL2ltYWdlcy9pbmRleC5qcyc7XG5pbXBvcnQgY2hlY2tPdmVyZmxvdyBmcm9tICcuL2NoZWNrLW92ZXJmbG93L2luZGV4LmpzJztcbmltcG9ydCBkZWZhdWx0cyBmcm9tICcuL2RlZmF1bHRzLmpzJztcbmltcG9ydCBtb2R1bGVFeHRlbmRQYXJhbXMgZnJvbSAnLi9tb2R1bGVFeHRlbmRQYXJhbXMuanMnO1xuY29uc3QgcHJvdG90eXBlcyA9IHtcbiAgZXZlbnRzRW1pdHRlcixcbiAgdXBkYXRlLFxuICB0cmFuc2xhdGUsXG4gIHRyYW5zaXRpb24sXG4gIHNsaWRlLFxuICBsb29wLFxuICBncmFiQ3Vyc29yLFxuICBldmVudHMsXG4gIGJyZWFrcG9pbnRzLFxuICBjaGVja092ZXJmbG93LFxuICBjbGFzc2VzLFxuICBpbWFnZXNcbn07XG5jb25zdCBleHRlbmRlZERlZmF1bHRzID0ge307XG5cbmNsYXNzIFN3aXBlciB7XG4gIGNvbnN0cnVjdG9yKC4uLmFyZ3MpIHtcbiAgICBsZXQgZWw7XG4gICAgbGV0IHBhcmFtcztcblxuICAgIGlmIChhcmdzLmxlbmd0aCA9PT0gMSAmJiBhcmdzWzBdLmNvbnN0cnVjdG9yICYmIE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChhcmdzWzBdKS5zbGljZSg4LCAtMSkgPT09ICdPYmplY3QnKSB7XG4gICAgICBwYXJhbXMgPSBhcmdzWzBdO1xuICAgIH0gZWxzZSB7XG4gICAgICBbZWwsIHBhcmFtc10gPSBhcmdzO1xuICAgIH1cblxuICAgIGlmICghcGFyYW1zKSBwYXJhbXMgPSB7fTtcbiAgICBwYXJhbXMgPSBleHRlbmQoe30sIHBhcmFtcyk7XG4gICAgaWYgKGVsICYmICFwYXJhbXMuZWwpIHBhcmFtcy5lbCA9IGVsO1xuXG4gICAgaWYgKHBhcmFtcy5lbCAmJiAkKHBhcmFtcy5lbCkubGVuZ3RoID4gMSkge1xuICAgICAgY29uc3Qgc3dpcGVycyA9IFtdO1xuICAgICAgJChwYXJhbXMuZWwpLmVhY2goY29udGFpbmVyRWwgPT4ge1xuICAgICAgICBjb25zdCBuZXdQYXJhbXMgPSBleHRlbmQoe30sIHBhcmFtcywge1xuICAgICAgICAgIGVsOiBjb250YWluZXJFbFxuICAgICAgICB9KTtcbiAgICAgICAgc3dpcGVycy5wdXNoKG5ldyBTd2lwZXIobmV3UGFyYW1zKSk7XG4gICAgICB9KTsgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnN0cnVjdG9yLXJldHVyblxuXG4gICAgICByZXR1cm4gc3dpcGVycztcbiAgICB9IC8vIFN3aXBlciBJbnN0YW5jZVxuXG5cbiAgICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICAgIHN3aXBlci5fX3N3aXBlcl9fID0gdHJ1ZTtcbiAgICBzd2lwZXIuc3VwcG9ydCA9IGdldFN1cHBvcnQoKTtcbiAgICBzd2lwZXIuZGV2aWNlID0gZ2V0RGV2aWNlKHtcbiAgICAgIHVzZXJBZ2VudDogcGFyYW1zLnVzZXJBZ2VudFxuICAgIH0pO1xuICAgIHN3aXBlci5icm93c2VyID0gZ2V0QnJvd3NlcigpO1xuICAgIHN3aXBlci5ldmVudHNMaXN0ZW5lcnMgPSB7fTtcbiAgICBzd2lwZXIuZXZlbnRzQW55TGlzdGVuZXJzID0gW107XG4gICAgc3dpcGVyLm1vZHVsZXMgPSBbLi4uc3dpcGVyLl9fbW9kdWxlc19fXTtcblxuICAgIGlmIChwYXJhbXMubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KHBhcmFtcy5tb2R1bGVzKSkge1xuICAgICAgc3dpcGVyLm1vZHVsZXMucHVzaCguLi5wYXJhbXMubW9kdWxlcyk7XG4gICAgfVxuXG4gICAgY29uc3QgYWxsTW9kdWxlc1BhcmFtcyA9IHt9O1xuICAgIHN3aXBlci5tb2R1bGVzLmZvckVhY2gobW9kID0+IHtcbiAgICAgIG1vZCh7XG4gICAgICAgIHN3aXBlcixcbiAgICAgICAgZXh0ZW5kUGFyYW1zOiBtb2R1bGVFeHRlbmRQYXJhbXMocGFyYW1zLCBhbGxNb2R1bGVzUGFyYW1zKSxcbiAgICAgICAgb246IHN3aXBlci5vbi5iaW5kKHN3aXBlciksXG4gICAgICAgIG9uY2U6IHN3aXBlci5vbmNlLmJpbmQoc3dpcGVyKSxcbiAgICAgICAgb2ZmOiBzd2lwZXIub2ZmLmJpbmQoc3dpcGVyKSxcbiAgICAgICAgZW1pdDogc3dpcGVyLmVtaXQuYmluZChzd2lwZXIpXG4gICAgICB9KTtcbiAgICB9KTsgLy8gRXh0ZW5kIGRlZmF1bHRzIHdpdGggbW9kdWxlcyBwYXJhbXNcblxuICAgIGNvbnN0IHN3aXBlclBhcmFtcyA9IGV4dGVuZCh7fSwgZGVmYXVsdHMsIGFsbE1vZHVsZXNQYXJhbXMpOyAvLyBFeHRlbmQgZGVmYXVsdHMgd2l0aCBwYXNzZWQgcGFyYW1zXG5cbiAgICBzd2lwZXIucGFyYW1zID0gZXh0ZW5kKHt9LCBzd2lwZXJQYXJhbXMsIGV4dGVuZGVkRGVmYXVsdHMsIHBhcmFtcyk7XG4gICAgc3dpcGVyLm9yaWdpbmFsUGFyYW1zID0gZXh0ZW5kKHt9LCBzd2lwZXIucGFyYW1zKTtcbiAgICBzd2lwZXIucGFzc2VkUGFyYW1zID0gZXh0ZW5kKHt9LCBwYXJhbXMpOyAvLyBhZGQgZXZlbnQgbGlzdGVuZXJzXG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcyAmJiBzd2lwZXIucGFyYW1zLm9uKSB7XG4gICAgICBPYmplY3Qua2V5cyhzd2lwZXIucGFyYW1zLm9uKS5mb3JFYWNoKGV2ZW50TmFtZSA9PiB7XG4gICAgICAgIHN3aXBlci5vbihldmVudE5hbWUsIHN3aXBlci5wYXJhbXMub25bZXZlbnROYW1lXSk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcyAmJiBzd2lwZXIucGFyYW1zLm9uQW55KSB7XG4gICAgICBzd2lwZXIub25Bbnkoc3dpcGVyLnBhcmFtcy5vbkFueSk7XG4gICAgfSAvLyBTYXZlIERvbSBsaWJcblxuXG4gICAgc3dpcGVyLiQgPSAkOyAvLyBFeHRlbmQgU3dpcGVyXG5cbiAgICBPYmplY3QuYXNzaWduKHN3aXBlciwge1xuICAgICAgZW5hYmxlZDogc3dpcGVyLnBhcmFtcy5lbmFibGVkLFxuICAgICAgZWwsXG4gICAgICAvLyBDbGFzc2VzXG4gICAgICBjbGFzc05hbWVzOiBbXSxcbiAgICAgIC8vIFNsaWRlc1xuICAgICAgc2xpZGVzOiAkKCksXG4gICAgICBzbGlkZXNHcmlkOiBbXSxcbiAgICAgIHNuYXBHcmlkOiBbXSxcbiAgICAgIHNsaWRlc1NpemVzR3JpZDogW10sXG5cbiAgICAgIC8vIGlzRGlyZWN0aW9uXG4gICAgICBpc0hvcml6b250YWwoKSB7XG4gICAgICAgIHJldHVybiBzd2lwZXIucGFyYW1zLmRpcmVjdGlvbiA9PT0gJ2hvcml6b250YWwnO1xuICAgICAgfSxcblxuICAgICAgaXNWZXJ0aWNhbCgpIHtcbiAgICAgICAgcmV0dXJuIHN3aXBlci5wYXJhbXMuZGlyZWN0aW9uID09PSAndmVydGljYWwnO1xuICAgICAgfSxcblxuICAgICAgLy8gSW5kZXhlc1xuICAgICAgYWN0aXZlSW5kZXg6IDAsXG4gICAgICByZWFsSW5kZXg6IDAsXG4gICAgICAvL1xuICAgICAgaXNCZWdpbm5pbmc6IHRydWUsXG4gICAgICBpc0VuZDogZmFsc2UsXG4gICAgICAvLyBQcm9wc1xuICAgICAgdHJhbnNsYXRlOiAwLFxuICAgICAgcHJldmlvdXNUcmFuc2xhdGU6IDAsXG4gICAgICBwcm9ncmVzczogMCxcbiAgICAgIHZlbG9jaXR5OiAwLFxuICAgICAgYW5pbWF0aW5nOiBmYWxzZSxcbiAgICAgIC8vIExvY2tzXG4gICAgICBhbGxvd1NsaWRlTmV4dDogc3dpcGVyLnBhcmFtcy5hbGxvd1NsaWRlTmV4dCxcbiAgICAgIGFsbG93U2xpZGVQcmV2OiBzd2lwZXIucGFyYW1zLmFsbG93U2xpZGVQcmV2LFxuICAgICAgLy8gVG91Y2ggRXZlbnRzXG4gICAgICB0b3VjaEV2ZW50czogZnVuY3Rpb24gdG91Y2hFdmVudHMoKSB7XG4gICAgICAgIGNvbnN0IHRvdWNoID0gWyd0b3VjaHN0YXJ0JywgJ3RvdWNobW92ZScsICd0b3VjaGVuZCcsICd0b3VjaGNhbmNlbCddO1xuICAgICAgICBjb25zdCBkZXNrdG9wID0gWydwb2ludGVyZG93bicsICdwb2ludGVybW92ZScsICdwb2ludGVydXAnXTtcbiAgICAgICAgc3dpcGVyLnRvdWNoRXZlbnRzVG91Y2ggPSB7XG4gICAgICAgICAgc3RhcnQ6IHRvdWNoWzBdLFxuICAgICAgICAgIG1vdmU6IHRvdWNoWzFdLFxuICAgICAgICAgIGVuZDogdG91Y2hbMl0sXG4gICAgICAgICAgY2FuY2VsOiB0b3VjaFszXVxuICAgICAgICB9O1xuICAgICAgICBzd2lwZXIudG91Y2hFdmVudHNEZXNrdG9wID0ge1xuICAgICAgICAgIHN0YXJ0OiBkZXNrdG9wWzBdLFxuICAgICAgICAgIG1vdmU6IGRlc2t0b3BbMV0sXG4gICAgICAgICAgZW5kOiBkZXNrdG9wWzJdXG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiBzd2lwZXIuc3VwcG9ydC50b3VjaCB8fCAhc3dpcGVyLnBhcmFtcy5zaW11bGF0ZVRvdWNoID8gc3dpcGVyLnRvdWNoRXZlbnRzVG91Y2ggOiBzd2lwZXIudG91Y2hFdmVudHNEZXNrdG9wO1xuICAgICAgfSgpLFxuICAgICAgdG91Y2hFdmVudHNEYXRhOiB7XG4gICAgICAgIGlzVG91Y2hlZDogdW5kZWZpbmVkLFxuICAgICAgICBpc01vdmVkOiB1bmRlZmluZWQsXG4gICAgICAgIGFsbG93VG91Y2hDYWxsYmFja3M6IHVuZGVmaW5lZCxcbiAgICAgICAgdG91Y2hTdGFydFRpbWU6IHVuZGVmaW5lZCxcbiAgICAgICAgaXNTY3JvbGxpbmc6IHVuZGVmaW5lZCxcbiAgICAgICAgY3VycmVudFRyYW5zbGF0ZTogdW5kZWZpbmVkLFxuICAgICAgICBzdGFydFRyYW5zbGF0ZTogdW5kZWZpbmVkLFxuICAgICAgICBhbGxvd1RocmVzaG9sZE1vdmU6IHVuZGVmaW5lZCxcbiAgICAgICAgLy8gRm9ybSBlbGVtZW50cyB0byBtYXRjaFxuICAgICAgICBmb2N1c2FibGVFbGVtZW50czogc3dpcGVyLnBhcmFtcy5mb2N1c2FibGVFbGVtZW50cyxcbiAgICAgICAgLy8gTGFzdCBjbGljayB0aW1lXG4gICAgICAgIGxhc3RDbGlja1RpbWU6IG5vdygpLFxuICAgICAgICBjbGlja1RpbWVvdXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgLy8gVmVsb2NpdGllc1xuICAgICAgICB2ZWxvY2l0aWVzOiBbXSxcbiAgICAgICAgYWxsb3dNb21lbnR1bUJvdW5jZTogdW5kZWZpbmVkLFxuICAgICAgICBpc1RvdWNoRXZlbnQ6IHVuZGVmaW5lZCxcbiAgICAgICAgc3RhcnRNb3Zpbmc6IHVuZGVmaW5lZFxuICAgICAgfSxcbiAgICAgIC8vIENsaWNrc1xuICAgICAgYWxsb3dDbGljazogdHJ1ZSxcbiAgICAgIC8vIFRvdWNoZXNcbiAgICAgIGFsbG93VG91Y2hNb3ZlOiBzd2lwZXIucGFyYW1zLmFsbG93VG91Y2hNb3ZlLFxuICAgICAgdG91Y2hlczoge1xuICAgICAgICBzdGFydFg6IDAsXG4gICAgICAgIHN0YXJ0WTogMCxcbiAgICAgICAgY3VycmVudFg6IDAsXG4gICAgICAgIGN1cnJlbnRZOiAwLFxuICAgICAgICBkaWZmOiAwXG4gICAgICB9LFxuICAgICAgLy8gSW1hZ2VzXG4gICAgICBpbWFnZXNUb0xvYWQ6IFtdLFxuICAgICAgaW1hZ2VzTG9hZGVkOiAwXG4gICAgfSk7XG4gICAgc3dpcGVyLmVtaXQoJ19zd2lwZXInKTsgLy8gSW5pdFxuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMuaW5pdCkge1xuICAgICAgc3dpcGVyLmluaXQoKTtcbiAgICB9IC8vIFJldHVybiBhcHAgaW5zdGFuY2VcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc3RydWN0b3ItcmV0dXJuXG5cblxuICAgIHJldHVybiBzd2lwZXI7XG4gIH1cblxuICBlbmFibGUoKSB7XG4gICAgY29uc3Qgc3dpcGVyID0gdGhpcztcbiAgICBpZiAoc3dpcGVyLmVuYWJsZWQpIHJldHVybjtcbiAgICBzd2lwZXIuZW5hYmxlZCA9IHRydWU7XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5ncmFiQ3Vyc29yKSB7XG4gICAgICBzd2lwZXIuc2V0R3JhYkN1cnNvcigpO1xuICAgIH1cblxuICAgIHN3aXBlci5lbWl0KCdlbmFibGUnKTtcbiAgfVxuXG4gIGRpc2FibGUoKSB7XG4gICAgY29uc3Qgc3dpcGVyID0gdGhpcztcbiAgICBpZiAoIXN3aXBlci5lbmFibGVkKSByZXR1cm47XG4gICAgc3dpcGVyLmVuYWJsZWQgPSBmYWxzZTtcblxuICAgIGlmIChzd2lwZXIucGFyYW1zLmdyYWJDdXJzb3IpIHtcbiAgICAgIHN3aXBlci51bnNldEdyYWJDdXJzb3IoKTtcbiAgICB9XG5cbiAgICBzd2lwZXIuZW1pdCgnZGlzYWJsZScpO1xuICB9XG5cbiAgc2V0UHJvZ3Jlc3MocHJvZ3Jlc3MsIHNwZWVkKSB7XG4gICAgY29uc3Qgc3dpcGVyID0gdGhpcztcbiAgICBwcm9ncmVzcyA9IE1hdGgubWluKE1hdGgubWF4KHByb2dyZXNzLCAwKSwgMSk7XG4gICAgY29uc3QgbWluID0gc3dpcGVyLm1pblRyYW5zbGF0ZSgpO1xuICAgIGNvbnN0IG1heCA9IHN3aXBlci5tYXhUcmFuc2xhdGUoKTtcbiAgICBjb25zdCBjdXJyZW50ID0gKG1heCAtIG1pbikgKiBwcm9ncmVzcyArIG1pbjtcbiAgICBzd2lwZXIudHJhbnNsYXRlVG8oY3VycmVudCwgdHlwZW9mIHNwZWVkID09PSAndW5kZWZpbmVkJyA/IDAgOiBzcGVlZCk7XG4gICAgc3dpcGVyLnVwZGF0ZUFjdGl2ZUluZGV4KCk7XG4gICAgc3dpcGVyLnVwZGF0ZVNsaWRlc0NsYXNzZXMoKTtcbiAgfVxuXG4gIGVtaXRDb250YWluZXJDbGFzc2VzKCkge1xuICAgIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gICAgaWYgKCFzd2lwZXIucGFyYW1zLl9lbWl0Q2xhc3NlcyB8fCAhc3dpcGVyLmVsKSByZXR1cm47XG4gICAgY29uc3QgY2xzID0gc3dpcGVyLmVsLmNsYXNzTmFtZS5zcGxpdCgnICcpLmZpbHRlcihjbGFzc05hbWUgPT4ge1xuICAgICAgcmV0dXJuIGNsYXNzTmFtZS5pbmRleE9mKCdzd2lwZXInKSA9PT0gMCB8fCBjbGFzc05hbWUuaW5kZXhPZihzd2lwZXIucGFyYW1zLmNvbnRhaW5lck1vZGlmaWVyQ2xhc3MpID09PSAwO1xuICAgIH0pO1xuICAgIHN3aXBlci5lbWl0KCdfY29udGFpbmVyQ2xhc3NlcycsIGNscy5qb2luKCcgJykpO1xuICB9XG5cbiAgZ2V0U2xpZGVDbGFzc2VzKHNsaWRlRWwpIHtcbiAgICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICAgIGlmIChzd2lwZXIuZGVzdHJveWVkKSByZXR1cm4gJyc7XG4gICAgcmV0dXJuIHNsaWRlRWwuY2xhc3NOYW1lLnNwbGl0KCcgJykuZmlsdGVyKGNsYXNzTmFtZSA9PiB7XG4gICAgICByZXR1cm4gY2xhc3NOYW1lLmluZGV4T2YoJ3N3aXBlci1zbGlkZScpID09PSAwIHx8IGNsYXNzTmFtZS5pbmRleE9mKHN3aXBlci5wYXJhbXMuc2xpZGVDbGFzcykgPT09IDA7XG4gICAgfSkuam9pbignICcpO1xuICB9XG5cbiAgZW1pdFNsaWRlc0NsYXNzZXMoKSB7XG4gICAgY29uc3Qgc3dpcGVyID0gdGhpcztcbiAgICBpZiAoIXN3aXBlci5wYXJhbXMuX2VtaXRDbGFzc2VzIHx8ICFzd2lwZXIuZWwpIHJldHVybjtcbiAgICBjb25zdCB1cGRhdGVzID0gW107XG4gICAgc3dpcGVyLnNsaWRlcy5lYWNoKHNsaWRlRWwgPT4ge1xuICAgICAgY29uc3QgY2xhc3NOYW1lcyA9IHN3aXBlci5nZXRTbGlkZUNsYXNzZXMoc2xpZGVFbCk7XG4gICAgICB1cGRhdGVzLnB1c2goe1xuICAgICAgICBzbGlkZUVsLFxuICAgICAgICBjbGFzc05hbWVzXG4gICAgICB9KTtcbiAgICAgIHN3aXBlci5lbWl0KCdfc2xpZGVDbGFzcycsIHNsaWRlRWwsIGNsYXNzTmFtZXMpO1xuICAgIH0pO1xuICAgIHN3aXBlci5lbWl0KCdfc2xpZGVDbGFzc2VzJywgdXBkYXRlcyk7XG4gIH1cblxuICBzbGlkZXNQZXJWaWV3RHluYW1pYyh2aWV3ID0gJ2N1cnJlbnQnLCBleGFjdCA9IGZhbHNlKSB7XG4gICAgY29uc3Qgc3dpcGVyID0gdGhpcztcbiAgICBjb25zdCB7XG4gICAgICBwYXJhbXMsXG4gICAgICBzbGlkZXMsXG4gICAgICBzbGlkZXNHcmlkLFxuICAgICAgc2xpZGVzU2l6ZXNHcmlkLFxuICAgICAgc2l6ZTogc3dpcGVyU2l6ZSxcbiAgICAgIGFjdGl2ZUluZGV4XG4gICAgfSA9IHN3aXBlcjtcbiAgICBsZXQgc3B2ID0gMTtcblxuICAgIGlmIChwYXJhbXMuY2VudGVyZWRTbGlkZXMpIHtcbiAgICAgIGxldCBzbGlkZVNpemUgPSBzbGlkZXNbYWN0aXZlSW5kZXhdLnN3aXBlclNsaWRlU2l6ZTtcbiAgICAgIGxldCBicmVha0xvb3A7XG5cbiAgICAgIGZvciAobGV0IGkgPSBhY3RpdmVJbmRleCArIDE7IGkgPCBzbGlkZXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgaWYgKHNsaWRlc1tpXSAmJiAhYnJlYWtMb29wKSB7XG4gICAgICAgICAgc2xpZGVTaXplICs9IHNsaWRlc1tpXS5zd2lwZXJTbGlkZVNpemU7XG4gICAgICAgICAgc3B2ICs9IDE7XG4gICAgICAgICAgaWYgKHNsaWRlU2l6ZSA+IHN3aXBlclNpemUpIGJyZWFrTG9vcCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgZm9yIChsZXQgaSA9IGFjdGl2ZUluZGV4IC0gMTsgaSA+PSAwOyBpIC09IDEpIHtcbiAgICAgICAgaWYgKHNsaWRlc1tpXSAmJiAhYnJlYWtMb29wKSB7XG4gICAgICAgICAgc2xpZGVTaXplICs9IHNsaWRlc1tpXS5zd2lwZXJTbGlkZVNpemU7XG4gICAgICAgICAgc3B2ICs9IDE7XG4gICAgICAgICAgaWYgKHNsaWRlU2l6ZSA+IHN3aXBlclNpemUpIGJyZWFrTG9vcCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG4gICAgICBpZiAodmlldyA9PT0gJ2N1cnJlbnQnKSB7XG4gICAgICAgIGZvciAobGV0IGkgPSBhY3RpdmVJbmRleCArIDE7IGkgPCBzbGlkZXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgICBjb25zdCBzbGlkZUluVmlldyA9IGV4YWN0ID8gc2xpZGVzR3JpZFtpXSArIHNsaWRlc1NpemVzR3JpZFtpXSAtIHNsaWRlc0dyaWRbYWN0aXZlSW5kZXhdIDwgc3dpcGVyU2l6ZSA6IHNsaWRlc0dyaWRbaV0gLSBzbGlkZXNHcmlkW2FjdGl2ZUluZGV4XSA8IHN3aXBlclNpemU7XG5cbiAgICAgICAgICBpZiAoc2xpZGVJblZpZXcpIHtcbiAgICAgICAgICAgIHNwdiArPSAxO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gcHJldmlvdXNcbiAgICAgICAgZm9yIChsZXQgaSA9IGFjdGl2ZUluZGV4IC0gMTsgaSA+PSAwOyBpIC09IDEpIHtcbiAgICAgICAgICBjb25zdCBzbGlkZUluVmlldyA9IHNsaWRlc0dyaWRbYWN0aXZlSW5kZXhdIC0gc2xpZGVzR3JpZFtpXSA8IHN3aXBlclNpemU7XG5cbiAgICAgICAgICBpZiAoc2xpZGVJblZpZXcpIHtcbiAgICAgICAgICAgIHNwdiArPSAxO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBzcHY7XG4gIH1cblxuICB1cGRhdGUoKSB7XG4gICAgY29uc3Qgc3dpcGVyID0gdGhpcztcbiAgICBpZiAoIXN3aXBlciB8fCBzd2lwZXIuZGVzdHJveWVkKSByZXR1cm47XG4gICAgY29uc3Qge1xuICAgICAgc25hcEdyaWQsXG4gICAgICBwYXJhbXNcbiAgICB9ID0gc3dpcGVyOyAvLyBCcmVha3BvaW50c1xuXG4gICAgaWYgKHBhcmFtcy5icmVha3BvaW50cykge1xuICAgICAgc3dpcGVyLnNldEJyZWFrcG9pbnQoKTtcbiAgICB9XG5cbiAgICBzd2lwZXIudXBkYXRlU2l6ZSgpO1xuICAgIHN3aXBlci51cGRhdGVTbGlkZXMoKTtcbiAgICBzd2lwZXIudXBkYXRlUHJvZ3Jlc3MoKTtcbiAgICBzd2lwZXIudXBkYXRlU2xpZGVzQ2xhc3NlcygpO1xuXG4gICAgZnVuY3Rpb24gc2V0VHJhbnNsYXRlKCkge1xuICAgICAgY29uc3QgdHJhbnNsYXRlVmFsdWUgPSBzd2lwZXIucnRsVHJhbnNsYXRlID8gc3dpcGVyLnRyYW5zbGF0ZSAqIC0xIDogc3dpcGVyLnRyYW5zbGF0ZTtcbiAgICAgIGNvbnN0IG5ld1RyYW5zbGF0ZSA9IE1hdGgubWluKE1hdGgubWF4KHRyYW5zbGF0ZVZhbHVlLCBzd2lwZXIubWF4VHJhbnNsYXRlKCkpLCBzd2lwZXIubWluVHJhbnNsYXRlKCkpO1xuICAgICAgc3dpcGVyLnNldFRyYW5zbGF0ZShuZXdUcmFuc2xhdGUpO1xuICAgICAgc3dpcGVyLnVwZGF0ZUFjdGl2ZUluZGV4KCk7XG4gICAgICBzd2lwZXIudXBkYXRlU2xpZGVzQ2xhc3NlcygpO1xuICAgIH1cblxuICAgIGxldCB0cmFuc2xhdGVkO1xuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMuZnJlZU1vZGUgJiYgc3dpcGVyLnBhcmFtcy5mcmVlTW9kZS5lbmFibGVkKSB7XG4gICAgICBzZXRUcmFuc2xhdGUoKTtcblxuICAgICAgaWYgKHN3aXBlci5wYXJhbXMuYXV0b0hlaWdodCkge1xuICAgICAgICBzd2lwZXIudXBkYXRlQXV0b0hlaWdodCgpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoKHN3aXBlci5wYXJhbXMuc2xpZGVzUGVyVmlldyA9PT0gJ2F1dG8nIHx8IHN3aXBlci5wYXJhbXMuc2xpZGVzUGVyVmlldyA+IDEpICYmIHN3aXBlci5pc0VuZCAmJiAhc3dpcGVyLnBhcmFtcy5jZW50ZXJlZFNsaWRlcykge1xuICAgICAgICB0cmFuc2xhdGVkID0gc3dpcGVyLnNsaWRlVG8oc3dpcGVyLnNsaWRlcy5sZW5ndGggLSAxLCAwLCBmYWxzZSwgdHJ1ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0cmFuc2xhdGVkID0gc3dpcGVyLnNsaWRlVG8oc3dpcGVyLmFjdGl2ZUluZGV4LCAwLCBmYWxzZSwgdHJ1ZSk7XG4gICAgICB9XG5cbiAgICAgIGlmICghdHJhbnNsYXRlZCkge1xuICAgICAgICBzZXRUcmFuc2xhdGUoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAocGFyYW1zLndhdGNoT3ZlcmZsb3cgJiYgc25hcEdyaWQgIT09IHN3aXBlci5zbmFwR3JpZCkge1xuICAgICAgc3dpcGVyLmNoZWNrT3ZlcmZsb3coKTtcbiAgICB9XG5cbiAgICBzd2lwZXIuZW1pdCgndXBkYXRlJyk7XG4gIH1cblxuICBjaGFuZ2VEaXJlY3Rpb24obmV3RGlyZWN0aW9uLCBuZWVkVXBkYXRlID0gdHJ1ZSkge1xuICAgIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gICAgY29uc3QgY3VycmVudERpcmVjdGlvbiA9IHN3aXBlci5wYXJhbXMuZGlyZWN0aW9uO1xuXG4gICAgaWYgKCFuZXdEaXJlY3Rpb24pIHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuICAgICAgbmV3RGlyZWN0aW9uID0gY3VycmVudERpcmVjdGlvbiA9PT0gJ2hvcml6b250YWwnID8gJ3ZlcnRpY2FsJyA6ICdob3Jpem9udGFsJztcbiAgICB9XG5cbiAgICBpZiAobmV3RGlyZWN0aW9uID09PSBjdXJyZW50RGlyZWN0aW9uIHx8IG5ld0RpcmVjdGlvbiAhPT0gJ2hvcml6b250YWwnICYmIG5ld0RpcmVjdGlvbiAhPT0gJ3ZlcnRpY2FsJykge1xuICAgICAgcmV0dXJuIHN3aXBlcjtcbiAgICB9XG5cbiAgICBzd2lwZXIuJGVsLnJlbW92ZUNsYXNzKGAke3N3aXBlci5wYXJhbXMuY29udGFpbmVyTW9kaWZpZXJDbGFzc30ke2N1cnJlbnREaXJlY3Rpb259YCkuYWRkQ2xhc3MoYCR7c3dpcGVyLnBhcmFtcy5jb250YWluZXJNb2RpZmllckNsYXNzfSR7bmV3RGlyZWN0aW9ufWApO1xuICAgIHN3aXBlci5lbWl0Q29udGFpbmVyQ2xhc3NlcygpO1xuICAgIHN3aXBlci5wYXJhbXMuZGlyZWN0aW9uID0gbmV3RGlyZWN0aW9uO1xuICAgIHN3aXBlci5zbGlkZXMuZWFjaChzbGlkZUVsID0+IHtcbiAgICAgIGlmIChuZXdEaXJlY3Rpb24gPT09ICd2ZXJ0aWNhbCcpIHtcbiAgICAgICAgc2xpZGVFbC5zdHlsZS53aWR0aCA9ICcnO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc2xpZGVFbC5zdHlsZS5oZWlnaHQgPSAnJztcbiAgICAgIH1cbiAgICB9KTtcbiAgICBzd2lwZXIuZW1pdCgnY2hhbmdlRGlyZWN0aW9uJyk7XG4gICAgaWYgKG5lZWRVcGRhdGUpIHN3aXBlci51cGRhdGUoKTtcbiAgICByZXR1cm4gc3dpcGVyO1xuICB9XG5cbiAgY2hhbmdlTGFuZ3VhZ2VEaXJlY3Rpb24oZGlyZWN0aW9uKSB7XG4gICAgY29uc3Qgc3dpcGVyID0gdGhpcztcbiAgICBpZiAoc3dpcGVyLnJ0bCAmJiBkaXJlY3Rpb24gPT09ICdydGwnIHx8ICFzd2lwZXIucnRsICYmIGRpcmVjdGlvbiA9PT0gJ2x0cicpIHJldHVybjtcbiAgICBzd2lwZXIucnRsID0gZGlyZWN0aW9uID09PSAncnRsJztcbiAgICBzd2lwZXIucnRsVHJhbnNsYXRlID0gc3dpcGVyLnBhcmFtcy5kaXJlY3Rpb24gPT09ICdob3Jpem9udGFsJyAmJiBzd2lwZXIucnRsO1xuXG4gICAgaWYgKHN3aXBlci5ydGwpIHtcbiAgICAgIHN3aXBlci4kZWwuYWRkQ2xhc3MoYCR7c3dpcGVyLnBhcmFtcy5jb250YWluZXJNb2RpZmllckNsYXNzfXJ0bGApO1xuICAgICAgc3dpcGVyLmVsLmRpciA9ICdydGwnO1xuICAgIH0gZWxzZSB7XG4gICAgICBzd2lwZXIuJGVsLnJlbW92ZUNsYXNzKGAke3N3aXBlci5wYXJhbXMuY29udGFpbmVyTW9kaWZpZXJDbGFzc31ydGxgKTtcbiAgICAgIHN3aXBlci5lbC5kaXIgPSAnbHRyJztcbiAgICB9XG5cbiAgICBzd2lwZXIudXBkYXRlKCk7XG4gIH1cblxuICBtb3VudChlbCkge1xuICAgIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gICAgaWYgKHN3aXBlci5tb3VudGVkKSByZXR1cm4gdHJ1ZTsgLy8gRmluZCBlbFxuXG4gICAgY29uc3QgJGVsID0gJChlbCB8fCBzd2lwZXIucGFyYW1zLmVsKTtcbiAgICBlbCA9ICRlbFswXTtcblxuICAgIGlmICghZWwpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBlbC5zd2lwZXIgPSBzd2lwZXI7XG5cbiAgICBjb25zdCBnZXRXcmFwcGVyU2VsZWN0b3IgPSAoKSA9PiB7XG4gICAgICByZXR1cm4gYC4keyhzd2lwZXIucGFyYW1zLndyYXBwZXJDbGFzcyB8fCAnJykudHJpbSgpLnNwbGl0KCcgJykuam9pbignLicpfWA7XG4gICAgfTtcblxuICAgIGNvbnN0IGdldFdyYXBwZXIgPSAoKSA9PiB7XG4gICAgICBpZiAoZWwgJiYgZWwuc2hhZG93Um9vdCAmJiBlbC5zaGFkb3dSb290LnF1ZXJ5U2VsZWN0b3IpIHtcbiAgICAgICAgY29uc3QgcmVzID0gJChlbC5zaGFkb3dSb290LnF1ZXJ5U2VsZWN0b3IoZ2V0V3JhcHBlclNlbGVjdG9yKCkpKTsgLy8gQ2hpbGRyZW4gbmVlZHMgdG8gcmV0dXJuIHNsb3QgaXRlbXNcblxuICAgICAgICByZXMuY2hpbGRyZW4gPSBvcHRpb25zID0+ICRlbC5jaGlsZHJlbihvcHRpb25zKTtcblxuICAgICAgICByZXR1cm4gcmVzO1xuICAgICAgfVxuXG4gICAgICBpZiAoISRlbC5jaGlsZHJlbikge1xuICAgICAgICByZXR1cm4gJCgkZWwpLmNoaWxkcmVuKGdldFdyYXBwZXJTZWxlY3RvcigpKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuICRlbC5jaGlsZHJlbihnZXRXcmFwcGVyU2VsZWN0b3IoKSk7XG4gICAgfTsgLy8gRmluZCBXcmFwcGVyXG5cblxuICAgIGxldCAkd3JhcHBlckVsID0gZ2V0V3JhcHBlcigpO1xuXG4gICAgaWYgKCR3cmFwcGVyRWwubGVuZ3RoID09PSAwICYmIHN3aXBlci5wYXJhbXMuY3JlYXRlRWxlbWVudHMpIHtcbiAgICAgIGNvbnN0IGRvY3VtZW50ID0gZ2V0RG9jdW1lbnQoKTtcbiAgICAgIGNvbnN0IHdyYXBwZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICAgICR3cmFwcGVyRWwgPSAkKHdyYXBwZXIpO1xuICAgICAgd3JhcHBlci5jbGFzc05hbWUgPSBzd2lwZXIucGFyYW1zLndyYXBwZXJDbGFzcztcbiAgICAgICRlbC5hcHBlbmQod3JhcHBlcik7XG4gICAgICAkZWwuY2hpbGRyZW4oYC4ke3N3aXBlci5wYXJhbXMuc2xpZGVDbGFzc31gKS5lYWNoKHNsaWRlRWwgPT4ge1xuICAgICAgICAkd3JhcHBlckVsLmFwcGVuZChzbGlkZUVsKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIE9iamVjdC5hc3NpZ24oc3dpcGVyLCB7XG4gICAgICAkZWwsXG4gICAgICBlbCxcbiAgICAgICR3cmFwcGVyRWwsXG4gICAgICB3cmFwcGVyRWw6ICR3cmFwcGVyRWxbMF0sXG4gICAgICBtb3VudGVkOiB0cnVlLFxuICAgICAgLy8gUlRMXG4gICAgICBydGw6IGVsLmRpci50b0xvd2VyQ2FzZSgpID09PSAncnRsJyB8fCAkZWwuY3NzKCdkaXJlY3Rpb24nKSA9PT0gJ3J0bCcsXG4gICAgICBydGxUcmFuc2xhdGU6IHN3aXBlci5wYXJhbXMuZGlyZWN0aW9uID09PSAnaG9yaXpvbnRhbCcgJiYgKGVsLmRpci50b0xvd2VyQ2FzZSgpID09PSAncnRsJyB8fCAkZWwuY3NzKCdkaXJlY3Rpb24nKSA9PT0gJ3J0bCcpLFxuICAgICAgd3JvbmdSVEw6ICR3cmFwcGVyRWwuY3NzKCdkaXNwbGF5JykgPT09ICctd2Via2l0LWJveCdcbiAgICB9KTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGluaXQoZWwpIHtcbiAgICBjb25zdCBzd2lwZXIgPSB0aGlzO1xuICAgIGlmIChzd2lwZXIuaW5pdGlhbGl6ZWQpIHJldHVybiBzd2lwZXI7XG4gICAgY29uc3QgbW91bnRlZCA9IHN3aXBlci5tb3VudChlbCk7XG4gICAgaWYgKG1vdW50ZWQgPT09IGZhbHNlKSByZXR1cm4gc3dpcGVyO1xuICAgIHN3aXBlci5lbWl0KCdiZWZvcmVJbml0Jyk7IC8vIFNldCBicmVha3BvaW50XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5icmVha3BvaW50cykge1xuICAgICAgc3dpcGVyLnNldEJyZWFrcG9pbnQoKTtcbiAgICB9IC8vIEFkZCBDbGFzc2VzXG5cblxuICAgIHN3aXBlci5hZGRDbGFzc2VzKCk7IC8vIENyZWF0ZSBsb29wXG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5sb29wKSB7XG4gICAgICBzd2lwZXIubG9vcENyZWF0ZSgpO1xuICAgIH0gLy8gVXBkYXRlIHNpemVcblxuXG4gICAgc3dpcGVyLnVwZGF0ZVNpemUoKTsgLy8gVXBkYXRlIHNsaWRlc1xuXG4gICAgc3dpcGVyLnVwZGF0ZVNsaWRlcygpO1xuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMud2F0Y2hPdmVyZmxvdykge1xuICAgICAgc3dpcGVyLmNoZWNrT3ZlcmZsb3coKTtcbiAgICB9IC8vIFNldCBHcmFiIEN1cnNvclxuXG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5ncmFiQ3Vyc29yICYmIHN3aXBlci5lbmFibGVkKSB7XG4gICAgICBzd2lwZXIuc2V0R3JhYkN1cnNvcigpO1xuICAgIH1cblxuICAgIGlmIChzd2lwZXIucGFyYW1zLnByZWxvYWRJbWFnZXMpIHtcbiAgICAgIHN3aXBlci5wcmVsb2FkSW1hZ2VzKCk7XG4gICAgfSAvLyBTbGlkZSBUbyBJbml0aWFsIFNsaWRlXG5cblxuICAgIGlmIChzd2lwZXIucGFyYW1zLmxvb3ApIHtcbiAgICAgIHN3aXBlci5zbGlkZVRvKHN3aXBlci5wYXJhbXMuaW5pdGlhbFNsaWRlICsgc3dpcGVyLmxvb3BlZFNsaWRlcywgMCwgc3dpcGVyLnBhcmFtcy5ydW5DYWxsYmFja3NPbkluaXQsIGZhbHNlLCB0cnVlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgc3dpcGVyLnNsaWRlVG8oc3dpcGVyLnBhcmFtcy5pbml0aWFsU2xpZGUsIDAsIHN3aXBlci5wYXJhbXMucnVuQ2FsbGJhY2tzT25Jbml0LCBmYWxzZSwgdHJ1ZSk7XG4gICAgfSAvLyBBdHRhY2ggZXZlbnRzXG5cblxuICAgIHN3aXBlci5hdHRhY2hFdmVudHMoKTsgLy8gSW5pdCBGbGFnXG5cbiAgICBzd2lwZXIuaW5pdGlhbGl6ZWQgPSB0cnVlOyAvLyBFbWl0XG5cbiAgICBzd2lwZXIuZW1pdCgnaW5pdCcpO1xuICAgIHN3aXBlci5lbWl0KCdhZnRlckluaXQnKTtcbiAgICByZXR1cm4gc3dpcGVyO1xuICB9XG5cbiAgZGVzdHJveShkZWxldGVJbnN0YW5jZSA9IHRydWUsIGNsZWFuU3R5bGVzID0gdHJ1ZSkge1xuICAgIGNvbnN0IHN3aXBlciA9IHRoaXM7XG4gICAgY29uc3Qge1xuICAgICAgcGFyYW1zLFxuICAgICAgJGVsLFxuICAgICAgJHdyYXBwZXJFbCxcbiAgICAgIHNsaWRlc1xuICAgIH0gPSBzd2lwZXI7XG5cbiAgICBpZiAodHlwZW9mIHN3aXBlci5wYXJhbXMgPT09ICd1bmRlZmluZWQnIHx8IHN3aXBlci5kZXN0cm95ZWQpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHN3aXBlci5lbWl0KCdiZWZvcmVEZXN0cm95Jyk7IC8vIEluaXQgRmxhZ1xuXG4gICAgc3dpcGVyLmluaXRpYWxpemVkID0gZmFsc2U7IC8vIERldGFjaCBldmVudHNcblxuICAgIHN3aXBlci5kZXRhY2hFdmVudHMoKTsgLy8gRGVzdHJveSBsb29wXG5cbiAgICBpZiAocGFyYW1zLmxvb3ApIHtcbiAgICAgIHN3aXBlci5sb29wRGVzdHJveSgpO1xuICAgIH0gLy8gQ2xlYW51cCBzdHlsZXNcblxuXG4gICAgaWYgKGNsZWFuU3R5bGVzKSB7XG4gICAgICBzd2lwZXIucmVtb3ZlQ2xhc3NlcygpO1xuICAgICAgJGVsLnJlbW92ZUF0dHIoJ3N0eWxlJyk7XG4gICAgICAkd3JhcHBlckVsLnJlbW92ZUF0dHIoJ3N0eWxlJyk7XG5cbiAgICAgIGlmIChzbGlkZXMgJiYgc2xpZGVzLmxlbmd0aCkge1xuICAgICAgICBzbGlkZXMucmVtb3ZlQ2xhc3MoW3BhcmFtcy5zbGlkZVZpc2libGVDbGFzcywgcGFyYW1zLnNsaWRlQWN0aXZlQ2xhc3MsIHBhcmFtcy5zbGlkZU5leHRDbGFzcywgcGFyYW1zLnNsaWRlUHJldkNsYXNzXS5qb2luKCcgJykpLnJlbW92ZUF0dHIoJ3N0eWxlJykucmVtb3ZlQXR0cignZGF0YS1zd2lwZXItc2xpZGUtaW5kZXgnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBzd2lwZXIuZW1pdCgnZGVzdHJveScpOyAvLyBEZXRhY2ggZW1pdHRlciBldmVudHNcblxuICAgIE9iamVjdC5rZXlzKHN3aXBlci5ldmVudHNMaXN0ZW5lcnMpLmZvckVhY2goZXZlbnROYW1lID0+IHtcbiAgICAgIHN3aXBlci5vZmYoZXZlbnROYW1lKTtcbiAgICB9KTtcblxuICAgIGlmIChkZWxldGVJbnN0YW5jZSAhPT0gZmFsc2UpIHtcbiAgICAgIHN3aXBlci4kZWxbMF0uc3dpcGVyID0gbnVsbDtcbiAgICAgIGRlbGV0ZVByb3BzKHN3aXBlcik7XG4gICAgfVxuXG4gICAgc3dpcGVyLmRlc3Ryb3llZCA9IHRydWU7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBzdGF0aWMgZXh0ZW5kRGVmYXVsdHMobmV3RGVmYXVsdHMpIHtcbiAgICBleHRlbmQoZXh0ZW5kZWREZWZhdWx0cywgbmV3RGVmYXVsdHMpO1xuICB9XG5cbiAgc3RhdGljIGdldCBleHRlbmRlZERlZmF1bHRzKCkge1xuICAgIHJldHVybiBleHRlbmRlZERlZmF1bHRzO1xuICB9XG5cbiAgc3RhdGljIGdldCBkZWZhdWx0cygpIHtcbiAgICByZXR1cm4gZGVmYXVsdHM7XG4gIH1cblxuICBzdGF0aWMgaW5zdGFsbE1vZHVsZShtb2QpIHtcbiAgICBpZiAoIVN3aXBlci5wcm90b3R5cGUuX19tb2R1bGVzX18pIFN3aXBlci5wcm90b3R5cGUuX19tb2R1bGVzX18gPSBbXTtcbiAgICBjb25zdCBtb2R1bGVzID0gU3dpcGVyLnByb3RvdHlwZS5fX21vZHVsZXNfXztcblxuICAgIGlmICh0eXBlb2YgbW9kID09PSAnZnVuY3Rpb24nICYmIG1vZHVsZXMuaW5kZXhPZihtb2QpIDwgMCkge1xuICAgICAgbW9kdWxlcy5wdXNoKG1vZCk7XG4gICAgfVxuICB9XG5cbiAgc3RhdGljIHVzZShtb2R1bGUpIHtcbiAgICBpZiAoQXJyYXkuaXNBcnJheShtb2R1bGUpKSB7XG4gICAgICBtb2R1bGUuZm9yRWFjaChtID0+IFN3aXBlci5pbnN0YWxsTW9kdWxlKG0pKTtcbiAgICAgIHJldHVybiBTd2lwZXI7XG4gICAgfVxuXG4gICAgU3dpcGVyLmluc3RhbGxNb2R1bGUobW9kdWxlKTtcbiAgICByZXR1cm4gU3dpcGVyO1xuICB9XG5cbn1cblxuT2JqZWN0LmtleXMocHJvdG90eXBlcykuZm9yRWFjaChwcm90b3R5cGVHcm91cCA9PiB7XG4gIE9iamVjdC5rZXlzKHByb3RvdHlwZXNbcHJvdG90eXBlR3JvdXBdKS5mb3JFYWNoKHByb3RvTWV0aG9kID0+IHtcbiAgICBTd2lwZXIucHJvdG90eXBlW3Byb3RvTWV0aG9kXSA9IHByb3RvdHlwZXNbcHJvdG90eXBlR3JvdXBdW3Byb3RvTWV0aG9kXTtcbiAgfSk7XG59KTtcblN3aXBlci51c2UoW1Jlc2l6ZSwgT2JzZXJ2ZXJdKTtcbmV4cG9ydCBkZWZhdWx0IFN3aXBlcjsiLCJpbXBvcnQgJCBmcm9tICcuLi8uLi9zaGFyZWQvZG9tLmpzJztcbmltcG9ydCB7IHNldENTU1Byb3BlcnR5IH0gZnJvbSAnLi4vLi4vc2hhcmVkL3V0aWxzLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIFZpcnR1YWwoe1xuICBzd2lwZXIsXG4gIGV4dGVuZFBhcmFtcyxcbiAgb24sXG4gIGVtaXRcbn0pIHtcbiAgZXh0ZW5kUGFyYW1zKHtcbiAgICB2aXJ0dWFsOiB7XG4gICAgICBlbmFibGVkOiBmYWxzZSxcbiAgICAgIHNsaWRlczogW10sXG4gICAgICBjYWNoZTogdHJ1ZSxcbiAgICAgIHJlbmRlclNsaWRlOiBudWxsLFxuICAgICAgcmVuZGVyRXh0ZXJuYWw6IG51bGwsXG4gICAgICByZW5kZXJFeHRlcm5hbFVwZGF0ZTogdHJ1ZSxcbiAgICAgIGFkZFNsaWRlc0JlZm9yZTogMCxcbiAgICAgIGFkZFNsaWRlc0FmdGVyOiAwXG4gICAgfVxuICB9KTtcbiAgbGV0IGNzc01vZGVUaW1lb3V0O1xuICBzd2lwZXIudmlydHVhbCA9IHtcbiAgICBjYWNoZToge30sXG4gICAgZnJvbTogdW5kZWZpbmVkLFxuICAgIHRvOiB1bmRlZmluZWQsXG4gICAgc2xpZGVzOiBbXSxcbiAgICBvZmZzZXQ6IDAsXG4gICAgc2xpZGVzR3JpZDogW11cbiAgfTtcblxuICBmdW5jdGlvbiByZW5kZXJTbGlkZShzbGlkZSwgaW5kZXgpIHtcbiAgICBjb25zdCBwYXJhbXMgPSBzd2lwZXIucGFyYW1zLnZpcnR1YWw7XG5cbiAgICBpZiAocGFyYW1zLmNhY2hlICYmIHN3aXBlci52aXJ0dWFsLmNhY2hlW2luZGV4XSkge1xuICAgICAgcmV0dXJuIHN3aXBlci52aXJ0dWFsLmNhY2hlW2luZGV4XTtcbiAgICB9XG5cbiAgICBjb25zdCAkc2xpZGVFbCA9IHBhcmFtcy5yZW5kZXJTbGlkZSA/ICQocGFyYW1zLnJlbmRlclNsaWRlLmNhbGwoc3dpcGVyLCBzbGlkZSwgaW5kZXgpKSA6ICQoYDxkaXYgY2xhc3M9XCIke3N3aXBlci5wYXJhbXMuc2xpZGVDbGFzc31cIiBkYXRhLXN3aXBlci1zbGlkZS1pbmRleD1cIiR7aW5kZXh9XCI+JHtzbGlkZX08L2Rpdj5gKTtcbiAgICBpZiAoISRzbGlkZUVsLmF0dHIoJ2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4JykpICRzbGlkZUVsLmF0dHIoJ2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4JywgaW5kZXgpO1xuICAgIGlmIChwYXJhbXMuY2FjaGUpIHN3aXBlci52aXJ0dWFsLmNhY2hlW2luZGV4XSA9ICRzbGlkZUVsO1xuICAgIHJldHVybiAkc2xpZGVFbDtcbiAgfVxuXG4gIGZ1bmN0aW9uIHVwZGF0ZShmb3JjZSkge1xuICAgIGNvbnN0IHtcbiAgICAgIHNsaWRlc1BlclZpZXcsXG4gICAgICBzbGlkZXNQZXJHcm91cCxcbiAgICAgIGNlbnRlcmVkU2xpZGVzXG4gICAgfSA9IHN3aXBlci5wYXJhbXM7XG4gICAgY29uc3Qge1xuICAgICAgYWRkU2xpZGVzQmVmb3JlLFxuICAgICAgYWRkU2xpZGVzQWZ0ZXJcbiAgICB9ID0gc3dpcGVyLnBhcmFtcy52aXJ0dWFsO1xuICAgIGNvbnN0IHtcbiAgICAgIGZyb206IHByZXZpb3VzRnJvbSxcbiAgICAgIHRvOiBwcmV2aW91c1RvLFxuICAgICAgc2xpZGVzLFxuICAgICAgc2xpZGVzR3JpZDogcHJldmlvdXNTbGlkZXNHcmlkLFxuICAgICAgb2Zmc2V0OiBwcmV2aW91c09mZnNldFxuICAgIH0gPSBzd2lwZXIudmlydHVhbDtcblxuICAgIGlmICghc3dpcGVyLnBhcmFtcy5jc3NNb2RlKSB7XG4gICAgICBzd2lwZXIudXBkYXRlQWN0aXZlSW5kZXgoKTtcbiAgICB9XG5cbiAgICBjb25zdCBhY3RpdmVJbmRleCA9IHN3aXBlci5hY3RpdmVJbmRleCB8fCAwO1xuICAgIGxldCBvZmZzZXRQcm9wO1xuICAgIGlmIChzd2lwZXIucnRsVHJhbnNsYXRlKSBvZmZzZXRQcm9wID0gJ3JpZ2h0JztlbHNlIG9mZnNldFByb3AgPSBzd2lwZXIuaXNIb3Jpem9udGFsKCkgPyAnbGVmdCcgOiAndG9wJztcbiAgICBsZXQgc2xpZGVzQWZ0ZXI7XG4gICAgbGV0IHNsaWRlc0JlZm9yZTtcblxuICAgIGlmIChjZW50ZXJlZFNsaWRlcykge1xuICAgICAgc2xpZGVzQWZ0ZXIgPSBNYXRoLmZsb29yKHNsaWRlc1BlclZpZXcgLyAyKSArIHNsaWRlc1Blckdyb3VwICsgYWRkU2xpZGVzQWZ0ZXI7XG4gICAgICBzbGlkZXNCZWZvcmUgPSBNYXRoLmZsb29yKHNsaWRlc1BlclZpZXcgLyAyKSArIHNsaWRlc1Blckdyb3VwICsgYWRkU2xpZGVzQmVmb3JlO1xuICAgIH0gZWxzZSB7XG4gICAgICBzbGlkZXNBZnRlciA9IHNsaWRlc1BlclZpZXcgKyAoc2xpZGVzUGVyR3JvdXAgLSAxKSArIGFkZFNsaWRlc0FmdGVyO1xuICAgICAgc2xpZGVzQmVmb3JlID0gc2xpZGVzUGVyR3JvdXAgKyBhZGRTbGlkZXNCZWZvcmU7XG4gICAgfVxuXG4gICAgY29uc3QgZnJvbSA9IE1hdGgubWF4KChhY3RpdmVJbmRleCB8fCAwKSAtIHNsaWRlc0JlZm9yZSwgMCk7XG4gICAgY29uc3QgdG8gPSBNYXRoLm1pbigoYWN0aXZlSW5kZXggfHwgMCkgKyBzbGlkZXNBZnRlciwgc2xpZGVzLmxlbmd0aCAtIDEpO1xuICAgIGNvbnN0IG9mZnNldCA9IChzd2lwZXIuc2xpZGVzR3JpZFtmcm9tXSB8fCAwKSAtIChzd2lwZXIuc2xpZGVzR3JpZFswXSB8fCAwKTtcbiAgICBPYmplY3QuYXNzaWduKHN3aXBlci52aXJ0dWFsLCB7XG4gICAgICBmcm9tLFxuICAgICAgdG8sXG4gICAgICBvZmZzZXQsXG4gICAgICBzbGlkZXNHcmlkOiBzd2lwZXIuc2xpZGVzR3JpZFxuICAgIH0pO1xuXG4gICAgZnVuY3Rpb24gb25SZW5kZXJlZCgpIHtcbiAgICAgIHN3aXBlci51cGRhdGVTbGlkZXMoKTtcbiAgICAgIHN3aXBlci51cGRhdGVQcm9ncmVzcygpO1xuICAgICAgc3dpcGVyLnVwZGF0ZVNsaWRlc0NsYXNzZXMoKTtcblxuICAgICAgaWYgKHN3aXBlci5sYXp5ICYmIHN3aXBlci5wYXJhbXMubGF6eS5lbmFibGVkKSB7XG4gICAgICAgIHN3aXBlci5sYXp5LmxvYWQoKTtcbiAgICAgIH1cblxuICAgICAgZW1pdCgndmlydHVhbFVwZGF0ZScpO1xuICAgIH1cblxuICAgIGlmIChwcmV2aW91c0Zyb20gPT09IGZyb20gJiYgcHJldmlvdXNUbyA9PT0gdG8gJiYgIWZvcmNlKSB7XG4gICAgICBpZiAoc3dpcGVyLnNsaWRlc0dyaWQgIT09IHByZXZpb3VzU2xpZGVzR3JpZCAmJiBvZmZzZXQgIT09IHByZXZpb3VzT2Zmc2V0KSB7XG4gICAgICAgIHN3aXBlci5zbGlkZXMuY3NzKG9mZnNldFByb3AsIGAke29mZnNldH1weGApO1xuICAgICAgfVxuXG4gICAgICBzd2lwZXIudXBkYXRlUHJvZ3Jlc3MoKTtcbiAgICAgIGVtaXQoJ3ZpcnR1YWxVcGRhdGUnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy52aXJ0dWFsLnJlbmRlckV4dGVybmFsKSB7XG4gICAgICBzd2lwZXIucGFyYW1zLnZpcnR1YWwucmVuZGVyRXh0ZXJuYWwuY2FsbChzd2lwZXIsIHtcbiAgICAgICAgb2Zmc2V0LFxuICAgICAgICBmcm9tLFxuICAgICAgICB0byxcbiAgICAgICAgc2xpZGVzOiBmdW5jdGlvbiBnZXRTbGlkZXMoKSB7XG4gICAgICAgICAgY29uc3Qgc2xpZGVzVG9SZW5kZXIgPSBbXTtcblxuICAgICAgICAgIGZvciAobGV0IGkgPSBmcm9tOyBpIDw9IHRvOyBpICs9IDEpIHtcbiAgICAgICAgICAgIHNsaWRlc1RvUmVuZGVyLnB1c2goc2xpZGVzW2ldKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gc2xpZGVzVG9SZW5kZXI7XG4gICAgICAgIH0oKVxuICAgICAgfSk7XG5cbiAgICAgIGlmIChzd2lwZXIucGFyYW1zLnZpcnR1YWwucmVuZGVyRXh0ZXJuYWxVcGRhdGUpIHtcbiAgICAgICAgb25SZW5kZXJlZCgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZW1pdCgndmlydHVhbFVwZGF0ZScpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgcHJlcGVuZEluZGV4ZXMgPSBbXTtcbiAgICBjb25zdCBhcHBlbmRJbmRleGVzID0gW107XG5cbiAgICBpZiAoZm9yY2UpIHtcbiAgICAgIHN3aXBlci4kd3JhcHBlckVsLmZpbmQoYC4ke3N3aXBlci5wYXJhbXMuc2xpZGVDbGFzc31gKS5yZW1vdmUoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZm9yIChsZXQgaSA9IHByZXZpb3VzRnJvbTsgaSA8PSBwcmV2aW91c1RvOyBpICs9IDEpIHtcbiAgICAgICAgaWYgKGkgPCBmcm9tIHx8IGkgPiB0bykge1xuICAgICAgICAgIHN3aXBlci4kd3JhcHBlckVsLmZpbmQoYC4ke3N3aXBlci5wYXJhbXMuc2xpZGVDbGFzc31bZGF0YS1zd2lwZXItc2xpZGUtaW5kZXg9XCIke2l9XCJdYCkucmVtb3ZlKCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNsaWRlcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgaWYgKGkgPj0gZnJvbSAmJiBpIDw9IHRvKSB7XG4gICAgICAgIGlmICh0eXBlb2YgcHJldmlvdXNUbyA9PT0gJ3VuZGVmaW5lZCcgfHwgZm9yY2UpIHtcbiAgICAgICAgICBhcHBlbmRJbmRleGVzLnB1c2goaSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaWYgKGkgPiBwcmV2aW91c1RvKSBhcHBlbmRJbmRleGVzLnB1c2goaSk7XG4gICAgICAgICAgaWYgKGkgPCBwcmV2aW91c0Zyb20pIHByZXBlbmRJbmRleGVzLnB1c2goaSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBhcHBlbmRJbmRleGVzLmZvckVhY2goaW5kZXggPT4ge1xuICAgICAgc3dpcGVyLiR3cmFwcGVyRWwuYXBwZW5kKHJlbmRlclNsaWRlKHNsaWRlc1tpbmRleF0sIGluZGV4KSk7XG4gICAgfSk7XG4gICAgcHJlcGVuZEluZGV4ZXMuc29ydCgoYSwgYikgPT4gYiAtIGEpLmZvckVhY2goaW5kZXggPT4ge1xuICAgICAgc3dpcGVyLiR3cmFwcGVyRWwucHJlcGVuZChyZW5kZXJTbGlkZShzbGlkZXNbaW5kZXhdLCBpbmRleCkpO1xuICAgIH0pO1xuICAgIHN3aXBlci4kd3JhcHBlckVsLmNoaWxkcmVuKCcuc3dpcGVyLXNsaWRlJykuY3NzKG9mZnNldFByb3AsIGAke29mZnNldH1weGApO1xuICAgIG9uUmVuZGVyZWQoKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGFwcGVuZFNsaWRlKHNsaWRlcykge1xuICAgIGlmICh0eXBlb2Ygc2xpZGVzID09PSAnb2JqZWN0JyAmJiAnbGVuZ3RoJyBpbiBzbGlkZXMpIHtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2xpZGVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICAgIGlmIChzbGlkZXNbaV0pIHN3aXBlci52aXJ0dWFsLnNsaWRlcy5wdXNoKHNsaWRlc1tpXSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHN3aXBlci52aXJ0dWFsLnNsaWRlcy5wdXNoKHNsaWRlcyk7XG4gICAgfVxuXG4gICAgdXBkYXRlKHRydWUpO1xuICB9XG5cbiAgZnVuY3Rpb24gcHJlcGVuZFNsaWRlKHNsaWRlcykge1xuICAgIGNvbnN0IGFjdGl2ZUluZGV4ID0gc3dpcGVyLmFjdGl2ZUluZGV4O1xuICAgIGxldCBuZXdBY3RpdmVJbmRleCA9IGFjdGl2ZUluZGV4ICsgMTtcbiAgICBsZXQgbnVtYmVyT2ZOZXdTbGlkZXMgPSAxO1xuXG4gICAgaWYgKEFycmF5LmlzQXJyYXkoc2xpZGVzKSkge1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzbGlkZXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgaWYgKHNsaWRlc1tpXSkgc3dpcGVyLnZpcnR1YWwuc2xpZGVzLnVuc2hpZnQoc2xpZGVzW2ldKTtcbiAgICAgIH1cblxuICAgICAgbmV3QWN0aXZlSW5kZXggPSBhY3RpdmVJbmRleCArIHNsaWRlcy5sZW5ndGg7XG4gICAgICBudW1iZXJPZk5ld1NsaWRlcyA9IHNsaWRlcy5sZW5ndGg7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN3aXBlci52aXJ0dWFsLnNsaWRlcy51bnNoaWZ0KHNsaWRlcyk7XG4gICAgfVxuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMudmlydHVhbC5jYWNoZSkge1xuICAgICAgY29uc3QgY2FjaGUgPSBzd2lwZXIudmlydHVhbC5jYWNoZTtcbiAgICAgIGNvbnN0IG5ld0NhY2hlID0ge307XG4gICAgICBPYmplY3Qua2V5cyhjYWNoZSkuZm9yRWFjaChjYWNoZWRJbmRleCA9PiB7XG4gICAgICAgIGNvbnN0ICRjYWNoZWRFbCA9IGNhY2hlW2NhY2hlZEluZGV4XTtcbiAgICAgICAgY29uc3QgY2FjaGVkRWxJbmRleCA9ICRjYWNoZWRFbC5hdHRyKCdkYXRhLXN3aXBlci1zbGlkZS1pbmRleCcpO1xuXG4gICAgICAgIGlmIChjYWNoZWRFbEluZGV4KSB7XG4gICAgICAgICAgJGNhY2hlZEVsLmF0dHIoJ2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4JywgcGFyc2VJbnQoY2FjaGVkRWxJbmRleCwgMTApICsgbnVtYmVyT2ZOZXdTbGlkZXMpO1xuICAgICAgICB9XG5cbiAgICAgICAgbmV3Q2FjaGVbcGFyc2VJbnQoY2FjaGVkSW5kZXgsIDEwKSArIG51bWJlck9mTmV3U2xpZGVzXSA9ICRjYWNoZWRFbDtcbiAgICAgIH0pO1xuICAgICAgc3dpcGVyLnZpcnR1YWwuY2FjaGUgPSBuZXdDYWNoZTtcbiAgICB9XG5cbiAgICB1cGRhdGUodHJ1ZSk7XG4gICAgc3dpcGVyLnNsaWRlVG8obmV3QWN0aXZlSW5kZXgsIDApO1xuICB9XG5cbiAgZnVuY3Rpb24gcmVtb3ZlU2xpZGUoc2xpZGVzSW5kZXhlcykge1xuICAgIGlmICh0eXBlb2Ygc2xpZGVzSW5kZXhlcyA9PT0gJ3VuZGVmaW5lZCcgfHwgc2xpZGVzSW5kZXhlcyA9PT0gbnVsbCkgcmV0dXJuO1xuICAgIGxldCBhY3RpdmVJbmRleCA9IHN3aXBlci5hY3RpdmVJbmRleDtcblxuICAgIGlmIChBcnJheS5pc0FycmF5KHNsaWRlc0luZGV4ZXMpKSB7XG4gICAgICBmb3IgKGxldCBpID0gc2xpZGVzSW5kZXhlcy5sZW5ndGggLSAxOyBpID49IDA7IGkgLT0gMSkge1xuICAgICAgICBzd2lwZXIudmlydHVhbC5zbGlkZXMuc3BsaWNlKHNsaWRlc0luZGV4ZXNbaV0sIDEpO1xuXG4gICAgICAgIGlmIChzd2lwZXIucGFyYW1zLnZpcnR1YWwuY2FjaGUpIHtcbiAgICAgICAgICBkZWxldGUgc3dpcGVyLnZpcnR1YWwuY2FjaGVbc2xpZGVzSW5kZXhlc1tpXV07XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoc2xpZGVzSW5kZXhlc1tpXSA8IGFjdGl2ZUluZGV4KSBhY3RpdmVJbmRleCAtPSAxO1xuICAgICAgICBhY3RpdmVJbmRleCA9IE1hdGgubWF4KGFjdGl2ZUluZGV4LCAwKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgc3dpcGVyLnZpcnR1YWwuc2xpZGVzLnNwbGljZShzbGlkZXNJbmRleGVzLCAxKTtcblxuICAgICAgaWYgKHN3aXBlci5wYXJhbXMudmlydHVhbC5jYWNoZSkge1xuICAgICAgICBkZWxldGUgc3dpcGVyLnZpcnR1YWwuY2FjaGVbc2xpZGVzSW5kZXhlc107XG4gICAgICB9XG5cbiAgICAgIGlmIChzbGlkZXNJbmRleGVzIDwgYWN0aXZlSW5kZXgpIGFjdGl2ZUluZGV4IC09IDE7XG4gICAgICBhY3RpdmVJbmRleCA9IE1hdGgubWF4KGFjdGl2ZUluZGV4LCAwKTtcbiAgICB9XG5cbiAgICB1cGRhdGUodHJ1ZSk7XG4gICAgc3dpcGVyLnNsaWRlVG8oYWN0aXZlSW5kZXgsIDApO1xuICB9XG5cbiAgZnVuY3Rpb24gcmVtb3ZlQWxsU2xpZGVzKCkge1xuICAgIHN3aXBlci52aXJ0dWFsLnNsaWRlcyA9IFtdO1xuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMudmlydHVhbC5jYWNoZSkge1xuICAgICAgc3dpcGVyLnZpcnR1YWwuY2FjaGUgPSB7fTtcbiAgICB9XG5cbiAgICB1cGRhdGUodHJ1ZSk7XG4gICAgc3dpcGVyLnNsaWRlVG8oMCwgMCk7XG4gIH1cblxuICBvbignYmVmb3JlSW5pdCcsICgpID0+IHtcbiAgICBpZiAoIXN3aXBlci5wYXJhbXMudmlydHVhbC5lbmFibGVkKSByZXR1cm47XG4gICAgc3dpcGVyLnZpcnR1YWwuc2xpZGVzID0gc3dpcGVyLnBhcmFtcy52aXJ0dWFsLnNsaWRlcztcbiAgICBzd2lwZXIuY2xhc3NOYW1lcy5wdXNoKGAke3N3aXBlci5wYXJhbXMuY29udGFpbmVyTW9kaWZpZXJDbGFzc312aXJ0dWFsYCk7XG4gICAgc3dpcGVyLnBhcmFtcy53YXRjaFNsaWRlc1Byb2dyZXNzID0gdHJ1ZTtcbiAgICBzd2lwZXIub3JpZ2luYWxQYXJhbXMud2F0Y2hTbGlkZXNQcm9ncmVzcyA9IHRydWU7XG5cbiAgICBpZiAoIXN3aXBlci5wYXJhbXMuaW5pdGlhbFNsaWRlKSB7XG4gICAgICB1cGRhdGUoKTtcbiAgICB9XG4gIH0pO1xuICBvbignc2V0VHJhbnNsYXRlJywgKCkgPT4ge1xuICAgIGlmICghc3dpcGVyLnBhcmFtcy52aXJ0dWFsLmVuYWJsZWQpIHJldHVybjtcblxuICAgIGlmIChzd2lwZXIucGFyYW1zLmNzc01vZGUgJiYgIXN3aXBlci5faW1tZWRpYXRlVmlydHVhbCkge1xuICAgICAgY2xlYXJUaW1lb3V0KGNzc01vZGVUaW1lb3V0KTtcbiAgICAgIGNzc01vZGVUaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHVwZGF0ZSgpO1xuICAgICAgfSwgMTAwKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdXBkYXRlKCk7XG4gICAgfVxuICB9KTtcbiAgb24oJ2luaXQgdXBkYXRlIHJlc2l6ZScsICgpID0+IHtcbiAgICBpZiAoIXN3aXBlci5wYXJhbXMudmlydHVhbC5lbmFibGVkKSByZXR1cm47XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5jc3NNb2RlKSB7XG4gICAgICBzZXRDU1NQcm9wZXJ0eShzd2lwZXIud3JhcHBlckVsLCAnLS1zd2lwZXItdmlydHVhbC1zaXplJywgYCR7c3dpcGVyLnZpcnR1YWxTaXplfXB4YCk7XG4gICAgfVxuICB9KTtcbiAgT2JqZWN0LmFzc2lnbihzd2lwZXIudmlydHVhbCwge1xuICAgIGFwcGVuZFNsaWRlLFxuICAgIHByZXBlbmRTbGlkZSxcbiAgICByZW1vdmVTbGlkZSxcbiAgICByZW1vdmVBbGxTbGlkZXMsXG4gICAgdXBkYXRlXG4gIH0pO1xufSIsIi8qIGVzbGludC1kaXNhYmxlIGNvbnNpc3RlbnQtcmV0dXJuICovXG5pbXBvcnQgeyBnZXRXaW5kb3csIGdldERvY3VtZW50IH0gZnJvbSAnc3NyLXdpbmRvdyc7XG5pbXBvcnQgJCBmcm9tICcuLi8uLi9zaGFyZWQvZG9tLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIEtleWJvYXJkKHtcbiAgc3dpcGVyLFxuICBleHRlbmRQYXJhbXMsXG4gIG9uLFxuICBlbWl0XG59KSB7XG4gIGNvbnN0IGRvY3VtZW50ID0gZ2V0RG9jdW1lbnQoKTtcbiAgY29uc3Qgd2luZG93ID0gZ2V0V2luZG93KCk7XG4gIHN3aXBlci5rZXlib2FyZCA9IHtcbiAgICBlbmFibGVkOiBmYWxzZVxuICB9O1xuICBleHRlbmRQYXJhbXMoe1xuICAgIGtleWJvYXJkOiB7XG4gICAgICBlbmFibGVkOiBmYWxzZSxcbiAgICAgIG9ubHlJblZpZXdwb3J0OiB0cnVlLFxuICAgICAgcGFnZVVwRG93bjogdHJ1ZVxuICAgIH1cbiAgfSk7XG5cbiAgZnVuY3Rpb24gaGFuZGxlKGV2ZW50KSB7XG4gICAgaWYgKCFzd2lwZXIuZW5hYmxlZCkgcmV0dXJuO1xuICAgIGNvbnN0IHtcbiAgICAgIHJ0bFRyYW5zbGF0ZTogcnRsXG4gICAgfSA9IHN3aXBlcjtcbiAgICBsZXQgZSA9IGV2ZW50O1xuICAgIGlmIChlLm9yaWdpbmFsRXZlbnQpIGUgPSBlLm9yaWdpbmFsRXZlbnQ7IC8vIGpxdWVyeSBmaXhcblxuICAgIGNvbnN0IGtjID0gZS5rZXlDb2RlIHx8IGUuY2hhckNvZGU7XG4gICAgY29uc3QgcGFnZVVwRG93biA9IHN3aXBlci5wYXJhbXMua2V5Ym9hcmQucGFnZVVwRG93bjtcbiAgICBjb25zdCBpc1BhZ2VVcCA9IHBhZ2VVcERvd24gJiYga2MgPT09IDMzO1xuICAgIGNvbnN0IGlzUGFnZURvd24gPSBwYWdlVXBEb3duICYmIGtjID09PSAzNDtcbiAgICBjb25zdCBpc0Fycm93TGVmdCA9IGtjID09PSAzNztcbiAgICBjb25zdCBpc0Fycm93UmlnaHQgPSBrYyA9PT0gMzk7XG4gICAgY29uc3QgaXNBcnJvd1VwID0ga2MgPT09IDM4O1xuICAgIGNvbnN0IGlzQXJyb3dEb3duID0ga2MgPT09IDQwOyAvLyBEaXJlY3Rpb25zIGxvY2tzXG5cbiAgICBpZiAoIXN3aXBlci5hbGxvd1NsaWRlTmV4dCAmJiAoc3dpcGVyLmlzSG9yaXpvbnRhbCgpICYmIGlzQXJyb3dSaWdodCB8fCBzd2lwZXIuaXNWZXJ0aWNhbCgpICYmIGlzQXJyb3dEb3duIHx8IGlzUGFnZURvd24pKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKCFzd2lwZXIuYWxsb3dTbGlkZVByZXYgJiYgKHN3aXBlci5pc0hvcml6b250YWwoKSAmJiBpc0Fycm93TGVmdCB8fCBzd2lwZXIuaXNWZXJ0aWNhbCgpICYmIGlzQXJyb3dVcCB8fCBpc1BhZ2VVcCkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAoZS5zaGlmdEtleSB8fCBlLmFsdEtleSB8fCBlLmN0cmxLZXkgfHwgZS5tZXRhS2V5KSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIGlmIChkb2N1bWVudC5hY3RpdmVFbGVtZW50ICYmIGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQubm9kZU5hbWUgJiYgKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQubm9kZU5hbWUudG9Mb3dlckNhc2UoKSA9PT0gJ2lucHV0JyB8fCBkb2N1bWVudC5hY3RpdmVFbGVtZW50Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09ICd0ZXh0YXJlYScpKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIGlmIChzd2lwZXIucGFyYW1zLmtleWJvYXJkLm9ubHlJblZpZXdwb3J0ICYmIChpc1BhZ2VVcCB8fCBpc1BhZ2VEb3duIHx8IGlzQXJyb3dMZWZ0IHx8IGlzQXJyb3dSaWdodCB8fCBpc0Fycm93VXAgfHwgaXNBcnJvd0Rvd24pKSB7XG4gICAgICBsZXQgaW5WaWV3ID0gZmFsc2U7IC8vIENoZWNrIHRoYXQgc3dpcGVyIHNob3VsZCBiZSBpbnNpZGUgb2YgdmlzaWJsZSBhcmVhIG9mIHdpbmRvd1xuXG4gICAgICBpZiAoc3dpcGVyLiRlbC5wYXJlbnRzKGAuJHtzd2lwZXIucGFyYW1zLnNsaWRlQ2xhc3N9YCkubGVuZ3RoID4gMCAmJiBzd2lwZXIuJGVsLnBhcmVudHMoYC4ke3N3aXBlci5wYXJhbXMuc2xpZGVBY3RpdmVDbGFzc31gKS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgIH1cblxuICAgICAgY29uc3QgJGVsID0gc3dpcGVyLiRlbDtcbiAgICAgIGNvbnN0IHN3aXBlcldpZHRoID0gJGVsWzBdLmNsaWVudFdpZHRoO1xuICAgICAgY29uc3Qgc3dpcGVySGVpZ2h0ID0gJGVsWzBdLmNsaWVudEhlaWdodDtcbiAgICAgIGNvbnN0IHdpbmRvd1dpZHRoID0gd2luZG93LmlubmVyV2lkdGg7XG4gICAgICBjb25zdCB3aW5kb3dIZWlnaHQgPSB3aW5kb3cuaW5uZXJIZWlnaHQ7XG4gICAgICBjb25zdCBzd2lwZXJPZmZzZXQgPSBzd2lwZXIuJGVsLm9mZnNldCgpO1xuICAgICAgaWYgKHJ0bCkgc3dpcGVyT2Zmc2V0LmxlZnQgLT0gc3dpcGVyLiRlbFswXS5zY3JvbGxMZWZ0O1xuICAgICAgY29uc3Qgc3dpcGVyQ29vcmQgPSBbW3N3aXBlck9mZnNldC5sZWZ0LCBzd2lwZXJPZmZzZXQudG9wXSwgW3N3aXBlck9mZnNldC5sZWZ0ICsgc3dpcGVyV2lkdGgsIHN3aXBlck9mZnNldC50b3BdLCBbc3dpcGVyT2Zmc2V0LmxlZnQsIHN3aXBlck9mZnNldC50b3AgKyBzd2lwZXJIZWlnaHRdLCBbc3dpcGVyT2Zmc2V0LmxlZnQgKyBzd2lwZXJXaWR0aCwgc3dpcGVyT2Zmc2V0LnRvcCArIHN3aXBlckhlaWdodF1dO1xuXG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHN3aXBlckNvb3JkLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICAgIGNvbnN0IHBvaW50ID0gc3dpcGVyQ29vcmRbaV07XG5cbiAgICAgICAgaWYgKHBvaW50WzBdID49IDAgJiYgcG9pbnRbMF0gPD0gd2luZG93V2lkdGggJiYgcG9pbnRbMV0gPj0gMCAmJiBwb2ludFsxXSA8PSB3aW5kb3dIZWlnaHQpIHtcbiAgICAgICAgICBpZiAocG9pbnRbMF0gPT09IDAgJiYgcG9pbnRbMV0gPT09IDApIGNvbnRpbnVlOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lXG5cbiAgICAgICAgICBpblZpZXcgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICghaW5WaWV3KSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIGlmIChzd2lwZXIuaXNIb3Jpem9udGFsKCkpIHtcbiAgICAgIGlmIChpc1BhZ2VVcCB8fCBpc1BhZ2VEb3duIHx8IGlzQXJyb3dMZWZ0IHx8IGlzQXJyb3dSaWdodCkge1xuICAgICAgICBpZiAoZS5wcmV2ZW50RGVmYXVsdCkgZS5wcmV2ZW50RGVmYXVsdCgpO2Vsc2UgZS5yZXR1cm5WYWx1ZSA9IGZhbHNlO1xuICAgICAgfVxuXG4gICAgICBpZiAoKGlzUGFnZURvd24gfHwgaXNBcnJvd1JpZ2h0KSAmJiAhcnRsIHx8IChpc1BhZ2VVcCB8fCBpc0Fycm93TGVmdCkgJiYgcnRsKSBzd2lwZXIuc2xpZGVOZXh0KCk7XG4gICAgICBpZiAoKGlzUGFnZVVwIHx8IGlzQXJyb3dMZWZ0KSAmJiAhcnRsIHx8IChpc1BhZ2VEb3duIHx8IGlzQXJyb3dSaWdodCkgJiYgcnRsKSBzd2lwZXIuc2xpZGVQcmV2KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmIChpc1BhZ2VVcCB8fCBpc1BhZ2VEb3duIHx8IGlzQXJyb3dVcCB8fCBpc0Fycm93RG93bikge1xuICAgICAgICBpZiAoZS5wcmV2ZW50RGVmYXVsdCkgZS5wcmV2ZW50RGVmYXVsdCgpO2Vsc2UgZS5yZXR1cm5WYWx1ZSA9IGZhbHNlO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNQYWdlRG93biB8fCBpc0Fycm93RG93bikgc3dpcGVyLnNsaWRlTmV4dCgpO1xuICAgICAgaWYgKGlzUGFnZVVwIHx8IGlzQXJyb3dVcCkgc3dpcGVyLnNsaWRlUHJldigpO1xuICAgIH1cblxuICAgIGVtaXQoJ2tleVByZXNzJywga2MpO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBmdW5jdGlvbiBlbmFibGUoKSB7XG4gICAgaWYgKHN3aXBlci5rZXlib2FyZC5lbmFibGVkKSByZXR1cm47XG4gICAgJChkb2N1bWVudCkub24oJ2tleWRvd24nLCBoYW5kbGUpO1xuICAgIHN3aXBlci5rZXlib2FyZC5lbmFibGVkID0gdHJ1ZTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGRpc2FibGUoKSB7XG4gICAgaWYgKCFzd2lwZXIua2V5Ym9hcmQuZW5hYmxlZCkgcmV0dXJuO1xuICAgICQoZG9jdW1lbnQpLm9mZigna2V5ZG93bicsIGhhbmRsZSk7XG4gICAgc3dpcGVyLmtleWJvYXJkLmVuYWJsZWQgPSBmYWxzZTtcbiAgfVxuXG4gIG9uKCdpbml0JywgKCkgPT4ge1xuICAgIGlmIChzd2lwZXIucGFyYW1zLmtleWJvYXJkLmVuYWJsZWQpIHtcbiAgICAgIGVuYWJsZSgpO1xuICAgIH1cbiAgfSk7XG4gIG9uKCdkZXN0cm95JywgKCkgPT4ge1xuICAgIGlmIChzd2lwZXIua2V5Ym9hcmQuZW5hYmxlZCkge1xuICAgICAgZGlzYWJsZSgpO1xuICAgIH1cbiAgfSk7XG4gIE9iamVjdC5hc3NpZ24oc3dpcGVyLmtleWJvYXJkLCB7XG4gICAgZW5hYmxlLFxuICAgIGRpc2FibGVcbiAgfSk7XG59IiwiLyogZXNsaW50LWRpc2FibGUgY29uc2lzdGVudC1yZXR1cm4gKi9cbmltcG9ydCB7IGdldFdpbmRvdyB9IGZyb20gJ3Nzci13aW5kb3cnO1xuaW1wb3J0ICQgZnJvbSAnLi4vLi4vc2hhcmVkL2RvbS5qcyc7XG5pbXBvcnQgeyBub3csIG5leHRUaWNrIH0gZnJvbSAnLi4vLi4vc2hhcmVkL3V0aWxzLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIE1vdXNld2hlZWwoe1xuICBzd2lwZXIsXG4gIGV4dGVuZFBhcmFtcyxcbiAgb24sXG4gIGVtaXRcbn0pIHtcbiAgY29uc3Qgd2luZG93ID0gZ2V0V2luZG93KCk7XG4gIGV4dGVuZFBhcmFtcyh7XG4gICAgbW91c2V3aGVlbDoge1xuICAgICAgZW5hYmxlZDogZmFsc2UsXG4gICAgICByZWxlYXNlT25FZGdlczogZmFsc2UsXG4gICAgICBpbnZlcnQ6IGZhbHNlLFxuICAgICAgZm9yY2VUb0F4aXM6IGZhbHNlLFxuICAgICAgc2Vuc2l0aXZpdHk6IDEsXG4gICAgICBldmVudHNUYXJnZXQ6ICdjb250YWluZXInLFxuICAgICAgdGhyZXNob2xkRGVsdGE6IG51bGwsXG4gICAgICB0aHJlc2hvbGRUaW1lOiBudWxsXG4gICAgfVxuICB9KTtcbiAgc3dpcGVyLm1vdXNld2hlZWwgPSB7XG4gICAgZW5hYmxlZDogZmFsc2VcbiAgfTtcbiAgbGV0IHRpbWVvdXQ7XG4gIGxldCBsYXN0U2Nyb2xsVGltZSA9IG5vdygpO1xuICBsZXQgbGFzdEV2ZW50QmVmb3JlU25hcDtcbiAgY29uc3QgcmVjZW50V2hlZWxFdmVudHMgPSBbXTtcblxuICBmdW5jdGlvbiBub3JtYWxpemUoZSkge1xuICAgIC8vIFJlYXNvbmFibGUgZGVmYXVsdHNcbiAgICBjb25zdCBQSVhFTF9TVEVQID0gMTA7XG4gICAgY29uc3QgTElORV9IRUlHSFQgPSA0MDtcbiAgICBjb25zdCBQQUdFX0hFSUdIVCA9IDgwMDtcbiAgICBsZXQgc1ggPSAwO1xuICAgIGxldCBzWSA9IDA7IC8vIHNwaW5YLCBzcGluWVxuXG4gICAgbGV0IHBYID0gMDtcbiAgICBsZXQgcFkgPSAwOyAvLyBwaXhlbFgsIHBpeGVsWVxuICAgIC8vIExlZ2FjeVxuXG4gICAgaWYgKCdkZXRhaWwnIGluIGUpIHtcbiAgICAgIHNZID0gZS5kZXRhaWw7XG4gICAgfVxuXG4gICAgaWYgKCd3aGVlbERlbHRhJyBpbiBlKSB7XG4gICAgICBzWSA9IC1lLndoZWVsRGVsdGEgLyAxMjA7XG4gICAgfVxuXG4gICAgaWYgKCd3aGVlbERlbHRhWScgaW4gZSkge1xuICAgICAgc1kgPSAtZS53aGVlbERlbHRhWSAvIDEyMDtcbiAgICB9XG5cbiAgICBpZiAoJ3doZWVsRGVsdGFYJyBpbiBlKSB7XG4gICAgICBzWCA9IC1lLndoZWVsRGVsdGFYIC8gMTIwO1xuICAgIH0gLy8gc2lkZSBzY3JvbGxpbmcgb24gRkYgd2l0aCBET01Nb3VzZVNjcm9sbFxuXG5cbiAgICBpZiAoJ2F4aXMnIGluIGUgJiYgZS5heGlzID09PSBlLkhPUklaT05UQUxfQVhJUykge1xuICAgICAgc1ggPSBzWTtcbiAgICAgIHNZID0gMDtcbiAgICB9XG5cbiAgICBwWCA9IHNYICogUElYRUxfU1RFUDtcbiAgICBwWSA9IHNZICogUElYRUxfU1RFUDtcblxuICAgIGlmICgnZGVsdGFZJyBpbiBlKSB7XG4gICAgICBwWSA9IGUuZGVsdGFZO1xuICAgIH1cblxuICAgIGlmICgnZGVsdGFYJyBpbiBlKSB7XG4gICAgICBwWCA9IGUuZGVsdGFYO1xuICAgIH1cblxuICAgIGlmIChlLnNoaWZ0S2V5ICYmICFwWCkge1xuICAgICAgLy8gaWYgdXNlciBzY3JvbGxzIHdpdGggc2hpZnQgaGUgd2FudHMgaG9yaXpvbnRhbCBzY3JvbGxcbiAgICAgIHBYID0gcFk7XG4gICAgICBwWSA9IDA7XG4gICAgfVxuXG4gICAgaWYgKChwWCB8fCBwWSkgJiYgZS5kZWx0YU1vZGUpIHtcbiAgICAgIGlmIChlLmRlbHRhTW9kZSA9PT0gMSkge1xuICAgICAgICAvLyBkZWx0YSBpbiBMSU5FIHVuaXRzXG4gICAgICAgIHBYICo9IExJTkVfSEVJR0hUO1xuICAgICAgICBwWSAqPSBMSU5FX0hFSUdIVDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGRlbHRhIGluIFBBR0UgdW5pdHNcbiAgICAgICAgcFggKj0gUEFHRV9IRUlHSFQ7XG4gICAgICAgIHBZICo9IFBBR0VfSEVJR0hUO1xuICAgICAgfVxuICAgIH0gLy8gRmFsbC1iYWNrIGlmIHNwaW4gY2Fubm90IGJlIGRldGVybWluZWRcblxuXG4gICAgaWYgKHBYICYmICFzWCkge1xuICAgICAgc1ggPSBwWCA8IDEgPyAtMSA6IDE7XG4gICAgfVxuXG4gICAgaWYgKHBZICYmICFzWSkge1xuICAgICAgc1kgPSBwWSA8IDEgPyAtMSA6IDE7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHNwaW5YOiBzWCxcbiAgICAgIHNwaW5ZOiBzWSxcbiAgICAgIHBpeGVsWDogcFgsXG4gICAgICBwaXhlbFk6IHBZXG4gICAgfTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGhhbmRsZU1vdXNlRW50ZXIoKSB7XG4gICAgaWYgKCFzd2lwZXIuZW5hYmxlZCkgcmV0dXJuO1xuICAgIHN3aXBlci5tb3VzZUVudGVyZWQgPSB0cnVlO1xuICB9XG5cbiAgZnVuY3Rpb24gaGFuZGxlTW91c2VMZWF2ZSgpIHtcbiAgICBpZiAoIXN3aXBlci5lbmFibGVkKSByZXR1cm47XG4gICAgc3dpcGVyLm1vdXNlRW50ZXJlZCA9IGZhbHNlO1xuICB9XG5cbiAgZnVuY3Rpb24gYW5pbWF0ZVNsaWRlcihuZXdFdmVudCkge1xuICAgIGlmIChzd2lwZXIucGFyYW1zLm1vdXNld2hlZWwudGhyZXNob2xkRGVsdGEgJiYgbmV3RXZlbnQuZGVsdGEgPCBzd2lwZXIucGFyYW1zLm1vdXNld2hlZWwudGhyZXNob2xkRGVsdGEpIHtcbiAgICAgIC8vIFByZXZlbnQgaWYgZGVsdGEgb2Ygd2hlZWwgc2Nyb2xsIGRlbHRhIGlzIGJlbG93IGNvbmZpZ3VyZWQgdGhyZXNob2xkXG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMubW91c2V3aGVlbC50aHJlc2hvbGRUaW1lICYmIG5vdygpIC0gbGFzdFNjcm9sbFRpbWUgPCBzd2lwZXIucGFyYW1zLm1vdXNld2hlZWwudGhyZXNob2xkVGltZSkge1xuICAgICAgLy8gUHJldmVudCBpZiB0aW1lIGJldHdlZW4gc2Nyb2xscyBpcyBiZWxvdyBjb25maWd1cmVkIHRocmVzaG9sZFxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0gLy8gSWYgdGhlIG1vdmVtZW50IGlzIE5PVCBiaWcgZW5vdWdoIGFuZFxuICAgIC8vIGlmIHRoZSBsYXN0IHRpbWUgdGhlIHVzZXIgc2Nyb2xsZWQgd2FzIHRvbyBjbG9zZSB0byB0aGUgY3VycmVudCBvbmUgKGF2b2lkIGNvbnRpbnVvdXNseSB0cmlnZ2VyaW5nIHRoZSBzbGlkZXIpOlxuICAgIC8vICAgRG9uJ3QgZ28gYW55IGZ1cnRoZXIgKGF2b2lkIGluc2lnbmlmaWNhbnQgc2Nyb2xsIG1vdmVtZW50KS5cblxuXG4gICAgaWYgKG5ld0V2ZW50LmRlbHRhID49IDYgJiYgbm93KCkgLSBsYXN0U2Nyb2xsVGltZSA8IDYwKSB7XG4gICAgICAvLyBSZXR1cm4gZmFsc2UgYXMgYSBkZWZhdWx0XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IC8vIElmIHVzZXIgaXMgc2Nyb2xsaW5nIHRvd2FyZHMgdGhlIGVuZDpcbiAgICAvLyAgIElmIHRoZSBzbGlkZXIgaGFzbid0IGhpdCB0aGUgbGF0ZXN0IHNsaWRlIG9yXG4gICAgLy8gICBpZiB0aGUgc2xpZGVyIGlzIGEgbG9vcCBhbmRcbiAgICAvLyAgIGlmIHRoZSBzbGlkZXIgaXNuJ3QgbW92aW5nIHJpZ2h0IG5vdzpcbiAgICAvLyAgICAgR28gdG8gbmV4dCBzbGlkZSBhbmRcbiAgICAvLyAgICAgZW1pdCBhIHNjcm9sbCBldmVudC5cbiAgICAvLyBFbHNlICh0aGUgdXNlciBpcyBzY3JvbGxpbmcgdG93YXJkcyB0aGUgYmVnaW5uaW5nKSBhbmRcbiAgICAvLyBpZiB0aGUgc2xpZGVyIGhhc24ndCBoaXQgdGhlIGZpcnN0IHNsaWRlIG9yXG4gICAgLy8gaWYgdGhlIHNsaWRlciBpcyBhIGxvb3AgYW5kXG4gICAgLy8gaWYgdGhlIHNsaWRlciBpc24ndCBtb3ZpbmcgcmlnaHQgbm93OlxuICAgIC8vICAgR28gdG8gcHJldiBzbGlkZSBhbmRcbiAgICAvLyAgIGVtaXQgYSBzY3JvbGwgZXZlbnQuXG5cblxuICAgIGlmIChuZXdFdmVudC5kaXJlY3Rpb24gPCAwKSB7XG4gICAgICBpZiAoKCFzd2lwZXIuaXNFbmQgfHwgc3dpcGVyLnBhcmFtcy5sb29wKSAmJiAhc3dpcGVyLmFuaW1hdGluZykge1xuICAgICAgICBzd2lwZXIuc2xpZGVOZXh0KCk7XG4gICAgICAgIGVtaXQoJ3Njcm9sbCcsIG5ld0V2ZW50LnJhdyk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmICgoIXN3aXBlci5pc0JlZ2lubmluZyB8fCBzd2lwZXIucGFyYW1zLmxvb3ApICYmICFzd2lwZXIuYW5pbWF0aW5nKSB7XG4gICAgICBzd2lwZXIuc2xpZGVQcmV2KCk7XG4gICAgICBlbWl0KCdzY3JvbGwnLCBuZXdFdmVudC5yYXcpO1xuICAgIH0gLy8gSWYgeW91IGdvdCBoZXJlIGlzIGJlY2F1c2UgYW4gYW5pbWF0aW9uIGhhcyBiZWVuIHRyaWdnZXJlZCBzbyBzdG9yZSB0aGUgY3VycmVudCB0aW1lXG5cblxuICAgIGxhc3RTY3JvbGxUaW1lID0gbmV3IHdpbmRvdy5EYXRlKCkuZ2V0VGltZSgpOyAvLyBSZXR1cm4gZmFsc2UgYXMgYSBkZWZhdWx0XG5cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBmdW5jdGlvbiByZWxlYXNlU2Nyb2xsKG5ld0V2ZW50KSB7XG4gICAgY29uc3QgcGFyYW1zID0gc3dpcGVyLnBhcmFtcy5tb3VzZXdoZWVsO1xuXG4gICAgaWYgKG5ld0V2ZW50LmRpcmVjdGlvbiA8IDApIHtcbiAgICAgIGlmIChzd2lwZXIuaXNFbmQgJiYgIXN3aXBlci5wYXJhbXMubG9vcCAmJiBwYXJhbXMucmVsZWFzZU9uRWRnZXMpIHtcbiAgICAgICAgLy8gUmV0dXJuIHRydWUgdG8gYW5pbWF0ZSBzY3JvbGwgb24gZWRnZXNcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChzd2lwZXIuaXNCZWdpbm5pbmcgJiYgIXN3aXBlci5wYXJhbXMubG9vcCAmJiBwYXJhbXMucmVsZWFzZU9uRWRnZXMpIHtcbiAgICAgIC8vIFJldHVybiB0cnVlIHRvIGFuaW1hdGUgc2Nyb2xsIG9uIGVkZ2VzXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBmdW5jdGlvbiBoYW5kbGUoZXZlbnQpIHtcbiAgICBsZXQgZSA9IGV2ZW50O1xuICAgIGxldCBkaXNhYmxlUGFyZW50U3dpcGVyID0gdHJ1ZTtcbiAgICBpZiAoIXN3aXBlci5lbmFibGVkKSByZXR1cm47XG4gICAgY29uc3QgcGFyYW1zID0gc3dpcGVyLnBhcmFtcy5tb3VzZXdoZWVsO1xuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMuY3NzTW9kZSkge1xuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIH1cblxuICAgIGxldCB0YXJnZXQgPSBzd2lwZXIuJGVsO1xuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMubW91c2V3aGVlbC5ldmVudHNUYXJnZXQgIT09ICdjb250YWluZXInKSB7XG4gICAgICB0YXJnZXQgPSAkKHN3aXBlci5wYXJhbXMubW91c2V3aGVlbC5ldmVudHNUYXJnZXQpO1xuICAgIH1cblxuICAgIGlmICghc3dpcGVyLm1vdXNlRW50ZXJlZCAmJiAhdGFyZ2V0WzBdLmNvbnRhaW5zKGUudGFyZ2V0KSAmJiAhcGFyYW1zLnJlbGVhc2VPbkVkZ2VzKSByZXR1cm4gdHJ1ZTtcbiAgICBpZiAoZS5vcmlnaW5hbEV2ZW50KSBlID0gZS5vcmlnaW5hbEV2ZW50OyAvLyBqcXVlcnkgZml4XG5cbiAgICBsZXQgZGVsdGEgPSAwO1xuICAgIGNvbnN0IHJ0bEZhY3RvciA9IHN3aXBlci5ydGxUcmFuc2xhdGUgPyAtMSA6IDE7XG4gICAgY29uc3QgZGF0YSA9IG5vcm1hbGl6ZShlKTtcblxuICAgIGlmIChwYXJhbXMuZm9yY2VUb0F4aXMpIHtcbiAgICAgIGlmIChzd2lwZXIuaXNIb3Jpem9udGFsKCkpIHtcbiAgICAgICAgaWYgKE1hdGguYWJzKGRhdGEucGl4ZWxYKSA+IE1hdGguYWJzKGRhdGEucGl4ZWxZKSkgZGVsdGEgPSAtZGF0YS5waXhlbFggKiBydGxGYWN0b3I7ZWxzZSByZXR1cm4gdHJ1ZTtcbiAgICAgIH0gZWxzZSBpZiAoTWF0aC5hYnMoZGF0YS5waXhlbFkpID4gTWF0aC5hYnMoZGF0YS5waXhlbFgpKSBkZWx0YSA9IC1kYXRhLnBpeGVsWTtlbHNlIHJldHVybiB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICBkZWx0YSA9IE1hdGguYWJzKGRhdGEucGl4ZWxYKSA+IE1hdGguYWJzKGRhdGEucGl4ZWxZKSA/IC1kYXRhLnBpeGVsWCAqIHJ0bEZhY3RvciA6IC1kYXRhLnBpeGVsWTtcbiAgICB9XG5cbiAgICBpZiAoZGVsdGEgPT09IDApIHJldHVybiB0cnVlO1xuICAgIGlmIChwYXJhbXMuaW52ZXJ0KSBkZWx0YSA9IC1kZWx0YTsgLy8gR2V0IHRoZSBzY3JvbGwgcG9zaXRpb25zXG5cbiAgICBsZXQgcG9zaXRpb25zID0gc3dpcGVyLmdldFRyYW5zbGF0ZSgpICsgZGVsdGEgKiBwYXJhbXMuc2Vuc2l0aXZpdHk7XG4gICAgaWYgKHBvc2l0aW9ucyA+PSBzd2lwZXIubWluVHJhbnNsYXRlKCkpIHBvc2l0aW9ucyA9IHN3aXBlci5taW5UcmFuc2xhdGUoKTtcbiAgICBpZiAocG9zaXRpb25zIDw9IHN3aXBlci5tYXhUcmFuc2xhdGUoKSkgcG9zaXRpb25zID0gc3dpcGVyLm1heFRyYW5zbGF0ZSgpOyAvLyBXaGVuIGxvb3AgaXMgdHJ1ZTpcbiAgICAvLyAgICAgdGhlIGRpc2FibGVQYXJlbnRTd2lwZXIgd2lsbCBiZSB0cnVlLlxuICAgIC8vIFdoZW4gbG9vcCBpcyBmYWxzZTpcbiAgICAvLyAgICAgaWYgdGhlIHNjcm9sbCBwb3NpdGlvbnMgaXMgbm90IG9uIGVkZ2UsXG4gICAgLy8gICAgIHRoZW4gdGhlIGRpc2FibGVQYXJlbnRTd2lwZXIgd2lsbCBiZSB0cnVlLlxuICAgIC8vICAgICBpZiB0aGUgc2Nyb2xsIG9uIGVkZ2UgcG9zaXRpb25zLFxuICAgIC8vICAgICB0aGVuIHRoZSBkaXNhYmxlUGFyZW50U3dpcGVyIHdpbGwgYmUgZmFsc2UuXG5cbiAgICBkaXNhYmxlUGFyZW50U3dpcGVyID0gc3dpcGVyLnBhcmFtcy5sb29wID8gdHJ1ZSA6ICEocG9zaXRpb25zID09PSBzd2lwZXIubWluVHJhbnNsYXRlKCkgfHwgcG9zaXRpb25zID09PSBzd2lwZXIubWF4VHJhbnNsYXRlKCkpO1xuICAgIGlmIChkaXNhYmxlUGFyZW50U3dpcGVyICYmIHN3aXBlci5wYXJhbXMubmVzdGVkKSBlLnN0b3BQcm9wYWdhdGlvbigpO1xuXG4gICAgaWYgKCFzd2lwZXIucGFyYW1zLmZyZWVNb2RlIHx8ICFzd2lwZXIucGFyYW1zLmZyZWVNb2RlLmVuYWJsZWQpIHtcbiAgICAgIC8vIFJlZ2lzdGVyIHRoZSBuZXcgZXZlbnQgaW4gYSB2YXJpYWJsZSB3aGljaCBzdG9yZXMgdGhlIHJlbGV2YW50IGRhdGFcbiAgICAgIGNvbnN0IG5ld0V2ZW50ID0ge1xuICAgICAgICB0aW1lOiBub3coKSxcbiAgICAgICAgZGVsdGE6IE1hdGguYWJzKGRlbHRhKSxcbiAgICAgICAgZGlyZWN0aW9uOiBNYXRoLnNpZ24oZGVsdGEpLFxuICAgICAgICByYXc6IGV2ZW50XG4gICAgICB9OyAvLyBLZWVwIHRoZSBtb3N0IHJlY2VudCBldmVudHNcblxuICAgICAgaWYgKHJlY2VudFdoZWVsRXZlbnRzLmxlbmd0aCA+PSAyKSB7XG4gICAgICAgIHJlY2VudFdoZWVsRXZlbnRzLnNoaWZ0KCk7IC8vIG9ubHkgc3RvcmUgdGhlIGxhc3QgTiBldmVudHNcbiAgICAgIH1cblxuICAgICAgY29uc3QgcHJldkV2ZW50ID0gcmVjZW50V2hlZWxFdmVudHMubGVuZ3RoID8gcmVjZW50V2hlZWxFdmVudHNbcmVjZW50V2hlZWxFdmVudHMubGVuZ3RoIC0gMV0gOiB1bmRlZmluZWQ7XG4gICAgICByZWNlbnRXaGVlbEV2ZW50cy5wdXNoKG5ld0V2ZW50KTsgLy8gSWYgdGhlcmUgaXMgYXQgbGVhc3Qgb25lIHByZXZpb3VzIHJlY29yZGVkIGV2ZW50OlxuICAgICAgLy8gICBJZiBkaXJlY3Rpb24gaGFzIGNoYW5nZWQgb3JcbiAgICAgIC8vICAgaWYgdGhlIHNjcm9sbCBpcyBxdWlja2VyIHRoYW4gdGhlIHByZXZpb3VzIG9uZTpcbiAgICAgIC8vICAgICBBbmltYXRlIHRoZSBzbGlkZXIuXG4gICAgICAvLyBFbHNlICh0aGlzIGlzIHRoZSBmaXJzdCB0aW1lIHRoZSB3aGVlbCBpcyBtb3ZlZCk6XG4gICAgICAvLyAgICAgQW5pbWF0ZSB0aGUgc2xpZGVyLlxuXG4gICAgICBpZiAocHJldkV2ZW50KSB7XG4gICAgICAgIGlmIChuZXdFdmVudC5kaXJlY3Rpb24gIT09IHByZXZFdmVudC5kaXJlY3Rpb24gfHwgbmV3RXZlbnQuZGVsdGEgPiBwcmV2RXZlbnQuZGVsdGEgfHwgbmV3RXZlbnQudGltZSA+IHByZXZFdmVudC50aW1lICsgMTUwKSB7XG4gICAgICAgICAgYW5pbWF0ZVNsaWRlcihuZXdFdmVudCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGFuaW1hdGVTbGlkZXIobmV3RXZlbnQpO1xuICAgICAgfSAvLyBJZiBpdCdzIHRpbWUgdG8gcmVsZWFzZSB0aGUgc2Nyb2xsOlxuICAgICAgLy8gICBSZXR1cm4gbm93IHNvIHlvdSBkb24ndCBoaXQgdGhlIHByZXZlbnREZWZhdWx0LlxuXG5cbiAgICAgIGlmIChyZWxlYXNlU2Nyb2xsKG5ld0V2ZW50KSkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gRnJlZW1vZGUgb3Igc2Nyb2xsQ29udGFpbmVyOlxuICAgICAgLy8gSWYgd2UgcmVjZW50bHkgc25hcHBlZCBhZnRlciBhIG1vbWVudHVtIHNjcm9sbCwgdGhlbiBpZ25vcmUgd2hlZWwgZXZlbnRzXG4gICAgICAvLyB0byBnaXZlIHRpbWUgZm9yIHRoZSBkZWNlbGVyYXRpb24gdG8gZmluaXNoLiBTdG9wIGlnbm9yaW5nIGFmdGVyIDUwMCBtc2Vjc1xuICAgICAgLy8gb3IgaWYgaXQncyBhIG5ldyBzY3JvbGwgKGxhcmdlciBkZWx0YSBvciBpbnZlcnNlIHNpZ24gYXMgbGFzdCBldmVudCBiZWZvcmVcbiAgICAgIC8vIGFuIGVuZC1vZi1tb21lbnR1bSBzbmFwKS5cbiAgICAgIGNvbnN0IG5ld0V2ZW50ID0ge1xuICAgICAgICB0aW1lOiBub3coKSxcbiAgICAgICAgZGVsdGE6IE1hdGguYWJzKGRlbHRhKSxcbiAgICAgICAgZGlyZWN0aW9uOiBNYXRoLnNpZ24oZGVsdGEpXG4gICAgICB9O1xuICAgICAgY29uc3QgaWdub3JlV2hlZWxFdmVudHMgPSBsYXN0RXZlbnRCZWZvcmVTbmFwICYmIG5ld0V2ZW50LnRpbWUgPCBsYXN0RXZlbnRCZWZvcmVTbmFwLnRpbWUgKyA1MDAgJiYgbmV3RXZlbnQuZGVsdGEgPD0gbGFzdEV2ZW50QmVmb3JlU25hcC5kZWx0YSAmJiBuZXdFdmVudC5kaXJlY3Rpb24gPT09IGxhc3RFdmVudEJlZm9yZVNuYXAuZGlyZWN0aW9uO1xuXG4gICAgICBpZiAoIWlnbm9yZVdoZWVsRXZlbnRzKSB7XG4gICAgICAgIGxhc3RFdmVudEJlZm9yZVNuYXAgPSB1bmRlZmluZWQ7XG5cbiAgICAgICAgaWYgKHN3aXBlci5wYXJhbXMubG9vcCkge1xuICAgICAgICAgIHN3aXBlci5sb29wRml4KCk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgcG9zaXRpb24gPSBzd2lwZXIuZ2V0VHJhbnNsYXRlKCkgKyBkZWx0YSAqIHBhcmFtcy5zZW5zaXRpdml0eTtcbiAgICAgICAgY29uc3Qgd2FzQmVnaW5uaW5nID0gc3dpcGVyLmlzQmVnaW5uaW5nO1xuICAgICAgICBjb25zdCB3YXNFbmQgPSBzd2lwZXIuaXNFbmQ7XG4gICAgICAgIGlmIChwb3NpdGlvbiA+PSBzd2lwZXIubWluVHJhbnNsYXRlKCkpIHBvc2l0aW9uID0gc3dpcGVyLm1pblRyYW5zbGF0ZSgpO1xuICAgICAgICBpZiAocG9zaXRpb24gPD0gc3dpcGVyLm1heFRyYW5zbGF0ZSgpKSBwb3NpdGlvbiA9IHN3aXBlci5tYXhUcmFuc2xhdGUoKTtcbiAgICAgICAgc3dpcGVyLnNldFRyYW5zaXRpb24oMCk7XG4gICAgICAgIHN3aXBlci5zZXRUcmFuc2xhdGUocG9zaXRpb24pO1xuICAgICAgICBzd2lwZXIudXBkYXRlUHJvZ3Jlc3MoKTtcbiAgICAgICAgc3dpcGVyLnVwZGF0ZUFjdGl2ZUluZGV4KCk7XG4gICAgICAgIHN3aXBlci51cGRhdGVTbGlkZXNDbGFzc2VzKCk7XG5cbiAgICAgICAgaWYgKCF3YXNCZWdpbm5pbmcgJiYgc3dpcGVyLmlzQmVnaW5uaW5nIHx8ICF3YXNFbmQgJiYgc3dpcGVyLmlzRW5kKSB7XG4gICAgICAgICAgc3dpcGVyLnVwZGF0ZVNsaWRlc0NsYXNzZXMoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChzd2lwZXIucGFyYW1zLmZyZWVNb2RlLnN0aWNreSkge1xuICAgICAgICAgIC8vIFdoZW4gd2hlZWwgc2Nyb2xsaW5nIHN0YXJ0cyB3aXRoIHN0aWNreSAoYWthIHNuYXApIGVuYWJsZWQsIHRoZW4gZGV0ZWN0XG4gICAgICAgICAgLy8gdGhlIGVuZCBvZiBhIG1vbWVudHVtIHNjcm9sbCBieSBzdG9yaW5nIHJlY2VudCAoTj0xNT8pIHdoZWVsIGV2ZW50cy5cbiAgICAgICAgICAvLyAxLiBkbyBhbGwgTiBldmVudHMgaGF2ZSBkZWNyZWFzaW5nIG9yIHNhbWUgKGFic29sdXRlIHZhbHVlKSBkZWx0YT9cbiAgICAgICAgICAvLyAyLiBkaWQgYWxsIE4gZXZlbnRzIGFycml2ZSBpbiB0aGUgbGFzdCBNIChNPTUwMD8pIG1zZWNzP1xuICAgICAgICAgIC8vIDMuIGRvZXMgdGhlIGVhcmxpZXN0IGV2ZW50IGhhdmUgYW4gKGFic29sdXRlIHZhbHVlKSBkZWx0YSB0aGF0J3NcbiAgICAgICAgICAvLyAgICBhdCBsZWFzdCBQIChQPTE/KSBsYXJnZXIgdGhhbiB0aGUgbW9zdCByZWNlbnQgZXZlbnQncyBkZWx0YT9cbiAgICAgICAgICAvLyA0LiBkb2VzIHRoZSBsYXRlc3QgZXZlbnQgaGF2ZSBhIGRlbHRhIHRoYXQncyBzbWFsbGVyIHRoYW4gUSAoUT02PykgcGl4ZWxzP1xuICAgICAgICAgIC8vIElmIDEtNCBhcmUgXCJ5ZXNcIiB0aGVuIHdlJ3JlIG5lYXIgdGhlIGVuZCBvZiBhIG1vbWVudHVtIHNjcm9sbCBkZWNlbGVyYXRpb24uXG4gICAgICAgICAgLy8gU25hcCBpbW1lZGlhdGVseSBhbmQgaWdub3JlIHJlbWFpbmluZyB3aGVlbCBldmVudHMgaW4gdGhpcyBzY3JvbGwuXG4gICAgICAgICAgLy8gU2VlIGNvbW1lbnQgYWJvdmUgZm9yIFwicmVtYWluaW5nIHdoZWVsIGV2ZW50cyBpbiB0aGlzIHNjcm9sbFwiIGRldGVybWluYXRpb24uXG4gICAgICAgICAgLy8gSWYgMS00IGFyZW4ndCBzYXRpc2ZpZWQsIHRoZW4gd2FpdCB0byBzbmFwIHVudGlsIDUwMG1zIGFmdGVyIHRoZSBsYXN0IGV2ZW50LlxuICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICAgICAgICB0aW1lb3V0ID0gdW5kZWZpbmVkO1xuXG4gICAgICAgICAgaWYgKHJlY2VudFdoZWVsRXZlbnRzLmxlbmd0aCA+PSAxNSkge1xuICAgICAgICAgICAgcmVjZW50V2hlZWxFdmVudHMuc2hpZnQoKTsgLy8gb25seSBzdG9yZSB0aGUgbGFzdCBOIGV2ZW50c1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IHByZXZFdmVudCA9IHJlY2VudFdoZWVsRXZlbnRzLmxlbmd0aCA/IHJlY2VudFdoZWVsRXZlbnRzW3JlY2VudFdoZWVsRXZlbnRzLmxlbmd0aCAtIDFdIDogdW5kZWZpbmVkO1xuICAgICAgICAgIGNvbnN0IGZpcnN0RXZlbnQgPSByZWNlbnRXaGVlbEV2ZW50c1swXTtcbiAgICAgICAgICByZWNlbnRXaGVlbEV2ZW50cy5wdXNoKG5ld0V2ZW50KTtcblxuICAgICAgICAgIGlmIChwcmV2RXZlbnQgJiYgKG5ld0V2ZW50LmRlbHRhID4gcHJldkV2ZW50LmRlbHRhIHx8IG5ld0V2ZW50LmRpcmVjdGlvbiAhPT0gcHJldkV2ZW50LmRpcmVjdGlvbikpIHtcbiAgICAgICAgICAgIC8vIEluY3JlYXNpbmcgb3IgcmV2ZXJzZS1zaWduIGRlbHRhIG1lYW5zIHRoZSB1c2VyIHN0YXJ0ZWQgc2Nyb2xsaW5nIGFnYWluLiBDbGVhciB0aGUgd2hlZWwgZXZlbnQgbG9nLlxuICAgICAgICAgICAgcmVjZW50V2hlZWxFdmVudHMuc3BsaWNlKDApO1xuICAgICAgICAgIH0gZWxzZSBpZiAocmVjZW50V2hlZWxFdmVudHMubGVuZ3RoID49IDE1ICYmIG5ld0V2ZW50LnRpbWUgLSBmaXJzdEV2ZW50LnRpbWUgPCA1MDAgJiYgZmlyc3RFdmVudC5kZWx0YSAtIG5ld0V2ZW50LmRlbHRhID49IDEgJiYgbmV3RXZlbnQuZGVsdGEgPD0gNikge1xuICAgICAgICAgICAgLy8gV2UncmUgYXQgdGhlIGVuZCBvZiB0aGUgZGVjZWxlcmF0aW9uIG9mIGEgbW9tZW50dW0gc2Nyb2xsLCBzbyB0aGVyZSdzIG5vIG5lZWRcbiAgICAgICAgICAgIC8vIHRvIHdhaXQgZm9yIG1vcmUgZXZlbnRzLiBTbmFwIEFTQVAgb24gdGhlIG5leHQgdGljay5cbiAgICAgICAgICAgIC8vIEFsc28sIGJlY2F1c2UgdGhlcmUncyBzb21lIHJlbWFpbmluZyBtb21lbnR1bSB3ZSdsbCBiaWFzIHRoZSBzbmFwIGluIHRoZVxuICAgICAgICAgICAgLy8gZGlyZWN0aW9uIG9mIHRoZSBvbmdvaW5nIHNjcm9sbCBiZWNhdXNlIGl0J3MgYmV0dGVyIFVYIGZvciB0aGUgc2Nyb2xsIHRvIHNuYXBcbiAgICAgICAgICAgIC8vIGluIHRoZSBzYW1lIGRpcmVjdGlvbiBhcyB0aGUgc2Nyb2xsIGluc3RlYWQgb2YgcmV2ZXJzaW5nIHRvIHNuYXAuICBUaGVyZWZvcmUsXG4gICAgICAgICAgICAvLyBpZiBpdCdzIGFscmVhZHkgc2Nyb2xsZWQgbW9yZSB0aGFuIDIwJSBpbiB0aGUgY3VycmVudCBkaXJlY3Rpb24sIGtlZXAgZ29pbmcuXG4gICAgICAgICAgICBjb25zdCBzbmFwVG9UaHJlc2hvbGQgPSBkZWx0YSA+IDAgPyAwLjggOiAwLjI7XG4gICAgICAgICAgICBsYXN0RXZlbnRCZWZvcmVTbmFwID0gbmV3RXZlbnQ7XG4gICAgICAgICAgICByZWNlbnRXaGVlbEV2ZW50cy5zcGxpY2UoMCk7XG4gICAgICAgICAgICB0aW1lb3V0ID0gbmV4dFRpY2soKCkgPT4ge1xuICAgICAgICAgICAgICBzd2lwZXIuc2xpZGVUb0Nsb3Nlc3Qoc3dpcGVyLnBhcmFtcy5zcGVlZCwgdHJ1ZSwgdW5kZWZpbmVkLCBzbmFwVG9UaHJlc2hvbGQpO1xuICAgICAgICAgICAgfSwgMCk7IC8vIG5vIGRlbGF5OyBtb3ZlIG9uIG5leHQgdGlja1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICghdGltZW91dCkge1xuICAgICAgICAgICAgLy8gaWYgd2UgZ2V0IGhlcmUsIHRoZW4gd2UgaGF2ZW4ndCBkZXRlY3RlZCB0aGUgZW5kIG9mIGEgbW9tZW50dW0gc2Nyb2xsLCBzb1xuICAgICAgICAgICAgLy8gd2UnbGwgY29uc2lkZXIgYSBzY3JvbGwgXCJjb21wbGV0ZVwiIHdoZW4gdGhlcmUgaGF2ZW4ndCBiZWVuIGFueSB3aGVlbCBldmVudHNcbiAgICAgICAgICAgIC8vIGZvciA1MDBtcy5cbiAgICAgICAgICAgIHRpbWVvdXQgPSBuZXh0VGljaygoKSA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0IHNuYXBUb1RocmVzaG9sZCA9IDAuNTtcbiAgICAgICAgICAgICAgbGFzdEV2ZW50QmVmb3JlU25hcCA9IG5ld0V2ZW50O1xuICAgICAgICAgICAgICByZWNlbnRXaGVlbEV2ZW50cy5zcGxpY2UoMCk7XG4gICAgICAgICAgICAgIHN3aXBlci5zbGlkZVRvQ2xvc2VzdChzd2lwZXIucGFyYW1zLnNwZWVkLCB0cnVlLCB1bmRlZmluZWQsIHNuYXBUb1RocmVzaG9sZCk7XG4gICAgICAgICAgICB9LCA1MDApO1xuICAgICAgICAgIH1cbiAgICAgICAgfSAvLyBFbWl0IGV2ZW50XG5cblxuICAgICAgICBpZiAoIWlnbm9yZVdoZWVsRXZlbnRzKSBlbWl0KCdzY3JvbGwnLCBlKTsgLy8gU3RvcCBhdXRvcGxheVxuXG4gICAgICAgIGlmIChzd2lwZXIucGFyYW1zLmF1dG9wbGF5ICYmIHN3aXBlci5wYXJhbXMuYXV0b3BsYXlEaXNhYmxlT25JbnRlcmFjdGlvbikgc3dpcGVyLmF1dG9wbGF5LnN0b3AoKTsgLy8gUmV0dXJuIHBhZ2Ugc2Nyb2xsIG9uIGVkZ2UgcG9zaXRpb25zXG5cbiAgICAgICAgaWYgKHBvc2l0aW9uID09PSBzd2lwZXIubWluVHJhbnNsYXRlKCkgfHwgcG9zaXRpb24gPT09IHN3aXBlci5tYXhUcmFuc2xhdGUoKSkgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGUucHJldmVudERlZmF1bHQpIGUucHJldmVudERlZmF1bHQoKTtlbHNlIGUucmV0dXJuVmFsdWUgPSBmYWxzZTtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBmdW5jdGlvbiBldmVudHMobWV0aG9kKSB7XG4gICAgbGV0IHRhcmdldCA9IHN3aXBlci4kZWw7XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5tb3VzZXdoZWVsLmV2ZW50c1RhcmdldCAhPT0gJ2NvbnRhaW5lcicpIHtcbiAgICAgIHRhcmdldCA9ICQoc3dpcGVyLnBhcmFtcy5tb3VzZXdoZWVsLmV2ZW50c1RhcmdldCk7XG4gICAgfVxuXG4gICAgdGFyZ2V0W21ldGhvZF0oJ21vdXNlZW50ZXInLCBoYW5kbGVNb3VzZUVudGVyKTtcbiAgICB0YXJnZXRbbWV0aG9kXSgnbW91c2VsZWF2ZScsIGhhbmRsZU1vdXNlTGVhdmUpO1xuICAgIHRhcmdldFttZXRob2RdKCd3aGVlbCcsIGhhbmRsZSk7XG4gIH1cblxuICBmdW5jdGlvbiBlbmFibGUoKSB7XG4gICAgaWYgKHN3aXBlci5wYXJhbXMuY3NzTW9kZSkge1xuICAgICAgc3dpcGVyLndyYXBwZXJFbC5yZW1vdmVFdmVudExpc3RlbmVyKCd3aGVlbCcsIGhhbmRsZSk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICBpZiAoc3dpcGVyLm1vdXNld2hlZWwuZW5hYmxlZCkgcmV0dXJuIGZhbHNlO1xuICAgIGV2ZW50cygnb24nKTtcbiAgICBzd2lwZXIubW91c2V3aGVlbC5lbmFibGVkID0gdHJ1ZTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGRpc2FibGUoKSB7XG4gICAgaWYgKHN3aXBlci5wYXJhbXMuY3NzTW9kZSkge1xuICAgICAgc3dpcGVyLndyYXBwZXJFbC5hZGRFdmVudExpc3RlbmVyKGV2ZW50LCBoYW5kbGUpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgaWYgKCFzd2lwZXIubW91c2V3aGVlbC5lbmFibGVkKSByZXR1cm4gZmFsc2U7XG4gICAgZXZlbnRzKCdvZmYnKTtcbiAgICBzd2lwZXIubW91c2V3aGVlbC5lbmFibGVkID0gZmFsc2U7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBvbignaW5pdCcsICgpID0+IHtcbiAgICBpZiAoIXN3aXBlci5wYXJhbXMubW91c2V3aGVlbC5lbmFibGVkICYmIHN3aXBlci5wYXJhbXMuY3NzTW9kZSkge1xuICAgICAgZGlzYWJsZSgpO1xuICAgIH1cblxuICAgIGlmIChzd2lwZXIucGFyYW1zLm1vdXNld2hlZWwuZW5hYmxlZCkgZW5hYmxlKCk7XG4gIH0pO1xuICBvbignZGVzdHJveScsICgpID0+IHtcbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5jc3NNb2RlKSB7XG4gICAgICBlbmFibGUoKTtcbiAgICB9XG5cbiAgICBpZiAoc3dpcGVyLm1vdXNld2hlZWwuZW5hYmxlZCkgZGlzYWJsZSgpO1xuICB9KTtcbiAgT2JqZWN0LmFzc2lnbihzd2lwZXIubW91c2V3aGVlbCwge1xuICAgIGVuYWJsZSxcbiAgICBkaXNhYmxlXG4gIH0pO1xufSIsImltcG9ydCB7IGdldERvY3VtZW50IH0gZnJvbSAnc3NyLXdpbmRvdyc7XG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBjcmVhdGVFbGVtZW50SWZOb3REZWZpbmVkKHN3aXBlciwgb3JpZ2luYWxQYXJhbXMsIHBhcmFtcywgY2hlY2tQcm9wcykge1xuICBjb25zdCBkb2N1bWVudCA9IGdldERvY3VtZW50KCk7XG5cbiAgaWYgKHN3aXBlci5wYXJhbXMuY3JlYXRlRWxlbWVudHMpIHtcbiAgICBPYmplY3Qua2V5cyhjaGVja1Byb3BzKS5mb3JFYWNoKGtleSA9PiB7XG4gICAgICBpZiAoIXBhcmFtc1trZXldICYmIHBhcmFtcy5hdXRvID09PSB0cnVlKSB7XG4gICAgICAgIGxldCBlbGVtZW50ID0gc3dpcGVyLiRlbC5jaGlsZHJlbihgLiR7Y2hlY2tQcm9wc1trZXldfWApWzBdO1xuXG4gICAgICAgIGlmICghZWxlbWVudCkge1xuICAgICAgICAgIGVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICAgICAgICBlbGVtZW50LmNsYXNzTmFtZSA9IGNoZWNrUHJvcHNba2V5XTtcbiAgICAgICAgICBzd2lwZXIuJGVsLmFwcGVuZChlbGVtZW50KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHBhcmFtc1trZXldID0gZWxlbWVudDtcbiAgICAgICAgb3JpZ2luYWxQYXJhbXNba2V5XSA9IGVsZW1lbnQ7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gcGFyYW1zO1xufSIsImltcG9ydCBjcmVhdGVFbGVtZW50SWZOb3REZWZpbmVkIGZyb20gJy4uLy4uL3NoYXJlZC9jcmVhdGUtZWxlbWVudC1pZi1ub3QtZGVmaW5lZC5qcyc7XG5pbXBvcnQgJCBmcm9tICcuLi8uLi9zaGFyZWQvZG9tLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIE5hdmlnYXRpb24oe1xuICBzd2lwZXIsXG4gIGV4dGVuZFBhcmFtcyxcbiAgb24sXG4gIGVtaXRcbn0pIHtcbiAgZXh0ZW5kUGFyYW1zKHtcbiAgICBuYXZpZ2F0aW9uOiB7XG4gICAgICBuZXh0RWw6IG51bGwsXG4gICAgICBwcmV2RWw6IG51bGwsXG4gICAgICBoaWRlT25DbGljazogZmFsc2UsXG4gICAgICBkaXNhYmxlZENsYXNzOiAnc3dpcGVyLWJ1dHRvbi1kaXNhYmxlZCcsXG4gICAgICBoaWRkZW5DbGFzczogJ3N3aXBlci1idXR0b24taGlkZGVuJyxcbiAgICAgIGxvY2tDbGFzczogJ3N3aXBlci1idXR0b24tbG9jaycsXG4gICAgICBuYXZpZ2F0aW9uRGlzYWJsZWRDbGFzczogJ3N3aXBlci1uYXZpZ2F0aW9uLWRpc2FibGVkJ1xuICAgIH1cbiAgfSk7XG4gIHN3aXBlci5uYXZpZ2F0aW9uID0ge1xuICAgIG5leHRFbDogbnVsbCxcbiAgICAkbmV4dEVsOiBudWxsLFxuICAgIHByZXZFbDogbnVsbCxcbiAgICAkcHJldkVsOiBudWxsXG4gIH07XG5cbiAgZnVuY3Rpb24gZ2V0RWwoZWwpIHtcbiAgICBsZXQgJGVsO1xuXG4gICAgaWYgKGVsKSB7XG4gICAgICAkZWwgPSAkKGVsKTtcblxuICAgICAgaWYgKHN3aXBlci5wYXJhbXMudW5pcXVlTmF2RWxlbWVudHMgJiYgdHlwZW9mIGVsID09PSAnc3RyaW5nJyAmJiAkZWwubGVuZ3RoID4gMSAmJiBzd2lwZXIuJGVsLmZpbmQoZWwpLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAkZWwgPSBzd2lwZXIuJGVsLmZpbmQoZWwpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiAkZWw7XG4gIH1cblxuICBmdW5jdGlvbiB0b2dnbGVFbCgkZWwsIGRpc2FibGVkKSB7XG4gICAgY29uc3QgcGFyYW1zID0gc3dpcGVyLnBhcmFtcy5uYXZpZ2F0aW9uO1xuXG4gICAgaWYgKCRlbCAmJiAkZWwubGVuZ3RoID4gMCkge1xuICAgICAgJGVsW2Rpc2FibGVkID8gJ2FkZENsYXNzJyA6ICdyZW1vdmVDbGFzcyddKHBhcmFtcy5kaXNhYmxlZENsYXNzKTtcbiAgICAgIGlmICgkZWxbMF0gJiYgJGVsWzBdLnRhZ05hbWUgPT09ICdCVVRUT04nKSAkZWxbMF0uZGlzYWJsZWQgPSBkaXNhYmxlZDtcblxuICAgICAgaWYgKHN3aXBlci5wYXJhbXMud2F0Y2hPdmVyZmxvdyAmJiBzd2lwZXIuZW5hYmxlZCkge1xuICAgICAgICAkZWxbc3dpcGVyLmlzTG9ja2VkID8gJ2FkZENsYXNzJyA6ICdyZW1vdmVDbGFzcyddKHBhcmFtcy5sb2NrQ2xhc3MpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIHVwZGF0ZSgpIHtcbiAgICAvLyBVcGRhdGUgTmF2aWdhdGlvbiBCdXR0b25zXG4gICAgaWYgKHN3aXBlci5wYXJhbXMubG9vcCkgcmV0dXJuO1xuICAgIGNvbnN0IHtcbiAgICAgICRuZXh0RWwsXG4gICAgICAkcHJldkVsXG4gICAgfSA9IHN3aXBlci5uYXZpZ2F0aW9uO1xuICAgIHRvZ2dsZUVsKCRwcmV2RWwsIHN3aXBlci5pc0JlZ2lubmluZyAmJiAhc3dpcGVyLnBhcmFtcy5yZXdpbmQpO1xuICAgIHRvZ2dsZUVsKCRuZXh0RWwsIHN3aXBlci5pc0VuZCAmJiAhc3dpcGVyLnBhcmFtcy5yZXdpbmQpO1xuICB9XG5cbiAgZnVuY3Rpb24gb25QcmV2Q2xpY2soZSkge1xuICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICBpZiAoc3dpcGVyLmlzQmVnaW5uaW5nICYmICFzd2lwZXIucGFyYW1zLmxvb3AgJiYgIXN3aXBlci5wYXJhbXMucmV3aW5kKSByZXR1cm47XG4gICAgc3dpcGVyLnNsaWRlUHJldigpO1xuICAgIGVtaXQoJ25hdmlnYXRpb25QcmV2Jyk7XG4gIH1cblxuICBmdW5jdGlvbiBvbk5leHRDbGljayhlKSB7XG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGlmIChzd2lwZXIuaXNFbmQgJiYgIXN3aXBlci5wYXJhbXMubG9vcCAmJiAhc3dpcGVyLnBhcmFtcy5yZXdpbmQpIHJldHVybjtcbiAgICBzd2lwZXIuc2xpZGVOZXh0KCk7XG4gICAgZW1pdCgnbmF2aWdhdGlvbk5leHQnKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGluaXQoKSB7XG4gICAgY29uc3QgcGFyYW1zID0gc3dpcGVyLnBhcmFtcy5uYXZpZ2F0aW9uO1xuICAgIHN3aXBlci5wYXJhbXMubmF2aWdhdGlvbiA9IGNyZWF0ZUVsZW1lbnRJZk5vdERlZmluZWQoc3dpcGVyLCBzd2lwZXIub3JpZ2luYWxQYXJhbXMubmF2aWdhdGlvbiwgc3dpcGVyLnBhcmFtcy5uYXZpZ2F0aW9uLCB7XG4gICAgICBuZXh0RWw6ICdzd2lwZXItYnV0dG9uLW5leHQnLFxuICAgICAgcHJldkVsOiAnc3dpcGVyLWJ1dHRvbi1wcmV2J1xuICAgIH0pO1xuICAgIGlmICghKHBhcmFtcy5uZXh0RWwgfHwgcGFyYW1zLnByZXZFbCkpIHJldHVybjtcbiAgICBjb25zdCAkbmV4dEVsID0gZ2V0RWwocGFyYW1zLm5leHRFbCk7XG4gICAgY29uc3QgJHByZXZFbCA9IGdldEVsKHBhcmFtcy5wcmV2RWwpO1xuXG4gICAgaWYgKCRuZXh0RWwgJiYgJG5leHRFbC5sZW5ndGggPiAwKSB7XG4gICAgICAkbmV4dEVsLm9uKCdjbGljaycsIG9uTmV4dENsaWNrKTtcbiAgICB9XG5cbiAgICBpZiAoJHByZXZFbCAmJiAkcHJldkVsLmxlbmd0aCA+IDApIHtcbiAgICAgICRwcmV2RWwub24oJ2NsaWNrJywgb25QcmV2Q2xpY2spO1xuICAgIH1cblxuICAgIE9iamVjdC5hc3NpZ24oc3dpcGVyLm5hdmlnYXRpb24sIHtcbiAgICAgICRuZXh0RWwsXG4gICAgICBuZXh0RWw6ICRuZXh0RWwgJiYgJG5leHRFbFswXSxcbiAgICAgICRwcmV2RWwsXG4gICAgICBwcmV2RWw6ICRwcmV2RWwgJiYgJHByZXZFbFswXVxuICAgIH0pO1xuXG4gICAgaWYgKCFzd2lwZXIuZW5hYmxlZCkge1xuICAgICAgaWYgKCRuZXh0RWwpICRuZXh0RWwuYWRkQ2xhc3MocGFyYW1zLmxvY2tDbGFzcyk7XG4gICAgICBpZiAoJHByZXZFbCkgJHByZXZFbC5hZGRDbGFzcyhwYXJhbXMubG9ja0NsYXNzKTtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBkZXN0cm95KCkge1xuICAgIGNvbnN0IHtcbiAgICAgICRuZXh0RWwsXG4gICAgICAkcHJldkVsXG4gICAgfSA9IHN3aXBlci5uYXZpZ2F0aW9uO1xuXG4gICAgaWYgKCRuZXh0RWwgJiYgJG5leHRFbC5sZW5ndGgpIHtcbiAgICAgICRuZXh0RWwub2ZmKCdjbGljaycsIG9uTmV4dENsaWNrKTtcbiAgICAgICRuZXh0RWwucmVtb3ZlQ2xhc3Moc3dpcGVyLnBhcmFtcy5uYXZpZ2F0aW9uLmRpc2FibGVkQ2xhc3MpO1xuICAgIH1cblxuICAgIGlmICgkcHJldkVsICYmICRwcmV2RWwubGVuZ3RoKSB7XG4gICAgICAkcHJldkVsLm9mZignY2xpY2snLCBvblByZXZDbGljayk7XG4gICAgICAkcHJldkVsLnJlbW92ZUNsYXNzKHN3aXBlci5wYXJhbXMubmF2aWdhdGlvbi5kaXNhYmxlZENsYXNzKTtcbiAgICB9XG4gIH1cblxuICBvbignaW5pdCcsICgpID0+IHtcbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5uYXZpZ2F0aW9uLmVuYWJsZWQgPT09IGZhbHNlKSB7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmVcbiAgICAgIGRpc2FibGUoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaW5pdCgpO1xuICAgICAgdXBkYXRlKCk7XG4gICAgfVxuICB9KTtcbiAgb24oJ3RvRWRnZSBmcm9tRWRnZSBsb2NrIHVubG9jaycsICgpID0+IHtcbiAgICB1cGRhdGUoKTtcbiAgfSk7XG4gIG9uKCdkZXN0cm95JywgKCkgPT4ge1xuICAgIGRlc3Ryb3koKTtcbiAgfSk7XG4gIG9uKCdlbmFibGUgZGlzYWJsZScsICgpID0+IHtcbiAgICBjb25zdCB7XG4gICAgICAkbmV4dEVsLFxuICAgICAgJHByZXZFbFxuICAgIH0gPSBzd2lwZXIubmF2aWdhdGlvbjtcblxuICAgIGlmICgkbmV4dEVsKSB7XG4gICAgICAkbmV4dEVsW3N3aXBlci5lbmFibGVkID8gJ3JlbW92ZUNsYXNzJyA6ICdhZGRDbGFzcyddKHN3aXBlci5wYXJhbXMubmF2aWdhdGlvbi5sb2NrQ2xhc3MpO1xuICAgIH1cblxuICAgIGlmICgkcHJldkVsKSB7XG4gICAgICAkcHJldkVsW3N3aXBlci5lbmFibGVkID8gJ3JlbW92ZUNsYXNzJyA6ICdhZGRDbGFzcyddKHN3aXBlci5wYXJhbXMubmF2aWdhdGlvbi5sb2NrQ2xhc3MpO1xuICAgIH1cbiAgfSk7XG4gIG9uKCdjbGljaycsIChfcywgZSkgPT4ge1xuICAgIGNvbnN0IHtcbiAgICAgICRuZXh0RWwsXG4gICAgICAkcHJldkVsXG4gICAgfSA9IHN3aXBlci5uYXZpZ2F0aW9uO1xuICAgIGNvbnN0IHRhcmdldEVsID0gZS50YXJnZXQ7XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5uYXZpZ2F0aW9uLmhpZGVPbkNsaWNrICYmICEkKHRhcmdldEVsKS5pcygkcHJldkVsKSAmJiAhJCh0YXJnZXRFbCkuaXMoJG5leHRFbCkpIHtcbiAgICAgIGlmIChzd2lwZXIucGFnaW5hdGlvbiAmJiBzd2lwZXIucGFyYW1zLnBhZ2luYXRpb24gJiYgc3dpcGVyLnBhcmFtcy5wYWdpbmF0aW9uLmNsaWNrYWJsZSAmJiAoc3dpcGVyLnBhZ2luYXRpb24uZWwgPT09IHRhcmdldEVsIHx8IHN3aXBlci5wYWdpbmF0aW9uLmVsLmNvbnRhaW5zKHRhcmdldEVsKSkpIHJldHVybjtcbiAgICAgIGxldCBpc0hpZGRlbjtcblxuICAgICAgaWYgKCRuZXh0RWwpIHtcbiAgICAgICAgaXNIaWRkZW4gPSAkbmV4dEVsLmhhc0NsYXNzKHN3aXBlci5wYXJhbXMubmF2aWdhdGlvbi5oaWRkZW5DbGFzcyk7XG4gICAgICB9IGVsc2UgaWYgKCRwcmV2RWwpIHtcbiAgICAgICAgaXNIaWRkZW4gPSAkcHJldkVsLmhhc0NsYXNzKHN3aXBlci5wYXJhbXMubmF2aWdhdGlvbi5oaWRkZW5DbGFzcyk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0hpZGRlbiA9PT0gdHJ1ZSkge1xuICAgICAgICBlbWl0KCduYXZpZ2F0aW9uU2hvdycpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZW1pdCgnbmF2aWdhdGlvbkhpZGUnKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCRuZXh0RWwpIHtcbiAgICAgICAgJG5leHRFbC50b2dnbGVDbGFzcyhzd2lwZXIucGFyYW1zLm5hdmlnYXRpb24uaGlkZGVuQ2xhc3MpO1xuICAgICAgfVxuXG4gICAgICBpZiAoJHByZXZFbCkge1xuICAgICAgICAkcHJldkVsLnRvZ2dsZUNsYXNzKHN3aXBlci5wYXJhbXMubmF2aWdhdGlvbi5oaWRkZW5DbGFzcyk7XG4gICAgICB9XG4gICAgfVxuICB9KTtcblxuICBjb25zdCBlbmFibGUgPSAoKSA9PiB7XG4gICAgc3dpcGVyLiRlbC5yZW1vdmVDbGFzcyhzd2lwZXIucGFyYW1zLm5hdmlnYXRpb24ubmF2aWdhdGlvbkRpc2FibGVkQ2xhc3MpO1xuICAgIGluaXQoKTtcbiAgICB1cGRhdGUoKTtcbiAgfTtcblxuICBjb25zdCBkaXNhYmxlID0gKCkgPT4ge1xuICAgIHN3aXBlci4kZWwuYWRkQ2xhc3Moc3dpcGVyLnBhcmFtcy5uYXZpZ2F0aW9uLm5hdmlnYXRpb25EaXNhYmxlZENsYXNzKTtcbiAgICBkZXN0cm95KCk7XG4gIH07XG5cbiAgT2JqZWN0LmFzc2lnbihzd2lwZXIubmF2aWdhdGlvbiwge1xuICAgIGVuYWJsZSxcbiAgICBkaXNhYmxlLFxuICAgIHVwZGF0ZSxcbiAgICBpbml0LFxuICAgIGRlc3Ryb3lcbiAgfSk7XG59IiwiaW1wb3J0ICQgZnJvbSAnLi4vLi4vc2hhcmVkL2RvbS5qcyc7XG5pbXBvcnQgY2xhc3Nlc1RvU2VsZWN0b3IgZnJvbSAnLi4vLi4vc2hhcmVkL2NsYXNzZXMtdG8tc2VsZWN0b3IuanMnO1xuaW1wb3J0IGNyZWF0ZUVsZW1lbnRJZk5vdERlZmluZWQgZnJvbSAnLi4vLi4vc2hhcmVkL2NyZWF0ZS1lbGVtZW50LWlmLW5vdC1kZWZpbmVkLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIFBhZ2luYXRpb24oe1xuICBzd2lwZXIsXG4gIGV4dGVuZFBhcmFtcyxcbiAgb24sXG4gIGVtaXRcbn0pIHtcbiAgY29uc3QgcGZ4ID0gJ3N3aXBlci1wYWdpbmF0aW9uJztcbiAgZXh0ZW5kUGFyYW1zKHtcbiAgICBwYWdpbmF0aW9uOiB7XG4gICAgICBlbDogbnVsbCxcbiAgICAgIGJ1bGxldEVsZW1lbnQ6ICdzcGFuJyxcbiAgICAgIGNsaWNrYWJsZTogZmFsc2UsXG4gICAgICBoaWRlT25DbGljazogZmFsc2UsXG4gICAgICByZW5kZXJCdWxsZXQ6IG51bGwsXG4gICAgICByZW5kZXJQcm9ncmVzc2JhcjogbnVsbCxcbiAgICAgIHJlbmRlckZyYWN0aW9uOiBudWxsLFxuICAgICAgcmVuZGVyQ3VzdG9tOiBudWxsLFxuICAgICAgcHJvZ3Jlc3NiYXJPcHBvc2l0ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYnVsbGV0cycsXG4gICAgICAvLyAnYnVsbGV0cycgb3IgJ3Byb2dyZXNzYmFyJyBvciAnZnJhY3Rpb24nIG9yICdjdXN0b20nXG4gICAgICBkeW5hbWljQnVsbGV0czogZmFsc2UsXG4gICAgICBkeW5hbWljTWFpbkJ1bGxldHM6IDEsXG4gICAgICBmb3JtYXRGcmFjdGlvbkN1cnJlbnQ6IG51bWJlciA9PiBudW1iZXIsXG4gICAgICBmb3JtYXRGcmFjdGlvblRvdGFsOiBudW1iZXIgPT4gbnVtYmVyLFxuICAgICAgYnVsbGV0Q2xhc3M6IGAke3BmeH0tYnVsbGV0YCxcbiAgICAgIGJ1bGxldEFjdGl2ZUNsYXNzOiBgJHtwZnh9LWJ1bGxldC1hY3RpdmVgLFxuICAgICAgbW9kaWZpZXJDbGFzczogYCR7cGZ4fS1gLFxuICAgICAgY3VycmVudENsYXNzOiBgJHtwZnh9LWN1cnJlbnRgLFxuICAgICAgdG90YWxDbGFzczogYCR7cGZ4fS10b3RhbGAsXG4gICAgICBoaWRkZW5DbGFzczogYCR7cGZ4fS1oaWRkZW5gLFxuICAgICAgcHJvZ3Jlc3NiYXJGaWxsQ2xhc3M6IGAke3BmeH0tcHJvZ3Jlc3NiYXItZmlsbGAsXG4gICAgICBwcm9ncmVzc2Jhck9wcG9zaXRlQ2xhc3M6IGAke3BmeH0tcHJvZ3Jlc3NiYXItb3Bwb3NpdGVgLFxuICAgICAgY2xpY2thYmxlQ2xhc3M6IGAke3BmeH0tY2xpY2thYmxlYCxcbiAgICAgIGxvY2tDbGFzczogYCR7cGZ4fS1sb2NrYCxcbiAgICAgIGhvcml6b250YWxDbGFzczogYCR7cGZ4fS1ob3Jpem9udGFsYCxcbiAgICAgIHZlcnRpY2FsQ2xhc3M6IGAke3BmeH0tdmVydGljYWxgLFxuICAgICAgcGFnaW5hdGlvbkRpc2FibGVkQ2xhc3M6IGAke3BmeH0tZGlzYWJsZWRgXG4gICAgfVxuICB9KTtcbiAgc3dpcGVyLnBhZ2luYXRpb24gPSB7XG4gICAgZWw6IG51bGwsXG4gICAgJGVsOiBudWxsLFxuICAgIGJ1bGxldHM6IFtdXG4gIH07XG4gIGxldCBidWxsZXRTaXplO1xuICBsZXQgZHluYW1pY0J1bGxldEluZGV4ID0gMDtcblxuICBmdW5jdGlvbiBpc1BhZ2luYXRpb25EaXNhYmxlZCgpIHtcbiAgICByZXR1cm4gIXN3aXBlci5wYXJhbXMucGFnaW5hdGlvbi5lbCB8fCAhc3dpcGVyLnBhZ2luYXRpb24uZWwgfHwgIXN3aXBlci5wYWdpbmF0aW9uLiRlbCB8fCBzd2lwZXIucGFnaW5hdGlvbi4kZWwubGVuZ3RoID09PSAwO1xuICB9XG5cbiAgZnVuY3Rpb24gc2V0U2lkZUJ1bGxldHMoJGJ1bGxldEVsLCBwb3NpdGlvbikge1xuICAgIGNvbnN0IHtcbiAgICAgIGJ1bGxldEFjdGl2ZUNsYXNzXG4gICAgfSA9IHN3aXBlci5wYXJhbXMucGFnaW5hdGlvbjtcbiAgICAkYnVsbGV0RWxbcG9zaXRpb25dKCkuYWRkQ2xhc3MoYCR7YnVsbGV0QWN0aXZlQ2xhc3N9LSR7cG9zaXRpb259YClbcG9zaXRpb25dKCkuYWRkQ2xhc3MoYCR7YnVsbGV0QWN0aXZlQ2xhc3N9LSR7cG9zaXRpb259LSR7cG9zaXRpb259YCk7XG4gIH1cblxuICBmdW5jdGlvbiB1cGRhdGUoKSB7XG4gICAgLy8gUmVuZGVyIHx8IFVwZGF0ZSBQYWdpbmF0aW9uIGJ1bGxldHMvaXRlbXNcbiAgICBjb25zdCBydGwgPSBzd2lwZXIucnRsO1xuICAgIGNvbnN0IHBhcmFtcyA9IHN3aXBlci5wYXJhbXMucGFnaW5hdGlvbjtcbiAgICBpZiAoaXNQYWdpbmF0aW9uRGlzYWJsZWQoKSkgcmV0dXJuO1xuICAgIGNvbnN0IHNsaWRlc0xlbmd0aCA9IHN3aXBlci52aXJ0dWFsICYmIHN3aXBlci5wYXJhbXMudmlydHVhbC5lbmFibGVkID8gc3dpcGVyLnZpcnR1YWwuc2xpZGVzLmxlbmd0aCA6IHN3aXBlci5zbGlkZXMubGVuZ3RoO1xuICAgIGNvbnN0ICRlbCA9IHN3aXBlci5wYWdpbmF0aW9uLiRlbDsgLy8gQ3VycmVudC9Ub3RhbFxuXG4gICAgbGV0IGN1cnJlbnQ7XG4gICAgY29uc3QgdG90YWwgPSBzd2lwZXIucGFyYW1zLmxvb3AgPyBNYXRoLmNlaWwoKHNsaWRlc0xlbmd0aCAtIHN3aXBlci5sb29wZWRTbGlkZXMgKiAyKSAvIHN3aXBlci5wYXJhbXMuc2xpZGVzUGVyR3JvdXApIDogc3dpcGVyLnNuYXBHcmlkLmxlbmd0aDtcblxuICAgIGlmIChzd2lwZXIucGFyYW1zLmxvb3ApIHtcbiAgICAgIGN1cnJlbnQgPSBNYXRoLmNlaWwoKHN3aXBlci5hY3RpdmVJbmRleCAtIHN3aXBlci5sb29wZWRTbGlkZXMpIC8gc3dpcGVyLnBhcmFtcy5zbGlkZXNQZXJHcm91cCk7XG5cbiAgICAgIGlmIChjdXJyZW50ID4gc2xpZGVzTGVuZ3RoIC0gMSAtIHN3aXBlci5sb29wZWRTbGlkZXMgKiAyKSB7XG4gICAgICAgIGN1cnJlbnQgLT0gc2xpZGVzTGVuZ3RoIC0gc3dpcGVyLmxvb3BlZFNsaWRlcyAqIDI7XG4gICAgICB9XG5cbiAgICAgIGlmIChjdXJyZW50ID4gdG90YWwgLSAxKSBjdXJyZW50IC09IHRvdGFsO1xuICAgICAgaWYgKGN1cnJlbnQgPCAwICYmIHN3aXBlci5wYXJhbXMucGFnaW5hdGlvblR5cGUgIT09ICdidWxsZXRzJykgY3VycmVudCA9IHRvdGFsICsgY3VycmVudDtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBzd2lwZXIuc25hcEluZGV4ICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgY3VycmVudCA9IHN3aXBlci5zbmFwSW5kZXg7XG4gICAgfSBlbHNlIHtcbiAgICAgIGN1cnJlbnQgPSBzd2lwZXIuYWN0aXZlSW5kZXggfHwgMDtcbiAgICB9IC8vIFR5cGVzXG5cblxuICAgIGlmIChwYXJhbXMudHlwZSA9PT0gJ2J1bGxldHMnICYmIHN3aXBlci5wYWdpbmF0aW9uLmJ1bGxldHMgJiYgc3dpcGVyLnBhZ2luYXRpb24uYnVsbGV0cy5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBidWxsZXRzID0gc3dpcGVyLnBhZ2luYXRpb24uYnVsbGV0cztcbiAgICAgIGxldCBmaXJzdEluZGV4O1xuICAgICAgbGV0IGxhc3RJbmRleDtcbiAgICAgIGxldCBtaWRJbmRleDtcblxuICAgICAgaWYgKHBhcmFtcy5keW5hbWljQnVsbGV0cykge1xuICAgICAgICBidWxsZXRTaXplID0gYnVsbGV0cy5lcSgwKVtzd2lwZXIuaXNIb3Jpem9udGFsKCkgPyAnb3V0ZXJXaWR0aCcgOiAnb3V0ZXJIZWlnaHQnXSh0cnVlKTtcbiAgICAgICAgJGVsLmNzcyhzd2lwZXIuaXNIb3Jpem9udGFsKCkgPyAnd2lkdGgnIDogJ2hlaWdodCcsIGAke2J1bGxldFNpemUgKiAocGFyYW1zLmR5bmFtaWNNYWluQnVsbGV0cyArIDQpfXB4YCk7XG5cbiAgICAgICAgaWYgKHBhcmFtcy5keW5hbWljTWFpbkJ1bGxldHMgPiAxICYmIHN3aXBlci5wcmV2aW91c0luZGV4ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBkeW5hbWljQnVsbGV0SW5kZXggKz0gY3VycmVudCAtIChzd2lwZXIucHJldmlvdXNJbmRleCAtIHN3aXBlci5sb29wZWRTbGlkZXMgfHwgMCk7XG5cbiAgICAgICAgICBpZiAoZHluYW1pY0J1bGxldEluZGV4ID4gcGFyYW1zLmR5bmFtaWNNYWluQnVsbGV0cyAtIDEpIHtcbiAgICAgICAgICAgIGR5bmFtaWNCdWxsZXRJbmRleCA9IHBhcmFtcy5keW5hbWljTWFpbkJ1bGxldHMgLSAxO1xuICAgICAgICAgIH0gZWxzZSBpZiAoZHluYW1pY0J1bGxldEluZGV4IDwgMCkge1xuICAgICAgICAgICAgZHluYW1pY0J1bGxldEluZGV4ID0gMDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmaXJzdEluZGV4ID0gTWF0aC5tYXgoY3VycmVudCAtIGR5bmFtaWNCdWxsZXRJbmRleCwgMCk7XG4gICAgICAgIGxhc3RJbmRleCA9IGZpcnN0SW5kZXggKyAoTWF0aC5taW4oYnVsbGV0cy5sZW5ndGgsIHBhcmFtcy5keW5hbWljTWFpbkJ1bGxldHMpIC0gMSk7XG4gICAgICAgIG1pZEluZGV4ID0gKGxhc3RJbmRleCArIGZpcnN0SW5kZXgpIC8gMjtcbiAgICAgIH1cblxuICAgICAgYnVsbGV0cy5yZW1vdmVDbGFzcyhbJycsICctbmV4dCcsICctbmV4dC1uZXh0JywgJy1wcmV2JywgJy1wcmV2LXByZXYnLCAnLW1haW4nXS5tYXAoc3VmZml4ID0+IGAke3BhcmFtcy5idWxsZXRBY3RpdmVDbGFzc30ke3N1ZmZpeH1gKS5qb2luKCcgJykpO1xuXG4gICAgICBpZiAoJGVsLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgYnVsbGV0cy5lYWNoKGJ1bGxldCA9PiB7XG4gICAgICAgICAgY29uc3QgJGJ1bGxldCA9ICQoYnVsbGV0KTtcbiAgICAgICAgICBjb25zdCBidWxsZXRJbmRleCA9ICRidWxsZXQuaW5kZXgoKTtcblxuICAgICAgICAgIGlmIChidWxsZXRJbmRleCA9PT0gY3VycmVudCkge1xuICAgICAgICAgICAgJGJ1bGxldC5hZGRDbGFzcyhwYXJhbXMuYnVsbGV0QWN0aXZlQ2xhc3MpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChwYXJhbXMuZHluYW1pY0J1bGxldHMpIHtcbiAgICAgICAgICAgIGlmIChidWxsZXRJbmRleCA+PSBmaXJzdEluZGV4ICYmIGJ1bGxldEluZGV4IDw9IGxhc3RJbmRleCkge1xuICAgICAgICAgICAgICAkYnVsbGV0LmFkZENsYXNzKGAke3BhcmFtcy5idWxsZXRBY3RpdmVDbGFzc30tbWFpbmApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoYnVsbGV0SW5kZXggPT09IGZpcnN0SW5kZXgpIHtcbiAgICAgICAgICAgICAgc2V0U2lkZUJ1bGxldHMoJGJ1bGxldCwgJ3ByZXYnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGJ1bGxldEluZGV4ID09PSBsYXN0SW5kZXgpIHtcbiAgICAgICAgICAgICAgc2V0U2lkZUJ1bGxldHMoJGJ1bGxldCwgJ25leHQnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgJGJ1bGxldCA9IGJ1bGxldHMuZXEoY3VycmVudCk7XG4gICAgICAgIGNvbnN0IGJ1bGxldEluZGV4ID0gJGJ1bGxldC5pbmRleCgpO1xuICAgICAgICAkYnVsbGV0LmFkZENsYXNzKHBhcmFtcy5idWxsZXRBY3RpdmVDbGFzcyk7XG5cbiAgICAgICAgaWYgKHBhcmFtcy5keW5hbWljQnVsbGV0cykge1xuICAgICAgICAgIGNvbnN0ICRmaXJzdERpc3BsYXllZEJ1bGxldCA9IGJ1bGxldHMuZXEoZmlyc3RJbmRleCk7XG4gICAgICAgICAgY29uc3QgJGxhc3REaXNwbGF5ZWRCdWxsZXQgPSBidWxsZXRzLmVxKGxhc3RJbmRleCk7XG5cbiAgICAgICAgICBmb3IgKGxldCBpID0gZmlyc3RJbmRleDsgaSA8PSBsYXN0SW5kZXg7IGkgKz0gMSkge1xuICAgICAgICAgICAgYnVsbGV0cy5lcShpKS5hZGRDbGFzcyhgJHtwYXJhbXMuYnVsbGV0QWN0aXZlQ2xhc3N9LW1haW5gKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoc3dpcGVyLnBhcmFtcy5sb29wKSB7XG4gICAgICAgICAgICBpZiAoYnVsbGV0SW5kZXggPj0gYnVsbGV0cy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IHBhcmFtcy5keW5hbWljTWFpbkJ1bGxldHM7IGkgPj0gMDsgaSAtPSAxKSB7XG4gICAgICAgICAgICAgICAgYnVsbGV0cy5lcShidWxsZXRzLmxlbmd0aCAtIGkpLmFkZENsYXNzKGAke3BhcmFtcy5idWxsZXRBY3RpdmVDbGFzc30tbWFpbmApO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgYnVsbGV0cy5lcShidWxsZXRzLmxlbmd0aCAtIHBhcmFtcy5keW5hbWljTWFpbkJ1bGxldHMgLSAxKS5hZGRDbGFzcyhgJHtwYXJhbXMuYnVsbGV0QWN0aXZlQ2xhc3N9LXByZXZgKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHNldFNpZGVCdWxsZXRzKCRmaXJzdERpc3BsYXllZEJ1bGxldCwgJ3ByZXYnKTtcbiAgICAgICAgICAgICAgc2V0U2lkZUJ1bGxldHMoJGxhc3REaXNwbGF5ZWRCdWxsZXQsICduZXh0Jyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHNldFNpZGVCdWxsZXRzKCRmaXJzdERpc3BsYXllZEJ1bGxldCwgJ3ByZXYnKTtcbiAgICAgICAgICAgIHNldFNpZGVCdWxsZXRzKCRsYXN0RGlzcGxheWVkQnVsbGV0LCAnbmV4dCcpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAocGFyYW1zLmR5bmFtaWNCdWxsZXRzKSB7XG4gICAgICAgIGNvbnN0IGR5bmFtaWNCdWxsZXRzTGVuZ3RoID0gTWF0aC5taW4oYnVsbGV0cy5sZW5ndGgsIHBhcmFtcy5keW5hbWljTWFpbkJ1bGxldHMgKyA0KTtcbiAgICAgICAgY29uc3QgYnVsbGV0c09mZnNldCA9IChidWxsZXRTaXplICogZHluYW1pY0J1bGxldHNMZW5ndGggLSBidWxsZXRTaXplKSAvIDIgLSBtaWRJbmRleCAqIGJ1bGxldFNpemU7XG4gICAgICAgIGNvbnN0IG9mZnNldFByb3AgPSBydGwgPyAncmlnaHQnIDogJ2xlZnQnO1xuICAgICAgICBidWxsZXRzLmNzcyhzd2lwZXIuaXNIb3Jpem9udGFsKCkgPyBvZmZzZXRQcm9wIDogJ3RvcCcsIGAke2J1bGxldHNPZmZzZXR9cHhgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAocGFyYW1zLnR5cGUgPT09ICdmcmFjdGlvbicpIHtcbiAgICAgICRlbC5maW5kKGNsYXNzZXNUb1NlbGVjdG9yKHBhcmFtcy5jdXJyZW50Q2xhc3MpKS50ZXh0KHBhcmFtcy5mb3JtYXRGcmFjdGlvbkN1cnJlbnQoY3VycmVudCArIDEpKTtcbiAgICAgICRlbC5maW5kKGNsYXNzZXNUb1NlbGVjdG9yKHBhcmFtcy50b3RhbENsYXNzKSkudGV4dChwYXJhbXMuZm9ybWF0RnJhY3Rpb25Ub3RhbCh0b3RhbCkpO1xuICAgIH1cblxuICAgIGlmIChwYXJhbXMudHlwZSA9PT0gJ3Byb2dyZXNzYmFyJykge1xuICAgICAgbGV0IHByb2dyZXNzYmFyRGlyZWN0aW9uO1xuXG4gICAgICBpZiAocGFyYW1zLnByb2dyZXNzYmFyT3Bwb3NpdGUpIHtcbiAgICAgICAgcHJvZ3Jlc3NiYXJEaXJlY3Rpb24gPSBzd2lwZXIuaXNIb3Jpem9udGFsKCkgPyAndmVydGljYWwnIDogJ2hvcml6b250YWwnO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcHJvZ3Jlc3NiYXJEaXJlY3Rpb24gPSBzd2lwZXIuaXNIb3Jpem9udGFsKCkgPyAnaG9yaXpvbnRhbCcgOiAndmVydGljYWwnO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzY2FsZSA9IChjdXJyZW50ICsgMSkgLyB0b3RhbDtcbiAgICAgIGxldCBzY2FsZVggPSAxO1xuICAgICAgbGV0IHNjYWxlWSA9IDE7XG5cbiAgICAgIGlmIChwcm9ncmVzc2JhckRpcmVjdGlvbiA9PT0gJ2hvcml6b250YWwnKSB7XG4gICAgICAgIHNjYWxlWCA9IHNjYWxlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc2NhbGVZID0gc2NhbGU7XG4gICAgICB9XG5cbiAgICAgICRlbC5maW5kKGNsYXNzZXNUb1NlbGVjdG9yKHBhcmFtcy5wcm9ncmVzc2JhckZpbGxDbGFzcykpLnRyYW5zZm9ybShgdHJhbnNsYXRlM2QoMCwwLDApIHNjYWxlWCgke3NjYWxlWH0pIHNjYWxlWSgke3NjYWxlWX0pYCkudHJhbnNpdGlvbihzd2lwZXIucGFyYW1zLnNwZWVkKTtcbiAgICB9XG5cbiAgICBpZiAocGFyYW1zLnR5cGUgPT09ICdjdXN0b20nICYmIHBhcmFtcy5yZW5kZXJDdXN0b20pIHtcbiAgICAgICRlbC5odG1sKHBhcmFtcy5yZW5kZXJDdXN0b20oc3dpcGVyLCBjdXJyZW50ICsgMSwgdG90YWwpKTtcbiAgICAgIGVtaXQoJ3BhZ2luYXRpb25SZW5kZXInLCAkZWxbMF0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBlbWl0KCdwYWdpbmF0aW9uVXBkYXRlJywgJGVsWzBdKTtcbiAgICB9XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy53YXRjaE92ZXJmbG93ICYmIHN3aXBlci5lbmFibGVkKSB7XG4gICAgICAkZWxbc3dpcGVyLmlzTG9ja2VkID8gJ2FkZENsYXNzJyA6ICdyZW1vdmVDbGFzcyddKHBhcmFtcy5sb2NrQ2xhc3MpO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIHJlbmRlcigpIHtcbiAgICAvLyBSZW5kZXIgQ29udGFpbmVyXG4gICAgY29uc3QgcGFyYW1zID0gc3dpcGVyLnBhcmFtcy5wYWdpbmF0aW9uO1xuICAgIGlmIChpc1BhZ2luYXRpb25EaXNhYmxlZCgpKSByZXR1cm47XG4gICAgY29uc3Qgc2xpZGVzTGVuZ3RoID0gc3dpcGVyLnZpcnR1YWwgJiYgc3dpcGVyLnBhcmFtcy52aXJ0dWFsLmVuYWJsZWQgPyBzd2lwZXIudmlydHVhbC5zbGlkZXMubGVuZ3RoIDogc3dpcGVyLnNsaWRlcy5sZW5ndGg7XG4gICAgY29uc3QgJGVsID0gc3dpcGVyLnBhZ2luYXRpb24uJGVsO1xuICAgIGxldCBwYWdpbmF0aW9uSFRNTCA9ICcnO1xuXG4gICAgaWYgKHBhcmFtcy50eXBlID09PSAnYnVsbGV0cycpIHtcbiAgICAgIGxldCBudW1iZXJPZkJ1bGxldHMgPSBzd2lwZXIucGFyYW1zLmxvb3AgPyBNYXRoLmNlaWwoKHNsaWRlc0xlbmd0aCAtIHN3aXBlci5sb29wZWRTbGlkZXMgKiAyKSAvIHN3aXBlci5wYXJhbXMuc2xpZGVzUGVyR3JvdXApIDogc3dpcGVyLnNuYXBHcmlkLmxlbmd0aDtcblxuICAgICAgaWYgKHN3aXBlci5wYXJhbXMuZnJlZU1vZGUgJiYgc3dpcGVyLnBhcmFtcy5mcmVlTW9kZS5lbmFibGVkICYmICFzd2lwZXIucGFyYW1zLmxvb3AgJiYgbnVtYmVyT2ZCdWxsZXRzID4gc2xpZGVzTGVuZ3RoKSB7XG4gICAgICAgIG51bWJlck9mQnVsbGV0cyA9IHNsaWRlc0xlbmd0aDtcbiAgICAgIH1cblxuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBudW1iZXJPZkJ1bGxldHM7IGkgKz0gMSkge1xuICAgICAgICBpZiAocGFyYW1zLnJlbmRlckJ1bGxldCkge1xuICAgICAgICAgIHBhZ2luYXRpb25IVE1MICs9IHBhcmFtcy5yZW5kZXJCdWxsZXQuY2FsbChzd2lwZXIsIGksIHBhcmFtcy5idWxsZXRDbGFzcyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcGFnaW5hdGlvbkhUTUwgKz0gYDwke3BhcmFtcy5idWxsZXRFbGVtZW50fSBjbGFzcz1cIiR7cGFyYW1zLmJ1bGxldENsYXNzfVwiPjwvJHtwYXJhbXMuYnVsbGV0RWxlbWVudH0+YDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAkZWwuaHRtbChwYWdpbmF0aW9uSFRNTCk7XG4gICAgICBzd2lwZXIucGFnaW5hdGlvbi5idWxsZXRzID0gJGVsLmZpbmQoY2xhc3Nlc1RvU2VsZWN0b3IocGFyYW1zLmJ1bGxldENsYXNzKSk7XG4gICAgfVxuXG4gICAgaWYgKHBhcmFtcy50eXBlID09PSAnZnJhY3Rpb24nKSB7XG4gICAgICBpZiAocGFyYW1zLnJlbmRlckZyYWN0aW9uKSB7XG4gICAgICAgIHBhZ2luYXRpb25IVE1MID0gcGFyYW1zLnJlbmRlckZyYWN0aW9uLmNhbGwoc3dpcGVyLCBwYXJhbXMuY3VycmVudENsYXNzLCBwYXJhbXMudG90YWxDbGFzcyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwYWdpbmF0aW9uSFRNTCA9IGA8c3BhbiBjbGFzcz1cIiR7cGFyYW1zLmN1cnJlbnRDbGFzc31cIj48L3NwYW4+YCArICcgLyAnICsgYDxzcGFuIGNsYXNzPVwiJHtwYXJhbXMudG90YWxDbGFzc31cIj48L3NwYW4+YDtcbiAgICAgIH1cblxuICAgICAgJGVsLmh0bWwocGFnaW5hdGlvbkhUTUwpO1xuICAgIH1cblxuICAgIGlmIChwYXJhbXMudHlwZSA9PT0gJ3Byb2dyZXNzYmFyJykge1xuICAgICAgaWYgKHBhcmFtcy5yZW5kZXJQcm9ncmVzc2Jhcikge1xuICAgICAgICBwYWdpbmF0aW9uSFRNTCA9IHBhcmFtcy5yZW5kZXJQcm9ncmVzc2Jhci5jYWxsKHN3aXBlciwgcGFyYW1zLnByb2dyZXNzYmFyRmlsbENsYXNzKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBhZ2luYXRpb25IVE1MID0gYDxzcGFuIGNsYXNzPVwiJHtwYXJhbXMucHJvZ3Jlc3NiYXJGaWxsQ2xhc3N9XCI+PC9zcGFuPmA7XG4gICAgICB9XG5cbiAgICAgICRlbC5odG1sKHBhZ2luYXRpb25IVE1MKTtcbiAgICB9XG5cbiAgICBpZiAocGFyYW1zLnR5cGUgIT09ICdjdXN0b20nKSB7XG4gICAgICBlbWl0KCdwYWdpbmF0aW9uUmVuZGVyJywgc3dpcGVyLnBhZ2luYXRpb24uJGVsWzBdKTtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBpbml0KCkge1xuICAgIHN3aXBlci5wYXJhbXMucGFnaW5hdGlvbiA9IGNyZWF0ZUVsZW1lbnRJZk5vdERlZmluZWQoc3dpcGVyLCBzd2lwZXIub3JpZ2luYWxQYXJhbXMucGFnaW5hdGlvbiwgc3dpcGVyLnBhcmFtcy5wYWdpbmF0aW9uLCB7XG4gICAgICBlbDogJ3N3aXBlci1wYWdpbmF0aW9uJ1xuICAgIH0pO1xuICAgIGNvbnN0IHBhcmFtcyA9IHN3aXBlci5wYXJhbXMucGFnaW5hdGlvbjtcbiAgICBpZiAoIXBhcmFtcy5lbCkgcmV0dXJuO1xuICAgIGxldCAkZWwgPSAkKHBhcmFtcy5lbCk7XG4gICAgaWYgKCRlbC5sZW5ndGggPT09IDApIHJldHVybjtcblxuICAgIGlmIChzd2lwZXIucGFyYW1zLnVuaXF1ZU5hdkVsZW1lbnRzICYmIHR5cGVvZiBwYXJhbXMuZWwgPT09ICdzdHJpbmcnICYmICRlbC5sZW5ndGggPiAxKSB7XG4gICAgICAkZWwgPSBzd2lwZXIuJGVsLmZpbmQocGFyYW1zLmVsKTsgLy8gY2hlY2sgaWYgaXQgYmVsb25ncyB0byBhbm90aGVyIG5lc3RlZCBTd2lwZXJcblxuICAgICAgaWYgKCRlbC5sZW5ndGggPiAxKSB7XG4gICAgICAgICRlbCA9ICRlbC5maWx0ZXIoZWwgPT4ge1xuICAgICAgICAgIGlmICgkKGVsKS5wYXJlbnRzKCcuc3dpcGVyJylbMF0gIT09IHN3aXBlci5lbCkgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAocGFyYW1zLnR5cGUgPT09ICdidWxsZXRzJyAmJiBwYXJhbXMuY2xpY2thYmxlKSB7XG4gICAgICAkZWwuYWRkQ2xhc3MocGFyYW1zLmNsaWNrYWJsZUNsYXNzKTtcbiAgICB9XG5cbiAgICAkZWwuYWRkQ2xhc3MocGFyYW1zLm1vZGlmaWVyQ2xhc3MgKyBwYXJhbXMudHlwZSk7XG4gICAgJGVsLmFkZENsYXNzKHN3aXBlci5pc0hvcml6b250YWwoKSA/IHBhcmFtcy5ob3Jpem9udGFsQ2xhc3MgOiBwYXJhbXMudmVydGljYWxDbGFzcyk7XG5cbiAgICBpZiAocGFyYW1zLnR5cGUgPT09ICdidWxsZXRzJyAmJiBwYXJhbXMuZHluYW1pY0J1bGxldHMpIHtcbiAgICAgICRlbC5hZGRDbGFzcyhgJHtwYXJhbXMubW9kaWZpZXJDbGFzc30ke3BhcmFtcy50eXBlfS1keW5hbWljYCk7XG4gICAgICBkeW5hbWljQnVsbGV0SW5kZXggPSAwO1xuXG4gICAgICBpZiAocGFyYW1zLmR5bmFtaWNNYWluQnVsbGV0cyA8IDEpIHtcbiAgICAgICAgcGFyYW1zLmR5bmFtaWNNYWluQnVsbGV0cyA9IDE7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHBhcmFtcy50eXBlID09PSAncHJvZ3Jlc3NiYXInICYmIHBhcmFtcy5wcm9ncmVzc2Jhck9wcG9zaXRlKSB7XG4gICAgICAkZWwuYWRkQ2xhc3MocGFyYW1zLnByb2dyZXNzYmFyT3Bwb3NpdGVDbGFzcyk7XG4gICAgfVxuXG4gICAgaWYgKHBhcmFtcy5jbGlja2FibGUpIHtcbiAgICAgICRlbC5vbignY2xpY2snLCBjbGFzc2VzVG9TZWxlY3RvcihwYXJhbXMuYnVsbGV0Q2xhc3MpLCBmdW5jdGlvbiBvbkNsaWNrKGUpIHtcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBsZXQgaW5kZXggPSAkKHRoaXMpLmluZGV4KCkgKiBzd2lwZXIucGFyYW1zLnNsaWRlc1Blckdyb3VwO1xuICAgICAgICBpZiAoc3dpcGVyLnBhcmFtcy5sb29wKSBpbmRleCArPSBzd2lwZXIubG9vcGVkU2xpZGVzO1xuICAgICAgICBzd2lwZXIuc2xpZGVUbyhpbmRleCk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBPYmplY3QuYXNzaWduKHN3aXBlci5wYWdpbmF0aW9uLCB7XG4gICAgICAkZWwsXG4gICAgICBlbDogJGVsWzBdXG4gICAgfSk7XG5cbiAgICBpZiAoIXN3aXBlci5lbmFibGVkKSB7XG4gICAgICAkZWwuYWRkQ2xhc3MocGFyYW1zLmxvY2tDbGFzcyk7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gZGVzdHJveSgpIHtcbiAgICBjb25zdCBwYXJhbXMgPSBzd2lwZXIucGFyYW1zLnBhZ2luYXRpb247XG4gICAgaWYgKGlzUGFnaW5hdGlvbkRpc2FibGVkKCkpIHJldHVybjtcbiAgICBjb25zdCAkZWwgPSBzd2lwZXIucGFnaW5hdGlvbi4kZWw7XG4gICAgJGVsLnJlbW92ZUNsYXNzKHBhcmFtcy5oaWRkZW5DbGFzcyk7XG4gICAgJGVsLnJlbW92ZUNsYXNzKHBhcmFtcy5tb2RpZmllckNsYXNzICsgcGFyYW1zLnR5cGUpO1xuICAgICRlbC5yZW1vdmVDbGFzcyhzd2lwZXIuaXNIb3Jpem9udGFsKCkgPyBwYXJhbXMuaG9yaXpvbnRhbENsYXNzIDogcGFyYW1zLnZlcnRpY2FsQ2xhc3MpO1xuICAgIGlmIChzd2lwZXIucGFnaW5hdGlvbi5idWxsZXRzICYmIHN3aXBlci5wYWdpbmF0aW9uLmJ1bGxldHMucmVtb3ZlQ2xhc3MpIHN3aXBlci5wYWdpbmF0aW9uLmJ1bGxldHMucmVtb3ZlQ2xhc3MocGFyYW1zLmJ1bGxldEFjdGl2ZUNsYXNzKTtcblxuICAgIGlmIChwYXJhbXMuY2xpY2thYmxlKSB7XG4gICAgICAkZWwub2ZmKCdjbGljaycsIGNsYXNzZXNUb1NlbGVjdG9yKHBhcmFtcy5idWxsZXRDbGFzcykpO1xuICAgIH1cbiAgfVxuXG4gIG9uKCdpbml0JywgKCkgPT4ge1xuICAgIGlmIChzd2lwZXIucGFyYW1zLnBhZ2luYXRpb24uZW5hYmxlZCA9PT0gZmFsc2UpIHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuICAgICAgZGlzYWJsZSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICBpbml0KCk7XG4gICAgICByZW5kZXIoKTtcbiAgICAgIHVwZGF0ZSgpO1xuICAgIH1cbiAgfSk7XG4gIG9uKCdhY3RpdmVJbmRleENoYW5nZScsICgpID0+IHtcbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5sb29wKSB7XG4gICAgICB1cGRhdGUoKTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBzd2lwZXIuc25hcEluZGV4ID09PSAndW5kZWZpbmVkJykge1xuICAgICAgdXBkYXRlKCk7XG4gICAgfVxuICB9KTtcbiAgb24oJ3NuYXBJbmRleENoYW5nZScsICgpID0+IHtcbiAgICBpZiAoIXN3aXBlci5wYXJhbXMubG9vcCkge1xuICAgICAgdXBkYXRlKCk7XG4gICAgfVxuICB9KTtcbiAgb24oJ3NsaWRlc0xlbmd0aENoYW5nZScsICgpID0+IHtcbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5sb29wKSB7XG4gICAgICByZW5kZXIoKTtcbiAgICAgIHVwZGF0ZSgpO1xuICAgIH1cbiAgfSk7XG4gIG9uKCdzbmFwR3JpZExlbmd0aENoYW5nZScsICgpID0+IHtcbiAgICBpZiAoIXN3aXBlci5wYXJhbXMubG9vcCkge1xuICAgICAgcmVuZGVyKCk7XG4gICAgICB1cGRhdGUoKTtcbiAgICB9XG4gIH0pO1xuICBvbignZGVzdHJveScsICgpID0+IHtcbiAgICBkZXN0cm95KCk7XG4gIH0pO1xuICBvbignZW5hYmxlIGRpc2FibGUnLCAoKSA9PiB7XG4gICAgY29uc3Qge1xuICAgICAgJGVsXG4gICAgfSA9IHN3aXBlci5wYWdpbmF0aW9uO1xuXG4gICAgaWYgKCRlbCkge1xuICAgICAgJGVsW3N3aXBlci5lbmFibGVkID8gJ3JlbW92ZUNsYXNzJyA6ICdhZGRDbGFzcyddKHN3aXBlci5wYXJhbXMucGFnaW5hdGlvbi5sb2NrQ2xhc3MpO1xuICAgIH1cbiAgfSk7XG4gIG9uKCdsb2NrIHVubG9jaycsICgpID0+IHtcbiAgICB1cGRhdGUoKTtcbiAgfSk7XG4gIG9uKCdjbGljaycsIChfcywgZSkgPT4ge1xuICAgIGNvbnN0IHRhcmdldEVsID0gZS50YXJnZXQ7XG4gICAgY29uc3Qge1xuICAgICAgJGVsXG4gICAgfSA9IHN3aXBlci5wYWdpbmF0aW9uO1xuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMucGFnaW5hdGlvbi5lbCAmJiBzd2lwZXIucGFyYW1zLnBhZ2luYXRpb24uaGlkZU9uQ2xpY2sgJiYgJGVsICYmICRlbC5sZW5ndGggPiAwICYmICEkKHRhcmdldEVsKS5oYXNDbGFzcyhzd2lwZXIucGFyYW1zLnBhZ2luYXRpb24uYnVsbGV0Q2xhc3MpKSB7XG4gICAgICBpZiAoc3dpcGVyLm5hdmlnYXRpb24gJiYgKHN3aXBlci5uYXZpZ2F0aW9uLm5leHRFbCAmJiB0YXJnZXRFbCA9PT0gc3dpcGVyLm5hdmlnYXRpb24ubmV4dEVsIHx8IHN3aXBlci5uYXZpZ2F0aW9uLnByZXZFbCAmJiB0YXJnZXRFbCA9PT0gc3dpcGVyLm5hdmlnYXRpb24ucHJldkVsKSkgcmV0dXJuO1xuICAgICAgY29uc3QgaXNIaWRkZW4gPSAkZWwuaGFzQ2xhc3Moc3dpcGVyLnBhcmFtcy5wYWdpbmF0aW9uLmhpZGRlbkNsYXNzKTtcblxuICAgICAgaWYgKGlzSGlkZGVuID09PSB0cnVlKSB7XG4gICAgICAgIGVtaXQoJ3BhZ2luYXRpb25TaG93Jyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBlbWl0KCdwYWdpbmF0aW9uSGlkZScpO1xuICAgICAgfVxuXG4gICAgICAkZWwudG9nZ2xlQ2xhc3Moc3dpcGVyLnBhcmFtcy5wYWdpbmF0aW9uLmhpZGRlbkNsYXNzKTtcbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IGVuYWJsZSA9ICgpID0+IHtcbiAgICBzd2lwZXIuJGVsLnJlbW92ZUNsYXNzKHN3aXBlci5wYXJhbXMucGFnaW5hdGlvbi5wYWdpbmF0aW9uRGlzYWJsZWRDbGFzcyk7XG5cbiAgICBpZiAoc3dpcGVyLnBhZ2luYXRpb24uJGVsKSB7XG4gICAgICBzd2lwZXIucGFnaW5hdGlvbi4kZWwucmVtb3ZlQ2xhc3Moc3dpcGVyLnBhcmFtcy5wYWdpbmF0aW9uLnBhZ2luYXRpb25EaXNhYmxlZENsYXNzKTtcbiAgICB9XG5cbiAgICBpbml0KCk7XG4gICAgcmVuZGVyKCk7XG4gICAgdXBkYXRlKCk7XG4gIH07XG5cbiAgY29uc3QgZGlzYWJsZSA9ICgpID0+IHtcbiAgICBzd2lwZXIuJGVsLmFkZENsYXNzKHN3aXBlci5wYXJhbXMucGFnaW5hdGlvbi5wYWdpbmF0aW9uRGlzYWJsZWRDbGFzcyk7XG5cbiAgICBpZiAoc3dpcGVyLnBhZ2luYXRpb24uJGVsKSB7XG4gICAgICBzd2lwZXIucGFnaW5hdGlvbi4kZWwuYWRkQ2xhc3Moc3dpcGVyLnBhcmFtcy5wYWdpbmF0aW9uLnBhZ2luYXRpb25EaXNhYmxlZENsYXNzKTtcbiAgICB9XG5cbiAgICBkZXN0cm95KCk7XG4gIH07XG5cbiAgT2JqZWN0LmFzc2lnbihzd2lwZXIucGFnaW5hdGlvbiwge1xuICAgIGVuYWJsZSxcbiAgICBkaXNhYmxlLFxuICAgIHJlbmRlcixcbiAgICB1cGRhdGUsXG4gICAgaW5pdCxcbiAgICBkZXN0cm95XG4gIH0pO1xufSIsImltcG9ydCB7IGdldERvY3VtZW50IH0gZnJvbSAnc3NyLXdpbmRvdyc7XG5pbXBvcnQgJCBmcm9tICcuLi8uLi9zaGFyZWQvZG9tLmpzJztcbmltcG9ydCB7IG5leHRUaWNrIH0gZnJvbSAnLi4vLi4vc2hhcmVkL3V0aWxzLmpzJztcbmltcG9ydCBjcmVhdGVFbGVtZW50SWZOb3REZWZpbmVkIGZyb20gJy4uLy4uL3NoYXJlZC9jcmVhdGUtZWxlbWVudC1pZi1ub3QtZGVmaW5lZC5qcyc7XG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBTY3JvbGxiYXIoe1xuICBzd2lwZXIsXG4gIGV4dGVuZFBhcmFtcyxcbiAgb24sXG4gIGVtaXRcbn0pIHtcbiAgY29uc3QgZG9jdW1lbnQgPSBnZXREb2N1bWVudCgpO1xuICBsZXQgaXNUb3VjaGVkID0gZmFsc2U7XG4gIGxldCB0aW1lb3V0ID0gbnVsbDtcbiAgbGV0IGRyYWdUaW1lb3V0ID0gbnVsbDtcbiAgbGV0IGRyYWdTdGFydFBvcztcbiAgbGV0IGRyYWdTaXplO1xuICBsZXQgdHJhY2tTaXplO1xuICBsZXQgZGl2aWRlcjtcbiAgZXh0ZW5kUGFyYW1zKHtcbiAgICBzY3JvbGxiYXI6IHtcbiAgICAgIGVsOiBudWxsLFxuICAgICAgZHJhZ1NpemU6ICdhdXRvJyxcbiAgICAgIGhpZGU6IGZhbHNlLFxuICAgICAgZHJhZ2dhYmxlOiBmYWxzZSxcbiAgICAgIHNuYXBPblJlbGVhc2U6IHRydWUsXG4gICAgICBsb2NrQ2xhc3M6ICdzd2lwZXItc2Nyb2xsYmFyLWxvY2snLFxuICAgICAgZHJhZ0NsYXNzOiAnc3dpcGVyLXNjcm9sbGJhci1kcmFnJyxcbiAgICAgIHNjcm9sbGJhckRpc2FibGVkQ2xhc3M6ICdzd2lwZXItc2Nyb2xsYmFyLWRpc2FibGVkJyxcbiAgICAgIGhvcml6b250YWxDbGFzczogYHN3aXBlci1zY3JvbGxiYXItaG9yaXpvbnRhbGAsXG4gICAgICB2ZXJ0aWNhbENsYXNzOiBgc3dpcGVyLXNjcm9sbGJhci12ZXJ0aWNhbGBcbiAgICB9XG4gIH0pO1xuICBzd2lwZXIuc2Nyb2xsYmFyID0ge1xuICAgIGVsOiBudWxsLFxuICAgIGRyYWdFbDogbnVsbCxcbiAgICAkZWw6IG51bGwsXG4gICAgJGRyYWdFbDogbnVsbFxuICB9O1xuXG4gIGZ1bmN0aW9uIHNldFRyYW5zbGF0ZSgpIHtcbiAgICBpZiAoIXN3aXBlci5wYXJhbXMuc2Nyb2xsYmFyLmVsIHx8ICFzd2lwZXIuc2Nyb2xsYmFyLmVsKSByZXR1cm47XG4gICAgY29uc3Qge1xuICAgICAgc2Nyb2xsYmFyLFxuICAgICAgcnRsVHJhbnNsYXRlOiBydGwsXG4gICAgICBwcm9ncmVzc1xuICAgIH0gPSBzd2lwZXI7XG4gICAgY29uc3Qge1xuICAgICAgJGRyYWdFbCxcbiAgICAgICRlbFxuICAgIH0gPSBzY3JvbGxiYXI7XG4gICAgY29uc3QgcGFyYW1zID0gc3dpcGVyLnBhcmFtcy5zY3JvbGxiYXI7XG4gICAgbGV0IG5ld1NpemUgPSBkcmFnU2l6ZTtcbiAgICBsZXQgbmV3UG9zID0gKHRyYWNrU2l6ZSAtIGRyYWdTaXplKSAqIHByb2dyZXNzO1xuXG4gICAgaWYgKHJ0bCkge1xuICAgICAgbmV3UG9zID0gLW5ld1BvcztcblxuICAgICAgaWYgKG5ld1BvcyA+IDApIHtcbiAgICAgICAgbmV3U2l6ZSA9IGRyYWdTaXplIC0gbmV3UG9zO1xuICAgICAgICBuZXdQb3MgPSAwO1xuICAgICAgfSBlbHNlIGlmICgtbmV3UG9zICsgZHJhZ1NpemUgPiB0cmFja1NpemUpIHtcbiAgICAgICAgbmV3U2l6ZSA9IHRyYWNrU2l6ZSArIG5ld1BvcztcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKG5ld1BvcyA8IDApIHtcbiAgICAgIG5ld1NpemUgPSBkcmFnU2l6ZSArIG5ld1BvcztcbiAgICAgIG5ld1BvcyA9IDA7XG4gICAgfSBlbHNlIGlmIChuZXdQb3MgKyBkcmFnU2l6ZSA+IHRyYWNrU2l6ZSkge1xuICAgICAgbmV3U2l6ZSA9IHRyYWNrU2l6ZSAtIG5ld1BvcztcbiAgICB9XG5cbiAgICBpZiAoc3dpcGVyLmlzSG9yaXpvbnRhbCgpKSB7XG4gICAgICAkZHJhZ0VsLnRyYW5zZm9ybShgdHJhbnNsYXRlM2QoJHtuZXdQb3N9cHgsIDAsIDApYCk7XG4gICAgICAkZHJhZ0VsWzBdLnN0eWxlLndpZHRoID0gYCR7bmV3U2l6ZX1weGA7XG4gICAgfSBlbHNlIHtcbiAgICAgICRkcmFnRWwudHJhbnNmb3JtKGB0cmFuc2xhdGUzZCgwcHgsICR7bmV3UG9zfXB4LCAwKWApO1xuICAgICAgJGRyYWdFbFswXS5zdHlsZS5oZWlnaHQgPSBgJHtuZXdTaXplfXB4YDtcbiAgICB9XG5cbiAgICBpZiAocGFyYW1zLmhpZGUpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICAgICRlbFswXS5zdHlsZS5vcGFjaXR5ID0gMTtcbiAgICAgIHRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgJGVsWzBdLnN0eWxlLm9wYWNpdHkgPSAwO1xuICAgICAgICAkZWwudHJhbnNpdGlvbig0MDApO1xuICAgICAgfSwgMTAwMCk7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gc2V0VHJhbnNpdGlvbihkdXJhdGlvbikge1xuICAgIGlmICghc3dpcGVyLnBhcmFtcy5zY3JvbGxiYXIuZWwgfHwgIXN3aXBlci5zY3JvbGxiYXIuZWwpIHJldHVybjtcbiAgICBzd2lwZXIuc2Nyb2xsYmFyLiRkcmFnRWwudHJhbnNpdGlvbihkdXJhdGlvbik7XG4gIH1cblxuICBmdW5jdGlvbiB1cGRhdGVTaXplKCkge1xuICAgIGlmICghc3dpcGVyLnBhcmFtcy5zY3JvbGxiYXIuZWwgfHwgIXN3aXBlci5zY3JvbGxiYXIuZWwpIHJldHVybjtcbiAgICBjb25zdCB7XG4gICAgICBzY3JvbGxiYXJcbiAgICB9ID0gc3dpcGVyO1xuICAgIGNvbnN0IHtcbiAgICAgICRkcmFnRWwsXG4gICAgICAkZWxcbiAgICB9ID0gc2Nyb2xsYmFyO1xuICAgICRkcmFnRWxbMF0uc3R5bGUud2lkdGggPSAnJztcbiAgICAkZHJhZ0VsWzBdLnN0eWxlLmhlaWdodCA9ICcnO1xuICAgIHRyYWNrU2l6ZSA9IHN3aXBlci5pc0hvcml6b250YWwoKSA/ICRlbFswXS5vZmZzZXRXaWR0aCA6ICRlbFswXS5vZmZzZXRIZWlnaHQ7XG4gICAgZGl2aWRlciA9IHN3aXBlci5zaXplIC8gKHN3aXBlci52aXJ0dWFsU2l6ZSArIHN3aXBlci5wYXJhbXMuc2xpZGVzT2Zmc2V0QmVmb3JlIC0gKHN3aXBlci5wYXJhbXMuY2VudGVyZWRTbGlkZXMgPyBzd2lwZXIuc25hcEdyaWRbMF0gOiAwKSk7XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5zY3JvbGxiYXIuZHJhZ1NpemUgPT09ICdhdXRvJykge1xuICAgICAgZHJhZ1NpemUgPSB0cmFja1NpemUgKiBkaXZpZGVyO1xuICAgIH0gZWxzZSB7XG4gICAgICBkcmFnU2l6ZSA9IHBhcnNlSW50KHN3aXBlci5wYXJhbXMuc2Nyb2xsYmFyLmRyYWdTaXplLCAxMCk7XG4gICAgfVxuXG4gICAgaWYgKHN3aXBlci5pc0hvcml6b250YWwoKSkge1xuICAgICAgJGRyYWdFbFswXS5zdHlsZS53aWR0aCA9IGAke2RyYWdTaXplfXB4YDtcbiAgICB9IGVsc2Uge1xuICAgICAgJGRyYWdFbFswXS5zdHlsZS5oZWlnaHQgPSBgJHtkcmFnU2l6ZX1weGA7XG4gICAgfVxuXG4gICAgaWYgKGRpdmlkZXIgPj0gMSkge1xuICAgICAgJGVsWzBdLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgfSBlbHNlIHtcbiAgICAgICRlbFswXS5zdHlsZS5kaXNwbGF5ID0gJyc7XG4gICAgfVxuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMuc2Nyb2xsYmFyLmhpZGUpIHtcbiAgICAgICRlbFswXS5zdHlsZS5vcGFjaXR5ID0gMDtcbiAgICB9XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy53YXRjaE92ZXJmbG93ICYmIHN3aXBlci5lbmFibGVkKSB7XG4gICAgICBzY3JvbGxiYXIuJGVsW3N3aXBlci5pc0xvY2tlZCA/ICdhZGRDbGFzcycgOiAncmVtb3ZlQ2xhc3MnXShzd2lwZXIucGFyYW1zLnNjcm9sbGJhci5sb2NrQ2xhc3MpO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGdldFBvaW50ZXJQb3NpdGlvbihlKSB7XG4gICAgaWYgKHN3aXBlci5pc0hvcml6b250YWwoKSkge1xuICAgICAgcmV0dXJuIGUudHlwZSA9PT0gJ3RvdWNoc3RhcnQnIHx8IGUudHlwZSA9PT0gJ3RvdWNobW92ZScgPyBlLnRhcmdldFRvdWNoZXNbMF0uY2xpZW50WCA6IGUuY2xpZW50WDtcbiAgICB9XG5cbiAgICByZXR1cm4gZS50eXBlID09PSAndG91Y2hzdGFydCcgfHwgZS50eXBlID09PSAndG91Y2htb3ZlJyA/IGUudGFyZ2V0VG91Y2hlc1swXS5jbGllbnRZIDogZS5jbGllbnRZO1xuICB9XG5cbiAgZnVuY3Rpb24gc2V0RHJhZ1Bvc2l0aW9uKGUpIHtcbiAgICBjb25zdCB7XG4gICAgICBzY3JvbGxiYXIsXG4gICAgICBydGxUcmFuc2xhdGU6IHJ0bFxuICAgIH0gPSBzd2lwZXI7XG4gICAgY29uc3Qge1xuICAgICAgJGVsXG4gICAgfSA9IHNjcm9sbGJhcjtcbiAgICBsZXQgcG9zaXRpb25SYXRpbztcbiAgICBwb3NpdGlvblJhdGlvID0gKGdldFBvaW50ZXJQb3NpdGlvbihlKSAtICRlbC5vZmZzZXQoKVtzd2lwZXIuaXNIb3Jpem9udGFsKCkgPyAnbGVmdCcgOiAndG9wJ10gLSAoZHJhZ1N0YXJ0UG9zICE9PSBudWxsID8gZHJhZ1N0YXJ0UG9zIDogZHJhZ1NpemUgLyAyKSkgLyAodHJhY2tTaXplIC0gZHJhZ1NpemUpO1xuICAgIHBvc2l0aW9uUmF0aW8gPSBNYXRoLm1heChNYXRoLm1pbihwb3NpdGlvblJhdGlvLCAxKSwgMCk7XG5cbiAgICBpZiAocnRsKSB7XG4gICAgICBwb3NpdGlvblJhdGlvID0gMSAtIHBvc2l0aW9uUmF0aW87XG4gICAgfVxuXG4gICAgY29uc3QgcG9zaXRpb24gPSBzd2lwZXIubWluVHJhbnNsYXRlKCkgKyAoc3dpcGVyLm1heFRyYW5zbGF0ZSgpIC0gc3dpcGVyLm1pblRyYW5zbGF0ZSgpKSAqIHBvc2l0aW9uUmF0aW87XG4gICAgc3dpcGVyLnVwZGF0ZVByb2dyZXNzKHBvc2l0aW9uKTtcbiAgICBzd2lwZXIuc2V0VHJhbnNsYXRlKHBvc2l0aW9uKTtcbiAgICBzd2lwZXIudXBkYXRlQWN0aXZlSW5kZXgoKTtcbiAgICBzd2lwZXIudXBkYXRlU2xpZGVzQ2xhc3NlcygpO1xuICB9XG5cbiAgZnVuY3Rpb24gb25EcmFnU3RhcnQoZSkge1xuICAgIGNvbnN0IHBhcmFtcyA9IHN3aXBlci5wYXJhbXMuc2Nyb2xsYmFyO1xuICAgIGNvbnN0IHtcbiAgICAgIHNjcm9sbGJhcixcbiAgICAgICR3cmFwcGVyRWxcbiAgICB9ID0gc3dpcGVyO1xuICAgIGNvbnN0IHtcbiAgICAgICRlbCxcbiAgICAgICRkcmFnRWxcbiAgICB9ID0gc2Nyb2xsYmFyO1xuICAgIGlzVG91Y2hlZCA9IHRydWU7XG4gICAgZHJhZ1N0YXJ0UG9zID0gZS50YXJnZXQgPT09ICRkcmFnRWxbMF0gfHwgZS50YXJnZXQgPT09ICRkcmFnRWwgPyBnZXRQb2ludGVyUG9zaXRpb24oZSkgLSBlLnRhcmdldC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKVtzd2lwZXIuaXNIb3Jpem9udGFsKCkgPyAnbGVmdCcgOiAndG9wJ10gOiBudWxsO1xuICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICR3cmFwcGVyRWwudHJhbnNpdGlvbigxMDApO1xuICAgICRkcmFnRWwudHJhbnNpdGlvbigxMDApO1xuICAgIHNldERyYWdQb3NpdGlvbihlKTtcbiAgICBjbGVhclRpbWVvdXQoZHJhZ1RpbWVvdXQpO1xuICAgICRlbC50cmFuc2l0aW9uKDApO1xuXG4gICAgaWYgKHBhcmFtcy5oaWRlKSB7XG4gICAgICAkZWwuY3NzKCdvcGFjaXR5JywgMSk7XG4gICAgfVxuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMuY3NzTW9kZSkge1xuICAgICAgc3dpcGVyLiR3cmFwcGVyRWwuY3NzKCdzY3JvbGwtc25hcC10eXBlJywgJ25vbmUnKTtcbiAgICB9XG5cbiAgICBlbWl0KCdzY3JvbGxiYXJEcmFnU3RhcnQnLCBlKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIG9uRHJhZ01vdmUoZSkge1xuICAgIGNvbnN0IHtcbiAgICAgIHNjcm9sbGJhcixcbiAgICAgICR3cmFwcGVyRWxcbiAgICB9ID0gc3dpcGVyO1xuICAgIGNvbnN0IHtcbiAgICAgICRlbCxcbiAgICAgICRkcmFnRWxcbiAgICB9ID0gc2Nyb2xsYmFyO1xuICAgIGlmICghaXNUb3VjaGVkKSByZXR1cm47XG4gICAgaWYgKGUucHJldmVudERlZmF1bHQpIGUucHJldmVudERlZmF1bHQoKTtlbHNlIGUucmV0dXJuVmFsdWUgPSBmYWxzZTtcbiAgICBzZXREcmFnUG9zaXRpb24oZSk7XG4gICAgJHdyYXBwZXJFbC50cmFuc2l0aW9uKDApO1xuICAgICRlbC50cmFuc2l0aW9uKDApO1xuICAgICRkcmFnRWwudHJhbnNpdGlvbigwKTtcbiAgICBlbWl0KCdzY3JvbGxiYXJEcmFnTW92ZScsIGUpO1xuICB9XG5cbiAgZnVuY3Rpb24gb25EcmFnRW5kKGUpIHtcbiAgICBjb25zdCBwYXJhbXMgPSBzd2lwZXIucGFyYW1zLnNjcm9sbGJhcjtcbiAgICBjb25zdCB7XG4gICAgICBzY3JvbGxiYXIsXG4gICAgICAkd3JhcHBlckVsXG4gICAgfSA9IHN3aXBlcjtcbiAgICBjb25zdCB7XG4gICAgICAkZWxcbiAgICB9ID0gc2Nyb2xsYmFyO1xuICAgIGlmICghaXNUb3VjaGVkKSByZXR1cm47XG4gICAgaXNUb3VjaGVkID0gZmFsc2U7XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5jc3NNb2RlKSB7XG4gICAgICBzd2lwZXIuJHdyYXBwZXJFbC5jc3MoJ3Njcm9sbC1zbmFwLXR5cGUnLCAnJyk7XG4gICAgICAkd3JhcHBlckVsLnRyYW5zaXRpb24oJycpO1xuICAgIH1cblxuICAgIGlmIChwYXJhbXMuaGlkZSkge1xuICAgICAgY2xlYXJUaW1lb3V0KGRyYWdUaW1lb3V0KTtcbiAgICAgIGRyYWdUaW1lb3V0ID0gbmV4dFRpY2soKCkgPT4ge1xuICAgICAgICAkZWwuY3NzKCdvcGFjaXR5JywgMCk7XG4gICAgICAgICRlbC50cmFuc2l0aW9uKDQwMCk7XG4gICAgICB9LCAxMDAwKTtcbiAgICB9XG5cbiAgICBlbWl0KCdzY3JvbGxiYXJEcmFnRW5kJywgZSk7XG5cbiAgICBpZiAocGFyYW1zLnNuYXBPblJlbGVhc2UpIHtcbiAgICAgIHN3aXBlci5zbGlkZVRvQ2xvc2VzdCgpO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGV2ZW50cyhtZXRob2QpIHtcbiAgICBjb25zdCB7XG4gICAgICBzY3JvbGxiYXIsXG4gICAgICB0b3VjaEV2ZW50c1RvdWNoLFxuICAgICAgdG91Y2hFdmVudHNEZXNrdG9wLFxuICAgICAgcGFyYW1zLFxuICAgICAgc3VwcG9ydFxuICAgIH0gPSBzd2lwZXI7XG4gICAgY29uc3QgJGVsID0gc2Nyb2xsYmFyLiRlbDtcbiAgICBpZiAoISRlbCkgcmV0dXJuO1xuICAgIGNvbnN0IHRhcmdldCA9ICRlbFswXTtcbiAgICBjb25zdCBhY3RpdmVMaXN0ZW5lciA9IHN1cHBvcnQucGFzc2l2ZUxpc3RlbmVyICYmIHBhcmFtcy5wYXNzaXZlTGlzdGVuZXJzID8ge1xuICAgICAgcGFzc2l2ZTogZmFsc2UsXG4gICAgICBjYXB0dXJlOiBmYWxzZVxuICAgIH0gOiBmYWxzZTtcbiAgICBjb25zdCBwYXNzaXZlTGlzdGVuZXIgPSBzdXBwb3J0LnBhc3NpdmVMaXN0ZW5lciAmJiBwYXJhbXMucGFzc2l2ZUxpc3RlbmVycyA/IHtcbiAgICAgIHBhc3NpdmU6IHRydWUsXG4gICAgICBjYXB0dXJlOiBmYWxzZVxuICAgIH0gOiBmYWxzZTtcbiAgICBpZiAoIXRhcmdldCkgcmV0dXJuO1xuICAgIGNvbnN0IGV2ZW50TWV0aG9kID0gbWV0aG9kID09PSAnb24nID8gJ2FkZEV2ZW50TGlzdGVuZXInIDogJ3JlbW92ZUV2ZW50TGlzdGVuZXInO1xuXG4gICAgaWYgKCFzdXBwb3J0LnRvdWNoKSB7XG4gICAgICB0YXJnZXRbZXZlbnRNZXRob2RdKHRvdWNoRXZlbnRzRGVza3RvcC5zdGFydCwgb25EcmFnU3RhcnQsIGFjdGl2ZUxpc3RlbmVyKTtcbiAgICAgIGRvY3VtZW50W2V2ZW50TWV0aG9kXSh0b3VjaEV2ZW50c0Rlc2t0b3AubW92ZSwgb25EcmFnTW92ZSwgYWN0aXZlTGlzdGVuZXIpO1xuICAgICAgZG9jdW1lbnRbZXZlbnRNZXRob2RdKHRvdWNoRXZlbnRzRGVza3RvcC5lbmQsIG9uRHJhZ0VuZCwgcGFzc2l2ZUxpc3RlbmVyKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGFyZ2V0W2V2ZW50TWV0aG9kXSh0b3VjaEV2ZW50c1RvdWNoLnN0YXJ0LCBvbkRyYWdTdGFydCwgYWN0aXZlTGlzdGVuZXIpO1xuICAgICAgdGFyZ2V0W2V2ZW50TWV0aG9kXSh0b3VjaEV2ZW50c1RvdWNoLm1vdmUsIG9uRHJhZ01vdmUsIGFjdGl2ZUxpc3RlbmVyKTtcbiAgICAgIHRhcmdldFtldmVudE1ldGhvZF0odG91Y2hFdmVudHNUb3VjaC5lbmQsIG9uRHJhZ0VuZCwgcGFzc2l2ZUxpc3RlbmVyKTtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBlbmFibGVEcmFnZ2FibGUoKSB7XG4gICAgaWYgKCFzd2lwZXIucGFyYW1zLnNjcm9sbGJhci5lbCB8fCAhc3dpcGVyLnNjcm9sbGJhci5lbCkgcmV0dXJuO1xuICAgIGV2ZW50cygnb24nKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGRpc2FibGVEcmFnZ2FibGUoKSB7XG4gICAgaWYgKCFzd2lwZXIucGFyYW1zLnNjcm9sbGJhci5lbCB8fCAhc3dpcGVyLnNjcm9sbGJhci5lbCkgcmV0dXJuO1xuICAgIGV2ZW50cygnb2ZmJyk7XG4gIH1cblxuICBmdW5jdGlvbiBpbml0KCkge1xuICAgIGNvbnN0IHtcbiAgICAgIHNjcm9sbGJhcixcbiAgICAgICRlbDogJHN3aXBlckVsXG4gICAgfSA9IHN3aXBlcjtcbiAgICBzd2lwZXIucGFyYW1zLnNjcm9sbGJhciA9IGNyZWF0ZUVsZW1lbnRJZk5vdERlZmluZWQoc3dpcGVyLCBzd2lwZXIub3JpZ2luYWxQYXJhbXMuc2Nyb2xsYmFyLCBzd2lwZXIucGFyYW1zLnNjcm9sbGJhciwge1xuICAgICAgZWw6ICdzd2lwZXItc2Nyb2xsYmFyJ1xuICAgIH0pO1xuICAgIGNvbnN0IHBhcmFtcyA9IHN3aXBlci5wYXJhbXMuc2Nyb2xsYmFyO1xuICAgIGlmICghcGFyYW1zLmVsKSByZXR1cm47XG4gICAgbGV0ICRlbCA9ICQocGFyYW1zLmVsKTtcblxuICAgIGlmIChzd2lwZXIucGFyYW1zLnVuaXF1ZU5hdkVsZW1lbnRzICYmIHR5cGVvZiBwYXJhbXMuZWwgPT09ICdzdHJpbmcnICYmICRlbC5sZW5ndGggPiAxICYmICRzd2lwZXJFbC5maW5kKHBhcmFtcy5lbCkubGVuZ3RoID09PSAxKSB7XG4gICAgICAkZWwgPSAkc3dpcGVyRWwuZmluZChwYXJhbXMuZWwpO1xuICAgIH1cblxuICAgICRlbC5hZGRDbGFzcyhzd2lwZXIuaXNIb3Jpem9udGFsKCkgPyBwYXJhbXMuaG9yaXpvbnRhbENsYXNzIDogcGFyYW1zLnZlcnRpY2FsQ2xhc3MpO1xuICAgIGxldCAkZHJhZ0VsID0gJGVsLmZpbmQoYC4ke3N3aXBlci5wYXJhbXMuc2Nyb2xsYmFyLmRyYWdDbGFzc31gKTtcblxuICAgIGlmICgkZHJhZ0VsLmxlbmd0aCA9PT0gMCkge1xuICAgICAgJGRyYWdFbCA9ICQoYDxkaXYgY2xhc3M9XCIke3N3aXBlci5wYXJhbXMuc2Nyb2xsYmFyLmRyYWdDbGFzc31cIj48L2Rpdj5gKTtcbiAgICAgICRlbC5hcHBlbmQoJGRyYWdFbCk7XG4gICAgfVxuXG4gICAgT2JqZWN0LmFzc2lnbihzY3JvbGxiYXIsIHtcbiAgICAgICRlbCxcbiAgICAgIGVsOiAkZWxbMF0sXG4gICAgICAkZHJhZ0VsLFxuICAgICAgZHJhZ0VsOiAkZHJhZ0VsWzBdXG4gICAgfSk7XG5cbiAgICBpZiAocGFyYW1zLmRyYWdnYWJsZSkge1xuICAgICAgZW5hYmxlRHJhZ2dhYmxlKCk7XG4gICAgfVxuXG4gICAgaWYgKCRlbCkge1xuICAgICAgJGVsW3N3aXBlci5lbmFibGVkID8gJ3JlbW92ZUNsYXNzJyA6ICdhZGRDbGFzcyddKHN3aXBlci5wYXJhbXMuc2Nyb2xsYmFyLmxvY2tDbGFzcyk7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gZGVzdHJveSgpIHtcbiAgICBjb25zdCBwYXJhbXMgPSBzd2lwZXIucGFyYW1zLnNjcm9sbGJhcjtcbiAgICBjb25zdCAkZWwgPSBzd2lwZXIuc2Nyb2xsYmFyLiRlbDtcblxuICAgIGlmICgkZWwpIHtcbiAgICAgICRlbC5yZW1vdmVDbGFzcyhzd2lwZXIuaXNIb3Jpem9udGFsKCkgPyBwYXJhbXMuaG9yaXpvbnRhbENsYXNzIDogcGFyYW1zLnZlcnRpY2FsQ2xhc3MpO1xuICAgIH1cblxuICAgIGRpc2FibGVEcmFnZ2FibGUoKTtcbiAgfVxuXG4gIG9uKCdpbml0JywgKCkgPT4ge1xuICAgIGlmIChzd2lwZXIucGFyYW1zLnNjcm9sbGJhci5lbmFibGVkID09PSBmYWxzZSkge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG4gICAgICBkaXNhYmxlKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGluaXQoKTtcbiAgICAgIHVwZGF0ZVNpemUoKTtcbiAgICAgIHNldFRyYW5zbGF0ZSgpO1xuICAgIH1cbiAgfSk7XG4gIG9uKCd1cGRhdGUgcmVzaXplIG9ic2VydmVyVXBkYXRlIGxvY2sgdW5sb2NrJywgKCkgPT4ge1xuICAgIHVwZGF0ZVNpemUoKTtcbiAgfSk7XG4gIG9uKCdzZXRUcmFuc2xhdGUnLCAoKSA9PiB7XG4gICAgc2V0VHJhbnNsYXRlKCk7XG4gIH0pO1xuICBvbignc2V0VHJhbnNpdGlvbicsIChfcywgZHVyYXRpb24pID0+IHtcbiAgICBzZXRUcmFuc2l0aW9uKGR1cmF0aW9uKTtcbiAgfSk7XG4gIG9uKCdlbmFibGUgZGlzYWJsZScsICgpID0+IHtcbiAgICBjb25zdCB7XG4gICAgICAkZWxcbiAgICB9ID0gc3dpcGVyLnNjcm9sbGJhcjtcblxuICAgIGlmICgkZWwpIHtcbiAgICAgICRlbFtzd2lwZXIuZW5hYmxlZCA/ICdyZW1vdmVDbGFzcycgOiAnYWRkQ2xhc3MnXShzd2lwZXIucGFyYW1zLnNjcm9sbGJhci5sb2NrQ2xhc3MpO1xuICAgIH1cbiAgfSk7XG4gIG9uKCdkZXN0cm95JywgKCkgPT4ge1xuICAgIGRlc3Ryb3koKTtcbiAgfSk7XG5cbiAgY29uc3QgZW5hYmxlID0gKCkgPT4ge1xuICAgIHN3aXBlci4kZWwucmVtb3ZlQ2xhc3Moc3dpcGVyLnBhcmFtcy5zY3JvbGxiYXIuc2Nyb2xsYmFyRGlzYWJsZWRDbGFzcyk7XG5cbiAgICBpZiAoc3dpcGVyLnNjcm9sbGJhci4kZWwpIHtcbiAgICAgIHN3aXBlci5zY3JvbGxiYXIuJGVsLnJlbW92ZUNsYXNzKHN3aXBlci5wYXJhbXMuc2Nyb2xsYmFyLnNjcm9sbGJhckRpc2FibGVkQ2xhc3MpO1xuICAgIH1cblxuICAgIGluaXQoKTtcbiAgICB1cGRhdGVTaXplKCk7XG4gICAgc2V0VHJhbnNsYXRlKCk7XG4gIH07XG5cbiAgY29uc3QgZGlzYWJsZSA9ICgpID0+IHtcbiAgICBzd2lwZXIuJGVsLmFkZENsYXNzKHN3aXBlci5wYXJhbXMuc2Nyb2xsYmFyLnNjcm9sbGJhckRpc2FibGVkQ2xhc3MpO1xuXG4gICAgaWYgKHN3aXBlci5zY3JvbGxiYXIuJGVsKSB7XG4gICAgICBzd2lwZXIuc2Nyb2xsYmFyLiRlbC5hZGRDbGFzcyhzd2lwZXIucGFyYW1zLnNjcm9sbGJhci5zY3JvbGxiYXJEaXNhYmxlZENsYXNzKTtcbiAgICB9XG5cbiAgICBkZXN0cm95KCk7XG4gIH07XG5cbiAgT2JqZWN0LmFzc2lnbihzd2lwZXIuc2Nyb2xsYmFyLCB7XG4gICAgZW5hYmxlLFxuICAgIGRpc2FibGUsXG4gICAgdXBkYXRlU2l6ZSxcbiAgICBzZXRUcmFuc2xhdGUsXG4gICAgaW5pdCxcbiAgICBkZXN0cm95XG4gIH0pO1xufSIsImltcG9ydCAkIGZyb20gJy4uLy4uL3NoYXJlZC9kb20uanMnO1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gUGFyYWxsYXgoe1xuICBzd2lwZXIsXG4gIGV4dGVuZFBhcmFtcyxcbiAgb25cbn0pIHtcbiAgZXh0ZW5kUGFyYW1zKHtcbiAgICBwYXJhbGxheDoge1xuICAgICAgZW5hYmxlZDogZmFsc2VcbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IHNldFRyYW5zZm9ybSA9IChlbCwgcHJvZ3Jlc3MpID0+IHtcbiAgICBjb25zdCB7XG4gICAgICBydGxcbiAgICB9ID0gc3dpcGVyO1xuICAgIGNvbnN0ICRlbCA9ICQoZWwpO1xuICAgIGNvbnN0IHJ0bEZhY3RvciA9IHJ0bCA/IC0xIDogMTtcbiAgICBjb25zdCBwID0gJGVsLmF0dHIoJ2RhdGEtc3dpcGVyLXBhcmFsbGF4JykgfHwgJzAnO1xuICAgIGxldCB4ID0gJGVsLmF0dHIoJ2RhdGEtc3dpcGVyLXBhcmFsbGF4LXgnKTtcbiAgICBsZXQgeSA9ICRlbC5hdHRyKCdkYXRhLXN3aXBlci1wYXJhbGxheC15Jyk7XG4gICAgY29uc3Qgc2NhbGUgPSAkZWwuYXR0cignZGF0YS1zd2lwZXItcGFyYWxsYXgtc2NhbGUnKTtcbiAgICBjb25zdCBvcGFjaXR5ID0gJGVsLmF0dHIoJ2RhdGEtc3dpcGVyLXBhcmFsbGF4LW9wYWNpdHknKTtcblxuICAgIGlmICh4IHx8IHkpIHtcbiAgICAgIHggPSB4IHx8ICcwJztcbiAgICAgIHkgPSB5IHx8ICcwJztcbiAgICB9IGVsc2UgaWYgKHN3aXBlci5pc0hvcml6b250YWwoKSkge1xuICAgICAgeCA9IHA7XG4gICAgICB5ID0gJzAnO1xuICAgIH0gZWxzZSB7XG4gICAgICB5ID0gcDtcbiAgICAgIHggPSAnMCc7XG4gICAgfVxuXG4gICAgaWYgKHguaW5kZXhPZignJScpID49IDApIHtcbiAgICAgIHggPSBgJHtwYXJzZUludCh4LCAxMCkgKiBwcm9ncmVzcyAqIHJ0bEZhY3Rvcn0lYDtcbiAgICB9IGVsc2Uge1xuICAgICAgeCA9IGAke3ggKiBwcm9ncmVzcyAqIHJ0bEZhY3Rvcn1weGA7XG4gICAgfVxuXG4gICAgaWYgKHkuaW5kZXhPZignJScpID49IDApIHtcbiAgICAgIHkgPSBgJHtwYXJzZUludCh5LCAxMCkgKiBwcm9ncmVzc30lYDtcbiAgICB9IGVsc2Uge1xuICAgICAgeSA9IGAke3kgKiBwcm9ncmVzc31weGA7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBvcGFjaXR5ICE9PSAndW5kZWZpbmVkJyAmJiBvcGFjaXR5ICE9PSBudWxsKSB7XG4gICAgICBjb25zdCBjdXJyZW50T3BhY2l0eSA9IG9wYWNpdHkgLSAob3BhY2l0eSAtIDEpICogKDEgLSBNYXRoLmFicyhwcm9ncmVzcykpO1xuICAgICAgJGVsWzBdLnN0eWxlLm9wYWNpdHkgPSBjdXJyZW50T3BhY2l0eTtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIHNjYWxlID09PSAndW5kZWZpbmVkJyB8fCBzY2FsZSA9PT0gbnVsbCkge1xuICAgICAgJGVsLnRyYW5zZm9ybShgdHJhbnNsYXRlM2QoJHt4fSwgJHt5fSwgMHB4KWApO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBjdXJyZW50U2NhbGUgPSBzY2FsZSAtIChzY2FsZSAtIDEpICogKDEgLSBNYXRoLmFicyhwcm9ncmVzcykpO1xuICAgICAgJGVsLnRyYW5zZm9ybShgdHJhbnNsYXRlM2QoJHt4fSwgJHt5fSwgMHB4KSBzY2FsZSgke2N1cnJlbnRTY2FsZX0pYCk7XG4gICAgfVxuICB9O1xuXG4gIGNvbnN0IHNldFRyYW5zbGF0ZSA9ICgpID0+IHtcbiAgICBjb25zdCB7XG4gICAgICAkZWwsXG4gICAgICBzbGlkZXMsXG4gICAgICBwcm9ncmVzcyxcbiAgICAgIHNuYXBHcmlkXG4gICAgfSA9IHN3aXBlcjtcbiAgICAkZWwuY2hpbGRyZW4oJ1tkYXRhLXN3aXBlci1wYXJhbGxheF0sIFtkYXRhLXN3aXBlci1wYXJhbGxheC14XSwgW2RhdGEtc3dpcGVyLXBhcmFsbGF4LXldLCBbZGF0YS1zd2lwZXItcGFyYWxsYXgtb3BhY2l0eV0sIFtkYXRhLXN3aXBlci1wYXJhbGxheC1zY2FsZV0nKS5lYWNoKGVsID0+IHtcbiAgICAgIHNldFRyYW5zZm9ybShlbCwgcHJvZ3Jlc3MpO1xuICAgIH0pO1xuICAgIHNsaWRlcy5lYWNoKChzbGlkZUVsLCBzbGlkZUluZGV4KSA9PiB7XG4gICAgICBsZXQgc2xpZGVQcm9ncmVzcyA9IHNsaWRlRWwucHJvZ3Jlc3M7XG5cbiAgICAgIGlmIChzd2lwZXIucGFyYW1zLnNsaWRlc1Blckdyb3VwID4gMSAmJiBzd2lwZXIucGFyYW1zLnNsaWRlc1BlclZpZXcgIT09ICdhdXRvJykge1xuICAgICAgICBzbGlkZVByb2dyZXNzICs9IE1hdGguY2VpbChzbGlkZUluZGV4IC8gMikgLSBwcm9ncmVzcyAqIChzbmFwR3JpZC5sZW5ndGggLSAxKTtcbiAgICAgIH1cblxuICAgICAgc2xpZGVQcm9ncmVzcyA9IE1hdGgubWluKE1hdGgubWF4KHNsaWRlUHJvZ3Jlc3MsIC0xKSwgMSk7XG4gICAgICAkKHNsaWRlRWwpLmZpbmQoJ1tkYXRhLXN3aXBlci1wYXJhbGxheF0sIFtkYXRhLXN3aXBlci1wYXJhbGxheC14XSwgW2RhdGEtc3dpcGVyLXBhcmFsbGF4LXldLCBbZGF0YS1zd2lwZXItcGFyYWxsYXgtb3BhY2l0eV0sIFtkYXRhLXN3aXBlci1wYXJhbGxheC1zY2FsZV0nKS5lYWNoKGVsID0+IHtcbiAgICAgICAgc2V0VHJhbnNmb3JtKGVsLCBzbGlkZVByb2dyZXNzKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9O1xuXG4gIGNvbnN0IHNldFRyYW5zaXRpb24gPSAoZHVyYXRpb24gPSBzd2lwZXIucGFyYW1zLnNwZWVkKSA9PiB7XG4gICAgY29uc3Qge1xuICAgICAgJGVsXG4gICAgfSA9IHN3aXBlcjtcbiAgICAkZWwuZmluZCgnW2RhdGEtc3dpcGVyLXBhcmFsbGF4XSwgW2RhdGEtc3dpcGVyLXBhcmFsbGF4LXhdLCBbZGF0YS1zd2lwZXItcGFyYWxsYXgteV0sIFtkYXRhLXN3aXBlci1wYXJhbGxheC1vcGFjaXR5XSwgW2RhdGEtc3dpcGVyLXBhcmFsbGF4LXNjYWxlXScpLmVhY2gocGFyYWxsYXhFbCA9PiB7XG4gICAgICBjb25zdCAkcGFyYWxsYXhFbCA9ICQocGFyYWxsYXhFbCk7XG4gICAgICBsZXQgcGFyYWxsYXhEdXJhdGlvbiA9IHBhcnNlSW50KCRwYXJhbGxheEVsLmF0dHIoJ2RhdGEtc3dpcGVyLXBhcmFsbGF4LWR1cmF0aW9uJyksIDEwKSB8fCBkdXJhdGlvbjtcbiAgICAgIGlmIChkdXJhdGlvbiA9PT0gMCkgcGFyYWxsYXhEdXJhdGlvbiA9IDA7XG4gICAgICAkcGFyYWxsYXhFbC50cmFuc2l0aW9uKHBhcmFsbGF4RHVyYXRpb24pO1xuICAgIH0pO1xuICB9O1xuXG4gIG9uKCdiZWZvcmVJbml0JywgKCkgPT4ge1xuICAgIGlmICghc3dpcGVyLnBhcmFtcy5wYXJhbGxheC5lbmFibGVkKSByZXR1cm47XG4gICAgc3dpcGVyLnBhcmFtcy53YXRjaFNsaWRlc1Byb2dyZXNzID0gdHJ1ZTtcbiAgICBzd2lwZXIub3JpZ2luYWxQYXJhbXMud2F0Y2hTbGlkZXNQcm9ncmVzcyA9IHRydWU7XG4gIH0pO1xuICBvbignaW5pdCcsICgpID0+IHtcbiAgICBpZiAoIXN3aXBlci5wYXJhbXMucGFyYWxsYXguZW5hYmxlZCkgcmV0dXJuO1xuICAgIHNldFRyYW5zbGF0ZSgpO1xuICB9KTtcbiAgb24oJ3NldFRyYW5zbGF0ZScsICgpID0+IHtcbiAgICBpZiAoIXN3aXBlci5wYXJhbXMucGFyYWxsYXguZW5hYmxlZCkgcmV0dXJuO1xuICAgIHNldFRyYW5zbGF0ZSgpO1xuICB9KTtcbiAgb24oJ3NldFRyYW5zaXRpb24nLCAoX3N3aXBlciwgZHVyYXRpb24pID0+IHtcbiAgICBpZiAoIXN3aXBlci5wYXJhbXMucGFyYWxsYXguZW5hYmxlZCkgcmV0dXJuO1xuICAgIHNldFRyYW5zaXRpb24oZHVyYXRpb24pO1xuICB9KTtcbn0iLCJpbXBvcnQgeyBnZXRXaW5kb3cgfSBmcm9tICdzc3Itd2luZG93JztcbmltcG9ydCAkIGZyb20gJy4uLy4uL3NoYXJlZC9kb20uanMnO1xuaW1wb3J0IHsgZ2V0VHJhbnNsYXRlIH0gZnJvbSAnLi4vLi4vc2hhcmVkL3V0aWxzLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIFpvb20oe1xuICBzd2lwZXIsXG4gIGV4dGVuZFBhcmFtcyxcbiAgb24sXG4gIGVtaXRcbn0pIHtcbiAgY29uc3Qgd2luZG93ID0gZ2V0V2luZG93KCk7XG4gIGV4dGVuZFBhcmFtcyh7XG4gICAgem9vbToge1xuICAgICAgZW5hYmxlZDogZmFsc2UsXG4gICAgICBtYXhSYXRpbzogMyxcbiAgICAgIG1pblJhdGlvOiAxLFxuICAgICAgdG9nZ2xlOiB0cnVlLFxuICAgICAgY29udGFpbmVyQ2xhc3M6ICdzd2lwZXItem9vbS1jb250YWluZXInLFxuICAgICAgem9vbWVkU2xpZGVDbGFzczogJ3N3aXBlci1zbGlkZS16b29tZWQnXG4gICAgfVxuICB9KTtcbiAgc3dpcGVyLnpvb20gPSB7XG4gICAgZW5hYmxlZDogZmFsc2VcbiAgfTtcbiAgbGV0IGN1cnJlbnRTY2FsZSA9IDE7XG4gIGxldCBpc1NjYWxpbmcgPSBmYWxzZTtcbiAgbGV0IGdlc3R1cmVzRW5hYmxlZDtcbiAgbGV0IGZha2VHZXN0dXJlVG91Y2hlZDtcbiAgbGV0IGZha2VHZXN0dXJlTW92ZWQ7XG4gIGNvbnN0IGdlc3R1cmUgPSB7XG4gICAgJHNsaWRlRWw6IHVuZGVmaW5lZCxcbiAgICBzbGlkZVdpZHRoOiB1bmRlZmluZWQsXG4gICAgc2xpZGVIZWlnaHQ6IHVuZGVmaW5lZCxcbiAgICAkaW1hZ2VFbDogdW5kZWZpbmVkLFxuICAgICRpbWFnZVdyYXBFbDogdW5kZWZpbmVkLFxuICAgIG1heFJhdGlvOiAzXG4gIH07XG4gIGNvbnN0IGltYWdlID0ge1xuICAgIGlzVG91Y2hlZDogdW5kZWZpbmVkLFxuICAgIGlzTW92ZWQ6IHVuZGVmaW5lZCxcbiAgICBjdXJyZW50WDogdW5kZWZpbmVkLFxuICAgIGN1cnJlbnRZOiB1bmRlZmluZWQsXG4gICAgbWluWDogdW5kZWZpbmVkLFxuICAgIG1pblk6IHVuZGVmaW5lZCxcbiAgICBtYXhYOiB1bmRlZmluZWQsXG4gICAgbWF4WTogdW5kZWZpbmVkLFxuICAgIHdpZHRoOiB1bmRlZmluZWQsXG4gICAgaGVpZ2h0OiB1bmRlZmluZWQsXG4gICAgc3RhcnRYOiB1bmRlZmluZWQsXG4gICAgc3RhcnRZOiB1bmRlZmluZWQsXG4gICAgdG91Y2hlc1N0YXJ0OiB7fSxcbiAgICB0b3VjaGVzQ3VycmVudDoge31cbiAgfTtcbiAgY29uc3QgdmVsb2NpdHkgPSB7XG4gICAgeDogdW5kZWZpbmVkLFxuICAgIHk6IHVuZGVmaW5lZCxcbiAgICBwcmV2UG9zaXRpb25YOiB1bmRlZmluZWQsXG4gICAgcHJldlBvc2l0aW9uWTogdW5kZWZpbmVkLFxuICAgIHByZXZUaW1lOiB1bmRlZmluZWRcbiAgfTtcbiAgbGV0IHNjYWxlID0gMTtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHN3aXBlci56b29tLCAnc2NhbGUnLCB7XG4gICAgZ2V0KCkge1xuICAgICAgcmV0dXJuIHNjYWxlO1xuICAgIH0sXG5cbiAgICBzZXQodmFsdWUpIHtcbiAgICAgIGlmIChzY2FsZSAhPT0gdmFsdWUpIHtcbiAgICAgICAgY29uc3QgaW1hZ2VFbCA9IGdlc3R1cmUuJGltYWdlRWwgPyBnZXN0dXJlLiRpbWFnZUVsWzBdIDogdW5kZWZpbmVkO1xuICAgICAgICBjb25zdCBzbGlkZUVsID0gZ2VzdHVyZS4kc2xpZGVFbCA/IGdlc3R1cmUuJHNsaWRlRWxbMF0gOiB1bmRlZmluZWQ7XG4gICAgICAgIGVtaXQoJ3pvb21DaGFuZ2UnLCB2YWx1ZSwgaW1hZ2VFbCwgc2xpZGVFbCk7XG4gICAgICB9XG5cbiAgICAgIHNjYWxlID0gdmFsdWU7XG4gICAgfVxuXG4gIH0pO1xuXG4gIGZ1bmN0aW9uIGdldERpc3RhbmNlQmV0d2VlblRvdWNoZXMoZSkge1xuICAgIGlmIChlLnRhcmdldFRvdWNoZXMubGVuZ3RoIDwgMikgcmV0dXJuIDE7XG4gICAgY29uc3QgeDEgPSBlLnRhcmdldFRvdWNoZXNbMF0ucGFnZVg7XG4gICAgY29uc3QgeTEgPSBlLnRhcmdldFRvdWNoZXNbMF0ucGFnZVk7XG4gICAgY29uc3QgeDIgPSBlLnRhcmdldFRvdWNoZXNbMV0ucGFnZVg7XG4gICAgY29uc3QgeTIgPSBlLnRhcmdldFRvdWNoZXNbMV0ucGFnZVk7XG4gICAgY29uc3QgZGlzdGFuY2UgPSBNYXRoLnNxcnQoKHgyIC0geDEpICoqIDIgKyAoeTIgLSB5MSkgKiogMik7XG4gICAgcmV0dXJuIGRpc3RhbmNlO1xuICB9IC8vIEV2ZW50c1xuXG5cbiAgZnVuY3Rpb24gb25HZXN0dXJlU3RhcnQoZSkge1xuICAgIGNvbnN0IHN1cHBvcnQgPSBzd2lwZXIuc3VwcG9ydDtcbiAgICBjb25zdCBwYXJhbXMgPSBzd2lwZXIucGFyYW1zLnpvb207XG4gICAgZmFrZUdlc3R1cmVUb3VjaGVkID0gZmFsc2U7XG4gICAgZmFrZUdlc3R1cmVNb3ZlZCA9IGZhbHNlO1xuXG4gICAgaWYgKCFzdXBwb3J0Lmdlc3R1cmVzKSB7XG4gICAgICBpZiAoZS50eXBlICE9PSAndG91Y2hzdGFydCcgfHwgZS50eXBlID09PSAndG91Y2hzdGFydCcgJiYgZS50YXJnZXRUb3VjaGVzLmxlbmd0aCA8IDIpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBmYWtlR2VzdHVyZVRvdWNoZWQgPSB0cnVlO1xuICAgICAgZ2VzdHVyZS5zY2FsZVN0YXJ0ID0gZ2V0RGlzdGFuY2VCZXR3ZWVuVG91Y2hlcyhlKTtcbiAgICB9XG5cbiAgICBpZiAoIWdlc3R1cmUuJHNsaWRlRWwgfHwgIWdlc3R1cmUuJHNsaWRlRWwubGVuZ3RoKSB7XG4gICAgICBnZXN0dXJlLiRzbGlkZUVsID0gJChlLnRhcmdldCkuY2xvc2VzdChgLiR7c3dpcGVyLnBhcmFtcy5zbGlkZUNsYXNzfWApO1xuICAgICAgaWYgKGdlc3R1cmUuJHNsaWRlRWwubGVuZ3RoID09PSAwKSBnZXN0dXJlLiRzbGlkZUVsID0gc3dpcGVyLnNsaWRlcy5lcShzd2lwZXIuYWN0aXZlSW5kZXgpO1xuICAgICAgZ2VzdHVyZS4kaW1hZ2VFbCA9IGdlc3R1cmUuJHNsaWRlRWwuZmluZChgLiR7cGFyYW1zLmNvbnRhaW5lckNsYXNzfWApLmVxKDApLmZpbmQoJ3BpY3R1cmUsIGltZywgc3ZnLCBjYW52YXMsIC5zd2lwZXItem9vbS10YXJnZXQnKS5lcSgwKTtcbiAgICAgIGdlc3R1cmUuJGltYWdlV3JhcEVsID0gZ2VzdHVyZS4kaW1hZ2VFbC5wYXJlbnQoYC4ke3BhcmFtcy5jb250YWluZXJDbGFzc31gKTtcbiAgICAgIGdlc3R1cmUubWF4UmF0aW8gPSBnZXN0dXJlLiRpbWFnZVdyYXBFbC5hdHRyKCdkYXRhLXN3aXBlci16b29tJykgfHwgcGFyYW1zLm1heFJhdGlvO1xuXG4gICAgICBpZiAoZ2VzdHVyZS4kaW1hZ2VXcmFwRWwubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGdlc3R1cmUuJGltYWdlRWwgPSB1bmRlZmluZWQ7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoZ2VzdHVyZS4kaW1hZ2VFbCkge1xuICAgICAgZ2VzdHVyZS4kaW1hZ2VFbC50cmFuc2l0aW9uKDApO1xuICAgIH1cblxuICAgIGlzU2NhbGluZyA9IHRydWU7XG4gIH1cblxuICBmdW5jdGlvbiBvbkdlc3R1cmVDaGFuZ2UoZSkge1xuICAgIGNvbnN0IHN1cHBvcnQgPSBzd2lwZXIuc3VwcG9ydDtcbiAgICBjb25zdCBwYXJhbXMgPSBzd2lwZXIucGFyYW1zLnpvb207XG4gICAgY29uc3Qgem9vbSA9IHN3aXBlci56b29tO1xuXG4gICAgaWYgKCFzdXBwb3J0Lmdlc3R1cmVzKSB7XG4gICAgICBpZiAoZS50eXBlICE9PSAndG91Y2htb3ZlJyB8fCBlLnR5cGUgPT09ICd0b3VjaG1vdmUnICYmIGUudGFyZ2V0VG91Y2hlcy5sZW5ndGggPCAyKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgZmFrZUdlc3R1cmVNb3ZlZCA9IHRydWU7XG4gICAgICBnZXN0dXJlLnNjYWxlTW92ZSA9IGdldERpc3RhbmNlQmV0d2VlblRvdWNoZXMoZSk7XG4gICAgfVxuXG4gICAgaWYgKCFnZXN0dXJlLiRpbWFnZUVsIHx8IGdlc3R1cmUuJGltYWdlRWwubGVuZ3RoID09PSAwKSB7XG4gICAgICBpZiAoZS50eXBlID09PSAnZ2VzdHVyZWNoYW5nZScpIG9uR2VzdHVyZVN0YXJ0KGUpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChzdXBwb3J0Lmdlc3R1cmVzKSB7XG4gICAgICB6b29tLnNjYWxlID0gZS5zY2FsZSAqIGN1cnJlbnRTY2FsZTtcbiAgICB9IGVsc2Uge1xuICAgICAgem9vbS5zY2FsZSA9IGdlc3R1cmUuc2NhbGVNb3ZlIC8gZ2VzdHVyZS5zY2FsZVN0YXJ0ICogY3VycmVudFNjYWxlO1xuICAgIH1cblxuICAgIGlmICh6b29tLnNjYWxlID4gZ2VzdHVyZS5tYXhSYXRpbykge1xuICAgICAgem9vbS5zY2FsZSA9IGdlc3R1cmUubWF4UmF0aW8gLSAxICsgKHpvb20uc2NhbGUgLSBnZXN0dXJlLm1heFJhdGlvICsgMSkgKiogMC41O1xuICAgIH1cblxuICAgIGlmICh6b29tLnNjYWxlIDwgcGFyYW1zLm1pblJhdGlvKSB7XG4gICAgICB6b29tLnNjYWxlID0gcGFyYW1zLm1pblJhdGlvICsgMSAtIChwYXJhbXMubWluUmF0aW8gLSB6b29tLnNjYWxlICsgMSkgKiogMC41O1xuICAgIH1cblxuICAgIGdlc3R1cmUuJGltYWdlRWwudHJhbnNmb3JtKGB0cmFuc2xhdGUzZCgwLDAsMCkgc2NhbGUoJHt6b29tLnNjYWxlfSlgKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIG9uR2VzdHVyZUVuZChlKSB7XG4gICAgY29uc3QgZGV2aWNlID0gc3dpcGVyLmRldmljZTtcbiAgICBjb25zdCBzdXBwb3J0ID0gc3dpcGVyLnN1cHBvcnQ7XG4gICAgY29uc3QgcGFyYW1zID0gc3dpcGVyLnBhcmFtcy56b29tO1xuICAgIGNvbnN0IHpvb20gPSBzd2lwZXIuem9vbTtcblxuICAgIGlmICghc3VwcG9ydC5nZXN0dXJlcykge1xuICAgICAgaWYgKCFmYWtlR2VzdHVyZVRvdWNoZWQgfHwgIWZha2VHZXN0dXJlTW92ZWQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZS50eXBlICE9PSAndG91Y2hlbmQnIHx8IGUudHlwZSA9PT0gJ3RvdWNoZW5kJyAmJiBlLmNoYW5nZWRUb3VjaGVzLmxlbmd0aCA8IDIgJiYgIWRldmljZS5hbmRyb2lkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgZmFrZUdlc3R1cmVUb3VjaGVkID0gZmFsc2U7XG4gICAgICBmYWtlR2VzdHVyZU1vdmVkID0gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKCFnZXN0dXJlLiRpbWFnZUVsIHx8IGdlc3R1cmUuJGltYWdlRWwubGVuZ3RoID09PSAwKSByZXR1cm47XG4gICAgem9vbS5zY2FsZSA9IE1hdGgubWF4KE1hdGgubWluKHpvb20uc2NhbGUsIGdlc3R1cmUubWF4UmF0aW8pLCBwYXJhbXMubWluUmF0aW8pO1xuICAgIGdlc3R1cmUuJGltYWdlRWwudHJhbnNpdGlvbihzd2lwZXIucGFyYW1zLnNwZWVkKS50cmFuc2Zvcm0oYHRyYW5zbGF0ZTNkKDAsMCwwKSBzY2FsZSgke3pvb20uc2NhbGV9KWApO1xuICAgIGN1cnJlbnRTY2FsZSA9IHpvb20uc2NhbGU7XG4gICAgaXNTY2FsaW5nID0gZmFsc2U7XG4gICAgaWYgKHpvb20uc2NhbGUgPT09IDEpIGdlc3R1cmUuJHNsaWRlRWwgPSB1bmRlZmluZWQ7XG4gIH1cblxuICBmdW5jdGlvbiBvblRvdWNoU3RhcnQoZSkge1xuICAgIGNvbnN0IGRldmljZSA9IHN3aXBlci5kZXZpY2U7XG4gICAgaWYgKCFnZXN0dXJlLiRpbWFnZUVsIHx8IGdlc3R1cmUuJGltYWdlRWwubGVuZ3RoID09PSAwKSByZXR1cm47XG4gICAgaWYgKGltYWdlLmlzVG91Y2hlZCkgcmV0dXJuO1xuICAgIGlmIChkZXZpY2UuYW5kcm9pZCAmJiBlLmNhbmNlbGFibGUpIGUucHJldmVudERlZmF1bHQoKTtcbiAgICBpbWFnZS5pc1RvdWNoZWQgPSB0cnVlO1xuICAgIGltYWdlLnRvdWNoZXNTdGFydC54ID0gZS50eXBlID09PSAndG91Y2hzdGFydCcgPyBlLnRhcmdldFRvdWNoZXNbMF0ucGFnZVggOiBlLnBhZ2VYO1xuICAgIGltYWdlLnRvdWNoZXNTdGFydC55ID0gZS50eXBlID09PSAndG91Y2hzdGFydCcgPyBlLnRhcmdldFRvdWNoZXNbMF0ucGFnZVkgOiBlLnBhZ2VZO1xuICB9XG5cbiAgZnVuY3Rpb24gb25Ub3VjaE1vdmUoZSkge1xuICAgIGNvbnN0IHpvb20gPSBzd2lwZXIuem9vbTtcbiAgICBpZiAoIWdlc3R1cmUuJGltYWdlRWwgfHwgZ2VzdHVyZS4kaW1hZ2VFbC5sZW5ndGggPT09IDApIHJldHVybjtcbiAgICBzd2lwZXIuYWxsb3dDbGljayA9IGZhbHNlO1xuICAgIGlmICghaW1hZ2UuaXNUb3VjaGVkIHx8ICFnZXN0dXJlLiRzbGlkZUVsKSByZXR1cm47XG5cbiAgICBpZiAoIWltYWdlLmlzTW92ZWQpIHtcbiAgICAgIGltYWdlLndpZHRoID0gZ2VzdHVyZS4kaW1hZ2VFbFswXS5vZmZzZXRXaWR0aDtcbiAgICAgIGltYWdlLmhlaWdodCA9IGdlc3R1cmUuJGltYWdlRWxbMF0ub2Zmc2V0SGVpZ2h0O1xuICAgICAgaW1hZ2Uuc3RhcnRYID0gZ2V0VHJhbnNsYXRlKGdlc3R1cmUuJGltYWdlV3JhcEVsWzBdLCAneCcpIHx8IDA7XG4gICAgICBpbWFnZS5zdGFydFkgPSBnZXRUcmFuc2xhdGUoZ2VzdHVyZS4kaW1hZ2VXcmFwRWxbMF0sICd5JykgfHwgMDtcbiAgICAgIGdlc3R1cmUuc2xpZGVXaWR0aCA9IGdlc3R1cmUuJHNsaWRlRWxbMF0ub2Zmc2V0V2lkdGg7XG4gICAgICBnZXN0dXJlLnNsaWRlSGVpZ2h0ID0gZ2VzdHVyZS4kc2xpZGVFbFswXS5vZmZzZXRIZWlnaHQ7XG4gICAgICBnZXN0dXJlLiRpbWFnZVdyYXBFbC50cmFuc2l0aW9uKDApO1xuICAgIH0gLy8gRGVmaW5lIGlmIHdlIG5lZWQgaW1hZ2UgZHJhZ1xuXG5cbiAgICBjb25zdCBzY2FsZWRXaWR0aCA9IGltYWdlLndpZHRoICogem9vbS5zY2FsZTtcbiAgICBjb25zdCBzY2FsZWRIZWlnaHQgPSBpbWFnZS5oZWlnaHQgKiB6b29tLnNjYWxlO1xuICAgIGlmIChzY2FsZWRXaWR0aCA8IGdlc3R1cmUuc2xpZGVXaWR0aCAmJiBzY2FsZWRIZWlnaHQgPCBnZXN0dXJlLnNsaWRlSGVpZ2h0KSByZXR1cm47XG4gICAgaW1hZ2UubWluWCA9IE1hdGgubWluKGdlc3R1cmUuc2xpZGVXaWR0aCAvIDIgLSBzY2FsZWRXaWR0aCAvIDIsIDApO1xuICAgIGltYWdlLm1heFggPSAtaW1hZ2UubWluWDtcbiAgICBpbWFnZS5taW5ZID0gTWF0aC5taW4oZ2VzdHVyZS5zbGlkZUhlaWdodCAvIDIgLSBzY2FsZWRIZWlnaHQgLyAyLCAwKTtcbiAgICBpbWFnZS5tYXhZID0gLWltYWdlLm1pblk7XG4gICAgaW1hZ2UudG91Y2hlc0N1cnJlbnQueCA9IGUudHlwZSA9PT0gJ3RvdWNobW92ZScgPyBlLnRhcmdldFRvdWNoZXNbMF0ucGFnZVggOiBlLnBhZ2VYO1xuICAgIGltYWdlLnRvdWNoZXNDdXJyZW50LnkgPSBlLnR5cGUgPT09ICd0b3VjaG1vdmUnID8gZS50YXJnZXRUb3VjaGVzWzBdLnBhZ2VZIDogZS5wYWdlWTtcblxuICAgIGlmICghaW1hZ2UuaXNNb3ZlZCAmJiAhaXNTY2FsaW5nKSB7XG4gICAgICBpZiAoc3dpcGVyLmlzSG9yaXpvbnRhbCgpICYmIChNYXRoLmZsb29yKGltYWdlLm1pblgpID09PSBNYXRoLmZsb29yKGltYWdlLnN0YXJ0WCkgJiYgaW1hZ2UudG91Y2hlc0N1cnJlbnQueCA8IGltYWdlLnRvdWNoZXNTdGFydC54IHx8IE1hdGguZmxvb3IoaW1hZ2UubWF4WCkgPT09IE1hdGguZmxvb3IoaW1hZ2Uuc3RhcnRYKSAmJiBpbWFnZS50b3VjaGVzQ3VycmVudC54ID4gaW1hZ2UudG91Y2hlc1N0YXJ0LngpKSB7XG4gICAgICAgIGltYWdlLmlzVG91Y2hlZCA9IGZhbHNlO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICghc3dpcGVyLmlzSG9yaXpvbnRhbCgpICYmIChNYXRoLmZsb29yKGltYWdlLm1pblkpID09PSBNYXRoLmZsb29yKGltYWdlLnN0YXJ0WSkgJiYgaW1hZ2UudG91Y2hlc0N1cnJlbnQueSA8IGltYWdlLnRvdWNoZXNTdGFydC55IHx8IE1hdGguZmxvb3IoaW1hZ2UubWF4WSkgPT09IE1hdGguZmxvb3IoaW1hZ2Uuc3RhcnRZKSAmJiBpbWFnZS50b3VjaGVzQ3VycmVudC55ID4gaW1hZ2UudG91Y2hlc1N0YXJ0LnkpKSB7XG4gICAgICAgIGltYWdlLmlzVG91Y2hlZCA9IGZhbHNlO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGUuY2FuY2VsYWJsZSkge1xuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIH1cblxuICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgaW1hZ2UuaXNNb3ZlZCA9IHRydWU7XG4gICAgaW1hZ2UuY3VycmVudFggPSBpbWFnZS50b3VjaGVzQ3VycmVudC54IC0gaW1hZ2UudG91Y2hlc1N0YXJ0LnggKyBpbWFnZS5zdGFydFg7XG4gICAgaW1hZ2UuY3VycmVudFkgPSBpbWFnZS50b3VjaGVzQ3VycmVudC55IC0gaW1hZ2UudG91Y2hlc1N0YXJ0LnkgKyBpbWFnZS5zdGFydFk7XG5cbiAgICBpZiAoaW1hZ2UuY3VycmVudFggPCBpbWFnZS5taW5YKSB7XG4gICAgICBpbWFnZS5jdXJyZW50WCA9IGltYWdlLm1pblggKyAxIC0gKGltYWdlLm1pblggLSBpbWFnZS5jdXJyZW50WCArIDEpICoqIDAuODtcbiAgICB9XG5cbiAgICBpZiAoaW1hZ2UuY3VycmVudFggPiBpbWFnZS5tYXhYKSB7XG4gICAgICBpbWFnZS5jdXJyZW50WCA9IGltYWdlLm1heFggLSAxICsgKGltYWdlLmN1cnJlbnRYIC0gaW1hZ2UubWF4WCArIDEpICoqIDAuODtcbiAgICB9XG5cbiAgICBpZiAoaW1hZ2UuY3VycmVudFkgPCBpbWFnZS5taW5ZKSB7XG4gICAgICBpbWFnZS5jdXJyZW50WSA9IGltYWdlLm1pblkgKyAxIC0gKGltYWdlLm1pblkgLSBpbWFnZS5jdXJyZW50WSArIDEpICoqIDAuODtcbiAgICB9XG5cbiAgICBpZiAoaW1hZ2UuY3VycmVudFkgPiBpbWFnZS5tYXhZKSB7XG4gICAgICBpbWFnZS5jdXJyZW50WSA9IGltYWdlLm1heFkgLSAxICsgKGltYWdlLmN1cnJlbnRZIC0gaW1hZ2UubWF4WSArIDEpICoqIDAuODtcbiAgICB9IC8vIFZlbG9jaXR5XG5cblxuICAgIGlmICghdmVsb2NpdHkucHJldlBvc2l0aW9uWCkgdmVsb2NpdHkucHJldlBvc2l0aW9uWCA9IGltYWdlLnRvdWNoZXNDdXJyZW50Lng7XG4gICAgaWYgKCF2ZWxvY2l0eS5wcmV2UG9zaXRpb25ZKSB2ZWxvY2l0eS5wcmV2UG9zaXRpb25ZID0gaW1hZ2UudG91Y2hlc0N1cnJlbnQueTtcbiAgICBpZiAoIXZlbG9jaXR5LnByZXZUaW1lKSB2ZWxvY2l0eS5wcmV2VGltZSA9IERhdGUubm93KCk7XG4gICAgdmVsb2NpdHkueCA9IChpbWFnZS50b3VjaGVzQ3VycmVudC54IC0gdmVsb2NpdHkucHJldlBvc2l0aW9uWCkgLyAoRGF0ZS5ub3coKSAtIHZlbG9jaXR5LnByZXZUaW1lKSAvIDI7XG4gICAgdmVsb2NpdHkueSA9IChpbWFnZS50b3VjaGVzQ3VycmVudC55IC0gdmVsb2NpdHkucHJldlBvc2l0aW9uWSkgLyAoRGF0ZS5ub3coKSAtIHZlbG9jaXR5LnByZXZUaW1lKSAvIDI7XG4gICAgaWYgKE1hdGguYWJzKGltYWdlLnRvdWNoZXNDdXJyZW50LnggLSB2ZWxvY2l0eS5wcmV2UG9zaXRpb25YKSA8IDIpIHZlbG9jaXR5LnggPSAwO1xuICAgIGlmIChNYXRoLmFicyhpbWFnZS50b3VjaGVzQ3VycmVudC55IC0gdmVsb2NpdHkucHJldlBvc2l0aW9uWSkgPCAyKSB2ZWxvY2l0eS55ID0gMDtcbiAgICB2ZWxvY2l0eS5wcmV2UG9zaXRpb25YID0gaW1hZ2UudG91Y2hlc0N1cnJlbnQueDtcbiAgICB2ZWxvY2l0eS5wcmV2UG9zaXRpb25ZID0gaW1hZ2UudG91Y2hlc0N1cnJlbnQueTtcbiAgICB2ZWxvY2l0eS5wcmV2VGltZSA9IERhdGUubm93KCk7XG4gICAgZ2VzdHVyZS4kaW1hZ2VXcmFwRWwudHJhbnNmb3JtKGB0cmFuc2xhdGUzZCgke2ltYWdlLmN1cnJlbnRYfXB4LCAke2ltYWdlLmN1cnJlbnRZfXB4LDApYCk7XG4gIH1cblxuICBmdW5jdGlvbiBvblRvdWNoRW5kKCkge1xuICAgIGNvbnN0IHpvb20gPSBzd2lwZXIuem9vbTtcbiAgICBpZiAoIWdlc3R1cmUuJGltYWdlRWwgfHwgZ2VzdHVyZS4kaW1hZ2VFbC5sZW5ndGggPT09IDApIHJldHVybjtcblxuICAgIGlmICghaW1hZ2UuaXNUb3VjaGVkIHx8ICFpbWFnZS5pc01vdmVkKSB7XG4gICAgICBpbWFnZS5pc1RvdWNoZWQgPSBmYWxzZTtcbiAgICAgIGltYWdlLmlzTW92ZWQgPSBmYWxzZTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpbWFnZS5pc1RvdWNoZWQgPSBmYWxzZTtcbiAgICBpbWFnZS5pc01vdmVkID0gZmFsc2U7XG4gICAgbGV0IG1vbWVudHVtRHVyYXRpb25YID0gMzAwO1xuICAgIGxldCBtb21lbnR1bUR1cmF0aW9uWSA9IDMwMDtcbiAgICBjb25zdCBtb21lbnR1bURpc3RhbmNlWCA9IHZlbG9jaXR5LnggKiBtb21lbnR1bUR1cmF0aW9uWDtcbiAgICBjb25zdCBuZXdQb3NpdGlvblggPSBpbWFnZS5jdXJyZW50WCArIG1vbWVudHVtRGlzdGFuY2VYO1xuICAgIGNvbnN0IG1vbWVudHVtRGlzdGFuY2VZID0gdmVsb2NpdHkueSAqIG1vbWVudHVtRHVyYXRpb25ZO1xuICAgIGNvbnN0IG5ld1Bvc2l0aW9uWSA9IGltYWdlLmN1cnJlbnRZICsgbW9tZW50dW1EaXN0YW5jZVk7IC8vIEZpeCBkdXJhdGlvblxuXG4gICAgaWYgKHZlbG9jaXR5LnggIT09IDApIG1vbWVudHVtRHVyYXRpb25YID0gTWF0aC5hYnMoKG5ld1Bvc2l0aW9uWCAtIGltYWdlLmN1cnJlbnRYKSAvIHZlbG9jaXR5LngpO1xuICAgIGlmICh2ZWxvY2l0eS55ICE9PSAwKSBtb21lbnR1bUR1cmF0aW9uWSA9IE1hdGguYWJzKChuZXdQb3NpdGlvblkgLSBpbWFnZS5jdXJyZW50WSkgLyB2ZWxvY2l0eS55KTtcbiAgICBjb25zdCBtb21lbnR1bUR1cmF0aW9uID0gTWF0aC5tYXgobW9tZW50dW1EdXJhdGlvblgsIG1vbWVudHVtRHVyYXRpb25ZKTtcbiAgICBpbWFnZS5jdXJyZW50WCA9IG5ld1Bvc2l0aW9uWDtcbiAgICBpbWFnZS5jdXJyZW50WSA9IG5ld1Bvc2l0aW9uWTsgLy8gRGVmaW5lIGlmIHdlIG5lZWQgaW1hZ2UgZHJhZ1xuXG4gICAgY29uc3Qgc2NhbGVkV2lkdGggPSBpbWFnZS53aWR0aCAqIHpvb20uc2NhbGU7XG4gICAgY29uc3Qgc2NhbGVkSGVpZ2h0ID0gaW1hZ2UuaGVpZ2h0ICogem9vbS5zY2FsZTtcbiAgICBpbWFnZS5taW5YID0gTWF0aC5taW4oZ2VzdHVyZS5zbGlkZVdpZHRoIC8gMiAtIHNjYWxlZFdpZHRoIC8gMiwgMCk7XG4gICAgaW1hZ2UubWF4WCA9IC1pbWFnZS5taW5YO1xuICAgIGltYWdlLm1pblkgPSBNYXRoLm1pbihnZXN0dXJlLnNsaWRlSGVpZ2h0IC8gMiAtIHNjYWxlZEhlaWdodCAvIDIsIDApO1xuICAgIGltYWdlLm1heFkgPSAtaW1hZ2UubWluWTtcbiAgICBpbWFnZS5jdXJyZW50WCA9IE1hdGgubWF4KE1hdGgubWluKGltYWdlLmN1cnJlbnRYLCBpbWFnZS5tYXhYKSwgaW1hZ2UubWluWCk7XG4gICAgaW1hZ2UuY3VycmVudFkgPSBNYXRoLm1heChNYXRoLm1pbihpbWFnZS5jdXJyZW50WSwgaW1hZ2UubWF4WSksIGltYWdlLm1pblkpO1xuICAgIGdlc3R1cmUuJGltYWdlV3JhcEVsLnRyYW5zaXRpb24obW9tZW50dW1EdXJhdGlvbikudHJhbnNmb3JtKGB0cmFuc2xhdGUzZCgke2ltYWdlLmN1cnJlbnRYfXB4LCAke2ltYWdlLmN1cnJlbnRZfXB4LDApYCk7XG4gIH1cblxuICBmdW5jdGlvbiBvblRyYW5zaXRpb25FbmQoKSB7XG4gICAgY29uc3Qgem9vbSA9IHN3aXBlci56b29tO1xuXG4gICAgaWYgKGdlc3R1cmUuJHNsaWRlRWwgJiYgc3dpcGVyLnByZXZpb3VzSW5kZXggIT09IHN3aXBlci5hY3RpdmVJbmRleCkge1xuICAgICAgaWYgKGdlc3R1cmUuJGltYWdlRWwpIHtcbiAgICAgICAgZ2VzdHVyZS4kaW1hZ2VFbC50cmFuc2Zvcm0oJ3RyYW5zbGF0ZTNkKDAsMCwwKSBzY2FsZSgxKScpO1xuICAgICAgfVxuXG4gICAgICBpZiAoZ2VzdHVyZS4kaW1hZ2VXcmFwRWwpIHtcbiAgICAgICAgZ2VzdHVyZS4kaW1hZ2VXcmFwRWwudHJhbnNmb3JtKCd0cmFuc2xhdGUzZCgwLDAsMCknKTtcbiAgICAgIH1cblxuICAgICAgem9vbS5zY2FsZSA9IDE7XG4gICAgICBjdXJyZW50U2NhbGUgPSAxO1xuICAgICAgZ2VzdHVyZS4kc2xpZGVFbCA9IHVuZGVmaW5lZDtcbiAgICAgIGdlc3R1cmUuJGltYWdlRWwgPSB1bmRlZmluZWQ7XG4gICAgICBnZXN0dXJlLiRpbWFnZVdyYXBFbCA9IHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiB6b29tSW4oZSkge1xuICAgIGNvbnN0IHpvb20gPSBzd2lwZXIuem9vbTtcbiAgICBjb25zdCBwYXJhbXMgPSBzd2lwZXIucGFyYW1zLnpvb207XG5cbiAgICBpZiAoIWdlc3R1cmUuJHNsaWRlRWwpIHtcbiAgICAgIGlmIChlICYmIGUudGFyZ2V0KSB7XG4gICAgICAgIGdlc3R1cmUuJHNsaWRlRWwgPSAkKGUudGFyZ2V0KS5jbG9zZXN0KGAuJHtzd2lwZXIucGFyYW1zLnNsaWRlQ2xhc3N9YCk7XG4gICAgICB9XG5cbiAgICAgIGlmICghZ2VzdHVyZS4kc2xpZGVFbCkge1xuICAgICAgICBpZiAoc3dpcGVyLnBhcmFtcy52aXJ0dWFsICYmIHN3aXBlci5wYXJhbXMudmlydHVhbC5lbmFibGVkICYmIHN3aXBlci52aXJ0dWFsKSB7XG4gICAgICAgICAgZ2VzdHVyZS4kc2xpZGVFbCA9IHN3aXBlci4kd3JhcHBlckVsLmNoaWxkcmVuKGAuJHtzd2lwZXIucGFyYW1zLnNsaWRlQWN0aXZlQ2xhc3N9YCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZ2VzdHVyZS4kc2xpZGVFbCA9IHN3aXBlci5zbGlkZXMuZXEoc3dpcGVyLmFjdGl2ZUluZGV4KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBnZXN0dXJlLiRpbWFnZUVsID0gZ2VzdHVyZS4kc2xpZGVFbC5maW5kKGAuJHtwYXJhbXMuY29udGFpbmVyQ2xhc3N9YCkuZXEoMCkuZmluZCgncGljdHVyZSwgaW1nLCBzdmcsIGNhbnZhcywgLnN3aXBlci16b29tLXRhcmdldCcpLmVxKDApO1xuICAgICAgZ2VzdHVyZS4kaW1hZ2VXcmFwRWwgPSBnZXN0dXJlLiRpbWFnZUVsLnBhcmVudChgLiR7cGFyYW1zLmNvbnRhaW5lckNsYXNzfWApO1xuICAgIH1cblxuICAgIGlmICghZ2VzdHVyZS4kaW1hZ2VFbCB8fCBnZXN0dXJlLiRpbWFnZUVsLmxlbmd0aCA9PT0gMCB8fCAhZ2VzdHVyZS4kaW1hZ2VXcmFwRWwgfHwgZ2VzdHVyZS4kaW1hZ2VXcmFwRWwubGVuZ3RoID09PSAwKSByZXR1cm47XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5jc3NNb2RlKSB7XG4gICAgICBzd2lwZXIud3JhcHBlckVsLnN0eWxlLm92ZXJmbG93ID0gJ2hpZGRlbic7XG4gICAgICBzd2lwZXIud3JhcHBlckVsLnN0eWxlLnRvdWNoQWN0aW9uID0gJ25vbmUnO1xuICAgIH1cblxuICAgIGdlc3R1cmUuJHNsaWRlRWwuYWRkQ2xhc3MoYCR7cGFyYW1zLnpvb21lZFNsaWRlQ2xhc3N9YCk7XG4gICAgbGV0IHRvdWNoWDtcbiAgICBsZXQgdG91Y2hZO1xuICAgIGxldCBvZmZzZXRYO1xuICAgIGxldCBvZmZzZXRZO1xuICAgIGxldCBkaWZmWDtcbiAgICBsZXQgZGlmZlk7XG4gICAgbGV0IHRyYW5zbGF0ZVg7XG4gICAgbGV0IHRyYW5zbGF0ZVk7XG4gICAgbGV0IGltYWdlV2lkdGg7XG4gICAgbGV0IGltYWdlSGVpZ2h0O1xuICAgIGxldCBzY2FsZWRXaWR0aDtcbiAgICBsZXQgc2NhbGVkSGVpZ2h0O1xuICAgIGxldCB0cmFuc2xhdGVNaW5YO1xuICAgIGxldCB0cmFuc2xhdGVNaW5ZO1xuICAgIGxldCB0cmFuc2xhdGVNYXhYO1xuICAgIGxldCB0cmFuc2xhdGVNYXhZO1xuICAgIGxldCBzbGlkZVdpZHRoO1xuICAgIGxldCBzbGlkZUhlaWdodDtcblxuICAgIGlmICh0eXBlb2YgaW1hZ2UudG91Y2hlc1N0YXJ0LnggPT09ICd1bmRlZmluZWQnICYmIGUpIHtcbiAgICAgIHRvdWNoWCA9IGUudHlwZSA9PT0gJ3RvdWNoZW5kJyA/IGUuY2hhbmdlZFRvdWNoZXNbMF0ucGFnZVggOiBlLnBhZ2VYO1xuICAgICAgdG91Y2hZID0gZS50eXBlID09PSAndG91Y2hlbmQnID8gZS5jaGFuZ2VkVG91Y2hlc1swXS5wYWdlWSA6IGUucGFnZVk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRvdWNoWCA9IGltYWdlLnRvdWNoZXNTdGFydC54O1xuICAgICAgdG91Y2hZID0gaW1hZ2UudG91Y2hlc1N0YXJ0Lnk7XG4gICAgfVxuXG4gICAgem9vbS5zY2FsZSA9IGdlc3R1cmUuJGltYWdlV3JhcEVsLmF0dHIoJ2RhdGEtc3dpcGVyLXpvb20nKSB8fCBwYXJhbXMubWF4UmF0aW87XG4gICAgY3VycmVudFNjYWxlID0gZ2VzdHVyZS4kaW1hZ2VXcmFwRWwuYXR0cignZGF0YS1zd2lwZXItem9vbScpIHx8IHBhcmFtcy5tYXhSYXRpbztcblxuICAgIGlmIChlKSB7XG4gICAgICBzbGlkZVdpZHRoID0gZ2VzdHVyZS4kc2xpZGVFbFswXS5vZmZzZXRXaWR0aDtcbiAgICAgIHNsaWRlSGVpZ2h0ID0gZ2VzdHVyZS4kc2xpZGVFbFswXS5vZmZzZXRIZWlnaHQ7XG4gICAgICBvZmZzZXRYID0gZ2VzdHVyZS4kc2xpZGVFbC5vZmZzZXQoKS5sZWZ0ICsgd2luZG93LnNjcm9sbFg7XG4gICAgICBvZmZzZXRZID0gZ2VzdHVyZS4kc2xpZGVFbC5vZmZzZXQoKS50b3AgKyB3aW5kb3cuc2Nyb2xsWTtcbiAgICAgIGRpZmZYID0gb2Zmc2V0WCArIHNsaWRlV2lkdGggLyAyIC0gdG91Y2hYO1xuICAgICAgZGlmZlkgPSBvZmZzZXRZICsgc2xpZGVIZWlnaHQgLyAyIC0gdG91Y2hZO1xuICAgICAgaW1hZ2VXaWR0aCA9IGdlc3R1cmUuJGltYWdlRWxbMF0ub2Zmc2V0V2lkdGg7XG4gICAgICBpbWFnZUhlaWdodCA9IGdlc3R1cmUuJGltYWdlRWxbMF0ub2Zmc2V0SGVpZ2h0O1xuICAgICAgc2NhbGVkV2lkdGggPSBpbWFnZVdpZHRoICogem9vbS5zY2FsZTtcbiAgICAgIHNjYWxlZEhlaWdodCA9IGltYWdlSGVpZ2h0ICogem9vbS5zY2FsZTtcbiAgICAgIHRyYW5zbGF0ZU1pblggPSBNYXRoLm1pbihzbGlkZVdpZHRoIC8gMiAtIHNjYWxlZFdpZHRoIC8gMiwgMCk7XG4gICAgICB0cmFuc2xhdGVNaW5ZID0gTWF0aC5taW4oc2xpZGVIZWlnaHQgLyAyIC0gc2NhbGVkSGVpZ2h0IC8gMiwgMCk7XG4gICAgICB0cmFuc2xhdGVNYXhYID0gLXRyYW5zbGF0ZU1pblg7XG4gICAgICB0cmFuc2xhdGVNYXhZID0gLXRyYW5zbGF0ZU1pblk7XG4gICAgICB0cmFuc2xhdGVYID0gZGlmZlggKiB6b29tLnNjYWxlO1xuICAgICAgdHJhbnNsYXRlWSA9IGRpZmZZICogem9vbS5zY2FsZTtcblxuICAgICAgaWYgKHRyYW5zbGF0ZVggPCB0cmFuc2xhdGVNaW5YKSB7XG4gICAgICAgIHRyYW5zbGF0ZVggPSB0cmFuc2xhdGVNaW5YO1xuICAgICAgfVxuXG4gICAgICBpZiAodHJhbnNsYXRlWCA+IHRyYW5zbGF0ZU1heFgpIHtcbiAgICAgICAgdHJhbnNsYXRlWCA9IHRyYW5zbGF0ZU1heFg7XG4gICAgICB9XG5cbiAgICAgIGlmICh0cmFuc2xhdGVZIDwgdHJhbnNsYXRlTWluWSkge1xuICAgICAgICB0cmFuc2xhdGVZID0gdHJhbnNsYXRlTWluWTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRyYW5zbGF0ZVkgPiB0cmFuc2xhdGVNYXhZKSB7XG4gICAgICAgIHRyYW5zbGF0ZVkgPSB0cmFuc2xhdGVNYXhZO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICB0cmFuc2xhdGVYID0gMDtcbiAgICAgIHRyYW5zbGF0ZVkgPSAwO1xuICAgIH1cblxuICAgIGdlc3R1cmUuJGltYWdlV3JhcEVsLnRyYW5zaXRpb24oMzAwKS50cmFuc2Zvcm0oYHRyYW5zbGF0ZTNkKCR7dHJhbnNsYXRlWH1weCwgJHt0cmFuc2xhdGVZfXB4LDApYCk7XG4gICAgZ2VzdHVyZS4kaW1hZ2VFbC50cmFuc2l0aW9uKDMwMCkudHJhbnNmb3JtKGB0cmFuc2xhdGUzZCgwLDAsMCkgc2NhbGUoJHt6b29tLnNjYWxlfSlgKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHpvb21PdXQoKSB7XG4gICAgY29uc3Qgem9vbSA9IHN3aXBlci56b29tO1xuICAgIGNvbnN0IHBhcmFtcyA9IHN3aXBlci5wYXJhbXMuem9vbTtcblxuICAgIGlmICghZ2VzdHVyZS4kc2xpZGVFbCkge1xuICAgICAgaWYgKHN3aXBlci5wYXJhbXMudmlydHVhbCAmJiBzd2lwZXIucGFyYW1zLnZpcnR1YWwuZW5hYmxlZCAmJiBzd2lwZXIudmlydHVhbCkge1xuICAgICAgICBnZXN0dXJlLiRzbGlkZUVsID0gc3dpcGVyLiR3cmFwcGVyRWwuY2hpbGRyZW4oYC4ke3N3aXBlci5wYXJhbXMuc2xpZGVBY3RpdmVDbGFzc31gKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdlc3R1cmUuJHNsaWRlRWwgPSBzd2lwZXIuc2xpZGVzLmVxKHN3aXBlci5hY3RpdmVJbmRleCk7XG4gICAgICB9XG5cbiAgICAgIGdlc3R1cmUuJGltYWdlRWwgPSBnZXN0dXJlLiRzbGlkZUVsLmZpbmQoYC4ke3BhcmFtcy5jb250YWluZXJDbGFzc31gKS5lcSgwKS5maW5kKCdwaWN0dXJlLCBpbWcsIHN2ZywgY2FudmFzLCAuc3dpcGVyLXpvb20tdGFyZ2V0JykuZXEoMCk7XG4gICAgICBnZXN0dXJlLiRpbWFnZVdyYXBFbCA9IGdlc3R1cmUuJGltYWdlRWwucGFyZW50KGAuJHtwYXJhbXMuY29udGFpbmVyQ2xhc3N9YCk7XG4gICAgfVxuXG4gICAgaWYgKCFnZXN0dXJlLiRpbWFnZUVsIHx8IGdlc3R1cmUuJGltYWdlRWwubGVuZ3RoID09PSAwIHx8ICFnZXN0dXJlLiRpbWFnZVdyYXBFbCB8fCBnZXN0dXJlLiRpbWFnZVdyYXBFbC5sZW5ndGggPT09IDApIHJldHVybjtcblxuICAgIGlmIChzd2lwZXIucGFyYW1zLmNzc01vZGUpIHtcbiAgICAgIHN3aXBlci53cmFwcGVyRWwuc3R5bGUub3ZlcmZsb3cgPSAnJztcbiAgICAgIHN3aXBlci53cmFwcGVyRWwuc3R5bGUudG91Y2hBY3Rpb24gPSAnJztcbiAgICB9XG5cbiAgICB6b29tLnNjYWxlID0gMTtcbiAgICBjdXJyZW50U2NhbGUgPSAxO1xuICAgIGdlc3R1cmUuJGltYWdlV3JhcEVsLnRyYW5zaXRpb24oMzAwKS50cmFuc2Zvcm0oJ3RyYW5zbGF0ZTNkKDAsMCwwKScpO1xuICAgIGdlc3R1cmUuJGltYWdlRWwudHJhbnNpdGlvbigzMDApLnRyYW5zZm9ybSgndHJhbnNsYXRlM2QoMCwwLDApIHNjYWxlKDEpJyk7XG4gICAgZ2VzdHVyZS4kc2xpZGVFbC5yZW1vdmVDbGFzcyhgJHtwYXJhbXMuem9vbWVkU2xpZGVDbGFzc31gKTtcbiAgICBnZXN0dXJlLiRzbGlkZUVsID0gdW5kZWZpbmVkO1xuICB9IC8vIFRvZ2dsZSBab29tXG5cblxuICBmdW5jdGlvbiB6b29tVG9nZ2xlKGUpIHtcbiAgICBjb25zdCB6b29tID0gc3dpcGVyLnpvb207XG5cbiAgICBpZiAoem9vbS5zY2FsZSAmJiB6b29tLnNjYWxlICE9PSAxKSB7XG4gICAgICAvLyBab29tIE91dFxuICAgICAgem9vbU91dCgpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBab29tIEluXG4gICAgICB6b29tSW4oZSk7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gZ2V0TGlzdGVuZXJzKCkge1xuICAgIGNvbnN0IHN1cHBvcnQgPSBzd2lwZXIuc3VwcG9ydDtcbiAgICBjb25zdCBwYXNzaXZlTGlzdGVuZXIgPSBzd2lwZXIudG91Y2hFdmVudHMuc3RhcnQgPT09ICd0b3VjaHN0YXJ0JyAmJiBzdXBwb3J0LnBhc3NpdmVMaXN0ZW5lciAmJiBzd2lwZXIucGFyYW1zLnBhc3NpdmVMaXN0ZW5lcnMgPyB7XG4gICAgICBwYXNzaXZlOiB0cnVlLFxuICAgICAgY2FwdHVyZTogZmFsc2VcbiAgICB9IDogZmFsc2U7XG4gICAgY29uc3QgYWN0aXZlTGlzdGVuZXJXaXRoQ2FwdHVyZSA9IHN1cHBvcnQucGFzc2l2ZUxpc3RlbmVyID8ge1xuICAgICAgcGFzc2l2ZTogZmFsc2UsXG4gICAgICBjYXB0dXJlOiB0cnVlXG4gICAgfSA6IHRydWU7XG4gICAgcmV0dXJuIHtcbiAgICAgIHBhc3NpdmVMaXN0ZW5lcixcbiAgICAgIGFjdGl2ZUxpc3RlbmVyV2l0aENhcHR1cmVcbiAgICB9O1xuICB9XG5cbiAgZnVuY3Rpb24gZ2V0U2xpZGVTZWxlY3RvcigpIHtcbiAgICByZXR1cm4gYC4ke3N3aXBlci5wYXJhbXMuc2xpZGVDbGFzc31gO1xuICB9XG5cbiAgZnVuY3Rpb24gdG9nZ2xlR2VzdHVyZXMobWV0aG9kKSB7XG4gICAgY29uc3Qge1xuICAgICAgcGFzc2l2ZUxpc3RlbmVyXG4gICAgfSA9IGdldExpc3RlbmVycygpO1xuICAgIGNvbnN0IHNsaWRlU2VsZWN0b3IgPSBnZXRTbGlkZVNlbGVjdG9yKCk7XG4gICAgc3dpcGVyLiR3cmFwcGVyRWxbbWV0aG9kXSgnZ2VzdHVyZXN0YXJ0Jywgc2xpZGVTZWxlY3Rvciwgb25HZXN0dXJlU3RhcnQsIHBhc3NpdmVMaXN0ZW5lcik7XG4gICAgc3dpcGVyLiR3cmFwcGVyRWxbbWV0aG9kXSgnZ2VzdHVyZWNoYW5nZScsIHNsaWRlU2VsZWN0b3IsIG9uR2VzdHVyZUNoYW5nZSwgcGFzc2l2ZUxpc3RlbmVyKTtcbiAgICBzd2lwZXIuJHdyYXBwZXJFbFttZXRob2RdKCdnZXN0dXJlZW5kJywgc2xpZGVTZWxlY3Rvciwgb25HZXN0dXJlRW5kLCBwYXNzaXZlTGlzdGVuZXIpO1xuICB9XG5cbiAgZnVuY3Rpb24gZW5hYmxlR2VzdHVyZXMoKSB7XG4gICAgaWYgKGdlc3R1cmVzRW5hYmxlZCkgcmV0dXJuO1xuICAgIGdlc3R1cmVzRW5hYmxlZCA9IHRydWU7XG4gICAgdG9nZ2xlR2VzdHVyZXMoJ29uJyk7XG4gIH1cblxuICBmdW5jdGlvbiBkaXNhYmxlR2VzdHVyZXMoKSB7XG4gICAgaWYgKCFnZXN0dXJlc0VuYWJsZWQpIHJldHVybjtcbiAgICBnZXN0dXJlc0VuYWJsZWQgPSBmYWxzZTtcbiAgICB0b2dnbGVHZXN0dXJlcygnb2ZmJyk7XG4gIH0gLy8gQXR0YWNoL0RldGFjaCBFdmVudHNcblxuXG4gIGZ1bmN0aW9uIGVuYWJsZSgpIHtcbiAgICBjb25zdCB6b29tID0gc3dpcGVyLnpvb207XG4gICAgaWYgKHpvb20uZW5hYmxlZCkgcmV0dXJuO1xuICAgIHpvb20uZW5hYmxlZCA9IHRydWU7XG4gICAgY29uc3Qgc3VwcG9ydCA9IHN3aXBlci5zdXBwb3J0O1xuICAgIGNvbnN0IHtcbiAgICAgIHBhc3NpdmVMaXN0ZW5lcixcbiAgICAgIGFjdGl2ZUxpc3RlbmVyV2l0aENhcHR1cmVcbiAgICB9ID0gZ2V0TGlzdGVuZXJzKCk7XG4gICAgY29uc3Qgc2xpZGVTZWxlY3RvciA9IGdldFNsaWRlU2VsZWN0b3IoKTsgLy8gU2NhbGUgaW1hZ2VcblxuICAgIGlmIChzdXBwb3J0Lmdlc3R1cmVzKSB7XG4gICAgICBzd2lwZXIuJHdyYXBwZXJFbC5vbihzd2lwZXIudG91Y2hFdmVudHMuc3RhcnQsIGVuYWJsZUdlc3R1cmVzLCBwYXNzaXZlTGlzdGVuZXIpO1xuICAgICAgc3dpcGVyLiR3cmFwcGVyRWwub24oc3dpcGVyLnRvdWNoRXZlbnRzLmVuZCwgZGlzYWJsZUdlc3R1cmVzLCBwYXNzaXZlTGlzdGVuZXIpO1xuICAgIH0gZWxzZSBpZiAoc3dpcGVyLnRvdWNoRXZlbnRzLnN0YXJ0ID09PSAndG91Y2hzdGFydCcpIHtcbiAgICAgIHN3aXBlci4kd3JhcHBlckVsLm9uKHN3aXBlci50b3VjaEV2ZW50cy5zdGFydCwgc2xpZGVTZWxlY3Rvciwgb25HZXN0dXJlU3RhcnQsIHBhc3NpdmVMaXN0ZW5lcik7XG4gICAgICBzd2lwZXIuJHdyYXBwZXJFbC5vbihzd2lwZXIudG91Y2hFdmVudHMubW92ZSwgc2xpZGVTZWxlY3Rvciwgb25HZXN0dXJlQ2hhbmdlLCBhY3RpdmVMaXN0ZW5lcldpdGhDYXB0dXJlKTtcbiAgICAgIHN3aXBlci4kd3JhcHBlckVsLm9uKHN3aXBlci50b3VjaEV2ZW50cy5lbmQsIHNsaWRlU2VsZWN0b3IsIG9uR2VzdHVyZUVuZCwgcGFzc2l2ZUxpc3RlbmVyKTtcblxuICAgICAgaWYgKHN3aXBlci50b3VjaEV2ZW50cy5jYW5jZWwpIHtcbiAgICAgICAgc3dpcGVyLiR3cmFwcGVyRWwub24oc3dpcGVyLnRvdWNoRXZlbnRzLmNhbmNlbCwgc2xpZGVTZWxlY3Rvciwgb25HZXN0dXJlRW5kLCBwYXNzaXZlTGlzdGVuZXIpO1xuICAgICAgfVxuICAgIH0gLy8gTW92ZSBpbWFnZVxuXG5cbiAgICBzd2lwZXIuJHdyYXBwZXJFbC5vbihzd2lwZXIudG91Y2hFdmVudHMubW92ZSwgYC4ke3N3aXBlci5wYXJhbXMuem9vbS5jb250YWluZXJDbGFzc31gLCBvblRvdWNoTW92ZSwgYWN0aXZlTGlzdGVuZXJXaXRoQ2FwdHVyZSk7XG4gIH1cblxuICBmdW5jdGlvbiBkaXNhYmxlKCkge1xuICAgIGNvbnN0IHpvb20gPSBzd2lwZXIuem9vbTtcbiAgICBpZiAoIXpvb20uZW5hYmxlZCkgcmV0dXJuO1xuICAgIGNvbnN0IHN1cHBvcnQgPSBzd2lwZXIuc3VwcG9ydDtcbiAgICB6b29tLmVuYWJsZWQgPSBmYWxzZTtcbiAgICBjb25zdCB7XG4gICAgICBwYXNzaXZlTGlzdGVuZXIsXG4gICAgICBhY3RpdmVMaXN0ZW5lcldpdGhDYXB0dXJlXG4gICAgfSA9IGdldExpc3RlbmVycygpO1xuICAgIGNvbnN0IHNsaWRlU2VsZWN0b3IgPSBnZXRTbGlkZVNlbGVjdG9yKCk7IC8vIFNjYWxlIGltYWdlXG5cbiAgICBpZiAoc3VwcG9ydC5nZXN0dXJlcykge1xuICAgICAgc3dpcGVyLiR3cmFwcGVyRWwub2ZmKHN3aXBlci50b3VjaEV2ZW50cy5zdGFydCwgZW5hYmxlR2VzdHVyZXMsIHBhc3NpdmVMaXN0ZW5lcik7XG4gICAgICBzd2lwZXIuJHdyYXBwZXJFbC5vZmYoc3dpcGVyLnRvdWNoRXZlbnRzLmVuZCwgZGlzYWJsZUdlc3R1cmVzLCBwYXNzaXZlTGlzdGVuZXIpO1xuICAgIH0gZWxzZSBpZiAoc3dpcGVyLnRvdWNoRXZlbnRzLnN0YXJ0ID09PSAndG91Y2hzdGFydCcpIHtcbiAgICAgIHN3aXBlci4kd3JhcHBlckVsLm9mZihzd2lwZXIudG91Y2hFdmVudHMuc3RhcnQsIHNsaWRlU2VsZWN0b3IsIG9uR2VzdHVyZVN0YXJ0LCBwYXNzaXZlTGlzdGVuZXIpO1xuICAgICAgc3dpcGVyLiR3cmFwcGVyRWwub2ZmKHN3aXBlci50b3VjaEV2ZW50cy5tb3ZlLCBzbGlkZVNlbGVjdG9yLCBvbkdlc3R1cmVDaGFuZ2UsIGFjdGl2ZUxpc3RlbmVyV2l0aENhcHR1cmUpO1xuICAgICAgc3dpcGVyLiR3cmFwcGVyRWwub2ZmKHN3aXBlci50b3VjaEV2ZW50cy5lbmQsIHNsaWRlU2VsZWN0b3IsIG9uR2VzdHVyZUVuZCwgcGFzc2l2ZUxpc3RlbmVyKTtcblxuICAgICAgaWYgKHN3aXBlci50b3VjaEV2ZW50cy5jYW5jZWwpIHtcbiAgICAgICAgc3dpcGVyLiR3cmFwcGVyRWwub2ZmKHN3aXBlci50b3VjaEV2ZW50cy5jYW5jZWwsIHNsaWRlU2VsZWN0b3IsIG9uR2VzdHVyZUVuZCwgcGFzc2l2ZUxpc3RlbmVyKTtcbiAgICAgIH1cbiAgICB9IC8vIE1vdmUgaW1hZ2VcblxuXG4gICAgc3dpcGVyLiR3cmFwcGVyRWwub2ZmKHN3aXBlci50b3VjaEV2ZW50cy5tb3ZlLCBgLiR7c3dpcGVyLnBhcmFtcy56b29tLmNvbnRhaW5lckNsYXNzfWAsIG9uVG91Y2hNb3ZlLCBhY3RpdmVMaXN0ZW5lcldpdGhDYXB0dXJlKTtcbiAgfVxuXG4gIG9uKCdpbml0JywgKCkgPT4ge1xuICAgIGlmIChzd2lwZXIucGFyYW1zLnpvb20uZW5hYmxlZCkge1xuICAgICAgZW5hYmxlKCk7XG4gICAgfVxuICB9KTtcbiAgb24oJ2Rlc3Ryb3knLCAoKSA9PiB7XG4gICAgZGlzYWJsZSgpO1xuICB9KTtcbiAgb24oJ3RvdWNoU3RhcnQnLCAoX3MsIGUpID0+IHtcbiAgICBpZiAoIXN3aXBlci56b29tLmVuYWJsZWQpIHJldHVybjtcbiAgICBvblRvdWNoU3RhcnQoZSk7XG4gIH0pO1xuICBvbigndG91Y2hFbmQnLCAoX3MsIGUpID0+IHtcbiAgICBpZiAoIXN3aXBlci56b29tLmVuYWJsZWQpIHJldHVybjtcbiAgICBvblRvdWNoRW5kKGUpO1xuICB9KTtcbiAgb24oJ2RvdWJsZVRhcCcsIChfcywgZSkgPT4ge1xuICAgIGlmICghc3dpcGVyLmFuaW1hdGluZyAmJiBzd2lwZXIucGFyYW1zLnpvb20uZW5hYmxlZCAmJiBzd2lwZXIuem9vbS5lbmFibGVkICYmIHN3aXBlci5wYXJhbXMuem9vbS50b2dnbGUpIHtcbiAgICAgIHpvb21Ub2dnbGUoZSk7XG4gICAgfVxuICB9KTtcbiAgb24oJ3RyYW5zaXRpb25FbmQnLCAoKSA9PiB7XG4gICAgaWYgKHN3aXBlci56b29tLmVuYWJsZWQgJiYgc3dpcGVyLnBhcmFtcy56b29tLmVuYWJsZWQpIHtcbiAgICAgIG9uVHJhbnNpdGlvbkVuZCgpO1xuICAgIH1cbiAgfSk7XG4gIG9uKCdzbGlkZUNoYW5nZScsICgpID0+IHtcbiAgICBpZiAoc3dpcGVyLnpvb20uZW5hYmxlZCAmJiBzd2lwZXIucGFyYW1zLnpvb20uZW5hYmxlZCAmJiBzd2lwZXIucGFyYW1zLmNzc01vZGUpIHtcbiAgICAgIG9uVHJhbnNpdGlvbkVuZCgpO1xuICAgIH1cbiAgfSk7XG4gIE9iamVjdC5hc3NpZ24oc3dpcGVyLnpvb20sIHtcbiAgICBlbmFibGUsXG4gICAgZGlzYWJsZSxcbiAgICBpbjogem9vbUluLFxuICAgIG91dDogem9vbU91dCxcbiAgICB0b2dnbGU6IHpvb21Ub2dnbGVcbiAgfSk7XG59IiwiaW1wb3J0IHsgZ2V0V2luZG93IH0gZnJvbSAnc3NyLXdpbmRvdyc7XG5pbXBvcnQgJCBmcm9tICcuLi8uLi9zaGFyZWQvZG9tLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIExhenkoe1xuICBzd2lwZXIsXG4gIGV4dGVuZFBhcmFtcyxcbiAgb24sXG4gIGVtaXRcbn0pIHtcbiAgZXh0ZW5kUGFyYW1zKHtcbiAgICBsYXp5OiB7XG4gICAgICBjaGVja0luVmlldzogZmFsc2UsXG4gICAgICBlbmFibGVkOiBmYWxzZSxcbiAgICAgIGxvYWRQcmV2TmV4dDogZmFsc2UsXG4gICAgICBsb2FkUHJldk5leHRBbW91bnQ6IDEsXG4gICAgICBsb2FkT25UcmFuc2l0aW9uU3RhcnQ6IGZhbHNlLFxuICAgICAgc2Nyb2xsaW5nRWxlbWVudDogJycsXG4gICAgICBlbGVtZW50Q2xhc3M6ICdzd2lwZXItbGF6eScsXG4gICAgICBsb2FkaW5nQ2xhc3M6ICdzd2lwZXItbGF6eS1sb2FkaW5nJyxcbiAgICAgIGxvYWRlZENsYXNzOiAnc3dpcGVyLWxhenktbG9hZGVkJyxcbiAgICAgIHByZWxvYWRlckNsYXNzOiAnc3dpcGVyLWxhenktcHJlbG9hZGVyJ1xuICAgIH1cbiAgfSk7XG4gIHN3aXBlci5sYXp5ID0ge307XG4gIGxldCBzY3JvbGxIYW5kbGVyQXR0YWNoZWQgPSBmYWxzZTtcbiAgbGV0IGluaXRpYWxJbWFnZUxvYWRlZCA9IGZhbHNlO1xuXG4gIGZ1bmN0aW9uIGxvYWRJblNsaWRlKGluZGV4LCBsb2FkSW5EdXBsaWNhdGUgPSB0cnVlKSB7XG4gICAgY29uc3QgcGFyYW1zID0gc3dpcGVyLnBhcmFtcy5sYXp5O1xuICAgIGlmICh0eXBlb2YgaW5kZXggPT09ICd1bmRlZmluZWQnKSByZXR1cm47XG4gICAgaWYgKHN3aXBlci5zbGlkZXMubGVuZ3RoID09PSAwKSByZXR1cm47XG4gICAgY29uc3QgaXNWaXJ0dWFsID0gc3dpcGVyLnZpcnR1YWwgJiYgc3dpcGVyLnBhcmFtcy52aXJ0dWFsLmVuYWJsZWQ7XG4gICAgY29uc3QgJHNsaWRlRWwgPSBpc1ZpcnR1YWwgPyBzd2lwZXIuJHdyYXBwZXJFbC5jaGlsZHJlbihgLiR7c3dpcGVyLnBhcmFtcy5zbGlkZUNsYXNzfVtkYXRhLXN3aXBlci1zbGlkZS1pbmRleD1cIiR7aW5kZXh9XCJdYCkgOiBzd2lwZXIuc2xpZGVzLmVxKGluZGV4KTtcbiAgICBjb25zdCAkaW1hZ2VzID0gJHNsaWRlRWwuZmluZChgLiR7cGFyYW1zLmVsZW1lbnRDbGFzc306bm90KC4ke3BhcmFtcy5sb2FkZWRDbGFzc30pOm5vdCguJHtwYXJhbXMubG9hZGluZ0NsYXNzfSlgKTtcblxuICAgIGlmICgkc2xpZGVFbC5oYXNDbGFzcyhwYXJhbXMuZWxlbWVudENsYXNzKSAmJiAhJHNsaWRlRWwuaGFzQ2xhc3MocGFyYW1zLmxvYWRlZENsYXNzKSAmJiAhJHNsaWRlRWwuaGFzQ2xhc3MocGFyYW1zLmxvYWRpbmdDbGFzcykpIHtcbiAgICAgICRpbWFnZXMucHVzaCgkc2xpZGVFbFswXSk7XG4gICAgfVxuXG4gICAgaWYgKCRpbWFnZXMubGVuZ3RoID09PSAwKSByZXR1cm47XG4gICAgJGltYWdlcy5lYWNoKGltYWdlRWwgPT4ge1xuICAgICAgY29uc3QgJGltYWdlRWwgPSAkKGltYWdlRWwpO1xuICAgICAgJGltYWdlRWwuYWRkQ2xhc3MocGFyYW1zLmxvYWRpbmdDbGFzcyk7XG4gICAgICBjb25zdCBiYWNrZ3JvdW5kID0gJGltYWdlRWwuYXR0cignZGF0YS1iYWNrZ3JvdW5kJyk7XG4gICAgICBjb25zdCBzcmMgPSAkaW1hZ2VFbC5hdHRyKCdkYXRhLXNyYycpO1xuICAgICAgY29uc3Qgc3Jjc2V0ID0gJGltYWdlRWwuYXR0cignZGF0YS1zcmNzZXQnKTtcbiAgICAgIGNvbnN0IHNpemVzID0gJGltYWdlRWwuYXR0cignZGF0YS1zaXplcycpO1xuICAgICAgY29uc3QgJHBpY3R1cmVFbCA9ICRpbWFnZUVsLnBhcmVudCgncGljdHVyZScpO1xuICAgICAgc3dpcGVyLmxvYWRJbWFnZSgkaW1hZ2VFbFswXSwgc3JjIHx8IGJhY2tncm91bmQsIHNyY3NldCwgc2l6ZXMsIGZhbHNlLCAoKSA9PiB7XG4gICAgICAgIGlmICh0eXBlb2Ygc3dpcGVyID09PSAndW5kZWZpbmVkJyB8fCBzd2lwZXIgPT09IG51bGwgfHwgIXN3aXBlciB8fCBzd2lwZXIgJiYgIXN3aXBlci5wYXJhbXMgfHwgc3dpcGVyLmRlc3Ryb3llZCkgcmV0dXJuO1xuXG4gICAgICAgIGlmIChiYWNrZ3JvdW5kKSB7XG4gICAgICAgICAgJGltYWdlRWwuY3NzKCdiYWNrZ3JvdW5kLWltYWdlJywgYHVybChcIiR7YmFja2dyb3VuZH1cIilgKTtcbiAgICAgICAgICAkaW1hZ2VFbC5yZW1vdmVBdHRyKCdkYXRhLWJhY2tncm91bmQnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBpZiAoc3Jjc2V0KSB7XG4gICAgICAgICAgICAkaW1hZ2VFbC5hdHRyKCdzcmNzZXQnLCBzcmNzZXQpO1xuICAgICAgICAgICAgJGltYWdlRWwucmVtb3ZlQXR0cignZGF0YS1zcmNzZXQnKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoc2l6ZXMpIHtcbiAgICAgICAgICAgICRpbWFnZUVsLmF0dHIoJ3NpemVzJywgc2l6ZXMpO1xuICAgICAgICAgICAgJGltYWdlRWwucmVtb3ZlQXR0cignZGF0YS1zaXplcycpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICgkcGljdHVyZUVsLmxlbmd0aCkge1xuICAgICAgICAgICAgJHBpY3R1cmVFbC5jaGlsZHJlbignc291cmNlJykuZWFjaChzb3VyY2VFbCA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0ICRzb3VyY2UgPSAkKHNvdXJjZUVsKTtcblxuICAgICAgICAgICAgICBpZiAoJHNvdXJjZS5hdHRyKCdkYXRhLXNyY3NldCcpKSB7XG4gICAgICAgICAgICAgICAgJHNvdXJjZS5hdHRyKCdzcmNzZXQnLCAkc291cmNlLmF0dHIoJ2RhdGEtc3Jjc2V0JykpO1xuICAgICAgICAgICAgICAgICRzb3VyY2UucmVtb3ZlQXR0cignZGF0YS1zcmNzZXQnKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHNyYykge1xuICAgICAgICAgICAgJGltYWdlRWwuYXR0cignc3JjJywgc3JjKTtcbiAgICAgICAgICAgICRpbWFnZUVsLnJlbW92ZUF0dHIoJ2RhdGEtc3JjJyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgJGltYWdlRWwuYWRkQ2xhc3MocGFyYW1zLmxvYWRlZENsYXNzKS5yZW1vdmVDbGFzcyhwYXJhbXMubG9hZGluZ0NsYXNzKTtcbiAgICAgICAgJHNsaWRlRWwuZmluZChgLiR7cGFyYW1zLnByZWxvYWRlckNsYXNzfWApLnJlbW92ZSgpO1xuXG4gICAgICAgIGlmIChzd2lwZXIucGFyYW1zLmxvb3AgJiYgbG9hZEluRHVwbGljYXRlKSB7XG4gICAgICAgICAgY29uc3Qgc2xpZGVPcmlnaW5hbEluZGV4ID0gJHNsaWRlRWwuYXR0cignZGF0YS1zd2lwZXItc2xpZGUtaW5kZXgnKTtcblxuICAgICAgICAgIGlmICgkc2xpZGVFbC5oYXNDbGFzcyhzd2lwZXIucGFyYW1zLnNsaWRlRHVwbGljYXRlQ2xhc3MpKSB7XG4gICAgICAgICAgICBjb25zdCBvcmlnaW5hbFNsaWRlID0gc3dpcGVyLiR3cmFwcGVyRWwuY2hpbGRyZW4oYFtkYXRhLXN3aXBlci1zbGlkZS1pbmRleD1cIiR7c2xpZGVPcmlnaW5hbEluZGV4fVwiXTpub3QoLiR7c3dpcGVyLnBhcmFtcy5zbGlkZUR1cGxpY2F0ZUNsYXNzfSlgKTtcbiAgICAgICAgICAgIGxvYWRJblNsaWRlKG9yaWdpbmFsU2xpZGUuaW5kZXgoKSwgZmFsc2UpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBkdXBsaWNhdGVkU2xpZGUgPSBzd2lwZXIuJHdyYXBwZXJFbC5jaGlsZHJlbihgLiR7c3dpcGVyLnBhcmFtcy5zbGlkZUR1cGxpY2F0ZUNsYXNzfVtkYXRhLXN3aXBlci1zbGlkZS1pbmRleD1cIiR7c2xpZGVPcmlnaW5hbEluZGV4fVwiXWApO1xuICAgICAgICAgICAgbG9hZEluU2xpZGUoZHVwbGljYXRlZFNsaWRlLmluZGV4KCksIGZhbHNlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBlbWl0KCdsYXp5SW1hZ2VSZWFkeScsICRzbGlkZUVsWzBdLCAkaW1hZ2VFbFswXSk7XG5cbiAgICAgICAgaWYgKHN3aXBlci5wYXJhbXMuYXV0b0hlaWdodCkge1xuICAgICAgICAgIHN3aXBlci51cGRhdGVBdXRvSGVpZ2h0KCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgZW1pdCgnbGF6eUltYWdlTG9hZCcsICRzbGlkZUVsWzBdLCAkaW1hZ2VFbFswXSk7XG4gICAgfSk7XG4gIH1cblxuICBmdW5jdGlvbiBsb2FkKCkge1xuICAgIGNvbnN0IHtcbiAgICAgICR3cmFwcGVyRWwsXG4gICAgICBwYXJhbXM6IHN3aXBlclBhcmFtcyxcbiAgICAgIHNsaWRlcyxcbiAgICAgIGFjdGl2ZUluZGV4XG4gICAgfSA9IHN3aXBlcjtcbiAgICBjb25zdCBpc1ZpcnR1YWwgPSBzd2lwZXIudmlydHVhbCAmJiBzd2lwZXJQYXJhbXMudmlydHVhbC5lbmFibGVkO1xuICAgIGNvbnN0IHBhcmFtcyA9IHN3aXBlclBhcmFtcy5sYXp5O1xuICAgIGxldCBzbGlkZXNQZXJWaWV3ID0gc3dpcGVyUGFyYW1zLnNsaWRlc1BlclZpZXc7XG5cbiAgICBpZiAoc2xpZGVzUGVyVmlldyA9PT0gJ2F1dG8nKSB7XG4gICAgICBzbGlkZXNQZXJWaWV3ID0gMDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzbGlkZUV4aXN0KGluZGV4KSB7XG4gICAgICBpZiAoaXNWaXJ0dWFsKSB7XG4gICAgICAgIGlmICgkd3JhcHBlckVsLmNoaWxkcmVuKGAuJHtzd2lwZXJQYXJhbXMuc2xpZGVDbGFzc31bZGF0YS1zd2lwZXItc2xpZGUtaW5kZXg9XCIke2luZGV4fVwiXWApLmxlbmd0aCkge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHNsaWRlc1tpbmRleF0pIHJldHVybiB0cnVlO1xuXG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gc2xpZGVJbmRleChzbGlkZUVsKSB7XG4gICAgICBpZiAoaXNWaXJ0dWFsKSB7XG4gICAgICAgIHJldHVybiAkKHNsaWRlRWwpLmF0dHIoJ2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4Jyk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiAkKHNsaWRlRWwpLmluZGV4KCk7XG4gICAgfVxuXG4gICAgaWYgKCFpbml0aWFsSW1hZ2VMb2FkZWQpIGluaXRpYWxJbWFnZUxvYWRlZCA9IHRydWU7XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy53YXRjaFNsaWRlc1Byb2dyZXNzKSB7XG4gICAgICAkd3JhcHBlckVsLmNoaWxkcmVuKGAuJHtzd2lwZXJQYXJhbXMuc2xpZGVWaXNpYmxlQ2xhc3N9YCkuZWFjaChzbGlkZUVsID0+IHtcbiAgICAgICAgY29uc3QgaW5kZXggPSBpc1ZpcnR1YWwgPyAkKHNsaWRlRWwpLmF0dHIoJ2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4JykgOiAkKHNsaWRlRWwpLmluZGV4KCk7XG4gICAgICAgIGxvYWRJblNsaWRlKGluZGV4KTtcbiAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAoc2xpZGVzUGVyVmlldyA+IDEpIHtcbiAgICAgIGZvciAobGV0IGkgPSBhY3RpdmVJbmRleDsgaSA8IGFjdGl2ZUluZGV4ICsgc2xpZGVzUGVyVmlldzsgaSArPSAxKSB7XG4gICAgICAgIGlmIChzbGlkZUV4aXN0KGkpKSBsb2FkSW5TbGlkZShpKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgbG9hZEluU2xpZGUoYWN0aXZlSW5kZXgpO1xuICAgIH1cblxuICAgIGlmIChwYXJhbXMubG9hZFByZXZOZXh0KSB7XG4gICAgICBpZiAoc2xpZGVzUGVyVmlldyA+IDEgfHwgcGFyYW1zLmxvYWRQcmV2TmV4dEFtb3VudCAmJiBwYXJhbXMubG9hZFByZXZOZXh0QW1vdW50ID4gMSkge1xuICAgICAgICBjb25zdCBhbW91bnQgPSBwYXJhbXMubG9hZFByZXZOZXh0QW1vdW50O1xuICAgICAgICBjb25zdCBzcHYgPSBNYXRoLmNlaWwoc2xpZGVzUGVyVmlldyk7XG4gICAgICAgIGNvbnN0IG1heEluZGV4ID0gTWF0aC5taW4oYWN0aXZlSW5kZXggKyBzcHYgKyBNYXRoLm1heChhbW91bnQsIHNwdiksIHNsaWRlcy5sZW5ndGgpO1xuICAgICAgICBjb25zdCBtaW5JbmRleCA9IE1hdGgubWF4KGFjdGl2ZUluZGV4IC0gTWF0aC5tYXgoc3B2LCBhbW91bnQpLCAwKTsgLy8gTmV4dCBTbGlkZXNcblxuICAgICAgICBmb3IgKGxldCBpID0gYWN0aXZlSW5kZXggKyBzcHY7IGkgPCBtYXhJbmRleDsgaSArPSAxKSB7XG4gICAgICAgICAgaWYgKHNsaWRlRXhpc3QoaSkpIGxvYWRJblNsaWRlKGkpO1xuICAgICAgICB9IC8vIFByZXYgU2xpZGVzXG5cblxuICAgICAgICBmb3IgKGxldCBpID0gbWluSW5kZXg7IGkgPCBhY3RpdmVJbmRleDsgaSArPSAxKSB7XG4gICAgICAgICAgaWYgKHNsaWRlRXhpc3QoaSkpIGxvYWRJblNsaWRlKGkpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBuZXh0U2xpZGUgPSAkd3JhcHBlckVsLmNoaWxkcmVuKGAuJHtzd2lwZXJQYXJhbXMuc2xpZGVOZXh0Q2xhc3N9YCk7XG4gICAgICAgIGlmIChuZXh0U2xpZGUubGVuZ3RoID4gMCkgbG9hZEluU2xpZGUoc2xpZGVJbmRleChuZXh0U2xpZGUpKTtcbiAgICAgICAgY29uc3QgcHJldlNsaWRlID0gJHdyYXBwZXJFbC5jaGlsZHJlbihgLiR7c3dpcGVyUGFyYW1zLnNsaWRlUHJldkNsYXNzfWApO1xuICAgICAgICBpZiAocHJldlNsaWRlLmxlbmd0aCA+IDApIGxvYWRJblNsaWRlKHNsaWRlSW5kZXgocHJldlNsaWRlKSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gY2hlY2tJblZpZXdPbkxvYWQoKSB7XG4gICAgY29uc3Qgd2luZG93ID0gZ2V0V2luZG93KCk7XG4gICAgaWYgKCFzd2lwZXIgfHwgc3dpcGVyLmRlc3Ryb3llZCkgcmV0dXJuO1xuICAgIGNvbnN0ICRzY3JvbGxFbGVtZW50ID0gc3dpcGVyLnBhcmFtcy5sYXp5LnNjcm9sbGluZ0VsZW1lbnQgPyAkKHN3aXBlci5wYXJhbXMubGF6eS5zY3JvbGxpbmdFbGVtZW50KSA6ICQod2luZG93KTtcbiAgICBjb25zdCBpc1dpbmRvdyA9ICRzY3JvbGxFbGVtZW50WzBdID09PSB3aW5kb3c7XG4gICAgY29uc3Qgc2Nyb2xsRWxlbWVudFdpZHRoID0gaXNXaW5kb3cgPyB3aW5kb3cuaW5uZXJXaWR0aCA6ICRzY3JvbGxFbGVtZW50WzBdLm9mZnNldFdpZHRoO1xuICAgIGNvbnN0IHNjcm9sbEVsZW1lbnRIZWlnaHQgPSBpc1dpbmRvdyA/IHdpbmRvdy5pbm5lckhlaWdodCA6ICRzY3JvbGxFbGVtZW50WzBdLm9mZnNldEhlaWdodDtcbiAgICBjb25zdCBzd2lwZXJPZmZzZXQgPSBzd2lwZXIuJGVsLm9mZnNldCgpO1xuICAgIGNvbnN0IHtcbiAgICAgIHJ0bFRyYW5zbGF0ZTogcnRsXG4gICAgfSA9IHN3aXBlcjtcbiAgICBsZXQgaW5WaWV3ID0gZmFsc2U7XG4gICAgaWYgKHJ0bCkgc3dpcGVyT2Zmc2V0LmxlZnQgLT0gc3dpcGVyLiRlbFswXS5zY3JvbGxMZWZ0O1xuICAgIGNvbnN0IHN3aXBlckNvb3JkID0gW1tzd2lwZXJPZmZzZXQubGVmdCwgc3dpcGVyT2Zmc2V0LnRvcF0sIFtzd2lwZXJPZmZzZXQubGVmdCArIHN3aXBlci53aWR0aCwgc3dpcGVyT2Zmc2V0LnRvcF0sIFtzd2lwZXJPZmZzZXQubGVmdCwgc3dpcGVyT2Zmc2V0LnRvcCArIHN3aXBlci5oZWlnaHRdLCBbc3dpcGVyT2Zmc2V0LmxlZnQgKyBzd2lwZXIud2lkdGgsIHN3aXBlck9mZnNldC50b3AgKyBzd2lwZXIuaGVpZ2h0XV07XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHN3aXBlckNvb3JkLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICBjb25zdCBwb2ludCA9IHN3aXBlckNvb3JkW2ldO1xuXG4gICAgICBpZiAocG9pbnRbMF0gPj0gMCAmJiBwb2ludFswXSA8PSBzY3JvbGxFbGVtZW50V2lkdGggJiYgcG9pbnRbMV0gPj0gMCAmJiBwb2ludFsxXSA8PSBzY3JvbGxFbGVtZW50SGVpZ2h0KSB7XG4gICAgICAgIGlmIChwb2ludFswXSA9PT0gMCAmJiBwb2ludFsxXSA9PT0gMCkgY29udGludWU7IC8vIGVzbGludC1kaXNhYmxlLWxpbmVcblxuICAgICAgICBpblZpZXcgPSB0cnVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IHBhc3NpdmVMaXN0ZW5lciA9IHN3aXBlci50b3VjaEV2ZW50cy5zdGFydCA9PT0gJ3RvdWNoc3RhcnQnICYmIHN3aXBlci5zdXBwb3J0LnBhc3NpdmVMaXN0ZW5lciAmJiBzd2lwZXIucGFyYW1zLnBhc3NpdmVMaXN0ZW5lcnMgPyB7XG4gICAgICBwYXNzaXZlOiB0cnVlLFxuICAgICAgY2FwdHVyZTogZmFsc2VcbiAgICB9IDogZmFsc2U7XG5cbiAgICBpZiAoaW5WaWV3KSB7XG4gICAgICBsb2FkKCk7XG4gICAgICAkc2Nyb2xsRWxlbWVudC5vZmYoJ3Njcm9sbCcsIGNoZWNrSW5WaWV3T25Mb2FkLCBwYXNzaXZlTGlzdGVuZXIpO1xuICAgIH0gZWxzZSBpZiAoIXNjcm9sbEhhbmRsZXJBdHRhY2hlZCkge1xuICAgICAgc2Nyb2xsSGFuZGxlckF0dGFjaGVkID0gdHJ1ZTtcbiAgICAgICRzY3JvbGxFbGVtZW50Lm9uKCdzY3JvbGwnLCBjaGVja0luVmlld09uTG9hZCwgcGFzc2l2ZUxpc3RlbmVyKTtcbiAgICB9XG4gIH1cblxuICBvbignYmVmb3JlSW5pdCcsICgpID0+IHtcbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5sYXp5LmVuYWJsZWQgJiYgc3dpcGVyLnBhcmFtcy5wcmVsb2FkSW1hZ2VzKSB7XG4gICAgICBzd2lwZXIucGFyYW1zLnByZWxvYWRJbWFnZXMgPSBmYWxzZTtcbiAgICB9XG4gIH0pO1xuICBvbignaW5pdCcsICgpID0+IHtcbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5sYXp5LmVuYWJsZWQpIHtcbiAgICAgIGlmIChzd2lwZXIucGFyYW1zLmxhenkuY2hlY2tJblZpZXcpIHtcbiAgICAgICAgY2hlY2tJblZpZXdPbkxvYWQoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxvYWQoKTtcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xuICBvbignc2Nyb2xsJywgKCkgPT4ge1xuICAgIGlmIChzd2lwZXIucGFyYW1zLmZyZWVNb2RlICYmIHN3aXBlci5wYXJhbXMuZnJlZU1vZGUuZW5hYmxlZCAmJiAhc3dpcGVyLnBhcmFtcy5mcmVlTW9kZS5zdGlja3kpIHtcbiAgICAgIGxvYWQoKTtcbiAgICB9XG4gIH0pO1xuICBvbignc2Nyb2xsYmFyRHJhZ01vdmUgcmVzaXplIF9mcmVlTW9kZU5vTW9tZW50dW1SZWxlYXNlJywgKCkgPT4ge1xuICAgIGlmIChzd2lwZXIucGFyYW1zLmxhenkuZW5hYmxlZCkge1xuICAgICAgaWYgKHN3aXBlci5wYXJhbXMubGF6eS5jaGVja0luVmlldykge1xuICAgICAgICBjaGVja0luVmlld09uTG9hZCgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbG9hZCgpO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG4gIG9uKCd0cmFuc2l0aW9uU3RhcnQnLCAoKSA9PiB7XG4gICAgaWYgKHN3aXBlci5wYXJhbXMubGF6eS5lbmFibGVkKSB7XG4gICAgICBpZiAoc3dpcGVyLnBhcmFtcy5sYXp5LmxvYWRPblRyYW5zaXRpb25TdGFydCB8fCAhc3dpcGVyLnBhcmFtcy5sYXp5LmxvYWRPblRyYW5zaXRpb25TdGFydCAmJiAhaW5pdGlhbEltYWdlTG9hZGVkKSB7XG4gICAgICAgIGlmIChzd2lwZXIucGFyYW1zLmxhenkuY2hlY2tJblZpZXcpIHtcbiAgICAgICAgICBjaGVja0luVmlld09uTG9hZCgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGxvYWQoKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSk7XG4gIG9uKCd0cmFuc2l0aW9uRW5kJywgKCkgPT4ge1xuICAgIGlmIChzd2lwZXIucGFyYW1zLmxhenkuZW5hYmxlZCAmJiAhc3dpcGVyLnBhcmFtcy5sYXp5LmxvYWRPblRyYW5zaXRpb25TdGFydCkge1xuICAgICAgaWYgKHN3aXBlci5wYXJhbXMubGF6eS5jaGVja0luVmlldykge1xuICAgICAgICBjaGVja0luVmlld09uTG9hZCgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbG9hZCgpO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG4gIG9uKCdzbGlkZUNoYW5nZScsICgpID0+IHtcbiAgICBjb25zdCB7XG4gICAgICBsYXp5LFxuICAgICAgY3NzTW9kZSxcbiAgICAgIHdhdGNoU2xpZGVzUHJvZ3Jlc3MsXG4gICAgICB0b3VjaFJlbGVhc2VPbkVkZ2VzLFxuICAgICAgcmVzaXN0YW5jZVJhdGlvXG4gICAgfSA9IHN3aXBlci5wYXJhbXM7XG5cbiAgICBpZiAobGF6eS5lbmFibGVkICYmIChjc3NNb2RlIHx8IHdhdGNoU2xpZGVzUHJvZ3Jlc3MgJiYgKHRvdWNoUmVsZWFzZU9uRWRnZXMgfHwgcmVzaXN0YW5jZVJhdGlvID09PSAwKSkpIHtcbiAgICAgIGxvYWQoKTtcbiAgICB9XG4gIH0pO1xuICBvbignZGVzdHJveScsICgpID0+IHtcbiAgICBpZiAoIXN3aXBlci4kZWwpIHJldHVybjtcbiAgICBzd2lwZXIuJGVsLmZpbmQoYC4ke3N3aXBlci5wYXJhbXMubGF6eS5sb2FkaW5nQ2xhc3N9YCkucmVtb3ZlQ2xhc3Moc3dpcGVyLnBhcmFtcy5sYXp5LmxvYWRpbmdDbGFzcyk7XG4gIH0pO1xuICBPYmplY3QuYXNzaWduKHN3aXBlci5sYXp5LCB7XG4gICAgbG9hZCxcbiAgICBsb2FkSW5TbGlkZVxuICB9KTtcbn0iLCIvKiBlc2xpbnQgbm8tYml0d2lzZTogW1wiZXJyb3JcIiwgeyBcImFsbG93XCI6IFtcIj4+XCJdIH1dICovXG5pbXBvcnQgeyBuZXh0VGljayB9IGZyb20gJy4uLy4uL3NoYXJlZC91dGlscy5qcyc7XG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBDb250cm9sbGVyKHtcbiAgc3dpcGVyLFxuICBleHRlbmRQYXJhbXMsXG4gIG9uXG59KSB7XG4gIGV4dGVuZFBhcmFtcyh7XG4gICAgY29udHJvbGxlcjoge1xuICAgICAgY29udHJvbDogdW5kZWZpbmVkLFxuICAgICAgaW52ZXJzZTogZmFsc2UsXG4gICAgICBieTogJ3NsaWRlJyAvLyBvciAnY29udGFpbmVyJ1xuXG4gICAgfVxuICB9KTtcbiAgc3dpcGVyLmNvbnRyb2xsZXIgPSB7XG4gICAgY29udHJvbDogdW5kZWZpbmVkXG4gIH07XG5cbiAgZnVuY3Rpb24gTGluZWFyU3BsaW5lKHgsIHkpIHtcbiAgICBjb25zdCBiaW5hcnlTZWFyY2ggPSBmdW5jdGlvbiBzZWFyY2goKSB7XG4gICAgICBsZXQgbWF4SW5kZXg7XG4gICAgICBsZXQgbWluSW5kZXg7XG4gICAgICBsZXQgZ3Vlc3M7XG4gICAgICByZXR1cm4gKGFycmF5LCB2YWwpID0+IHtcbiAgICAgICAgbWluSW5kZXggPSAtMTtcbiAgICAgICAgbWF4SW5kZXggPSBhcnJheS5sZW5ndGg7XG5cbiAgICAgICAgd2hpbGUgKG1heEluZGV4IC0gbWluSW5kZXggPiAxKSB7XG4gICAgICAgICAgZ3Vlc3MgPSBtYXhJbmRleCArIG1pbkluZGV4ID4+IDE7XG5cbiAgICAgICAgICBpZiAoYXJyYXlbZ3Vlc3NdIDw9IHZhbCkge1xuICAgICAgICAgICAgbWluSW5kZXggPSBndWVzcztcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbWF4SW5kZXggPSBndWVzcztcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbWF4SW5kZXg7XG4gICAgICB9O1xuICAgIH0oKTtcblxuICAgIHRoaXMueCA9IHg7XG4gICAgdGhpcy55ID0geTtcbiAgICB0aGlzLmxhc3RJbmRleCA9IHgubGVuZ3RoIC0gMTsgLy8gR2l2ZW4gYW4geCB2YWx1ZSAoeDIpLCByZXR1cm4gdGhlIGV4cGVjdGVkIHkyIHZhbHVlOlxuICAgIC8vICh4MSx5MSkgaXMgdGhlIGtub3duIHBvaW50IGJlZm9yZSBnaXZlbiB2YWx1ZSxcbiAgICAvLyAoeDMseTMpIGlzIHRoZSBrbm93biBwb2ludCBhZnRlciBnaXZlbiB2YWx1ZS5cblxuICAgIGxldCBpMTtcbiAgICBsZXQgaTM7XG5cbiAgICB0aGlzLmludGVycG9sYXRlID0gZnVuY3Rpb24gaW50ZXJwb2xhdGUoeDIpIHtcbiAgICAgIGlmICgheDIpIHJldHVybiAwOyAvLyBHZXQgdGhlIGluZGV4ZXMgb2YgeDEgYW5kIHgzICh0aGUgYXJyYXkgaW5kZXhlcyBiZWZvcmUgYW5kIGFmdGVyIGdpdmVuIHgyKTpcblxuICAgICAgaTMgPSBiaW5hcnlTZWFyY2godGhpcy54LCB4Mik7XG4gICAgICBpMSA9IGkzIC0gMTsgLy8gV2UgaGF2ZSBvdXIgaW5kZXhlcyBpMSAmIGkzLCBzbyB3ZSBjYW4gY2FsY3VsYXRlIGFscmVhZHk6XG4gICAgICAvLyB5MiA6PSAoKHgy4oiSeDEpIMOXICh5M+KIknkxKSkgw7cgKHgz4oiSeDEpICsgeTFcblxuICAgICAgcmV0dXJuICh4MiAtIHRoaXMueFtpMV0pICogKHRoaXMueVtpM10gLSB0aGlzLnlbaTFdKSAvICh0aGlzLnhbaTNdIC0gdGhpcy54W2kxXSkgKyB0aGlzLnlbaTFdO1xuICAgIH07XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfSAvLyB4eHg6IGZvciBub3cgaSB3aWxsIGp1c3Qgc2F2ZSBvbmUgc3BsaW5lIGZ1bmN0aW9uIHRvIHRvXG5cblxuICBmdW5jdGlvbiBnZXRJbnRlcnBvbGF0ZUZ1bmN0aW9uKGMpIHtcbiAgICBpZiAoIXN3aXBlci5jb250cm9sbGVyLnNwbGluZSkge1xuICAgICAgc3dpcGVyLmNvbnRyb2xsZXIuc3BsaW5lID0gc3dpcGVyLnBhcmFtcy5sb29wID8gbmV3IExpbmVhclNwbGluZShzd2lwZXIuc2xpZGVzR3JpZCwgYy5zbGlkZXNHcmlkKSA6IG5ldyBMaW5lYXJTcGxpbmUoc3dpcGVyLnNuYXBHcmlkLCBjLnNuYXBHcmlkKTtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBzZXRUcmFuc2xhdGUoX3QsIGJ5Q29udHJvbGxlcikge1xuICAgIGNvbnN0IGNvbnRyb2xsZWQgPSBzd2lwZXIuY29udHJvbGxlci5jb250cm9sO1xuICAgIGxldCBtdWx0aXBsaWVyO1xuICAgIGxldCBjb250cm9sbGVkVHJhbnNsYXRlO1xuICAgIGNvbnN0IFN3aXBlciA9IHN3aXBlci5jb25zdHJ1Y3RvcjtcblxuICAgIGZ1bmN0aW9uIHNldENvbnRyb2xsZWRUcmFuc2xhdGUoYykge1xuICAgICAgLy8gdGhpcyB3aWxsIGNyZWF0ZSBhbiBJbnRlcnBvbGF0ZSBmdW5jdGlvbiBiYXNlZCBvbiB0aGUgc25hcEdyaWRzXG4gICAgICAvLyB4IGlzIHRoZSBHcmlkIG9mIHRoZSBzY3JvbGxlZCBzY3JvbGxlciBhbmQgeSB3aWxsIGJlIHRoZSBjb250cm9sbGVkIHNjcm9sbGVyXG4gICAgICAvLyBpdCBtYWtlcyBzZW5zZSB0byBjcmVhdGUgdGhpcyBvbmx5IG9uY2UgYW5kIHJlY2FsbCBpdCBmb3IgdGhlIGludGVycG9sYXRpb25cbiAgICAgIC8vIHRoZSBmdW5jdGlvbiBkb2VzIGEgbG90IG9mIHZhbHVlIGNhY2hpbmcgZm9yIHBlcmZvcm1hbmNlXG4gICAgICBjb25zdCB0cmFuc2xhdGUgPSBzd2lwZXIucnRsVHJhbnNsYXRlID8gLXN3aXBlci50cmFuc2xhdGUgOiBzd2lwZXIudHJhbnNsYXRlO1xuXG4gICAgICBpZiAoc3dpcGVyLnBhcmFtcy5jb250cm9sbGVyLmJ5ID09PSAnc2xpZGUnKSB7XG4gICAgICAgIGdldEludGVycG9sYXRlRnVuY3Rpb24oYyk7IC8vIGkgYW0gbm90IHN1cmUgd2h5IHRoZSB2YWx1ZXMgaGF2ZSB0byBiZSBtdWx0aXBsaWNhdGVkIHRoaXMgd2F5LCB0cmllZCB0byBpbnZlcnQgdGhlIHNuYXBHcmlkXG4gICAgICAgIC8vIGJ1dCBpdCBkaWQgbm90IHdvcmsgb3V0XG5cbiAgICAgICAgY29udHJvbGxlZFRyYW5zbGF0ZSA9IC1zd2lwZXIuY29udHJvbGxlci5zcGxpbmUuaW50ZXJwb2xhdGUoLXRyYW5zbGF0ZSk7XG4gICAgICB9XG5cbiAgICAgIGlmICghY29udHJvbGxlZFRyYW5zbGF0ZSB8fCBzd2lwZXIucGFyYW1zLmNvbnRyb2xsZXIuYnkgPT09ICdjb250YWluZXInKSB7XG4gICAgICAgIG11bHRpcGxpZXIgPSAoYy5tYXhUcmFuc2xhdGUoKSAtIGMubWluVHJhbnNsYXRlKCkpIC8gKHN3aXBlci5tYXhUcmFuc2xhdGUoKSAtIHN3aXBlci5taW5UcmFuc2xhdGUoKSk7XG4gICAgICAgIGNvbnRyb2xsZWRUcmFuc2xhdGUgPSAodHJhbnNsYXRlIC0gc3dpcGVyLm1pblRyYW5zbGF0ZSgpKSAqIG11bHRpcGxpZXIgKyBjLm1pblRyYW5zbGF0ZSgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoc3dpcGVyLnBhcmFtcy5jb250cm9sbGVyLmludmVyc2UpIHtcbiAgICAgICAgY29udHJvbGxlZFRyYW5zbGF0ZSA9IGMubWF4VHJhbnNsYXRlKCkgLSBjb250cm9sbGVkVHJhbnNsYXRlO1xuICAgICAgfVxuXG4gICAgICBjLnVwZGF0ZVByb2dyZXNzKGNvbnRyb2xsZWRUcmFuc2xhdGUpO1xuICAgICAgYy5zZXRUcmFuc2xhdGUoY29udHJvbGxlZFRyYW5zbGF0ZSwgc3dpcGVyKTtcbiAgICAgIGMudXBkYXRlQWN0aXZlSW5kZXgoKTtcbiAgICAgIGMudXBkYXRlU2xpZGVzQ2xhc3NlcygpO1xuICAgIH1cblxuICAgIGlmIChBcnJheS5pc0FycmF5KGNvbnRyb2xsZWQpKSB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNvbnRyb2xsZWQubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgaWYgKGNvbnRyb2xsZWRbaV0gIT09IGJ5Q29udHJvbGxlciAmJiBjb250cm9sbGVkW2ldIGluc3RhbmNlb2YgU3dpcGVyKSB7XG4gICAgICAgICAgc2V0Q29udHJvbGxlZFRyYW5zbGF0ZShjb250cm9sbGVkW2ldKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoY29udHJvbGxlZCBpbnN0YW5jZW9mIFN3aXBlciAmJiBieUNvbnRyb2xsZXIgIT09IGNvbnRyb2xsZWQpIHtcbiAgICAgIHNldENvbnRyb2xsZWRUcmFuc2xhdGUoY29udHJvbGxlZCk7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gc2V0VHJhbnNpdGlvbihkdXJhdGlvbiwgYnlDb250cm9sbGVyKSB7XG4gICAgY29uc3QgU3dpcGVyID0gc3dpcGVyLmNvbnN0cnVjdG9yO1xuICAgIGNvbnN0IGNvbnRyb2xsZWQgPSBzd2lwZXIuY29udHJvbGxlci5jb250cm9sO1xuICAgIGxldCBpO1xuXG4gICAgZnVuY3Rpb24gc2V0Q29udHJvbGxlZFRyYW5zaXRpb24oYykge1xuICAgICAgYy5zZXRUcmFuc2l0aW9uKGR1cmF0aW9uLCBzd2lwZXIpO1xuXG4gICAgICBpZiAoZHVyYXRpb24gIT09IDApIHtcbiAgICAgICAgYy50cmFuc2l0aW9uU3RhcnQoKTtcblxuICAgICAgICBpZiAoYy5wYXJhbXMuYXV0b0hlaWdodCkge1xuICAgICAgICAgIG5leHRUaWNrKCgpID0+IHtcbiAgICAgICAgICAgIGMudXBkYXRlQXV0b0hlaWdodCgpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgYy4kd3JhcHBlckVsLnRyYW5zaXRpb25FbmQoKCkgPT4ge1xuICAgICAgICAgIGlmICghY29udHJvbGxlZCkgcmV0dXJuO1xuXG4gICAgICAgICAgaWYgKGMucGFyYW1zLmxvb3AgJiYgc3dpcGVyLnBhcmFtcy5jb250cm9sbGVyLmJ5ID09PSAnc2xpZGUnKSB7XG4gICAgICAgICAgICBjLmxvb3BGaXgoKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjLnRyYW5zaXRpb25FbmQoKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKEFycmF5LmlzQXJyYXkoY29udHJvbGxlZCkpIHtcbiAgICAgIGZvciAoaSA9IDA7IGkgPCBjb250cm9sbGVkLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICAgIGlmIChjb250cm9sbGVkW2ldICE9PSBieUNvbnRyb2xsZXIgJiYgY29udHJvbGxlZFtpXSBpbnN0YW5jZW9mIFN3aXBlcikge1xuICAgICAgICAgIHNldENvbnRyb2xsZWRUcmFuc2l0aW9uKGNvbnRyb2xsZWRbaV0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChjb250cm9sbGVkIGluc3RhbmNlb2YgU3dpcGVyICYmIGJ5Q29udHJvbGxlciAhPT0gY29udHJvbGxlZCkge1xuICAgICAgc2V0Q29udHJvbGxlZFRyYW5zaXRpb24oY29udHJvbGxlZCk7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gcmVtb3ZlU3BsaW5lKCkge1xuICAgIGlmICghc3dpcGVyLmNvbnRyb2xsZXIuY29udHJvbCkgcmV0dXJuO1xuXG4gICAgaWYgKHN3aXBlci5jb250cm9sbGVyLnNwbGluZSkge1xuICAgICAgc3dpcGVyLmNvbnRyb2xsZXIuc3BsaW5lID0gdW5kZWZpbmVkO1xuICAgICAgZGVsZXRlIHN3aXBlci5jb250cm9sbGVyLnNwbGluZTtcbiAgICB9XG4gIH1cblxuICBvbignYmVmb3JlSW5pdCcsICgpID0+IHtcbiAgICBzd2lwZXIuY29udHJvbGxlci5jb250cm9sID0gc3dpcGVyLnBhcmFtcy5jb250cm9sbGVyLmNvbnRyb2w7XG4gIH0pO1xuICBvbigndXBkYXRlJywgKCkgPT4ge1xuICAgIHJlbW92ZVNwbGluZSgpO1xuICB9KTtcbiAgb24oJ3Jlc2l6ZScsICgpID0+IHtcbiAgICByZW1vdmVTcGxpbmUoKTtcbiAgfSk7XG4gIG9uKCdvYnNlcnZlclVwZGF0ZScsICgpID0+IHtcbiAgICByZW1vdmVTcGxpbmUoKTtcbiAgfSk7XG4gIG9uKCdzZXRUcmFuc2xhdGUnLCAoX3MsIHRyYW5zbGF0ZSwgYnlDb250cm9sbGVyKSA9PiB7XG4gICAgaWYgKCFzd2lwZXIuY29udHJvbGxlci5jb250cm9sKSByZXR1cm47XG4gICAgc3dpcGVyLmNvbnRyb2xsZXIuc2V0VHJhbnNsYXRlKHRyYW5zbGF0ZSwgYnlDb250cm9sbGVyKTtcbiAgfSk7XG4gIG9uKCdzZXRUcmFuc2l0aW9uJywgKF9zLCBkdXJhdGlvbiwgYnlDb250cm9sbGVyKSA9PiB7XG4gICAgaWYgKCFzd2lwZXIuY29udHJvbGxlci5jb250cm9sKSByZXR1cm47XG4gICAgc3dpcGVyLmNvbnRyb2xsZXIuc2V0VHJhbnNpdGlvbihkdXJhdGlvbiwgYnlDb250cm9sbGVyKTtcbiAgfSk7XG4gIE9iamVjdC5hc3NpZ24oc3dpcGVyLmNvbnRyb2xsZXIsIHtcbiAgICBzZXRUcmFuc2xhdGUsXG4gICAgc2V0VHJhbnNpdGlvblxuICB9KTtcbn0iLCJpbXBvcnQgY2xhc3Nlc1RvU2VsZWN0b3IgZnJvbSAnLi4vLi4vc2hhcmVkL2NsYXNzZXMtdG8tc2VsZWN0b3IuanMnO1xuaW1wb3J0ICQgZnJvbSAnLi4vLi4vc2hhcmVkL2RvbS5qcyc7XG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBBMTF5KHtcbiAgc3dpcGVyLFxuICBleHRlbmRQYXJhbXMsXG4gIG9uXG59KSB7XG4gIGV4dGVuZFBhcmFtcyh7XG4gICAgYTExeToge1xuICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgIG5vdGlmaWNhdGlvbkNsYXNzOiAnc3dpcGVyLW5vdGlmaWNhdGlvbicsXG4gICAgICBwcmV2U2xpZGVNZXNzYWdlOiAnUHJldmlvdXMgc2xpZGUnLFxuICAgICAgbmV4dFNsaWRlTWVzc2FnZTogJ05leHQgc2xpZGUnLFxuICAgICAgZmlyc3RTbGlkZU1lc3NhZ2U6ICdUaGlzIGlzIHRoZSBmaXJzdCBzbGlkZScsXG4gICAgICBsYXN0U2xpZGVNZXNzYWdlOiAnVGhpcyBpcyB0aGUgbGFzdCBzbGlkZScsXG4gICAgICBwYWdpbmF0aW9uQnVsbGV0TWVzc2FnZTogJ0dvIHRvIHNsaWRlIHt7aW5kZXh9fScsXG4gICAgICBzbGlkZUxhYmVsTWVzc2FnZTogJ3t7aW5kZXh9fSAvIHt7c2xpZGVzTGVuZ3RofX0nLFxuICAgICAgY29udGFpbmVyTWVzc2FnZTogbnVsbCxcbiAgICAgIGNvbnRhaW5lclJvbGVEZXNjcmlwdGlvbk1lc3NhZ2U6IG51bGwsXG4gICAgICBpdGVtUm9sZURlc2NyaXB0aW9uTWVzc2FnZTogbnVsbCxcbiAgICAgIHNsaWRlUm9sZTogJ2dyb3VwJyxcbiAgICAgIGlkOiBudWxsXG4gICAgfVxuICB9KTtcbiAgc3dpcGVyLmExMXkgPSB7XG4gICAgY2xpY2tlZDogZmFsc2VcbiAgfTtcbiAgbGV0IGxpdmVSZWdpb24gPSBudWxsO1xuXG4gIGZ1bmN0aW9uIG5vdGlmeShtZXNzYWdlKSB7XG4gICAgY29uc3Qgbm90aWZpY2F0aW9uID0gbGl2ZVJlZ2lvbjtcbiAgICBpZiAobm90aWZpY2F0aW9uLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICAgIG5vdGlmaWNhdGlvbi5odG1sKCcnKTtcbiAgICBub3RpZmljYXRpb24uaHRtbChtZXNzYWdlKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGdldFJhbmRvbU51bWJlcihzaXplID0gMTYpIHtcbiAgICBjb25zdCByYW5kb21DaGFyID0gKCkgPT4gTWF0aC5yb3VuZCgxNiAqIE1hdGgucmFuZG9tKCkpLnRvU3RyaW5nKDE2KTtcblxuICAgIHJldHVybiAneCcucmVwZWF0KHNpemUpLnJlcGxhY2UoL3gvZywgcmFuZG9tQ2hhcik7XG4gIH1cblxuICBmdW5jdGlvbiBtYWtlRWxGb2N1c2FibGUoJGVsKSB7XG4gICAgJGVsLmF0dHIoJ3RhYkluZGV4JywgJzAnKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIG1ha2VFbE5vdEZvY3VzYWJsZSgkZWwpIHtcbiAgICAkZWwuYXR0cigndGFiSW5kZXgnLCAnLTEnKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGFkZEVsUm9sZSgkZWwsIHJvbGUpIHtcbiAgICAkZWwuYXR0cigncm9sZScsIHJvbGUpO1xuICB9XG5cbiAgZnVuY3Rpb24gYWRkRWxSb2xlRGVzY3JpcHRpb24oJGVsLCBkZXNjcmlwdGlvbikge1xuICAgICRlbC5hdHRyKCdhcmlhLXJvbGVkZXNjcmlwdGlvbicsIGRlc2NyaXB0aW9uKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGFkZEVsQ29udHJvbHMoJGVsLCBjb250cm9scykge1xuICAgICRlbC5hdHRyKCdhcmlhLWNvbnRyb2xzJywgY29udHJvbHMpO1xuICB9XG5cbiAgZnVuY3Rpb24gYWRkRWxMYWJlbCgkZWwsIGxhYmVsKSB7XG4gICAgJGVsLmF0dHIoJ2FyaWEtbGFiZWwnLCBsYWJlbCk7XG4gIH1cblxuICBmdW5jdGlvbiBhZGRFbElkKCRlbCwgaWQpIHtcbiAgICAkZWwuYXR0cignaWQnLCBpZCk7XG4gIH1cblxuICBmdW5jdGlvbiBhZGRFbExpdmUoJGVsLCBsaXZlKSB7XG4gICAgJGVsLmF0dHIoJ2FyaWEtbGl2ZScsIGxpdmUpO1xuICB9XG5cbiAgZnVuY3Rpb24gZGlzYWJsZUVsKCRlbCkge1xuICAgICRlbC5hdHRyKCdhcmlhLWRpc2FibGVkJywgdHJ1ZSk7XG4gIH1cblxuICBmdW5jdGlvbiBlbmFibGVFbCgkZWwpIHtcbiAgICAkZWwuYXR0cignYXJpYS1kaXNhYmxlZCcsIGZhbHNlKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIG9uRW50ZXJPclNwYWNlS2V5KGUpIHtcbiAgICBpZiAoZS5rZXlDb2RlICE9PSAxMyAmJiBlLmtleUNvZGUgIT09IDMyKSByZXR1cm47XG4gICAgY29uc3QgcGFyYW1zID0gc3dpcGVyLnBhcmFtcy5hMTF5O1xuICAgIGNvbnN0ICR0YXJnZXRFbCA9ICQoZS50YXJnZXQpO1xuXG4gICAgaWYgKHN3aXBlci5uYXZpZ2F0aW9uICYmIHN3aXBlci5uYXZpZ2F0aW9uLiRuZXh0RWwgJiYgJHRhcmdldEVsLmlzKHN3aXBlci5uYXZpZ2F0aW9uLiRuZXh0RWwpKSB7XG4gICAgICBpZiAoIShzd2lwZXIuaXNFbmQgJiYgIXN3aXBlci5wYXJhbXMubG9vcCkpIHtcbiAgICAgICAgc3dpcGVyLnNsaWRlTmV4dCgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoc3dpcGVyLmlzRW5kKSB7XG4gICAgICAgIG5vdGlmeShwYXJhbXMubGFzdFNsaWRlTWVzc2FnZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBub3RpZnkocGFyYW1zLm5leHRTbGlkZU1lc3NhZ2UpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChzd2lwZXIubmF2aWdhdGlvbiAmJiBzd2lwZXIubmF2aWdhdGlvbi4kcHJldkVsICYmICR0YXJnZXRFbC5pcyhzd2lwZXIubmF2aWdhdGlvbi4kcHJldkVsKSkge1xuICAgICAgaWYgKCEoc3dpcGVyLmlzQmVnaW5uaW5nICYmICFzd2lwZXIucGFyYW1zLmxvb3ApKSB7XG4gICAgICAgIHN3aXBlci5zbGlkZVByZXYoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHN3aXBlci5pc0JlZ2lubmluZykge1xuICAgICAgICBub3RpZnkocGFyYW1zLmZpcnN0U2xpZGVNZXNzYWdlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG5vdGlmeShwYXJhbXMucHJldlNsaWRlTWVzc2FnZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHN3aXBlci5wYWdpbmF0aW9uICYmICR0YXJnZXRFbC5pcyhjbGFzc2VzVG9TZWxlY3Rvcihzd2lwZXIucGFyYW1zLnBhZ2luYXRpb24uYnVsbGV0Q2xhc3MpKSkge1xuICAgICAgJHRhcmdldEVsWzBdLmNsaWNrKCk7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gdXBkYXRlTmF2aWdhdGlvbigpIHtcbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5sb29wIHx8IHN3aXBlci5wYXJhbXMucmV3aW5kIHx8ICFzd2lwZXIubmF2aWdhdGlvbikgcmV0dXJuO1xuICAgIGNvbnN0IHtcbiAgICAgICRuZXh0RWwsXG4gICAgICAkcHJldkVsXG4gICAgfSA9IHN3aXBlci5uYXZpZ2F0aW9uO1xuXG4gICAgaWYgKCRwcmV2RWwgJiYgJHByZXZFbC5sZW5ndGggPiAwKSB7XG4gICAgICBpZiAoc3dpcGVyLmlzQmVnaW5uaW5nKSB7XG4gICAgICAgIGRpc2FibGVFbCgkcHJldkVsKTtcbiAgICAgICAgbWFrZUVsTm90Rm9jdXNhYmxlKCRwcmV2RWwpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZW5hYmxlRWwoJHByZXZFbCk7XG4gICAgICAgIG1ha2VFbEZvY3VzYWJsZSgkcHJldkVsKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoJG5leHRFbCAmJiAkbmV4dEVsLmxlbmd0aCA+IDApIHtcbiAgICAgIGlmIChzd2lwZXIuaXNFbmQpIHtcbiAgICAgICAgZGlzYWJsZUVsKCRuZXh0RWwpO1xuICAgICAgICBtYWtlRWxOb3RGb2N1c2FibGUoJG5leHRFbCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBlbmFibGVFbCgkbmV4dEVsKTtcbiAgICAgICAgbWFrZUVsRm9jdXNhYmxlKCRuZXh0RWwpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGhhc1BhZ2luYXRpb24oKSB7XG4gICAgcmV0dXJuIHN3aXBlci5wYWdpbmF0aW9uICYmIHN3aXBlci5wYWdpbmF0aW9uLmJ1bGxldHMgJiYgc3dpcGVyLnBhZ2luYXRpb24uYnVsbGV0cy5sZW5ndGg7XG4gIH1cblxuICBmdW5jdGlvbiBoYXNDbGlja2FibGVQYWdpbmF0aW9uKCkge1xuICAgIHJldHVybiBoYXNQYWdpbmF0aW9uKCkgJiYgc3dpcGVyLnBhcmFtcy5wYWdpbmF0aW9uLmNsaWNrYWJsZTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHVwZGF0ZVBhZ2luYXRpb24oKSB7XG4gICAgY29uc3QgcGFyYW1zID0gc3dpcGVyLnBhcmFtcy5hMTF5O1xuICAgIGlmICghaGFzUGFnaW5hdGlvbigpKSByZXR1cm47XG4gICAgc3dpcGVyLnBhZ2luYXRpb24uYnVsbGV0cy5lYWNoKGJ1bGxldEVsID0+IHtcbiAgICAgIGNvbnN0ICRidWxsZXRFbCA9ICQoYnVsbGV0RWwpO1xuXG4gICAgICBpZiAoc3dpcGVyLnBhcmFtcy5wYWdpbmF0aW9uLmNsaWNrYWJsZSkge1xuICAgICAgICBtYWtlRWxGb2N1c2FibGUoJGJ1bGxldEVsKTtcblxuICAgICAgICBpZiAoIXN3aXBlci5wYXJhbXMucGFnaW5hdGlvbi5yZW5kZXJCdWxsZXQpIHtcbiAgICAgICAgICBhZGRFbFJvbGUoJGJ1bGxldEVsLCAnYnV0dG9uJyk7XG4gICAgICAgICAgYWRkRWxMYWJlbCgkYnVsbGV0RWwsIHBhcmFtcy5wYWdpbmF0aW9uQnVsbGV0TWVzc2FnZS5yZXBsYWNlKC9cXHtcXHtpbmRleFxcfVxcfS8sICRidWxsZXRFbC5pbmRleCgpICsgMSkpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICgkYnVsbGV0RWwuaXMoYC4ke3N3aXBlci5wYXJhbXMucGFnaW5hdGlvbi5idWxsZXRBY3RpdmVDbGFzc31gKSkge1xuICAgICAgICAkYnVsbGV0RWwuYXR0cignYXJpYS1jdXJyZW50JywgJ3RydWUnKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgICRidWxsZXRFbC5yZW1vdmVBdHRyKCdhcmlhLWN1cnJlbnQnKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIGNvbnN0IGluaXROYXZFbCA9ICgkZWwsIHdyYXBwZXJJZCwgbWVzc2FnZSkgPT4ge1xuICAgIG1ha2VFbEZvY3VzYWJsZSgkZWwpO1xuXG4gICAgaWYgKCRlbFswXS50YWdOYW1lICE9PSAnQlVUVE9OJykge1xuICAgICAgYWRkRWxSb2xlKCRlbCwgJ2J1dHRvbicpO1xuICAgICAgJGVsLm9uKCdrZXlkb3duJywgb25FbnRlck9yU3BhY2VLZXkpO1xuICAgIH1cblxuICAgIGFkZEVsTGFiZWwoJGVsLCBtZXNzYWdlKTtcbiAgICBhZGRFbENvbnRyb2xzKCRlbCwgd3JhcHBlcklkKTtcbiAgfTtcblxuICBjb25zdCBoYW5kbGVQb2ludGVyRG93biA9ICgpID0+IHtcbiAgICBzd2lwZXIuYTExeS5jbGlja2VkID0gdHJ1ZTtcbiAgfTtcblxuICBjb25zdCBoYW5kbGVQb2ludGVyVXAgPSAoKSA9PiB7XG4gICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICAgIGlmICghc3dpcGVyLmRlc3Ryb3llZCkge1xuICAgICAgICAgIHN3aXBlci5hMTF5LmNsaWNrZWQgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG4gIH07XG5cbiAgY29uc3QgaGFuZGxlRm9jdXMgPSBlID0+IHtcbiAgICBpZiAoc3dpcGVyLmExMXkuY2xpY2tlZCkgcmV0dXJuO1xuICAgIGNvbnN0IHNsaWRlRWwgPSBlLnRhcmdldC5jbG9zZXN0KGAuJHtzd2lwZXIucGFyYW1zLnNsaWRlQ2xhc3N9YCk7XG4gICAgaWYgKCFzbGlkZUVsIHx8ICFzd2lwZXIuc2xpZGVzLmluY2x1ZGVzKHNsaWRlRWwpKSByZXR1cm47XG4gICAgY29uc3QgaXNBY3RpdmUgPSBzd2lwZXIuc2xpZGVzLmluZGV4T2Yoc2xpZGVFbCkgPT09IHN3aXBlci5hY3RpdmVJbmRleDtcbiAgICBjb25zdCBpc1Zpc2libGUgPSBzd2lwZXIucGFyYW1zLndhdGNoU2xpZGVzUHJvZ3Jlc3MgJiYgc3dpcGVyLnZpc2libGVTbGlkZXMgJiYgc3dpcGVyLnZpc2libGVTbGlkZXMuaW5jbHVkZXMoc2xpZGVFbCk7XG4gICAgaWYgKGlzQWN0aXZlIHx8IGlzVmlzaWJsZSkgcmV0dXJuO1xuICAgIGlmIChlLnNvdXJjZUNhcGFiaWxpdGllcyAmJiBlLnNvdXJjZUNhcGFiaWxpdGllcy5maXJlc1RvdWNoRXZlbnRzKSByZXR1cm47XG5cbiAgICBpZiAoc3dpcGVyLmlzSG9yaXpvbnRhbCgpKSB7XG4gICAgICBzd2lwZXIuZWwuc2Nyb2xsTGVmdCA9IDA7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN3aXBlci5lbC5zY3JvbGxUb3AgPSAwO1xuICAgIH1cblxuICAgIHN3aXBlci5zbGlkZVRvKHN3aXBlci5zbGlkZXMuaW5kZXhPZihzbGlkZUVsKSwgMCk7XG4gIH07XG5cbiAgY29uc3QgaW5pdFNsaWRlcyA9ICgpID0+IHtcbiAgICBjb25zdCBwYXJhbXMgPSBzd2lwZXIucGFyYW1zLmExMXk7XG5cbiAgICBpZiAocGFyYW1zLml0ZW1Sb2xlRGVzY3JpcHRpb25NZXNzYWdlKSB7XG4gICAgICBhZGRFbFJvbGVEZXNjcmlwdGlvbigkKHN3aXBlci5zbGlkZXMpLCBwYXJhbXMuaXRlbVJvbGVEZXNjcmlwdGlvbk1lc3NhZ2UpO1xuICAgIH1cblxuICAgIGlmIChwYXJhbXMuc2xpZGVSb2xlKSB7XG4gICAgICBhZGRFbFJvbGUoJChzd2lwZXIuc2xpZGVzKSwgcGFyYW1zLnNsaWRlUm9sZSk7XG4gICAgfVxuXG4gICAgY29uc3Qgc2xpZGVzTGVuZ3RoID0gc3dpcGVyLnBhcmFtcy5sb29wID8gc3dpcGVyLnNsaWRlcy5maWx0ZXIoZWwgPT4gIWVsLmNsYXNzTGlzdC5jb250YWlucyhzd2lwZXIucGFyYW1zLnNsaWRlRHVwbGljYXRlQ2xhc3MpKS5sZW5ndGggOiBzd2lwZXIuc2xpZGVzLmxlbmd0aDtcblxuICAgIGlmIChwYXJhbXMuc2xpZGVMYWJlbE1lc3NhZ2UpIHtcbiAgICAgIHN3aXBlci5zbGlkZXMuZWFjaCgoc2xpZGVFbCwgaW5kZXgpID0+IHtcbiAgICAgICAgY29uc3QgJHNsaWRlRWwgPSAkKHNsaWRlRWwpO1xuICAgICAgICBjb25zdCBzbGlkZUluZGV4ID0gc3dpcGVyLnBhcmFtcy5sb29wID8gcGFyc2VJbnQoJHNsaWRlRWwuYXR0cignZGF0YS1zd2lwZXItc2xpZGUtaW5kZXgnKSwgMTApIDogaW5kZXg7XG4gICAgICAgIGNvbnN0IGFyaWFMYWJlbE1lc3NhZ2UgPSBwYXJhbXMuc2xpZGVMYWJlbE1lc3NhZ2UucmVwbGFjZSgvXFx7XFx7aW5kZXhcXH1cXH0vLCBzbGlkZUluZGV4ICsgMSkucmVwbGFjZSgvXFx7XFx7c2xpZGVzTGVuZ3RoXFx9XFx9Lywgc2xpZGVzTGVuZ3RoKTtcbiAgICAgICAgYWRkRWxMYWJlbCgkc2xpZGVFbCwgYXJpYUxhYmVsTWVzc2FnZSk7XG4gICAgICB9KTtcbiAgICB9XG4gIH07XG5cbiAgY29uc3QgaW5pdCA9ICgpID0+IHtcbiAgICBjb25zdCBwYXJhbXMgPSBzd2lwZXIucGFyYW1zLmExMXk7XG4gICAgc3dpcGVyLiRlbC5hcHBlbmQobGl2ZVJlZ2lvbik7IC8vIENvbnRhaW5lclxuXG4gICAgY29uc3QgJGNvbnRhaW5lckVsID0gc3dpcGVyLiRlbDtcblxuICAgIGlmIChwYXJhbXMuY29udGFpbmVyUm9sZURlc2NyaXB0aW9uTWVzc2FnZSkge1xuICAgICAgYWRkRWxSb2xlRGVzY3JpcHRpb24oJGNvbnRhaW5lckVsLCBwYXJhbXMuY29udGFpbmVyUm9sZURlc2NyaXB0aW9uTWVzc2FnZSk7XG4gICAgfVxuXG4gICAgaWYgKHBhcmFtcy5jb250YWluZXJNZXNzYWdlKSB7XG4gICAgICBhZGRFbExhYmVsKCRjb250YWluZXJFbCwgcGFyYW1zLmNvbnRhaW5lck1lc3NhZ2UpO1xuICAgIH0gLy8gV3JhcHBlclxuXG5cbiAgICBjb25zdCAkd3JhcHBlckVsID0gc3dpcGVyLiR3cmFwcGVyRWw7XG4gICAgY29uc3Qgd3JhcHBlcklkID0gcGFyYW1zLmlkIHx8ICR3cmFwcGVyRWwuYXR0cignaWQnKSB8fCBgc3dpcGVyLXdyYXBwZXItJHtnZXRSYW5kb21OdW1iZXIoMTYpfWA7XG4gICAgY29uc3QgbGl2ZSA9IHN3aXBlci5wYXJhbXMuYXV0b3BsYXkgJiYgc3dpcGVyLnBhcmFtcy5hdXRvcGxheS5lbmFibGVkID8gJ29mZicgOiAncG9saXRlJztcbiAgICBhZGRFbElkKCR3cmFwcGVyRWwsIHdyYXBwZXJJZCk7XG4gICAgYWRkRWxMaXZlKCR3cmFwcGVyRWwsIGxpdmUpOyAvLyBTbGlkZVxuXG4gICAgaW5pdFNsaWRlcygpOyAvLyBOYXZpZ2F0aW9uXG5cbiAgICBsZXQgJG5leHRFbDtcbiAgICBsZXQgJHByZXZFbDtcblxuICAgIGlmIChzd2lwZXIubmF2aWdhdGlvbiAmJiBzd2lwZXIubmF2aWdhdGlvbi4kbmV4dEVsKSB7XG4gICAgICAkbmV4dEVsID0gc3dpcGVyLm5hdmlnYXRpb24uJG5leHRFbDtcbiAgICB9XG5cbiAgICBpZiAoc3dpcGVyLm5hdmlnYXRpb24gJiYgc3dpcGVyLm5hdmlnYXRpb24uJHByZXZFbCkge1xuICAgICAgJHByZXZFbCA9IHN3aXBlci5uYXZpZ2F0aW9uLiRwcmV2RWw7XG4gICAgfVxuXG4gICAgaWYgKCRuZXh0RWwgJiYgJG5leHRFbC5sZW5ndGgpIHtcbiAgICAgIGluaXROYXZFbCgkbmV4dEVsLCB3cmFwcGVySWQsIHBhcmFtcy5uZXh0U2xpZGVNZXNzYWdlKTtcbiAgICB9XG5cbiAgICBpZiAoJHByZXZFbCAmJiAkcHJldkVsLmxlbmd0aCkge1xuICAgICAgaW5pdE5hdkVsKCRwcmV2RWwsIHdyYXBwZXJJZCwgcGFyYW1zLnByZXZTbGlkZU1lc3NhZ2UpO1xuICAgIH0gLy8gUGFnaW5hdGlvblxuXG5cbiAgICBpZiAoaGFzQ2xpY2thYmxlUGFnaW5hdGlvbigpKSB7XG4gICAgICBzd2lwZXIucGFnaW5hdGlvbi4kZWwub24oJ2tleWRvd24nLCBjbGFzc2VzVG9TZWxlY3Rvcihzd2lwZXIucGFyYW1zLnBhZ2luYXRpb24uYnVsbGV0Q2xhc3MpLCBvbkVudGVyT3JTcGFjZUtleSk7XG4gICAgfSAvLyBUYWIgZm9jdXNcblxuXG4gICAgc3dpcGVyLiRlbC5vbignZm9jdXMnLCBoYW5kbGVGb2N1cywgdHJ1ZSk7XG4gICAgc3dpcGVyLiRlbC5vbigncG9pbnRlcmRvd24nLCBoYW5kbGVQb2ludGVyRG93biwgdHJ1ZSk7XG4gICAgc3dpcGVyLiRlbC5vbigncG9pbnRlcnVwJywgaGFuZGxlUG9pbnRlclVwLCB0cnVlKTtcbiAgfTtcblxuICBmdW5jdGlvbiBkZXN0cm95KCkge1xuICAgIGlmIChsaXZlUmVnaW9uICYmIGxpdmVSZWdpb24ubGVuZ3RoID4gMCkgbGl2ZVJlZ2lvbi5yZW1vdmUoKTtcbiAgICBsZXQgJG5leHRFbDtcbiAgICBsZXQgJHByZXZFbDtcblxuICAgIGlmIChzd2lwZXIubmF2aWdhdGlvbiAmJiBzd2lwZXIubmF2aWdhdGlvbi4kbmV4dEVsKSB7XG4gICAgICAkbmV4dEVsID0gc3dpcGVyLm5hdmlnYXRpb24uJG5leHRFbDtcbiAgICB9XG5cbiAgICBpZiAoc3dpcGVyLm5hdmlnYXRpb24gJiYgc3dpcGVyLm5hdmlnYXRpb24uJHByZXZFbCkge1xuICAgICAgJHByZXZFbCA9IHN3aXBlci5uYXZpZ2F0aW9uLiRwcmV2RWw7XG4gICAgfVxuXG4gICAgaWYgKCRuZXh0RWwpIHtcbiAgICAgICRuZXh0RWwub2ZmKCdrZXlkb3duJywgb25FbnRlck9yU3BhY2VLZXkpO1xuICAgIH1cblxuICAgIGlmICgkcHJldkVsKSB7XG4gICAgICAkcHJldkVsLm9mZigna2V5ZG93bicsIG9uRW50ZXJPclNwYWNlS2V5KTtcbiAgICB9IC8vIFBhZ2luYXRpb25cblxuXG4gICAgaWYgKGhhc0NsaWNrYWJsZVBhZ2luYXRpb24oKSkge1xuICAgICAgc3dpcGVyLnBhZ2luYXRpb24uJGVsLm9mZigna2V5ZG93bicsIGNsYXNzZXNUb1NlbGVjdG9yKHN3aXBlci5wYXJhbXMucGFnaW5hdGlvbi5idWxsZXRDbGFzcyksIG9uRW50ZXJPclNwYWNlS2V5KTtcbiAgICB9IC8vIFRhYiBmb2N1c1xuXG5cbiAgICBzd2lwZXIuJGVsLm9mZignZm9jdXMnLCBoYW5kbGVGb2N1cywgdHJ1ZSk7XG4gICAgc3dpcGVyLiRlbC5vZmYoJ3BvaW50ZXJkb3duJywgaGFuZGxlUG9pbnRlckRvd24sIHRydWUpO1xuICAgIHN3aXBlci4kZWwub2ZmKCdwb2ludGVydXAnLCBoYW5kbGVQb2ludGVyVXAsIHRydWUpO1xuICB9XG5cbiAgb24oJ2JlZm9yZUluaXQnLCAoKSA9PiB7XG4gICAgbGl2ZVJlZ2lvbiA9ICQoYDxzcGFuIGNsYXNzPVwiJHtzd2lwZXIucGFyYW1zLmExMXkubm90aWZpY2F0aW9uQ2xhc3N9XCIgYXJpYS1saXZlPVwiYXNzZXJ0aXZlXCIgYXJpYS1hdG9taWM9XCJ0cnVlXCI+PC9zcGFuPmApO1xuICB9KTtcbiAgb24oJ2FmdGVySW5pdCcsICgpID0+IHtcbiAgICBpZiAoIXN3aXBlci5wYXJhbXMuYTExeS5lbmFibGVkKSByZXR1cm47XG4gICAgaW5pdCgpO1xuICB9KTtcbiAgb24oJ3NsaWRlc0xlbmd0aENoYW5nZSBzbmFwR3JpZExlbmd0aENoYW5nZSBzbGlkZXNHcmlkTGVuZ3RoQ2hhbmdlJywgKCkgPT4ge1xuICAgIGlmICghc3dpcGVyLnBhcmFtcy5hMTF5LmVuYWJsZWQpIHJldHVybjtcbiAgICBpbml0U2xpZGVzKCk7XG4gIH0pO1xuICBvbignZnJvbUVkZ2UgdG9FZGdlIGFmdGVySW5pdCBsb2NrIHVubG9jaycsICgpID0+IHtcbiAgICBpZiAoIXN3aXBlci5wYXJhbXMuYTExeS5lbmFibGVkKSByZXR1cm47XG4gICAgdXBkYXRlTmF2aWdhdGlvbigpO1xuICB9KTtcbiAgb24oJ3BhZ2luYXRpb25VcGRhdGUnLCAoKSA9PiB7XG4gICAgaWYgKCFzd2lwZXIucGFyYW1zLmExMXkuZW5hYmxlZCkgcmV0dXJuO1xuICAgIHVwZGF0ZVBhZ2luYXRpb24oKTtcbiAgfSk7XG4gIG9uKCdkZXN0cm95JywgKCkgPT4ge1xuICAgIGlmICghc3dpcGVyLnBhcmFtcy5hMTF5LmVuYWJsZWQpIHJldHVybjtcbiAgICBkZXN0cm95KCk7XG4gIH0pO1xufSIsImltcG9ydCB7IGdldFdpbmRvdyB9IGZyb20gJ3Nzci13aW5kb3cnO1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gSGlzdG9yeSh7XG4gIHN3aXBlcixcbiAgZXh0ZW5kUGFyYW1zLFxuICBvblxufSkge1xuICBleHRlbmRQYXJhbXMoe1xuICAgIGhpc3Rvcnk6IHtcbiAgICAgIGVuYWJsZWQ6IGZhbHNlLFxuICAgICAgcm9vdDogJycsXG4gICAgICByZXBsYWNlU3RhdGU6IGZhbHNlLFxuICAgICAga2V5OiAnc2xpZGVzJyxcbiAgICAgIGtlZXBRdWVyeTogZmFsc2VcbiAgICB9XG4gIH0pO1xuICBsZXQgaW5pdGlhbGl6ZWQgPSBmYWxzZTtcbiAgbGV0IHBhdGhzID0ge307XG5cbiAgY29uc3Qgc2x1Z2lmeSA9IHRleHQgPT4ge1xuICAgIHJldHVybiB0ZXh0LnRvU3RyaW5nKCkucmVwbGFjZSgvXFxzKy9nLCAnLScpLnJlcGxhY2UoL1teXFx3LV0rL2csICcnKS5yZXBsYWNlKC8tLSsvZywgJy0nKS5yZXBsYWNlKC9eLSsvLCAnJykucmVwbGFjZSgvLSskLywgJycpO1xuICB9O1xuXG4gIGNvbnN0IGdldFBhdGhWYWx1ZXMgPSB1cmxPdmVycmlkZSA9PiB7XG4gICAgY29uc3Qgd2luZG93ID0gZ2V0V2luZG93KCk7XG4gICAgbGV0IGxvY2F0aW9uO1xuXG4gICAgaWYgKHVybE92ZXJyaWRlKSB7XG4gICAgICBsb2NhdGlvbiA9IG5ldyBVUkwodXJsT3ZlcnJpZGUpO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2NhdGlvbiA9IHdpbmRvdy5sb2NhdGlvbjtcbiAgICB9XG5cbiAgICBjb25zdCBwYXRoQXJyYXkgPSBsb2NhdGlvbi5wYXRobmFtZS5zbGljZSgxKS5zcGxpdCgnLycpLmZpbHRlcihwYXJ0ID0+IHBhcnQgIT09ICcnKTtcbiAgICBjb25zdCB0b3RhbCA9IHBhdGhBcnJheS5sZW5ndGg7XG4gICAgY29uc3Qga2V5ID0gcGF0aEFycmF5W3RvdGFsIC0gMl07XG4gICAgY29uc3QgdmFsdWUgPSBwYXRoQXJyYXlbdG90YWwgLSAxXTtcbiAgICByZXR1cm4ge1xuICAgICAga2V5LFxuICAgICAgdmFsdWVcbiAgICB9O1xuICB9O1xuXG4gIGNvbnN0IHNldEhpc3RvcnkgPSAoa2V5LCBpbmRleCkgPT4ge1xuICAgIGNvbnN0IHdpbmRvdyA9IGdldFdpbmRvdygpO1xuICAgIGlmICghaW5pdGlhbGl6ZWQgfHwgIXN3aXBlci5wYXJhbXMuaGlzdG9yeS5lbmFibGVkKSByZXR1cm47XG4gICAgbGV0IGxvY2F0aW9uO1xuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMudXJsKSB7XG4gICAgICBsb2NhdGlvbiA9IG5ldyBVUkwoc3dpcGVyLnBhcmFtcy51cmwpO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2NhdGlvbiA9IHdpbmRvdy5sb2NhdGlvbjtcbiAgICB9XG5cbiAgICBjb25zdCBzbGlkZSA9IHN3aXBlci5zbGlkZXMuZXEoaW5kZXgpO1xuICAgIGxldCB2YWx1ZSA9IHNsdWdpZnkoc2xpZGUuYXR0cignZGF0YS1oaXN0b3J5JykpO1xuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMuaGlzdG9yeS5yb290Lmxlbmd0aCA+IDApIHtcbiAgICAgIGxldCByb290ID0gc3dpcGVyLnBhcmFtcy5oaXN0b3J5LnJvb3Q7XG4gICAgICBpZiAocm9vdFtyb290Lmxlbmd0aCAtIDFdID09PSAnLycpIHJvb3QgPSByb290LnNsaWNlKDAsIHJvb3QubGVuZ3RoIC0gMSk7XG4gICAgICB2YWx1ZSA9IGAke3Jvb3R9LyR7a2V5fS8ke3ZhbHVlfWA7XG4gICAgfSBlbHNlIGlmICghbG9jYXRpb24ucGF0aG5hbWUuaW5jbHVkZXMoa2V5KSkge1xuICAgICAgdmFsdWUgPSBgJHtrZXl9LyR7dmFsdWV9YDtcbiAgICB9XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5oaXN0b3J5LmtlZXBRdWVyeSkge1xuICAgICAgdmFsdWUgKz0gbG9jYXRpb24uc2VhcmNoO1xuICAgIH1cblxuICAgIGNvbnN0IGN1cnJlbnRTdGF0ZSA9IHdpbmRvdy5oaXN0b3J5LnN0YXRlO1xuXG4gICAgaWYgKGN1cnJlbnRTdGF0ZSAmJiBjdXJyZW50U3RhdGUudmFsdWUgPT09IHZhbHVlKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMuaGlzdG9yeS5yZXBsYWNlU3RhdGUpIHtcbiAgICAgIHdpbmRvdy5oaXN0b3J5LnJlcGxhY2VTdGF0ZSh7XG4gICAgICAgIHZhbHVlXG4gICAgICB9LCBudWxsLCB2YWx1ZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHdpbmRvdy5oaXN0b3J5LnB1c2hTdGF0ZSh7XG4gICAgICAgIHZhbHVlXG4gICAgICB9LCBudWxsLCB2YWx1ZSk7XG4gICAgfVxuICB9O1xuXG4gIGNvbnN0IHNjcm9sbFRvU2xpZGUgPSAoc3BlZWQsIHZhbHVlLCBydW5DYWxsYmFja3MpID0+IHtcbiAgICBpZiAodmFsdWUpIHtcbiAgICAgIGZvciAobGV0IGkgPSAwLCBsZW5ndGggPSBzd2lwZXIuc2xpZGVzLmxlbmd0aDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgICAgIGNvbnN0IHNsaWRlID0gc3dpcGVyLnNsaWRlcy5lcShpKTtcbiAgICAgICAgY29uc3Qgc2xpZGVIaXN0b3J5ID0gc2x1Z2lmeShzbGlkZS5hdHRyKCdkYXRhLWhpc3RvcnknKSk7XG5cbiAgICAgICAgaWYgKHNsaWRlSGlzdG9yeSA9PT0gdmFsdWUgJiYgIXNsaWRlLmhhc0NsYXNzKHN3aXBlci5wYXJhbXMuc2xpZGVEdXBsaWNhdGVDbGFzcykpIHtcbiAgICAgICAgICBjb25zdCBpbmRleCA9IHNsaWRlLmluZGV4KCk7XG4gICAgICAgICAgc3dpcGVyLnNsaWRlVG8oaW5kZXgsIHNwZWVkLCBydW5DYWxsYmFja3MpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHN3aXBlci5zbGlkZVRvKDAsIHNwZWVkLCBydW5DYWxsYmFja3MpO1xuICAgIH1cbiAgfTtcblxuICBjb25zdCBzZXRIaXN0b3J5UG9wU3RhdGUgPSAoKSA9PiB7XG4gICAgcGF0aHMgPSBnZXRQYXRoVmFsdWVzKHN3aXBlci5wYXJhbXMudXJsKTtcbiAgICBzY3JvbGxUb1NsaWRlKHN3aXBlci5wYXJhbXMuc3BlZWQsIHBhdGhzLnZhbHVlLCBmYWxzZSk7XG4gIH07XG5cbiAgY29uc3QgaW5pdCA9ICgpID0+IHtcbiAgICBjb25zdCB3aW5kb3cgPSBnZXRXaW5kb3coKTtcbiAgICBpZiAoIXN3aXBlci5wYXJhbXMuaGlzdG9yeSkgcmV0dXJuO1xuXG4gICAgaWYgKCF3aW5kb3cuaGlzdG9yeSB8fCAhd2luZG93Lmhpc3RvcnkucHVzaFN0YXRlKSB7XG4gICAgICBzd2lwZXIucGFyYW1zLmhpc3RvcnkuZW5hYmxlZCA9IGZhbHNlO1xuICAgICAgc3dpcGVyLnBhcmFtcy5oYXNoTmF2aWdhdGlvbi5lbmFibGVkID0gdHJ1ZTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpbml0aWFsaXplZCA9IHRydWU7XG4gICAgcGF0aHMgPSBnZXRQYXRoVmFsdWVzKHN3aXBlci5wYXJhbXMudXJsKTtcbiAgICBpZiAoIXBhdGhzLmtleSAmJiAhcGF0aHMudmFsdWUpIHJldHVybjtcbiAgICBzY3JvbGxUb1NsaWRlKDAsIHBhdGhzLnZhbHVlLCBzd2lwZXIucGFyYW1zLnJ1bkNhbGxiYWNrc09uSW5pdCk7XG5cbiAgICBpZiAoIXN3aXBlci5wYXJhbXMuaGlzdG9yeS5yZXBsYWNlU3RhdGUpIHtcbiAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdwb3BzdGF0ZScsIHNldEhpc3RvcnlQb3BTdGF0ZSk7XG4gICAgfVxuICB9O1xuXG4gIGNvbnN0IGRlc3Ryb3kgPSAoKSA9PiB7XG4gICAgY29uc3Qgd2luZG93ID0gZ2V0V2luZG93KCk7XG5cbiAgICBpZiAoIXN3aXBlci5wYXJhbXMuaGlzdG9yeS5yZXBsYWNlU3RhdGUpIHtcbiAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdwb3BzdGF0ZScsIHNldEhpc3RvcnlQb3BTdGF0ZSk7XG4gICAgfVxuICB9O1xuXG4gIG9uKCdpbml0JywgKCkgPT4ge1xuICAgIGlmIChzd2lwZXIucGFyYW1zLmhpc3RvcnkuZW5hYmxlZCkge1xuICAgICAgaW5pdCgpO1xuICAgIH1cbiAgfSk7XG4gIG9uKCdkZXN0cm95JywgKCkgPT4ge1xuICAgIGlmIChzd2lwZXIucGFyYW1zLmhpc3RvcnkuZW5hYmxlZCkge1xuICAgICAgZGVzdHJveSgpO1xuICAgIH1cbiAgfSk7XG4gIG9uKCd0cmFuc2l0aW9uRW5kIF9mcmVlTW9kZU5vTW9tZW50dW1SZWxlYXNlJywgKCkgPT4ge1xuICAgIGlmIChpbml0aWFsaXplZCkge1xuICAgICAgc2V0SGlzdG9yeShzd2lwZXIucGFyYW1zLmhpc3Rvcnkua2V5LCBzd2lwZXIuYWN0aXZlSW5kZXgpO1xuICAgIH1cbiAgfSk7XG4gIG9uKCdzbGlkZUNoYW5nZScsICgpID0+IHtcbiAgICBpZiAoaW5pdGlhbGl6ZWQgJiYgc3dpcGVyLnBhcmFtcy5jc3NNb2RlKSB7XG4gICAgICBzZXRIaXN0b3J5KHN3aXBlci5wYXJhbXMuaGlzdG9yeS5rZXksIHN3aXBlci5hY3RpdmVJbmRleCk7XG4gICAgfVxuICB9KTtcbn0iLCJpbXBvcnQgeyBnZXRXaW5kb3csIGdldERvY3VtZW50IH0gZnJvbSAnc3NyLXdpbmRvdyc7XG5pbXBvcnQgJCBmcm9tICcuLi8uLi9zaGFyZWQvZG9tLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIEhhc2hOYXZpZ2F0aW9uKHtcbiAgc3dpcGVyLFxuICBleHRlbmRQYXJhbXMsXG4gIGVtaXQsXG4gIG9uXG59KSB7XG4gIGxldCBpbml0aWFsaXplZCA9IGZhbHNlO1xuICBjb25zdCBkb2N1bWVudCA9IGdldERvY3VtZW50KCk7XG4gIGNvbnN0IHdpbmRvdyA9IGdldFdpbmRvdygpO1xuICBleHRlbmRQYXJhbXMoe1xuICAgIGhhc2hOYXZpZ2F0aW9uOiB7XG4gICAgICBlbmFibGVkOiBmYWxzZSxcbiAgICAgIHJlcGxhY2VTdGF0ZTogZmFsc2UsXG4gICAgICB3YXRjaFN0YXRlOiBmYWxzZVxuICAgIH1cbiAgfSk7XG5cbiAgY29uc3Qgb25IYXNoQ2hhbmdlID0gKCkgPT4ge1xuICAgIGVtaXQoJ2hhc2hDaGFuZ2UnKTtcbiAgICBjb25zdCBuZXdIYXNoID0gZG9jdW1lbnQubG9jYXRpb24uaGFzaC5yZXBsYWNlKCcjJywgJycpO1xuICAgIGNvbnN0IGFjdGl2ZVNsaWRlSGFzaCA9IHN3aXBlci5zbGlkZXMuZXEoc3dpcGVyLmFjdGl2ZUluZGV4KS5hdHRyKCdkYXRhLWhhc2gnKTtcblxuICAgIGlmIChuZXdIYXNoICE9PSBhY3RpdmVTbGlkZUhhc2gpIHtcbiAgICAgIGNvbnN0IG5ld0luZGV4ID0gc3dpcGVyLiR3cmFwcGVyRWwuY2hpbGRyZW4oYC4ke3N3aXBlci5wYXJhbXMuc2xpZGVDbGFzc31bZGF0YS1oYXNoPVwiJHtuZXdIYXNofVwiXWApLmluZGV4KCk7XG4gICAgICBpZiAodHlwZW9mIG5ld0luZGV4ID09PSAndW5kZWZpbmVkJykgcmV0dXJuO1xuICAgICAgc3dpcGVyLnNsaWRlVG8obmV3SW5kZXgpO1xuICAgIH1cbiAgfTtcblxuICBjb25zdCBzZXRIYXNoID0gKCkgPT4ge1xuICAgIGlmICghaW5pdGlhbGl6ZWQgfHwgIXN3aXBlci5wYXJhbXMuaGFzaE5hdmlnYXRpb24uZW5hYmxlZCkgcmV0dXJuO1xuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMuaGFzaE5hdmlnYXRpb24ucmVwbGFjZVN0YXRlICYmIHdpbmRvdy5oaXN0b3J5ICYmIHdpbmRvdy5oaXN0b3J5LnJlcGxhY2VTdGF0ZSkge1xuICAgICAgd2luZG93Lmhpc3RvcnkucmVwbGFjZVN0YXRlKG51bGwsIG51bGwsIGAjJHtzd2lwZXIuc2xpZGVzLmVxKHN3aXBlci5hY3RpdmVJbmRleCkuYXR0cignZGF0YS1oYXNoJyl9YCB8fCAnJyk7XG4gICAgICBlbWl0KCdoYXNoU2V0Jyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IHNsaWRlID0gc3dpcGVyLnNsaWRlcy5lcShzd2lwZXIuYWN0aXZlSW5kZXgpO1xuICAgICAgY29uc3QgaGFzaCA9IHNsaWRlLmF0dHIoJ2RhdGEtaGFzaCcpIHx8IHNsaWRlLmF0dHIoJ2RhdGEtaGlzdG9yeScpO1xuICAgICAgZG9jdW1lbnQubG9jYXRpb24uaGFzaCA9IGhhc2ggfHwgJyc7XG4gICAgICBlbWl0KCdoYXNoU2V0Jyk7XG4gICAgfVxuICB9O1xuXG4gIGNvbnN0IGluaXQgPSAoKSA9PiB7XG4gICAgaWYgKCFzd2lwZXIucGFyYW1zLmhhc2hOYXZpZ2F0aW9uLmVuYWJsZWQgfHwgc3dpcGVyLnBhcmFtcy5oaXN0b3J5ICYmIHN3aXBlci5wYXJhbXMuaGlzdG9yeS5lbmFibGVkKSByZXR1cm47XG4gICAgaW5pdGlhbGl6ZWQgPSB0cnVlO1xuICAgIGNvbnN0IGhhc2ggPSBkb2N1bWVudC5sb2NhdGlvbi5oYXNoLnJlcGxhY2UoJyMnLCAnJyk7XG5cbiAgICBpZiAoaGFzaCkge1xuICAgICAgY29uc3Qgc3BlZWQgPSAwO1xuXG4gICAgICBmb3IgKGxldCBpID0gMCwgbGVuZ3RoID0gc3dpcGVyLnNsaWRlcy5sZW5ndGg7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICBjb25zdCBzbGlkZSA9IHN3aXBlci5zbGlkZXMuZXEoaSk7XG4gICAgICAgIGNvbnN0IHNsaWRlSGFzaCA9IHNsaWRlLmF0dHIoJ2RhdGEtaGFzaCcpIHx8IHNsaWRlLmF0dHIoJ2RhdGEtaGlzdG9yeScpO1xuXG4gICAgICAgIGlmIChzbGlkZUhhc2ggPT09IGhhc2ggJiYgIXNsaWRlLmhhc0NsYXNzKHN3aXBlci5wYXJhbXMuc2xpZGVEdXBsaWNhdGVDbGFzcykpIHtcbiAgICAgICAgICBjb25zdCBpbmRleCA9IHNsaWRlLmluZGV4KCk7XG4gICAgICAgICAgc3dpcGVyLnNsaWRlVG8oaW5kZXgsIHNwZWVkLCBzd2lwZXIucGFyYW1zLnJ1bkNhbGxiYWNrc09uSW5pdCwgdHJ1ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5oYXNoTmF2aWdhdGlvbi53YXRjaFN0YXRlKSB7XG4gICAgICAkKHdpbmRvdykub24oJ2hhc2hjaGFuZ2UnLCBvbkhhc2hDaGFuZ2UpO1xuICAgIH1cbiAgfTtcblxuICBjb25zdCBkZXN0cm95ID0gKCkgPT4ge1xuICAgIGlmIChzd2lwZXIucGFyYW1zLmhhc2hOYXZpZ2F0aW9uLndhdGNoU3RhdGUpIHtcbiAgICAgICQod2luZG93KS5vZmYoJ2hhc2hjaGFuZ2UnLCBvbkhhc2hDaGFuZ2UpO1xuICAgIH1cbiAgfTtcblxuICBvbignaW5pdCcsICgpID0+IHtcbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5oYXNoTmF2aWdhdGlvbi5lbmFibGVkKSB7XG4gICAgICBpbml0KCk7XG4gICAgfVxuICB9KTtcbiAgb24oJ2Rlc3Ryb3knLCAoKSA9PiB7XG4gICAgaWYgKHN3aXBlci5wYXJhbXMuaGFzaE5hdmlnYXRpb24uZW5hYmxlZCkge1xuICAgICAgZGVzdHJveSgpO1xuICAgIH1cbiAgfSk7XG4gIG9uKCd0cmFuc2l0aW9uRW5kIF9mcmVlTW9kZU5vTW9tZW50dW1SZWxlYXNlJywgKCkgPT4ge1xuICAgIGlmIChpbml0aWFsaXplZCkge1xuICAgICAgc2V0SGFzaCgpO1xuICAgIH1cbiAgfSk7XG4gIG9uKCdzbGlkZUNoYW5nZScsICgpID0+IHtcbiAgICBpZiAoaW5pdGlhbGl6ZWQgJiYgc3dpcGVyLnBhcmFtcy5jc3NNb2RlKSB7XG4gICAgICBzZXRIYXNoKCk7XG4gICAgfVxuICB9KTtcbn0iLCIvKiBlc2xpbnQgbm8tdW5kZXJzY29yZS1kYW5nbGU6IFwib2ZmXCIgKi9cblxuLyogZXNsaW50IG5vLXVzZS1iZWZvcmUtZGVmaW5lOiBcIm9mZlwiICovXG5pbXBvcnQgeyBnZXREb2N1bWVudCB9IGZyb20gJ3Nzci13aW5kb3cnO1xuaW1wb3J0IHsgbmV4dFRpY2sgfSBmcm9tICcuLi8uLi9zaGFyZWQvdXRpbHMuanMnO1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gQXV0b3BsYXkoe1xuICBzd2lwZXIsXG4gIGV4dGVuZFBhcmFtcyxcbiAgb24sXG4gIGVtaXRcbn0pIHtcbiAgbGV0IHRpbWVvdXQ7XG4gIHN3aXBlci5hdXRvcGxheSA9IHtcbiAgICBydW5uaW5nOiBmYWxzZSxcbiAgICBwYXVzZWQ6IGZhbHNlXG4gIH07XG4gIGV4dGVuZFBhcmFtcyh7XG4gICAgYXV0b3BsYXk6IHtcbiAgICAgIGVuYWJsZWQ6IGZhbHNlLFxuICAgICAgZGVsYXk6IDMwMDAsXG4gICAgICB3YWl0Rm9yVHJhbnNpdGlvbjogdHJ1ZSxcbiAgICAgIGRpc2FibGVPbkludGVyYWN0aW9uOiB0cnVlLFxuICAgICAgc3RvcE9uTGFzdFNsaWRlOiBmYWxzZSxcbiAgICAgIHJldmVyc2VEaXJlY3Rpb246IGZhbHNlLFxuICAgICAgcGF1c2VPbk1vdXNlRW50ZXI6IGZhbHNlXG4gICAgfVxuICB9KTtcblxuICBmdW5jdGlvbiBydW4oKSB7XG4gICAgaWYgKCFzd2lwZXIuc2l6ZSkge1xuICAgICAgc3dpcGVyLmF1dG9wbGF5LnJ1bm5pbmcgPSBmYWxzZTtcbiAgICAgIHN3aXBlci5hdXRvcGxheS5wYXVzZWQgPSBmYWxzZTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCAkYWN0aXZlU2xpZGVFbCA9IHN3aXBlci5zbGlkZXMuZXEoc3dpcGVyLmFjdGl2ZUluZGV4KTtcbiAgICBsZXQgZGVsYXkgPSBzd2lwZXIucGFyYW1zLmF1dG9wbGF5LmRlbGF5O1xuXG4gICAgaWYgKCRhY3RpdmVTbGlkZUVsLmF0dHIoJ2RhdGEtc3dpcGVyLWF1dG9wbGF5JykpIHtcbiAgICAgIGRlbGF5ID0gJGFjdGl2ZVNsaWRlRWwuYXR0cignZGF0YS1zd2lwZXItYXV0b3BsYXknKSB8fCBzd2lwZXIucGFyYW1zLmF1dG9wbGF5LmRlbGF5O1xuICAgIH1cblxuICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICB0aW1lb3V0ID0gbmV4dFRpY2soKCkgPT4ge1xuICAgICAgbGV0IGF1dG9wbGF5UmVzdWx0O1xuXG4gICAgICBpZiAoc3dpcGVyLnBhcmFtcy5hdXRvcGxheS5yZXZlcnNlRGlyZWN0aW9uKSB7XG4gICAgICAgIGlmIChzd2lwZXIucGFyYW1zLmxvb3ApIHtcbiAgICAgICAgICBzd2lwZXIubG9vcEZpeCgpO1xuICAgICAgICAgIGF1dG9wbGF5UmVzdWx0ID0gc3dpcGVyLnNsaWRlUHJldihzd2lwZXIucGFyYW1zLnNwZWVkLCB0cnVlLCB0cnVlKTtcbiAgICAgICAgICBlbWl0KCdhdXRvcGxheScpO1xuICAgICAgICB9IGVsc2UgaWYgKCFzd2lwZXIuaXNCZWdpbm5pbmcpIHtcbiAgICAgICAgICBhdXRvcGxheVJlc3VsdCA9IHN3aXBlci5zbGlkZVByZXYoc3dpcGVyLnBhcmFtcy5zcGVlZCwgdHJ1ZSwgdHJ1ZSk7XG4gICAgICAgICAgZW1pdCgnYXV0b3BsYXknKTtcbiAgICAgICAgfSBlbHNlIGlmICghc3dpcGVyLnBhcmFtcy5hdXRvcGxheS5zdG9wT25MYXN0U2xpZGUpIHtcbiAgICAgICAgICBhdXRvcGxheVJlc3VsdCA9IHN3aXBlci5zbGlkZVRvKHN3aXBlci5zbGlkZXMubGVuZ3RoIC0gMSwgc3dpcGVyLnBhcmFtcy5zcGVlZCwgdHJ1ZSwgdHJ1ZSk7XG4gICAgICAgICAgZW1pdCgnYXV0b3BsYXknKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzdG9wKCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoc3dpcGVyLnBhcmFtcy5sb29wKSB7XG4gICAgICAgIHN3aXBlci5sb29wRml4KCk7XG4gICAgICAgIGF1dG9wbGF5UmVzdWx0ID0gc3dpcGVyLnNsaWRlTmV4dChzd2lwZXIucGFyYW1zLnNwZWVkLCB0cnVlLCB0cnVlKTtcbiAgICAgICAgZW1pdCgnYXV0b3BsYXknKTtcbiAgICAgIH0gZWxzZSBpZiAoIXN3aXBlci5pc0VuZCkge1xuICAgICAgICBhdXRvcGxheVJlc3VsdCA9IHN3aXBlci5zbGlkZU5leHQoc3dpcGVyLnBhcmFtcy5zcGVlZCwgdHJ1ZSwgdHJ1ZSk7XG4gICAgICAgIGVtaXQoJ2F1dG9wbGF5Jyk7XG4gICAgICB9IGVsc2UgaWYgKCFzd2lwZXIucGFyYW1zLmF1dG9wbGF5LnN0b3BPbkxhc3RTbGlkZSkge1xuICAgICAgICBhdXRvcGxheVJlc3VsdCA9IHN3aXBlci5zbGlkZVRvKDAsIHN3aXBlci5wYXJhbXMuc3BlZWQsIHRydWUsIHRydWUpO1xuICAgICAgICBlbWl0KCdhdXRvcGxheScpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc3RvcCgpO1xuICAgICAgfVxuXG4gICAgICBpZiAoc3dpcGVyLnBhcmFtcy5jc3NNb2RlICYmIHN3aXBlci5hdXRvcGxheS5ydW5uaW5nKSBydW4oKTtlbHNlIGlmIChhdXRvcGxheVJlc3VsdCA9PT0gZmFsc2UpIHtcbiAgICAgICAgcnVuKCk7XG4gICAgICB9XG4gICAgfSwgZGVsYXkpO1xuICB9XG5cbiAgZnVuY3Rpb24gc3RhcnQoKSB7XG4gICAgaWYgKHR5cGVvZiB0aW1lb3V0ICE9PSAndW5kZWZpbmVkJykgcmV0dXJuIGZhbHNlO1xuICAgIGlmIChzd2lwZXIuYXV0b3BsYXkucnVubmluZykgcmV0dXJuIGZhbHNlO1xuICAgIHN3aXBlci5hdXRvcGxheS5ydW5uaW5nID0gdHJ1ZTtcbiAgICBlbWl0KCdhdXRvcGxheVN0YXJ0Jyk7XG4gICAgcnVuKCk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBmdW5jdGlvbiBzdG9wKCkge1xuICAgIGlmICghc3dpcGVyLmF1dG9wbGF5LnJ1bm5pbmcpIHJldHVybiBmYWxzZTtcbiAgICBpZiAodHlwZW9mIHRpbWVvdXQgPT09ICd1bmRlZmluZWQnKSByZXR1cm4gZmFsc2U7XG5cbiAgICBpZiAodGltZW91dCkge1xuICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgdGltZW91dCA9IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBzd2lwZXIuYXV0b3BsYXkucnVubmluZyA9IGZhbHNlO1xuICAgIGVtaXQoJ2F1dG9wbGF5U3RvcCcpO1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgZnVuY3Rpb24gcGF1c2Uoc3BlZWQpIHtcbiAgICBpZiAoIXN3aXBlci5hdXRvcGxheS5ydW5uaW5nKSByZXR1cm47XG4gICAgaWYgKHN3aXBlci5hdXRvcGxheS5wYXVzZWQpIHJldHVybjtcbiAgICBpZiAodGltZW91dCkgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgIHN3aXBlci5hdXRvcGxheS5wYXVzZWQgPSB0cnVlO1xuXG4gICAgaWYgKHNwZWVkID09PSAwIHx8ICFzd2lwZXIucGFyYW1zLmF1dG9wbGF5LndhaXRGb3JUcmFuc2l0aW9uKSB7XG4gICAgICBzd2lwZXIuYXV0b3BsYXkucGF1c2VkID0gZmFsc2U7XG4gICAgICBydW4oKTtcbiAgICB9IGVsc2Uge1xuICAgICAgWyd0cmFuc2l0aW9uZW5kJywgJ3dlYmtpdFRyYW5zaXRpb25FbmQnXS5mb3JFYWNoKGV2ZW50ID0+IHtcbiAgICAgICAgc3dpcGVyLiR3cmFwcGVyRWxbMF0uYWRkRXZlbnRMaXN0ZW5lcihldmVudCwgb25UcmFuc2l0aW9uRW5kKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIG9uVmlzaWJpbGl0eUNoYW5nZSgpIHtcbiAgICBjb25zdCBkb2N1bWVudCA9IGdldERvY3VtZW50KCk7XG5cbiAgICBpZiAoZG9jdW1lbnQudmlzaWJpbGl0eVN0YXRlID09PSAnaGlkZGVuJyAmJiBzd2lwZXIuYXV0b3BsYXkucnVubmluZykge1xuICAgICAgcGF1c2UoKTtcbiAgICB9XG5cbiAgICBpZiAoZG9jdW1lbnQudmlzaWJpbGl0eVN0YXRlID09PSAndmlzaWJsZScgJiYgc3dpcGVyLmF1dG9wbGF5LnBhdXNlZCkge1xuICAgICAgcnVuKCk7XG4gICAgICBzd2lwZXIuYXV0b3BsYXkucGF1c2VkID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gb25UcmFuc2l0aW9uRW5kKGUpIHtcbiAgICBpZiAoIXN3aXBlciB8fCBzd2lwZXIuZGVzdHJveWVkIHx8ICFzd2lwZXIuJHdyYXBwZXJFbCkgcmV0dXJuO1xuICAgIGlmIChlLnRhcmdldCAhPT0gc3dpcGVyLiR3cmFwcGVyRWxbMF0pIHJldHVybjtcbiAgICBbJ3RyYW5zaXRpb25lbmQnLCAnd2Via2l0VHJhbnNpdGlvbkVuZCddLmZvckVhY2goZXZlbnQgPT4ge1xuICAgICAgc3dpcGVyLiR3cmFwcGVyRWxbMF0ucmVtb3ZlRXZlbnRMaXN0ZW5lcihldmVudCwgb25UcmFuc2l0aW9uRW5kKTtcbiAgICB9KTtcbiAgICBzd2lwZXIuYXV0b3BsYXkucGF1c2VkID0gZmFsc2U7XG5cbiAgICBpZiAoIXN3aXBlci5hdXRvcGxheS5ydW5uaW5nKSB7XG4gICAgICBzdG9wKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJ1bigpO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIG9uTW91c2VFbnRlcigpIHtcbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5hdXRvcGxheS5kaXNhYmxlT25JbnRlcmFjdGlvbikge1xuICAgICAgc3RvcCgpO1xuICAgIH0gZWxzZSB7XG4gICAgICBlbWl0KCdhdXRvcGxheVBhdXNlJyk7XG4gICAgICBwYXVzZSgpO1xuICAgIH1cblxuICAgIFsndHJhbnNpdGlvbmVuZCcsICd3ZWJraXRUcmFuc2l0aW9uRW5kJ10uZm9yRWFjaChldmVudCA9PiB7XG4gICAgICBzd2lwZXIuJHdyYXBwZXJFbFswXS5yZW1vdmVFdmVudExpc3RlbmVyKGV2ZW50LCBvblRyYW5zaXRpb25FbmQpO1xuICAgIH0pO1xuICB9XG5cbiAgZnVuY3Rpb24gb25Nb3VzZUxlYXZlKCkge1xuICAgIGlmIChzd2lwZXIucGFyYW1zLmF1dG9wbGF5LmRpc2FibGVPbkludGVyYWN0aW9uKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgc3dpcGVyLmF1dG9wbGF5LnBhdXNlZCA9IGZhbHNlO1xuICAgIGVtaXQoJ2F1dG9wbGF5UmVzdW1lJyk7XG4gICAgcnVuKCk7XG4gIH1cblxuICBmdW5jdGlvbiBhdHRhY2hNb3VzZUV2ZW50cygpIHtcbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5hdXRvcGxheS5wYXVzZU9uTW91c2VFbnRlcikge1xuICAgICAgc3dpcGVyLiRlbC5vbignbW91c2VlbnRlcicsIG9uTW91c2VFbnRlcik7XG4gICAgICBzd2lwZXIuJGVsLm9uKCdtb3VzZWxlYXZlJywgb25Nb3VzZUxlYXZlKTtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBkZXRhY2hNb3VzZUV2ZW50cygpIHtcbiAgICBzd2lwZXIuJGVsLm9mZignbW91c2VlbnRlcicsIG9uTW91c2VFbnRlcik7XG4gICAgc3dpcGVyLiRlbC5vZmYoJ21vdXNlbGVhdmUnLCBvbk1vdXNlTGVhdmUpO1xuICB9XG5cbiAgb24oJ2luaXQnLCAoKSA9PiB7XG4gICAgaWYgKHN3aXBlci5wYXJhbXMuYXV0b3BsYXkuZW5hYmxlZCkge1xuICAgICAgc3RhcnQoKTtcbiAgICAgIGNvbnN0IGRvY3VtZW50ID0gZ2V0RG9jdW1lbnQoKTtcbiAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3Zpc2liaWxpdHljaGFuZ2UnLCBvblZpc2liaWxpdHlDaGFuZ2UpO1xuICAgICAgYXR0YWNoTW91c2VFdmVudHMoKTtcbiAgICB9XG4gIH0pO1xuICBvbignYmVmb3JlVHJhbnNpdGlvblN0YXJ0JywgKF9zLCBzcGVlZCwgaW50ZXJuYWwpID0+IHtcbiAgICBpZiAoc3dpcGVyLmF1dG9wbGF5LnJ1bm5pbmcpIHtcbiAgICAgIGlmIChpbnRlcm5hbCB8fCAhc3dpcGVyLnBhcmFtcy5hdXRvcGxheS5kaXNhYmxlT25JbnRlcmFjdGlvbikge1xuICAgICAgICBzd2lwZXIuYXV0b3BsYXkucGF1c2Uoc3BlZWQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc3RvcCgpO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG4gIG9uKCdzbGlkZXJGaXJzdE1vdmUnLCAoKSA9PiB7XG4gICAgaWYgKHN3aXBlci5hdXRvcGxheS5ydW5uaW5nKSB7XG4gICAgICBpZiAoc3dpcGVyLnBhcmFtcy5hdXRvcGxheS5kaXNhYmxlT25JbnRlcmFjdGlvbikge1xuICAgICAgICBzdG9wKCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwYXVzZSgpO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG4gIG9uKCd0b3VjaEVuZCcsICgpID0+IHtcbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5jc3NNb2RlICYmIHN3aXBlci5hdXRvcGxheS5wYXVzZWQgJiYgIXN3aXBlci5wYXJhbXMuYXV0b3BsYXkuZGlzYWJsZU9uSW50ZXJhY3Rpb24pIHtcbiAgICAgIHJ1bigpO1xuICAgIH1cbiAgfSk7XG4gIG9uKCdkZXN0cm95JywgKCkgPT4ge1xuICAgIGRldGFjaE1vdXNlRXZlbnRzKCk7XG5cbiAgICBpZiAoc3dpcGVyLmF1dG9wbGF5LnJ1bm5pbmcpIHtcbiAgICAgIHN0b3AoKTtcbiAgICB9XG5cbiAgICBjb25zdCBkb2N1bWVudCA9IGdldERvY3VtZW50KCk7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigndmlzaWJpbGl0eWNoYW5nZScsIG9uVmlzaWJpbGl0eUNoYW5nZSk7XG4gIH0pO1xuICBPYmplY3QuYXNzaWduKHN3aXBlci5hdXRvcGxheSwge1xuICAgIHBhdXNlLFxuICAgIHJ1bixcbiAgICBzdGFydCxcbiAgICBzdG9wXG4gIH0pO1xufSIsImltcG9ydCB7IGlzT2JqZWN0IH0gZnJvbSAnLi4vLi4vc2hhcmVkL3V0aWxzLmpzJztcbmltcG9ydCAkIGZyb20gJy4uLy4uL3NoYXJlZC9kb20uanMnO1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gVGh1bWIoe1xuICBzd2lwZXIsXG4gIGV4dGVuZFBhcmFtcyxcbiAgb25cbn0pIHtcbiAgZXh0ZW5kUGFyYW1zKHtcbiAgICB0aHVtYnM6IHtcbiAgICAgIHN3aXBlcjogbnVsbCxcbiAgICAgIG11bHRpcGxlQWN0aXZlVGh1bWJzOiB0cnVlLFxuICAgICAgYXV0b1Njcm9sbE9mZnNldDogMCxcbiAgICAgIHNsaWRlVGh1bWJBY3RpdmVDbGFzczogJ3N3aXBlci1zbGlkZS10aHVtYi1hY3RpdmUnLFxuICAgICAgdGh1bWJzQ29udGFpbmVyQ2xhc3M6ICdzd2lwZXItdGh1bWJzJ1xuICAgIH1cbiAgfSk7XG4gIGxldCBpbml0aWFsaXplZCA9IGZhbHNlO1xuICBsZXQgc3dpcGVyQ3JlYXRlZCA9IGZhbHNlO1xuICBzd2lwZXIudGh1bWJzID0ge1xuICAgIHN3aXBlcjogbnVsbFxuICB9O1xuXG4gIGZ1bmN0aW9uIG9uVGh1bWJDbGljaygpIHtcbiAgICBjb25zdCB0aHVtYnNTd2lwZXIgPSBzd2lwZXIudGh1bWJzLnN3aXBlcjtcbiAgICBpZiAoIXRodW1ic1N3aXBlciB8fCB0aHVtYnNTd2lwZXIuZGVzdHJveWVkKSByZXR1cm47XG4gICAgY29uc3QgY2xpY2tlZEluZGV4ID0gdGh1bWJzU3dpcGVyLmNsaWNrZWRJbmRleDtcbiAgICBjb25zdCBjbGlja2VkU2xpZGUgPSB0aHVtYnNTd2lwZXIuY2xpY2tlZFNsaWRlO1xuICAgIGlmIChjbGlja2VkU2xpZGUgJiYgJChjbGlja2VkU2xpZGUpLmhhc0NsYXNzKHN3aXBlci5wYXJhbXMudGh1bWJzLnNsaWRlVGh1bWJBY3RpdmVDbGFzcykpIHJldHVybjtcbiAgICBpZiAodHlwZW9mIGNsaWNrZWRJbmRleCA9PT0gJ3VuZGVmaW5lZCcgfHwgY2xpY2tlZEluZGV4ID09PSBudWxsKSByZXR1cm47XG4gICAgbGV0IHNsaWRlVG9JbmRleDtcblxuICAgIGlmICh0aHVtYnNTd2lwZXIucGFyYW1zLmxvb3ApIHtcbiAgICAgIHNsaWRlVG9JbmRleCA9IHBhcnNlSW50KCQodGh1bWJzU3dpcGVyLmNsaWNrZWRTbGlkZSkuYXR0cignZGF0YS1zd2lwZXItc2xpZGUtaW5kZXgnKSwgMTApO1xuICAgIH0gZWxzZSB7XG4gICAgICBzbGlkZVRvSW5kZXggPSBjbGlja2VkSW5kZXg7XG4gICAgfVxuXG4gICAgaWYgKHN3aXBlci5wYXJhbXMubG9vcCkge1xuICAgICAgbGV0IGN1cnJlbnRJbmRleCA9IHN3aXBlci5hY3RpdmVJbmRleDtcblxuICAgICAgaWYgKHN3aXBlci5zbGlkZXMuZXEoY3VycmVudEluZGV4KS5oYXNDbGFzcyhzd2lwZXIucGFyYW1zLnNsaWRlRHVwbGljYXRlQ2xhc3MpKSB7XG4gICAgICAgIHN3aXBlci5sb29wRml4KCk7IC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuXG4gICAgICAgIHN3aXBlci5fY2xpZW50TGVmdCA9IHN3aXBlci4kd3JhcHBlckVsWzBdLmNsaWVudExlZnQ7XG4gICAgICAgIGN1cnJlbnRJbmRleCA9IHN3aXBlci5hY3RpdmVJbmRleDtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcHJldkluZGV4ID0gc3dpcGVyLnNsaWRlcy5lcShjdXJyZW50SW5kZXgpLnByZXZBbGwoYFtkYXRhLXN3aXBlci1zbGlkZS1pbmRleD1cIiR7c2xpZGVUb0luZGV4fVwiXWApLmVxKDApLmluZGV4KCk7XG4gICAgICBjb25zdCBuZXh0SW5kZXggPSBzd2lwZXIuc2xpZGVzLmVxKGN1cnJlbnRJbmRleCkubmV4dEFsbChgW2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4PVwiJHtzbGlkZVRvSW5kZXh9XCJdYCkuZXEoMCkuaW5kZXgoKTtcbiAgICAgIGlmICh0eXBlb2YgcHJldkluZGV4ID09PSAndW5kZWZpbmVkJykgc2xpZGVUb0luZGV4ID0gbmV4dEluZGV4O2Vsc2UgaWYgKHR5cGVvZiBuZXh0SW5kZXggPT09ICd1bmRlZmluZWQnKSBzbGlkZVRvSW5kZXggPSBwcmV2SW5kZXg7ZWxzZSBpZiAobmV4dEluZGV4IC0gY3VycmVudEluZGV4IDwgY3VycmVudEluZGV4IC0gcHJldkluZGV4KSBzbGlkZVRvSW5kZXggPSBuZXh0SW5kZXg7ZWxzZSBzbGlkZVRvSW5kZXggPSBwcmV2SW5kZXg7XG4gICAgfVxuXG4gICAgc3dpcGVyLnNsaWRlVG8oc2xpZGVUb0luZGV4KTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGluaXQoKSB7XG4gICAgY29uc3Qge1xuICAgICAgdGh1bWJzOiB0aHVtYnNQYXJhbXNcbiAgICB9ID0gc3dpcGVyLnBhcmFtcztcbiAgICBpZiAoaW5pdGlhbGl6ZWQpIHJldHVybiBmYWxzZTtcbiAgICBpbml0aWFsaXplZCA9IHRydWU7XG4gICAgY29uc3QgU3dpcGVyQ2xhc3MgPSBzd2lwZXIuY29uc3RydWN0b3I7XG5cbiAgICBpZiAodGh1bWJzUGFyYW1zLnN3aXBlciBpbnN0YW5jZW9mIFN3aXBlckNsYXNzKSB7XG4gICAgICBzd2lwZXIudGh1bWJzLnN3aXBlciA9IHRodW1ic1BhcmFtcy5zd2lwZXI7XG4gICAgICBPYmplY3QuYXNzaWduKHN3aXBlci50aHVtYnMuc3dpcGVyLm9yaWdpbmFsUGFyYW1zLCB7XG4gICAgICAgIHdhdGNoU2xpZGVzUHJvZ3Jlc3M6IHRydWUsXG4gICAgICAgIHNsaWRlVG9DbGlja2VkU2xpZGU6IGZhbHNlXG4gICAgICB9KTtcbiAgICAgIE9iamVjdC5hc3NpZ24oc3dpcGVyLnRodW1icy5zd2lwZXIucGFyYW1zLCB7XG4gICAgICAgIHdhdGNoU2xpZGVzUHJvZ3Jlc3M6IHRydWUsXG4gICAgICAgIHNsaWRlVG9DbGlja2VkU2xpZGU6IGZhbHNlXG4gICAgICB9KTtcbiAgICB9IGVsc2UgaWYgKGlzT2JqZWN0KHRodW1ic1BhcmFtcy5zd2lwZXIpKSB7XG4gICAgICBjb25zdCB0aHVtYnNTd2lwZXJQYXJhbXMgPSBPYmplY3QuYXNzaWduKHt9LCB0aHVtYnNQYXJhbXMuc3dpcGVyKTtcbiAgICAgIE9iamVjdC5hc3NpZ24odGh1bWJzU3dpcGVyUGFyYW1zLCB7XG4gICAgICAgIHdhdGNoU2xpZGVzUHJvZ3Jlc3M6IHRydWUsXG4gICAgICAgIHNsaWRlVG9DbGlja2VkU2xpZGU6IGZhbHNlXG4gICAgICB9KTtcbiAgICAgIHN3aXBlci50aHVtYnMuc3dpcGVyID0gbmV3IFN3aXBlckNsYXNzKHRodW1ic1N3aXBlclBhcmFtcyk7XG4gICAgICBzd2lwZXJDcmVhdGVkID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBzd2lwZXIudGh1bWJzLnN3aXBlci4kZWwuYWRkQ2xhc3Moc3dpcGVyLnBhcmFtcy50aHVtYnMudGh1bWJzQ29udGFpbmVyQ2xhc3MpO1xuICAgIHN3aXBlci50aHVtYnMuc3dpcGVyLm9uKCd0YXAnLCBvblRodW1iQ2xpY2spO1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgZnVuY3Rpb24gdXBkYXRlKGluaXRpYWwpIHtcbiAgICBjb25zdCB0aHVtYnNTd2lwZXIgPSBzd2lwZXIudGh1bWJzLnN3aXBlcjtcbiAgICBpZiAoIXRodW1ic1N3aXBlciB8fCB0aHVtYnNTd2lwZXIuZGVzdHJveWVkKSByZXR1cm47XG4gICAgY29uc3Qgc2xpZGVzUGVyVmlldyA9IHRodW1ic1N3aXBlci5wYXJhbXMuc2xpZGVzUGVyVmlldyA9PT0gJ2F1dG8nID8gdGh1bWJzU3dpcGVyLnNsaWRlc1BlclZpZXdEeW5hbWljKCkgOiB0aHVtYnNTd2lwZXIucGFyYW1zLnNsaWRlc1BlclZpZXc7IC8vIEFjdGl2YXRlIHRodW1ic1xuXG4gICAgbGV0IHRodW1ic1RvQWN0aXZhdGUgPSAxO1xuICAgIGNvbnN0IHRodW1iQWN0aXZlQ2xhc3MgPSBzd2lwZXIucGFyYW1zLnRodW1icy5zbGlkZVRodW1iQWN0aXZlQ2xhc3M7XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5zbGlkZXNQZXJWaWV3ID4gMSAmJiAhc3dpcGVyLnBhcmFtcy5jZW50ZXJlZFNsaWRlcykge1xuICAgICAgdGh1bWJzVG9BY3RpdmF0ZSA9IHN3aXBlci5wYXJhbXMuc2xpZGVzUGVyVmlldztcbiAgICB9XG5cbiAgICBpZiAoIXN3aXBlci5wYXJhbXMudGh1bWJzLm11bHRpcGxlQWN0aXZlVGh1bWJzKSB7XG4gICAgICB0aHVtYnNUb0FjdGl2YXRlID0gMTtcbiAgICB9XG5cbiAgICB0aHVtYnNUb0FjdGl2YXRlID0gTWF0aC5mbG9vcih0aHVtYnNUb0FjdGl2YXRlKTtcbiAgICB0aHVtYnNTd2lwZXIuc2xpZGVzLnJlbW92ZUNsYXNzKHRodW1iQWN0aXZlQ2xhc3MpO1xuXG4gICAgaWYgKHRodW1ic1N3aXBlci5wYXJhbXMubG9vcCB8fCB0aHVtYnNTd2lwZXIucGFyYW1zLnZpcnR1YWwgJiYgdGh1bWJzU3dpcGVyLnBhcmFtcy52aXJ0dWFsLmVuYWJsZWQpIHtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGh1bWJzVG9BY3RpdmF0ZTsgaSArPSAxKSB7XG4gICAgICAgIHRodW1ic1N3aXBlci4kd3JhcHBlckVsLmNoaWxkcmVuKGBbZGF0YS1zd2lwZXItc2xpZGUtaW5kZXg9XCIke3N3aXBlci5yZWFsSW5kZXggKyBpfVwiXWApLmFkZENsYXNzKHRodW1iQWN0aXZlQ2xhc3MpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRodW1ic1RvQWN0aXZhdGU7IGkgKz0gMSkge1xuICAgICAgICB0aHVtYnNTd2lwZXIuc2xpZGVzLmVxKHN3aXBlci5yZWFsSW5kZXggKyBpKS5hZGRDbGFzcyh0aHVtYkFjdGl2ZUNsYXNzKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBhdXRvU2Nyb2xsT2Zmc2V0ID0gc3dpcGVyLnBhcmFtcy50aHVtYnMuYXV0b1Njcm9sbE9mZnNldDtcbiAgICBjb25zdCB1c2VPZmZzZXQgPSBhdXRvU2Nyb2xsT2Zmc2V0ICYmICF0aHVtYnNTd2lwZXIucGFyYW1zLmxvb3A7XG5cbiAgICBpZiAoc3dpcGVyLnJlYWxJbmRleCAhPT0gdGh1bWJzU3dpcGVyLnJlYWxJbmRleCB8fCB1c2VPZmZzZXQpIHtcbiAgICAgIGxldCBjdXJyZW50VGh1bWJzSW5kZXggPSB0aHVtYnNTd2lwZXIuYWN0aXZlSW5kZXg7XG4gICAgICBsZXQgbmV3VGh1bWJzSW5kZXg7XG4gICAgICBsZXQgZGlyZWN0aW9uO1xuXG4gICAgICBpZiAodGh1bWJzU3dpcGVyLnBhcmFtcy5sb29wKSB7XG4gICAgICAgIGlmICh0aHVtYnNTd2lwZXIuc2xpZGVzLmVxKGN1cnJlbnRUaHVtYnNJbmRleCkuaGFzQ2xhc3ModGh1bWJzU3dpcGVyLnBhcmFtcy5zbGlkZUR1cGxpY2F0ZUNsYXNzKSkge1xuICAgICAgICAgIHRodW1ic1N3aXBlci5sb29wRml4KCk7IC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuXG4gICAgICAgICAgdGh1bWJzU3dpcGVyLl9jbGllbnRMZWZ0ID0gdGh1bWJzU3dpcGVyLiR3cmFwcGVyRWxbMF0uY2xpZW50TGVmdDtcbiAgICAgICAgICBjdXJyZW50VGh1bWJzSW5kZXggPSB0aHVtYnNTd2lwZXIuYWN0aXZlSW5kZXg7XG4gICAgICAgIH0gLy8gRmluZCBhY3R1YWwgdGh1bWJzIGluZGV4IHRvIHNsaWRlIHRvXG5cblxuICAgICAgICBjb25zdCBwcmV2VGh1bWJzSW5kZXggPSB0aHVtYnNTd2lwZXIuc2xpZGVzLmVxKGN1cnJlbnRUaHVtYnNJbmRleCkucHJldkFsbChgW2RhdGEtc3dpcGVyLXNsaWRlLWluZGV4PVwiJHtzd2lwZXIucmVhbEluZGV4fVwiXWApLmVxKDApLmluZGV4KCk7XG4gICAgICAgIGNvbnN0IG5leHRUaHVtYnNJbmRleCA9IHRodW1ic1N3aXBlci5zbGlkZXMuZXEoY3VycmVudFRodW1ic0luZGV4KS5uZXh0QWxsKGBbZGF0YS1zd2lwZXItc2xpZGUtaW5kZXg9XCIke3N3aXBlci5yZWFsSW5kZXh9XCJdYCkuZXEoMCkuaW5kZXgoKTtcblxuICAgICAgICBpZiAodHlwZW9mIHByZXZUaHVtYnNJbmRleCA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICBuZXdUaHVtYnNJbmRleCA9IG5leHRUaHVtYnNJbmRleDtcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgbmV4dFRodW1ic0luZGV4ID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgIG5ld1RodW1ic0luZGV4ID0gcHJldlRodW1ic0luZGV4O1xuICAgICAgICB9IGVsc2UgaWYgKG5leHRUaHVtYnNJbmRleCAtIGN1cnJlbnRUaHVtYnNJbmRleCA9PT0gY3VycmVudFRodW1ic0luZGV4IC0gcHJldlRodW1ic0luZGV4KSB7XG4gICAgICAgICAgbmV3VGh1bWJzSW5kZXggPSB0aHVtYnNTd2lwZXIucGFyYW1zLnNsaWRlc1Blckdyb3VwID4gMSA/IG5leHRUaHVtYnNJbmRleCA6IGN1cnJlbnRUaHVtYnNJbmRleDtcbiAgICAgICAgfSBlbHNlIGlmIChuZXh0VGh1bWJzSW5kZXggLSBjdXJyZW50VGh1bWJzSW5kZXggPCBjdXJyZW50VGh1bWJzSW5kZXggLSBwcmV2VGh1bWJzSW5kZXgpIHtcbiAgICAgICAgICBuZXdUaHVtYnNJbmRleCA9IG5leHRUaHVtYnNJbmRleDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBuZXdUaHVtYnNJbmRleCA9IHByZXZUaHVtYnNJbmRleDtcbiAgICAgICAgfVxuXG4gICAgICAgIGRpcmVjdGlvbiA9IHN3aXBlci5hY3RpdmVJbmRleCA+IHN3aXBlci5wcmV2aW91c0luZGV4ID8gJ25leHQnIDogJ3ByZXYnO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbmV3VGh1bWJzSW5kZXggPSBzd2lwZXIucmVhbEluZGV4O1xuICAgICAgICBkaXJlY3Rpb24gPSBuZXdUaHVtYnNJbmRleCA+IHN3aXBlci5wcmV2aW91c0luZGV4ID8gJ25leHQnIDogJ3ByZXYnO1xuICAgICAgfVxuXG4gICAgICBpZiAodXNlT2Zmc2V0KSB7XG4gICAgICAgIG5ld1RodW1ic0luZGV4ICs9IGRpcmVjdGlvbiA9PT0gJ25leHQnID8gYXV0b1Njcm9sbE9mZnNldCA6IC0xICogYXV0b1Njcm9sbE9mZnNldDtcbiAgICAgIH1cblxuICAgICAgaWYgKHRodW1ic1N3aXBlci52aXNpYmxlU2xpZGVzSW5kZXhlcyAmJiB0aHVtYnNTd2lwZXIudmlzaWJsZVNsaWRlc0luZGV4ZXMuaW5kZXhPZihuZXdUaHVtYnNJbmRleCkgPCAwKSB7XG4gICAgICAgIGlmICh0aHVtYnNTd2lwZXIucGFyYW1zLmNlbnRlcmVkU2xpZGVzKSB7XG4gICAgICAgICAgaWYgKG5ld1RodW1ic0luZGV4ID4gY3VycmVudFRodW1ic0luZGV4KSB7XG4gICAgICAgICAgICBuZXdUaHVtYnNJbmRleCA9IG5ld1RodW1ic0luZGV4IC0gTWF0aC5mbG9vcihzbGlkZXNQZXJWaWV3IC8gMikgKyAxO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBuZXdUaHVtYnNJbmRleCA9IG5ld1RodW1ic0luZGV4ICsgTWF0aC5mbG9vcihzbGlkZXNQZXJWaWV3IC8gMikgLSAxO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChuZXdUaHVtYnNJbmRleCA+IGN1cnJlbnRUaHVtYnNJbmRleCAmJiB0aHVtYnNTd2lwZXIucGFyYW1zLnNsaWRlc1Blckdyb3VwID09PSAxKSB7Ly8gbmV3VGh1bWJzSW5kZXggPSBuZXdUaHVtYnNJbmRleCAtIHNsaWRlc1BlclZpZXcgKyAxO1xuICAgICAgICB9XG5cbiAgICAgICAgdGh1bWJzU3dpcGVyLnNsaWRlVG8obmV3VGh1bWJzSW5kZXgsIGluaXRpYWwgPyAwIDogdW5kZWZpbmVkKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBvbignYmVmb3JlSW5pdCcsICgpID0+IHtcbiAgICBjb25zdCB7XG4gICAgICB0aHVtYnNcbiAgICB9ID0gc3dpcGVyLnBhcmFtcztcbiAgICBpZiAoIXRodW1icyB8fCAhdGh1bWJzLnN3aXBlcikgcmV0dXJuO1xuICAgIGluaXQoKTtcbiAgICB1cGRhdGUodHJ1ZSk7XG4gIH0pO1xuICBvbignc2xpZGVDaGFuZ2UgdXBkYXRlIHJlc2l6ZSBvYnNlcnZlclVwZGF0ZScsICgpID0+IHtcbiAgICB1cGRhdGUoKTtcbiAgfSk7XG4gIG9uKCdzZXRUcmFuc2l0aW9uJywgKF9zLCBkdXJhdGlvbikgPT4ge1xuICAgIGNvbnN0IHRodW1ic1N3aXBlciA9IHN3aXBlci50aHVtYnMuc3dpcGVyO1xuICAgIGlmICghdGh1bWJzU3dpcGVyIHx8IHRodW1ic1N3aXBlci5kZXN0cm95ZWQpIHJldHVybjtcbiAgICB0aHVtYnNTd2lwZXIuc2V0VHJhbnNpdGlvbihkdXJhdGlvbik7XG4gIH0pO1xuICBvbignYmVmb3JlRGVzdHJveScsICgpID0+IHtcbiAgICBjb25zdCB0aHVtYnNTd2lwZXIgPSBzd2lwZXIudGh1bWJzLnN3aXBlcjtcbiAgICBpZiAoIXRodW1ic1N3aXBlciB8fCB0aHVtYnNTd2lwZXIuZGVzdHJveWVkKSByZXR1cm47XG5cbiAgICBpZiAoc3dpcGVyQ3JlYXRlZCkge1xuICAgICAgdGh1bWJzU3dpcGVyLmRlc3Ryb3koKTtcbiAgICB9XG4gIH0pO1xuICBPYmplY3QuYXNzaWduKHN3aXBlci50aHVtYnMsIHtcbiAgICBpbml0LFxuICAgIHVwZGF0ZVxuICB9KTtcbn0iLCJpbXBvcnQgeyBub3cgfSBmcm9tICcuLi8uLi9zaGFyZWQvdXRpbHMuanMnO1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gZnJlZU1vZGUoe1xuICBzd2lwZXIsXG4gIGV4dGVuZFBhcmFtcyxcbiAgZW1pdCxcbiAgb25jZVxufSkge1xuICBleHRlbmRQYXJhbXMoe1xuICAgIGZyZWVNb2RlOiB7XG4gICAgICBlbmFibGVkOiBmYWxzZSxcbiAgICAgIG1vbWVudHVtOiB0cnVlLFxuICAgICAgbW9tZW50dW1SYXRpbzogMSxcbiAgICAgIG1vbWVudHVtQm91bmNlOiB0cnVlLFxuICAgICAgbW9tZW50dW1Cb3VuY2VSYXRpbzogMSxcbiAgICAgIG1vbWVudHVtVmVsb2NpdHlSYXRpbzogMSxcbiAgICAgIHN0aWNreTogZmFsc2UsXG4gICAgICBtaW5pbXVtVmVsb2NpdHk6IDAuMDJcbiAgICB9XG4gIH0pO1xuXG4gIGZ1bmN0aW9uIG9uVG91Y2hTdGFydCgpIHtcbiAgICBjb25zdCB0cmFuc2xhdGUgPSBzd2lwZXIuZ2V0VHJhbnNsYXRlKCk7XG4gICAgc3dpcGVyLnNldFRyYW5zbGF0ZSh0cmFuc2xhdGUpO1xuICAgIHN3aXBlci5zZXRUcmFuc2l0aW9uKDApO1xuICAgIHN3aXBlci50b3VjaEV2ZW50c0RhdGEudmVsb2NpdGllcy5sZW5ndGggPSAwO1xuICAgIHN3aXBlci5mcmVlTW9kZS5vblRvdWNoRW5kKHtcbiAgICAgIGN1cnJlbnRQb3M6IHN3aXBlci5ydGwgPyBzd2lwZXIudHJhbnNsYXRlIDogLXN3aXBlci50cmFuc2xhdGVcbiAgICB9KTtcbiAgfVxuXG4gIGZ1bmN0aW9uIG9uVG91Y2hNb3ZlKCkge1xuICAgIGNvbnN0IHtcbiAgICAgIHRvdWNoRXZlbnRzRGF0YTogZGF0YSxcbiAgICAgIHRvdWNoZXNcbiAgICB9ID0gc3dpcGVyOyAvLyBWZWxvY2l0eVxuXG4gICAgaWYgKGRhdGEudmVsb2NpdGllcy5sZW5ndGggPT09IDApIHtcbiAgICAgIGRhdGEudmVsb2NpdGllcy5wdXNoKHtcbiAgICAgICAgcG9zaXRpb246IHRvdWNoZXNbc3dpcGVyLmlzSG9yaXpvbnRhbCgpID8gJ3N0YXJ0WCcgOiAnc3RhcnRZJ10sXG4gICAgICAgIHRpbWU6IGRhdGEudG91Y2hTdGFydFRpbWVcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGRhdGEudmVsb2NpdGllcy5wdXNoKHtcbiAgICAgIHBvc2l0aW9uOiB0b3VjaGVzW3N3aXBlci5pc0hvcml6b250YWwoKSA/ICdjdXJyZW50WCcgOiAnY3VycmVudFknXSxcbiAgICAgIHRpbWU6IG5vdygpXG4gICAgfSk7XG4gIH1cblxuICBmdW5jdGlvbiBvblRvdWNoRW5kKHtcbiAgICBjdXJyZW50UG9zXG4gIH0pIHtcbiAgICBjb25zdCB7XG4gICAgICBwYXJhbXMsXG4gICAgICAkd3JhcHBlckVsLFxuICAgICAgcnRsVHJhbnNsYXRlOiBydGwsXG4gICAgICBzbmFwR3JpZCxcbiAgICAgIHRvdWNoRXZlbnRzRGF0YTogZGF0YVxuICAgIH0gPSBzd2lwZXI7IC8vIFRpbWUgZGlmZlxuXG4gICAgY29uc3QgdG91Y2hFbmRUaW1lID0gbm93KCk7XG4gICAgY29uc3QgdGltZURpZmYgPSB0b3VjaEVuZFRpbWUgLSBkYXRhLnRvdWNoU3RhcnRUaW1lO1xuXG4gICAgaWYgKGN1cnJlbnRQb3MgPCAtc3dpcGVyLm1pblRyYW5zbGF0ZSgpKSB7XG4gICAgICBzd2lwZXIuc2xpZGVUbyhzd2lwZXIuYWN0aXZlSW5kZXgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChjdXJyZW50UG9zID4gLXN3aXBlci5tYXhUcmFuc2xhdGUoKSkge1xuICAgICAgaWYgKHN3aXBlci5zbGlkZXMubGVuZ3RoIDwgc25hcEdyaWQubGVuZ3RoKSB7XG4gICAgICAgIHN3aXBlci5zbGlkZVRvKHNuYXBHcmlkLmxlbmd0aCAtIDEpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc3dpcGVyLnNsaWRlVG8oc3dpcGVyLnNsaWRlcy5sZW5ndGggLSAxKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChwYXJhbXMuZnJlZU1vZGUubW9tZW50dW0pIHtcbiAgICAgIGlmIChkYXRhLnZlbG9jaXRpZXMubGVuZ3RoID4gMSkge1xuICAgICAgICBjb25zdCBsYXN0TW92ZUV2ZW50ID0gZGF0YS52ZWxvY2l0aWVzLnBvcCgpO1xuICAgICAgICBjb25zdCB2ZWxvY2l0eUV2ZW50ID0gZGF0YS52ZWxvY2l0aWVzLnBvcCgpO1xuICAgICAgICBjb25zdCBkaXN0YW5jZSA9IGxhc3RNb3ZlRXZlbnQucG9zaXRpb24gLSB2ZWxvY2l0eUV2ZW50LnBvc2l0aW9uO1xuICAgICAgICBjb25zdCB0aW1lID0gbGFzdE1vdmVFdmVudC50aW1lIC0gdmVsb2NpdHlFdmVudC50aW1lO1xuICAgICAgICBzd2lwZXIudmVsb2NpdHkgPSBkaXN0YW5jZSAvIHRpbWU7XG4gICAgICAgIHN3aXBlci52ZWxvY2l0eSAvPSAyO1xuXG4gICAgICAgIGlmIChNYXRoLmFicyhzd2lwZXIudmVsb2NpdHkpIDwgcGFyYW1zLmZyZWVNb2RlLm1pbmltdW1WZWxvY2l0eSkge1xuICAgICAgICAgIHN3aXBlci52ZWxvY2l0eSA9IDA7XG4gICAgICAgIH0gLy8gdGhpcyBpbXBsaWVzIHRoYXQgdGhlIHVzZXIgc3RvcHBlZCBtb3ZpbmcgYSBmaW5nZXIgdGhlbiByZWxlYXNlZC5cbiAgICAgICAgLy8gVGhlcmUgd291bGQgYmUgbm8gZXZlbnRzIHdpdGggZGlzdGFuY2UgemVybywgc28gdGhlIGxhc3QgZXZlbnQgaXMgc3RhbGUuXG5cblxuICAgICAgICBpZiAodGltZSA+IDE1MCB8fCBub3coKSAtIGxhc3RNb3ZlRXZlbnQudGltZSA+IDMwMCkge1xuICAgICAgICAgIHN3aXBlci52ZWxvY2l0eSA9IDA7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHN3aXBlci52ZWxvY2l0eSA9IDA7XG4gICAgICB9XG5cbiAgICAgIHN3aXBlci52ZWxvY2l0eSAqPSBwYXJhbXMuZnJlZU1vZGUubW9tZW50dW1WZWxvY2l0eVJhdGlvO1xuICAgICAgZGF0YS52ZWxvY2l0aWVzLmxlbmd0aCA9IDA7XG4gICAgICBsZXQgbW9tZW50dW1EdXJhdGlvbiA9IDEwMDAgKiBwYXJhbXMuZnJlZU1vZGUubW9tZW50dW1SYXRpbztcbiAgICAgIGNvbnN0IG1vbWVudHVtRGlzdGFuY2UgPSBzd2lwZXIudmVsb2NpdHkgKiBtb21lbnR1bUR1cmF0aW9uO1xuICAgICAgbGV0IG5ld1Bvc2l0aW9uID0gc3dpcGVyLnRyYW5zbGF0ZSArIG1vbWVudHVtRGlzdGFuY2U7XG4gICAgICBpZiAocnRsKSBuZXdQb3NpdGlvbiA9IC1uZXdQb3NpdGlvbjtcbiAgICAgIGxldCBkb0JvdW5jZSA9IGZhbHNlO1xuICAgICAgbGV0IGFmdGVyQm91bmNlUG9zaXRpb247XG4gICAgICBjb25zdCBib3VuY2VBbW91bnQgPSBNYXRoLmFicyhzd2lwZXIudmVsb2NpdHkpICogMjAgKiBwYXJhbXMuZnJlZU1vZGUubW9tZW50dW1Cb3VuY2VSYXRpbztcbiAgICAgIGxldCBuZWVkc0xvb3BGaXg7XG5cbiAgICAgIGlmIChuZXdQb3NpdGlvbiA8IHN3aXBlci5tYXhUcmFuc2xhdGUoKSkge1xuICAgICAgICBpZiAocGFyYW1zLmZyZWVNb2RlLm1vbWVudHVtQm91bmNlKSB7XG4gICAgICAgICAgaWYgKG5ld1Bvc2l0aW9uICsgc3dpcGVyLm1heFRyYW5zbGF0ZSgpIDwgLWJvdW5jZUFtb3VudCkge1xuICAgICAgICAgICAgbmV3UG9zaXRpb24gPSBzd2lwZXIubWF4VHJhbnNsYXRlKCkgLSBib3VuY2VBbW91bnQ7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgYWZ0ZXJCb3VuY2VQb3NpdGlvbiA9IHN3aXBlci5tYXhUcmFuc2xhdGUoKTtcbiAgICAgICAgICBkb0JvdW5jZSA9IHRydWU7XG4gICAgICAgICAgZGF0YS5hbGxvd01vbWVudHVtQm91bmNlID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBuZXdQb3NpdGlvbiA9IHN3aXBlci5tYXhUcmFuc2xhdGUoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwYXJhbXMubG9vcCAmJiBwYXJhbXMuY2VudGVyZWRTbGlkZXMpIG5lZWRzTG9vcEZpeCA9IHRydWU7XG4gICAgICB9IGVsc2UgaWYgKG5ld1Bvc2l0aW9uID4gc3dpcGVyLm1pblRyYW5zbGF0ZSgpKSB7XG4gICAgICAgIGlmIChwYXJhbXMuZnJlZU1vZGUubW9tZW50dW1Cb3VuY2UpIHtcbiAgICAgICAgICBpZiAobmV3UG9zaXRpb24gLSBzd2lwZXIubWluVHJhbnNsYXRlKCkgPiBib3VuY2VBbW91bnQpIHtcbiAgICAgICAgICAgIG5ld1Bvc2l0aW9uID0gc3dpcGVyLm1pblRyYW5zbGF0ZSgpICsgYm91bmNlQW1vdW50O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGFmdGVyQm91bmNlUG9zaXRpb24gPSBzd2lwZXIubWluVHJhbnNsYXRlKCk7XG4gICAgICAgICAgZG9Cb3VuY2UgPSB0cnVlO1xuICAgICAgICAgIGRhdGEuYWxsb3dNb21lbnR1bUJvdW5jZSA9IHRydWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbmV3UG9zaXRpb24gPSBzd2lwZXIubWluVHJhbnNsYXRlKCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocGFyYW1zLmxvb3AgJiYgcGFyYW1zLmNlbnRlcmVkU2xpZGVzKSBuZWVkc0xvb3BGaXggPSB0cnVlO1xuICAgICAgfSBlbHNlIGlmIChwYXJhbXMuZnJlZU1vZGUuc3RpY2t5KSB7XG4gICAgICAgIGxldCBuZXh0U2xpZGU7XG5cbiAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBzbmFwR3JpZC5sZW5ndGg7IGogKz0gMSkge1xuICAgICAgICAgIGlmIChzbmFwR3JpZFtqXSA+IC1uZXdQb3NpdGlvbikge1xuICAgICAgICAgICAgbmV4dFNsaWRlID0gajtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChNYXRoLmFicyhzbmFwR3JpZFtuZXh0U2xpZGVdIC0gbmV3UG9zaXRpb24pIDwgTWF0aC5hYnMoc25hcEdyaWRbbmV4dFNsaWRlIC0gMV0gLSBuZXdQb3NpdGlvbikgfHwgc3dpcGVyLnN3aXBlRGlyZWN0aW9uID09PSAnbmV4dCcpIHtcbiAgICAgICAgICBuZXdQb3NpdGlvbiA9IHNuYXBHcmlkW25leHRTbGlkZV07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbmV3UG9zaXRpb24gPSBzbmFwR3JpZFtuZXh0U2xpZGUgLSAxXTtcbiAgICAgICAgfVxuXG4gICAgICAgIG5ld1Bvc2l0aW9uID0gLW5ld1Bvc2l0aW9uO1xuICAgICAgfVxuXG4gICAgICBpZiAobmVlZHNMb29wRml4KSB7XG4gICAgICAgIG9uY2UoJ3RyYW5zaXRpb25FbmQnLCAoKSA9PiB7XG4gICAgICAgICAgc3dpcGVyLmxvb3BGaXgoKTtcbiAgICAgICAgfSk7XG4gICAgICB9IC8vIEZpeCBkdXJhdGlvblxuXG5cbiAgICAgIGlmIChzd2lwZXIudmVsb2NpdHkgIT09IDApIHtcbiAgICAgICAgaWYgKHJ0bCkge1xuICAgICAgICAgIG1vbWVudHVtRHVyYXRpb24gPSBNYXRoLmFicygoLW5ld1Bvc2l0aW9uIC0gc3dpcGVyLnRyYW5zbGF0ZSkgLyBzd2lwZXIudmVsb2NpdHkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIG1vbWVudHVtRHVyYXRpb24gPSBNYXRoLmFicygobmV3UG9zaXRpb24gLSBzd2lwZXIudHJhbnNsYXRlKSAvIHN3aXBlci52ZWxvY2l0eSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocGFyYW1zLmZyZWVNb2RlLnN0aWNreSkge1xuICAgICAgICAgIC8vIElmIGZyZWVNb2RlLnN0aWNreSBpcyBhY3RpdmUgYW5kIHRoZSB1c2VyIGVuZHMgYSBzd2lwZSB3aXRoIGEgc2xvdy12ZWxvY2l0eVxuICAgICAgICAgIC8vIGV2ZW50LCB0aGVuIGR1cmF0aW9ucyBjYW4gYmUgMjArIHNlY29uZHMgdG8gc2xpZGUgb25lIChvciB6ZXJvISkgc2xpZGVzLlxuICAgICAgICAgIC8vIEl0J3MgZWFzeSB0byBzZWUgdGhpcyB3aGVuIHNpbXVsYXRpbmcgdG91Y2ggd2l0aCBtb3VzZSBldmVudHMuIFRvIGZpeCB0aGlzLFxuICAgICAgICAgIC8vIGxpbWl0IHNpbmdsZS1zbGlkZSBzd2lwZXMgdG8gdGhlIGRlZmF1bHQgc2xpZGUgZHVyYXRpb24uIFRoaXMgYWxzbyBoYXMgdGhlXG4gICAgICAgICAgLy8gbmljZSBzaWRlIGVmZmVjdCBvZiBtYXRjaGluZyBzbGlkZSBzcGVlZCBpZiB0aGUgdXNlciBzdG9wcGVkIG1vdmluZyBiZWZvcmVcbiAgICAgICAgICAvLyBsaWZ0aW5nIGZpbmdlciBvciBtb3VzZSB2cy4gbW92aW5nIHNsb3dseSBiZWZvcmUgbGlmdGluZyB0aGUgZmluZ2VyL21vdXNlLlxuICAgICAgICAgIC8vIEZvciBmYXN0ZXIgc3dpcGVzLCBhbHNvIGFwcGx5IGxpbWl0cyAoYWxiZWl0IGhpZ2hlciBvbmVzKS5cbiAgICAgICAgICBjb25zdCBtb3ZlRGlzdGFuY2UgPSBNYXRoLmFicygocnRsID8gLW5ld1Bvc2l0aW9uIDogbmV3UG9zaXRpb24pIC0gc3dpcGVyLnRyYW5zbGF0ZSk7XG4gICAgICAgICAgY29uc3QgY3VycmVudFNsaWRlU2l6ZSA9IHN3aXBlci5zbGlkZXNTaXplc0dyaWRbc3dpcGVyLmFjdGl2ZUluZGV4XTtcblxuICAgICAgICAgIGlmIChtb3ZlRGlzdGFuY2UgPCBjdXJyZW50U2xpZGVTaXplKSB7XG4gICAgICAgICAgICBtb21lbnR1bUR1cmF0aW9uID0gcGFyYW1zLnNwZWVkO1xuICAgICAgICAgIH0gZWxzZSBpZiAobW92ZURpc3RhbmNlIDwgMiAqIGN1cnJlbnRTbGlkZVNpemUpIHtcbiAgICAgICAgICAgIG1vbWVudHVtRHVyYXRpb24gPSBwYXJhbXMuc3BlZWQgKiAxLjU7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIG1vbWVudHVtRHVyYXRpb24gPSBwYXJhbXMuc3BlZWQgKiAyLjU7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHBhcmFtcy5mcmVlTW9kZS5zdGlja3kpIHtcbiAgICAgICAgc3dpcGVyLnNsaWRlVG9DbG9zZXN0KCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHBhcmFtcy5mcmVlTW9kZS5tb21lbnR1bUJvdW5jZSAmJiBkb0JvdW5jZSkge1xuICAgICAgICBzd2lwZXIudXBkYXRlUHJvZ3Jlc3MoYWZ0ZXJCb3VuY2VQb3NpdGlvbik7XG4gICAgICAgIHN3aXBlci5zZXRUcmFuc2l0aW9uKG1vbWVudHVtRHVyYXRpb24pO1xuICAgICAgICBzd2lwZXIuc2V0VHJhbnNsYXRlKG5ld1Bvc2l0aW9uKTtcbiAgICAgICAgc3dpcGVyLnRyYW5zaXRpb25TdGFydCh0cnVlLCBzd2lwZXIuc3dpcGVEaXJlY3Rpb24pO1xuICAgICAgICBzd2lwZXIuYW5pbWF0aW5nID0gdHJ1ZTtcbiAgICAgICAgJHdyYXBwZXJFbC50cmFuc2l0aW9uRW5kKCgpID0+IHtcbiAgICAgICAgICBpZiAoIXN3aXBlciB8fCBzd2lwZXIuZGVzdHJveWVkIHx8ICFkYXRhLmFsbG93TW9tZW50dW1Cb3VuY2UpIHJldHVybjtcbiAgICAgICAgICBlbWl0KCdtb21lbnR1bUJvdW5jZScpO1xuICAgICAgICAgIHN3aXBlci5zZXRUcmFuc2l0aW9uKHBhcmFtcy5zcGVlZCk7XG4gICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICBzd2lwZXIuc2V0VHJhbnNsYXRlKGFmdGVyQm91bmNlUG9zaXRpb24pO1xuICAgICAgICAgICAgJHdyYXBwZXJFbC50cmFuc2l0aW9uRW5kKCgpID0+IHtcbiAgICAgICAgICAgICAgaWYgKCFzd2lwZXIgfHwgc3dpcGVyLmRlc3Ryb3llZCkgcmV0dXJuO1xuICAgICAgICAgICAgICBzd2lwZXIudHJhbnNpdGlvbkVuZCgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSwgMCk7XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmIChzd2lwZXIudmVsb2NpdHkpIHtcbiAgICAgICAgZW1pdCgnX2ZyZWVNb2RlTm9Nb21lbnR1bVJlbGVhc2UnKTtcbiAgICAgICAgc3dpcGVyLnVwZGF0ZVByb2dyZXNzKG5ld1Bvc2l0aW9uKTtcbiAgICAgICAgc3dpcGVyLnNldFRyYW5zaXRpb24obW9tZW50dW1EdXJhdGlvbik7XG4gICAgICAgIHN3aXBlci5zZXRUcmFuc2xhdGUobmV3UG9zaXRpb24pO1xuICAgICAgICBzd2lwZXIudHJhbnNpdGlvblN0YXJ0KHRydWUsIHN3aXBlci5zd2lwZURpcmVjdGlvbik7XG5cbiAgICAgICAgaWYgKCFzd2lwZXIuYW5pbWF0aW5nKSB7XG4gICAgICAgICAgc3dpcGVyLmFuaW1hdGluZyA9IHRydWU7XG4gICAgICAgICAgJHdyYXBwZXJFbC50cmFuc2l0aW9uRW5kKCgpID0+IHtcbiAgICAgICAgICAgIGlmICghc3dpcGVyIHx8IHN3aXBlci5kZXN0cm95ZWQpIHJldHVybjtcbiAgICAgICAgICAgIHN3aXBlci50cmFuc2l0aW9uRW5kKCk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHN3aXBlci51cGRhdGVQcm9ncmVzcyhuZXdQb3NpdGlvbik7XG4gICAgICB9XG5cbiAgICAgIHN3aXBlci51cGRhdGVBY3RpdmVJbmRleCgpO1xuICAgICAgc3dpcGVyLnVwZGF0ZVNsaWRlc0NsYXNzZXMoKTtcbiAgICB9IGVsc2UgaWYgKHBhcmFtcy5mcmVlTW9kZS5zdGlja3kpIHtcbiAgICAgIHN3aXBlci5zbGlkZVRvQ2xvc2VzdCgpO1xuICAgICAgcmV0dXJuO1xuICAgIH0gZWxzZSBpZiAocGFyYW1zLmZyZWVNb2RlKSB7XG4gICAgICBlbWl0KCdfZnJlZU1vZGVOb01vbWVudHVtUmVsZWFzZScpO1xuICAgIH1cblxuICAgIGlmICghcGFyYW1zLmZyZWVNb2RlLm1vbWVudHVtIHx8IHRpbWVEaWZmID49IHBhcmFtcy5sb25nU3dpcGVzTXMpIHtcbiAgICAgIHN3aXBlci51cGRhdGVQcm9ncmVzcygpO1xuICAgICAgc3dpcGVyLnVwZGF0ZUFjdGl2ZUluZGV4KCk7XG4gICAgICBzd2lwZXIudXBkYXRlU2xpZGVzQ2xhc3NlcygpO1xuICAgIH1cbiAgfVxuXG4gIE9iamVjdC5hc3NpZ24oc3dpcGVyLCB7XG4gICAgZnJlZU1vZGU6IHtcbiAgICAgIG9uVG91Y2hTdGFydCxcbiAgICAgIG9uVG91Y2hNb3ZlLFxuICAgICAgb25Ub3VjaEVuZFxuICAgIH1cbiAgfSk7XG59IiwiaW1wb3J0ICQgZnJvbSAnLi4vLi4vc2hhcmVkL2RvbS5qcyc7XG5pbXBvcnQgZWZmZWN0SW5pdCBmcm9tICcuLi8uLi9zaGFyZWQvZWZmZWN0LWluaXQuanMnO1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gRWZmZWN0Q3ViZSh7XG4gIHN3aXBlcixcbiAgZXh0ZW5kUGFyYW1zLFxuICBvblxufSkge1xuICBleHRlbmRQYXJhbXMoe1xuICAgIGN1YmVFZmZlY3Q6IHtcbiAgICAgIHNsaWRlU2hhZG93czogdHJ1ZSxcbiAgICAgIHNoYWRvdzogdHJ1ZSxcbiAgICAgIHNoYWRvd09mZnNldDogMjAsXG4gICAgICBzaGFkb3dTY2FsZTogMC45NFxuICAgIH1cbiAgfSk7XG5cbiAgY29uc3QgY3JlYXRlU2xpZGVTaGFkb3dzID0gKCRzbGlkZUVsLCBwcm9ncmVzcywgaXNIb3Jpem9udGFsKSA9PiB7XG4gICAgbGV0IHNoYWRvd0JlZm9yZSA9IGlzSG9yaXpvbnRhbCA/ICRzbGlkZUVsLmZpbmQoJy5zd2lwZXItc2xpZGUtc2hhZG93LWxlZnQnKSA6ICRzbGlkZUVsLmZpbmQoJy5zd2lwZXItc2xpZGUtc2hhZG93LXRvcCcpO1xuICAgIGxldCBzaGFkb3dBZnRlciA9IGlzSG9yaXpvbnRhbCA/ICRzbGlkZUVsLmZpbmQoJy5zd2lwZXItc2xpZGUtc2hhZG93LXJpZ2h0JykgOiAkc2xpZGVFbC5maW5kKCcuc3dpcGVyLXNsaWRlLXNoYWRvdy1ib3R0b20nKTtcblxuICAgIGlmIChzaGFkb3dCZWZvcmUubGVuZ3RoID09PSAwKSB7XG4gICAgICBzaGFkb3dCZWZvcmUgPSAkKGA8ZGl2IGNsYXNzPVwic3dpcGVyLXNsaWRlLXNoYWRvdy0ke2lzSG9yaXpvbnRhbCA/ICdsZWZ0JyA6ICd0b3AnfVwiPjwvZGl2PmApO1xuICAgICAgJHNsaWRlRWwuYXBwZW5kKHNoYWRvd0JlZm9yZSk7XG4gICAgfVxuXG4gICAgaWYgKHNoYWRvd0FmdGVyLmxlbmd0aCA9PT0gMCkge1xuICAgICAgc2hhZG93QWZ0ZXIgPSAkKGA8ZGl2IGNsYXNzPVwic3dpcGVyLXNsaWRlLXNoYWRvdy0ke2lzSG9yaXpvbnRhbCA/ICdyaWdodCcgOiAnYm90dG9tJ31cIj48L2Rpdj5gKTtcbiAgICAgICRzbGlkZUVsLmFwcGVuZChzaGFkb3dBZnRlcik7XG4gICAgfVxuXG4gICAgaWYgKHNoYWRvd0JlZm9yZS5sZW5ndGgpIHNoYWRvd0JlZm9yZVswXS5zdHlsZS5vcGFjaXR5ID0gTWF0aC5tYXgoLXByb2dyZXNzLCAwKTtcbiAgICBpZiAoc2hhZG93QWZ0ZXIubGVuZ3RoKSBzaGFkb3dBZnRlclswXS5zdHlsZS5vcGFjaXR5ID0gTWF0aC5tYXgocHJvZ3Jlc3MsIDApO1xuICB9O1xuXG4gIGNvbnN0IHJlY3JlYXRlU2hhZG93cyA9ICgpID0+IHtcbiAgICAvLyBjcmVhdGUgbmV3IG9uZXNcbiAgICBjb25zdCBpc0hvcml6b250YWwgPSBzd2lwZXIuaXNIb3Jpem9udGFsKCk7XG4gICAgc3dpcGVyLnNsaWRlcy5lYWNoKHNsaWRlRWwgPT4ge1xuICAgICAgY29uc3QgcHJvZ3Jlc3MgPSBNYXRoLm1heChNYXRoLm1pbihzbGlkZUVsLnByb2dyZXNzLCAxKSwgLTEpO1xuICAgICAgY3JlYXRlU2xpZGVTaGFkb3dzKCQoc2xpZGVFbCksIHByb2dyZXNzLCBpc0hvcml6b250YWwpO1xuICAgIH0pO1xuICB9O1xuXG4gIGNvbnN0IHNldFRyYW5zbGF0ZSA9ICgpID0+IHtcbiAgICBjb25zdCB7XG4gICAgICAkZWwsXG4gICAgICAkd3JhcHBlckVsLFxuICAgICAgc2xpZGVzLFxuICAgICAgd2lkdGg6IHN3aXBlcldpZHRoLFxuICAgICAgaGVpZ2h0OiBzd2lwZXJIZWlnaHQsXG4gICAgICBydGxUcmFuc2xhdGU6IHJ0bCxcbiAgICAgIHNpemU6IHN3aXBlclNpemUsXG4gICAgICBicm93c2VyXG4gICAgfSA9IHN3aXBlcjtcbiAgICBjb25zdCBwYXJhbXMgPSBzd2lwZXIucGFyYW1zLmN1YmVFZmZlY3Q7XG4gICAgY29uc3QgaXNIb3Jpem9udGFsID0gc3dpcGVyLmlzSG9yaXpvbnRhbCgpO1xuICAgIGNvbnN0IGlzVmlydHVhbCA9IHN3aXBlci52aXJ0dWFsICYmIHN3aXBlci5wYXJhbXMudmlydHVhbC5lbmFibGVkO1xuICAgIGxldCB3cmFwcGVyUm90YXRlID0gMDtcbiAgICBsZXQgJGN1YmVTaGFkb3dFbDtcblxuICAgIGlmIChwYXJhbXMuc2hhZG93KSB7XG4gICAgICBpZiAoaXNIb3Jpem9udGFsKSB7XG4gICAgICAgICRjdWJlU2hhZG93RWwgPSAkd3JhcHBlckVsLmZpbmQoJy5zd2lwZXItY3ViZS1zaGFkb3cnKTtcblxuICAgICAgICBpZiAoJGN1YmVTaGFkb3dFbC5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAkY3ViZVNoYWRvd0VsID0gJCgnPGRpdiBjbGFzcz1cInN3aXBlci1jdWJlLXNoYWRvd1wiPjwvZGl2PicpO1xuICAgICAgICAgICR3cmFwcGVyRWwuYXBwZW5kKCRjdWJlU2hhZG93RWwpO1xuICAgICAgICB9XG5cbiAgICAgICAgJGN1YmVTaGFkb3dFbC5jc3Moe1xuICAgICAgICAgIGhlaWdodDogYCR7c3dpcGVyV2lkdGh9cHhgXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgJGN1YmVTaGFkb3dFbCA9ICRlbC5maW5kKCcuc3dpcGVyLWN1YmUtc2hhZG93Jyk7XG5cbiAgICAgICAgaWYgKCRjdWJlU2hhZG93RWwubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgJGN1YmVTaGFkb3dFbCA9ICQoJzxkaXYgY2xhc3M9XCJzd2lwZXItY3ViZS1zaGFkb3dcIj48L2Rpdj4nKTtcbiAgICAgICAgICAkZWwuYXBwZW5kKCRjdWJlU2hhZG93RWwpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzbGlkZXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgIGNvbnN0ICRzbGlkZUVsID0gc2xpZGVzLmVxKGkpO1xuICAgICAgbGV0IHNsaWRlSW5kZXggPSBpO1xuXG4gICAgICBpZiAoaXNWaXJ0dWFsKSB7XG4gICAgICAgIHNsaWRlSW5kZXggPSBwYXJzZUludCgkc2xpZGVFbC5hdHRyKCdkYXRhLXN3aXBlci1zbGlkZS1pbmRleCcpLCAxMCk7XG4gICAgICB9XG5cbiAgICAgIGxldCBzbGlkZUFuZ2xlID0gc2xpZGVJbmRleCAqIDkwO1xuICAgICAgbGV0IHJvdW5kID0gTWF0aC5mbG9vcihzbGlkZUFuZ2xlIC8gMzYwKTtcblxuICAgICAgaWYgKHJ0bCkge1xuICAgICAgICBzbGlkZUFuZ2xlID0gLXNsaWRlQW5nbGU7XG4gICAgICAgIHJvdW5kID0gTWF0aC5mbG9vcigtc2xpZGVBbmdsZSAvIDM2MCk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHByb2dyZXNzID0gTWF0aC5tYXgoTWF0aC5taW4oJHNsaWRlRWxbMF0ucHJvZ3Jlc3MsIDEpLCAtMSk7XG4gICAgICBsZXQgdHggPSAwO1xuICAgICAgbGV0IHR5ID0gMDtcbiAgICAgIGxldCB0eiA9IDA7XG5cbiAgICAgIGlmIChzbGlkZUluZGV4ICUgNCA9PT0gMCkge1xuICAgICAgICB0eCA9IC1yb3VuZCAqIDQgKiBzd2lwZXJTaXplO1xuICAgICAgICB0eiA9IDA7XG4gICAgICB9IGVsc2UgaWYgKChzbGlkZUluZGV4IC0gMSkgJSA0ID09PSAwKSB7XG4gICAgICAgIHR4ID0gMDtcbiAgICAgICAgdHogPSAtcm91bmQgKiA0ICogc3dpcGVyU2l6ZTtcbiAgICAgIH0gZWxzZSBpZiAoKHNsaWRlSW5kZXggLSAyKSAlIDQgPT09IDApIHtcbiAgICAgICAgdHggPSBzd2lwZXJTaXplICsgcm91bmQgKiA0ICogc3dpcGVyU2l6ZTtcbiAgICAgICAgdHogPSBzd2lwZXJTaXplO1xuICAgICAgfSBlbHNlIGlmICgoc2xpZGVJbmRleCAtIDMpICUgNCA9PT0gMCkge1xuICAgICAgICB0eCA9IC1zd2lwZXJTaXplO1xuICAgICAgICB0eiA9IDMgKiBzd2lwZXJTaXplICsgc3dpcGVyU2l6ZSAqIDQgKiByb3VuZDtcbiAgICAgIH1cblxuICAgICAgaWYgKHJ0bCkge1xuICAgICAgICB0eCA9IC10eDtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpc0hvcml6b250YWwpIHtcbiAgICAgICAgdHkgPSB0eDtcbiAgICAgICAgdHggPSAwO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB0cmFuc2Zvcm0gPSBgcm90YXRlWCgke2lzSG9yaXpvbnRhbCA/IDAgOiAtc2xpZGVBbmdsZX1kZWcpIHJvdGF0ZVkoJHtpc0hvcml6b250YWwgPyBzbGlkZUFuZ2xlIDogMH1kZWcpIHRyYW5zbGF0ZTNkKCR7dHh9cHgsICR7dHl9cHgsICR7dHp9cHgpYDtcblxuICAgICAgaWYgKHByb2dyZXNzIDw9IDEgJiYgcHJvZ3Jlc3MgPiAtMSkge1xuICAgICAgICB3cmFwcGVyUm90YXRlID0gc2xpZGVJbmRleCAqIDkwICsgcHJvZ3Jlc3MgKiA5MDtcbiAgICAgICAgaWYgKHJ0bCkgd3JhcHBlclJvdGF0ZSA9IC1zbGlkZUluZGV4ICogOTAgLSBwcm9ncmVzcyAqIDkwO1xuICAgICAgfVxuXG4gICAgICAkc2xpZGVFbC50cmFuc2Zvcm0odHJhbnNmb3JtKTtcblxuICAgICAgaWYgKHBhcmFtcy5zbGlkZVNoYWRvd3MpIHtcbiAgICAgICAgY3JlYXRlU2xpZGVTaGFkb3dzKCRzbGlkZUVsLCBwcm9ncmVzcywgaXNIb3Jpem9udGFsKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAkd3JhcHBlckVsLmNzcyh7XG4gICAgICAnLXdlYmtpdC10cmFuc2Zvcm0tb3JpZ2luJzogYDUwJSA1MCUgLSR7c3dpcGVyU2l6ZSAvIDJ9cHhgLFxuICAgICAgJ3RyYW5zZm9ybS1vcmlnaW4nOiBgNTAlIDUwJSAtJHtzd2lwZXJTaXplIC8gMn1weGBcbiAgICB9KTtcblxuICAgIGlmIChwYXJhbXMuc2hhZG93KSB7XG4gICAgICBpZiAoaXNIb3Jpem9udGFsKSB7XG4gICAgICAgICRjdWJlU2hhZG93RWwudHJhbnNmb3JtKGB0cmFuc2xhdGUzZCgwcHgsICR7c3dpcGVyV2lkdGggLyAyICsgcGFyYW1zLnNoYWRvd09mZnNldH1weCwgJHstc3dpcGVyV2lkdGggLyAyfXB4KSByb3RhdGVYKDkwZGVnKSByb3RhdGVaKDBkZWcpIHNjYWxlKCR7cGFyYW1zLnNoYWRvd1NjYWxlfSlgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHNoYWRvd0FuZ2xlID0gTWF0aC5hYnMod3JhcHBlclJvdGF0ZSkgLSBNYXRoLmZsb29yKE1hdGguYWJzKHdyYXBwZXJSb3RhdGUpIC8gOTApICogOTA7XG4gICAgICAgIGNvbnN0IG11bHRpcGxpZXIgPSAxLjUgLSAoTWF0aC5zaW4oc2hhZG93QW5nbGUgKiAyICogTWF0aC5QSSAvIDM2MCkgLyAyICsgTWF0aC5jb3Moc2hhZG93QW5nbGUgKiAyICogTWF0aC5QSSAvIDM2MCkgLyAyKTtcbiAgICAgICAgY29uc3Qgc2NhbGUxID0gcGFyYW1zLnNoYWRvd1NjYWxlO1xuICAgICAgICBjb25zdCBzY2FsZTIgPSBwYXJhbXMuc2hhZG93U2NhbGUgLyBtdWx0aXBsaWVyO1xuICAgICAgICBjb25zdCBvZmZzZXQgPSBwYXJhbXMuc2hhZG93T2Zmc2V0O1xuICAgICAgICAkY3ViZVNoYWRvd0VsLnRyYW5zZm9ybShgc2NhbGUzZCgke3NjYWxlMX0sIDEsICR7c2NhbGUyfSkgdHJhbnNsYXRlM2QoMHB4LCAke3N3aXBlckhlaWdodCAvIDIgKyBvZmZzZXR9cHgsICR7LXN3aXBlckhlaWdodCAvIDIgLyBzY2FsZTJ9cHgpIHJvdGF0ZVgoLTkwZGVnKWApO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IHpGYWN0b3IgPSBicm93c2VyLmlzU2FmYXJpIHx8IGJyb3dzZXIuaXNXZWJWaWV3ID8gLXN3aXBlclNpemUgLyAyIDogMDtcbiAgICAkd3JhcHBlckVsLnRyYW5zZm9ybShgdHJhbnNsYXRlM2QoMHB4LDAsJHt6RmFjdG9yfXB4KSByb3RhdGVYKCR7c3dpcGVyLmlzSG9yaXpvbnRhbCgpID8gMCA6IHdyYXBwZXJSb3RhdGV9ZGVnKSByb3RhdGVZKCR7c3dpcGVyLmlzSG9yaXpvbnRhbCgpID8gLXdyYXBwZXJSb3RhdGUgOiAwfWRlZylgKTtcbiAgICAkd3JhcHBlckVsWzBdLnN0eWxlLnNldFByb3BlcnR5KCctLXN3aXBlci1jdWJlLXRyYW5zbGF0ZS16JywgYCR7ekZhY3Rvcn1weGApO1xuICB9O1xuXG4gIGNvbnN0IHNldFRyYW5zaXRpb24gPSBkdXJhdGlvbiA9PiB7XG4gICAgY29uc3Qge1xuICAgICAgJGVsLFxuICAgICAgc2xpZGVzXG4gICAgfSA9IHN3aXBlcjtcbiAgICBzbGlkZXMudHJhbnNpdGlvbihkdXJhdGlvbikuZmluZCgnLnN3aXBlci1zbGlkZS1zaGFkb3ctdG9wLCAuc3dpcGVyLXNsaWRlLXNoYWRvdy1yaWdodCwgLnN3aXBlci1zbGlkZS1zaGFkb3ctYm90dG9tLCAuc3dpcGVyLXNsaWRlLXNoYWRvdy1sZWZ0JykudHJhbnNpdGlvbihkdXJhdGlvbik7XG5cbiAgICBpZiAoc3dpcGVyLnBhcmFtcy5jdWJlRWZmZWN0LnNoYWRvdyAmJiAhc3dpcGVyLmlzSG9yaXpvbnRhbCgpKSB7XG4gICAgICAkZWwuZmluZCgnLnN3aXBlci1jdWJlLXNoYWRvdycpLnRyYW5zaXRpb24oZHVyYXRpb24pO1xuICAgIH1cbiAgfTtcblxuICBlZmZlY3RJbml0KHtcbiAgICBlZmZlY3Q6ICdjdWJlJyxcbiAgICBzd2lwZXIsXG4gICAgb24sXG4gICAgc2V0VHJhbnNsYXRlLFxuICAgIHNldFRyYW5zaXRpb24sXG4gICAgcmVjcmVhdGVTaGFkb3dzLFxuICAgIGdldEVmZmVjdFBhcmFtczogKCkgPT4gc3dpcGVyLnBhcmFtcy5jdWJlRWZmZWN0LFxuICAgIHBlcnNwZWN0aXZlOiAoKSA9PiB0cnVlLFxuICAgIG92ZXJ3cml0ZVBhcmFtczogKCkgPT4gKHtcbiAgICAgIHNsaWRlc1BlclZpZXc6IDEsXG4gICAgICBzbGlkZXNQZXJHcm91cDogMSxcbiAgICAgIHdhdGNoU2xpZGVzUHJvZ3Jlc3M6IHRydWUsXG4gICAgICByZXNpc3RhbmNlUmF0aW86IDAsXG4gICAgICBzcGFjZUJldHdlZW46IDAsXG4gICAgICBjZW50ZXJlZFNsaWRlczogZmFsc2UsXG4gICAgICB2aXJ0dWFsVHJhbnNsYXRlOiB0cnVlXG4gICAgfSlcbiAgfSk7XG59IiwiaW1wb3J0ICQgZnJvbSAnLi9kb20uanMnO1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gY3JlYXRlU2hhZG93KHBhcmFtcywgJHNsaWRlRWwsIHNpZGUpIHtcbiAgY29uc3Qgc2hhZG93Q2xhc3MgPSBgc3dpcGVyLXNsaWRlLXNoYWRvdyR7c2lkZSA/IGAtJHtzaWRlfWAgOiAnJ31gO1xuICBjb25zdCAkc2hhZG93Q29udGFpbmVyID0gcGFyYW1zLnRyYW5zZm9ybUVsID8gJHNsaWRlRWwuZmluZChwYXJhbXMudHJhbnNmb3JtRWwpIDogJHNsaWRlRWw7XG4gIGxldCAkc2hhZG93RWwgPSAkc2hhZG93Q29udGFpbmVyLmNoaWxkcmVuKGAuJHtzaGFkb3dDbGFzc31gKTtcblxuICBpZiAoISRzaGFkb3dFbC5sZW5ndGgpIHtcbiAgICAkc2hhZG93RWwgPSAkKGA8ZGl2IGNsYXNzPVwic3dpcGVyLXNsaWRlLXNoYWRvdyR7c2lkZSA/IGAtJHtzaWRlfWAgOiAnJ31cIj48L2Rpdj5gKTtcbiAgICAkc2hhZG93Q29udGFpbmVyLmFwcGVuZCgkc2hhZG93RWwpO1xuICB9XG5cbiAgcmV0dXJuICRzaGFkb3dFbDtcbn0iLCJpbXBvcnQgJCBmcm9tICcuLi8uLi9zaGFyZWQvZG9tLmpzJztcbmltcG9ydCBjcmVhdGVTaGFkb3cgZnJvbSAnLi4vLi4vc2hhcmVkL2NyZWF0ZS1zaGFkb3cuanMnO1xuaW1wb3J0IGVmZmVjdEluaXQgZnJvbSAnLi4vLi4vc2hhcmVkL2VmZmVjdC1pbml0LmpzJztcbmltcG9ydCBlZmZlY3RUYXJnZXQgZnJvbSAnLi4vLi4vc2hhcmVkL2VmZmVjdC10YXJnZXQuanMnO1xuaW1wb3J0IGVmZmVjdFZpcnR1YWxUcmFuc2l0aW9uRW5kIGZyb20gJy4uLy4uL3NoYXJlZC9lZmZlY3QtdmlydHVhbC10cmFuc2l0aW9uLWVuZC5qcyc7XG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBFZmZlY3RGbGlwKHtcbiAgc3dpcGVyLFxuICBleHRlbmRQYXJhbXMsXG4gIG9uXG59KSB7XG4gIGV4dGVuZFBhcmFtcyh7XG4gICAgZmxpcEVmZmVjdDoge1xuICAgICAgc2xpZGVTaGFkb3dzOiB0cnVlLFxuICAgICAgbGltaXRSb3RhdGlvbjogdHJ1ZSxcbiAgICAgIHRyYW5zZm9ybUVsOiBudWxsXG4gICAgfVxuICB9KTtcblxuICBjb25zdCBjcmVhdGVTbGlkZVNoYWRvd3MgPSAoJHNsaWRlRWwsIHByb2dyZXNzLCBwYXJhbXMpID0+IHtcbiAgICBsZXQgc2hhZG93QmVmb3JlID0gc3dpcGVyLmlzSG9yaXpvbnRhbCgpID8gJHNsaWRlRWwuZmluZCgnLnN3aXBlci1zbGlkZS1zaGFkb3ctbGVmdCcpIDogJHNsaWRlRWwuZmluZCgnLnN3aXBlci1zbGlkZS1zaGFkb3ctdG9wJyk7XG4gICAgbGV0IHNoYWRvd0FmdGVyID0gc3dpcGVyLmlzSG9yaXpvbnRhbCgpID8gJHNsaWRlRWwuZmluZCgnLnN3aXBlci1zbGlkZS1zaGFkb3ctcmlnaHQnKSA6ICRzbGlkZUVsLmZpbmQoJy5zd2lwZXItc2xpZGUtc2hhZG93LWJvdHRvbScpO1xuXG4gICAgaWYgKHNoYWRvd0JlZm9yZS5sZW5ndGggPT09IDApIHtcbiAgICAgIHNoYWRvd0JlZm9yZSA9IGNyZWF0ZVNoYWRvdyhwYXJhbXMsICRzbGlkZUVsLCBzd2lwZXIuaXNIb3Jpem9udGFsKCkgPyAnbGVmdCcgOiAndG9wJyk7XG4gICAgfVxuXG4gICAgaWYgKHNoYWRvd0FmdGVyLmxlbmd0aCA9PT0gMCkge1xuICAgICAgc2hhZG93QWZ0ZXIgPSBjcmVhdGVTaGFkb3cocGFyYW1zLCAkc2xpZGVFbCwgc3dpcGVyLmlzSG9yaXpvbnRhbCgpID8gJ3JpZ2h0JyA6ICdib3R0b20nKTtcbiAgICB9XG5cbiAgICBpZiAoc2hhZG93QmVmb3JlLmxlbmd0aCkgc2hhZG93QmVmb3JlWzBdLnN0eWxlLm9wYWNpdHkgPSBNYXRoLm1heCgtcHJvZ3Jlc3MsIDApO1xuICAgIGlmIChzaGFkb3dBZnRlci5sZW5ndGgpIHNoYWRvd0FmdGVyWzBdLnN0eWxlLm9wYWNpdHkgPSBNYXRoLm1heChwcm9ncmVzcywgMCk7XG4gIH07XG5cbiAgY29uc3QgcmVjcmVhdGVTaGFkb3dzID0gKCkgPT4ge1xuICAgIC8vIFNldCBzaGFkb3dzXG4gICAgY29uc3QgcGFyYW1zID0gc3dpcGVyLnBhcmFtcy5mbGlwRWZmZWN0O1xuICAgIHN3aXBlci5zbGlkZXMuZWFjaChzbGlkZUVsID0+IHtcbiAgICAgIGNvbnN0ICRzbGlkZUVsID0gJChzbGlkZUVsKTtcbiAgICAgIGxldCBwcm9ncmVzcyA9ICRzbGlkZUVsWzBdLnByb2dyZXNzO1xuXG4gICAgICBpZiAoc3dpcGVyLnBhcmFtcy5mbGlwRWZmZWN0LmxpbWl0Um90YXRpb24pIHtcbiAgICAgICAgcHJvZ3Jlc3MgPSBNYXRoLm1heChNYXRoLm1pbihzbGlkZUVsLnByb2dyZXNzLCAxKSwgLTEpO1xuICAgICAgfVxuXG4gICAgICBjcmVhdGVTbGlkZVNoYWRvd3MoJHNsaWRlRWwsIHByb2dyZXNzLCBwYXJhbXMpO1xuICAgIH0pO1xuICB9O1xuXG4gIGNvbnN0IHNldFRyYW5zbGF0ZSA9ICgpID0+IHtcbiAgICBjb25zdCB7XG4gICAgICBzbGlkZXMsXG4gICAgICBydGxUcmFuc2xhdGU6IHJ0bFxuICAgIH0gPSBzd2lwZXI7XG4gICAgY29uc3QgcGFyYW1zID0gc3dpcGVyLnBhcmFtcy5mbGlwRWZmZWN0O1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzbGlkZXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgIGNvbnN0ICRzbGlkZUVsID0gc2xpZGVzLmVxKGkpO1xuICAgICAgbGV0IHByb2dyZXNzID0gJHNsaWRlRWxbMF0ucHJvZ3Jlc3M7XG5cbiAgICAgIGlmIChzd2lwZXIucGFyYW1zLmZsaXBFZmZlY3QubGltaXRSb3RhdGlvbikge1xuICAgICAgICBwcm9ncmVzcyA9IE1hdGgubWF4KE1hdGgubWluKCRzbGlkZUVsWzBdLnByb2dyZXNzLCAxKSwgLTEpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBvZmZzZXQgPSAkc2xpZGVFbFswXS5zd2lwZXJTbGlkZU9mZnNldDtcbiAgICAgIGNvbnN0IHJvdGF0ZSA9IC0xODAgKiBwcm9ncmVzcztcbiAgICAgIGxldCByb3RhdGVZID0gcm90YXRlO1xuICAgICAgbGV0IHJvdGF0ZVggPSAwO1xuICAgICAgbGV0IHR4ID0gc3dpcGVyLnBhcmFtcy5jc3NNb2RlID8gLW9mZnNldCAtIHN3aXBlci50cmFuc2xhdGUgOiAtb2Zmc2V0O1xuICAgICAgbGV0IHR5ID0gMDtcblxuICAgICAgaWYgKCFzd2lwZXIuaXNIb3Jpem9udGFsKCkpIHtcbiAgICAgICAgdHkgPSB0eDtcbiAgICAgICAgdHggPSAwO1xuICAgICAgICByb3RhdGVYID0gLXJvdGF0ZVk7XG4gICAgICAgIHJvdGF0ZVkgPSAwO1xuICAgICAgfSBlbHNlIGlmIChydGwpIHtcbiAgICAgICAgcm90YXRlWSA9IC1yb3RhdGVZO1xuICAgICAgfVxuXG4gICAgICAkc2xpZGVFbFswXS5zdHlsZS56SW5kZXggPSAtTWF0aC5hYnMoTWF0aC5yb3VuZChwcm9ncmVzcykpICsgc2xpZGVzLmxlbmd0aDtcblxuICAgICAgaWYgKHBhcmFtcy5zbGlkZVNoYWRvd3MpIHtcbiAgICAgICAgY3JlYXRlU2xpZGVTaGFkb3dzKCRzbGlkZUVsLCBwcm9ncmVzcywgcGFyYW1zKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgdHJhbnNmb3JtID0gYHRyYW5zbGF0ZTNkKCR7dHh9cHgsICR7dHl9cHgsIDBweCkgcm90YXRlWCgke3JvdGF0ZVh9ZGVnKSByb3RhdGVZKCR7cm90YXRlWX1kZWcpYDtcbiAgICAgIGNvbnN0ICR0YXJnZXRFbCA9IGVmZmVjdFRhcmdldChwYXJhbXMsICRzbGlkZUVsKTtcbiAgICAgICR0YXJnZXRFbC50cmFuc2Zvcm0odHJhbnNmb3JtKTtcbiAgICB9XG4gIH07XG5cbiAgY29uc3Qgc2V0VHJhbnNpdGlvbiA9IGR1cmF0aW9uID0+IHtcbiAgICBjb25zdCB7XG4gICAgICB0cmFuc2Zvcm1FbFxuICAgIH0gPSBzd2lwZXIucGFyYW1zLmZsaXBFZmZlY3Q7XG4gICAgY29uc3QgJHRyYW5zaXRpb25FbGVtZW50cyA9IHRyYW5zZm9ybUVsID8gc3dpcGVyLnNsaWRlcy5maW5kKHRyYW5zZm9ybUVsKSA6IHN3aXBlci5zbGlkZXM7XG4gICAgJHRyYW5zaXRpb25FbGVtZW50cy50cmFuc2l0aW9uKGR1cmF0aW9uKS5maW5kKCcuc3dpcGVyLXNsaWRlLXNoYWRvdy10b3AsIC5zd2lwZXItc2xpZGUtc2hhZG93LXJpZ2h0LCAuc3dpcGVyLXNsaWRlLXNoYWRvdy1ib3R0b20sIC5zd2lwZXItc2xpZGUtc2hhZG93LWxlZnQnKS50cmFuc2l0aW9uKGR1cmF0aW9uKTtcbiAgICBlZmZlY3RWaXJ0dWFsVHJhbnNpdGlvbkVuZCh7XG4gICAgICBzd2lwZXIsXG4gICAgICBkdXJhdGlvbixcbiAgICAgIHRyYW5zZm9ybUVsXG4gICAgfSk7XG4gIH07XG5cbiAgZWZmZWN0SW5pdCh7XG4gICAgZWZmZWN0OiAnZmxpcCcsXG4gICAgc3dpcGVyLFxuICAgIG9uLFxuICAgIHNldFRyYW5zbGF0ZSxcbiAgICBzZXRUcmFuc2l0aW9uLFxuICAgIHJlY3JlYXRlU2hhZG93cyxcbiAgICBnZXRFZmZlY3RQYXJhbXM6ICgpID0+IHN3aXBlci5wYXJhbXMuZmxpcEVmZmVjdCxcbiAgICBwZXJzcGVjdGl2ZTogKCkgPT4gdHJ1ZSxcbiAgICBvdmVyd3JpdGVQYXJhbXM6ICgpID0+ICh7XG4gICAgICBzbGlkZXNQZXJWaWV3OiAxLFxuICAgICAgc2xpZGVzUGVyR3JvdXA6IDEsXG4gICAgICB3YXRjaFNsaWRlc1Byb2dyZXNzOiB0cnVlLFxuICAgICAgc3BhY2VCZXR3ZWVuOiAwLFxuICAgICAgdmlydHVhbFRyYW5zbGF0ZTogIXN3aXBlci5wYXJhbXMuY3NzTW9kZVxuICAgIH0pXG4gIH0pO1xufSIsImltcG9ydCBjcmVhdGVTaGFkb3cgZnJvbSAnLi4vLi4vc2hhcmVkL2NyZWF0ZS1zaGFkb3cuanMnO1xuaW1wb3J0IGVmZmVjdEluaXQgZnJvbSAnLi4vLi4vc2hhcmVkL2VmZmVjdC1pbml0LmpzJztcbmltcG9ydCBlZmZlY3RUYXJnZXQgZnJvbSAnLi4vLi4vc2hhcmVkL2VmZmVjdC10YXJnZXQuanMnO1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gRWZmZWN0Q292ZXJmbG93KHtcbiAgc3dpcGVyLFxuICBleHRlbmRQYXJhbXMsXG4gIG9uXG59KSB7XG4gIGV4dGVuZFBhcmFtcyh7XG4gICAgY292ZXJmbG93RWZmZWN0OiB7XG4gICAgICByb3RhdGU6IDUwLFxuICAgICAgc3RyZXRjaDogMCxcbiAgICAgIGRlcHRoOiAxMDAsXG4gICAgICBzY2FsZTogMSxcbiAgICAgIG1vZGlmaWVyOiAxLFxuICAgICAgc2xpZGVTaGFkb3dzOiB0cnVlLFxuICAgICAgdHJhbnNmb3JtRWw6IG51bGxcbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IHNldFRyYW5zbGF0ZSA9ICgpID0+IHtcbiAgICBjb25zdCB7XG4gICAgICB3aWR0aDogc3dpcGVyV2lkdGgsXG4gICAgICBoZWlnaHQ6IHN3aXBlckhlaWdodCxcbiAgICAgIHNsaWRlcyxcbiAgICAgIHNsaWRlc1NpemVzR3JpZFxuICAgIH0gPSBzd2lwZXI7XG4gICAgY29uc3QgcGFyYW1zID0gc3dpcGVyLnBhcmFtcy5jb3ZlcmZsb3dFZmZlY3Q7XG4gICAgY29uc3QgaXNIb3Jpem9udGFsID0gc3dpcGVyLmlzSG9yaXpvbnRhbCgpO1xuICAgIGNvbnN0IHRyYW5zZm9ybSA9IHN3aXBlci50cmFuc2xhdGU7XG4gICAgY29uc3QgY2VudGVyID0gaXNIb3Jpem9udGFsID8gLXRyYW5zZm9ybSArIHN3aXBlcldpZHRoIC8gMiA6IC10cmFuc2Zvcm0gKyBzd2lwZXJIZWlnaHQgLyAyO1xuICAgIGNvbnN0IHJvdGF0ZSA9IGlzSG9yaXpvbnRhbCA/IHBhcmFtcy5yb3RhdGUgOiAtcGFyYW1zLnJvdGF0ZTtcbiAgICBjb25zdCB0cmFuc2xhdGUgPSBwYXJhbXMuZGVwdGg7IC8vIEVhY2ggc2xpZGUgb2Zmc2V0IGZyb20gY2VudGVyXG5cbiAgICBmb3IgKGxldCBpID0gMCwgbGVuZ3RoID0gc2xpZGVzLmxlbmd0aDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgICBjb25zdCAkc2xpZGVFbCA9IHNsaWRlcy5lcShpKTtcbiAgICAgIGNvbnN0IHNsaWRlU2l6ZSA9IHNsaWRlc1NpemVzR3JpZFtpXTtcbiAgICAgIGNvbnN0IHNsaWRlT2Zmc2V0ID0gJHNsaWRlRWxbMF0uc3dpcGVyU2xpZGVPZmZzZXQ7XG4gICAgICBjb25zdCBjZW50ZXJPZmZzZXQgPSAoY2VudGVyIC0gc2xpZGVPZmZzZXQgLSBzbGlkZVNpemUgLyAyKSAvIHNsaWRlU2l6ZTtcbiAgICAgIGNvbnN0IG9mZnNldE11bHRpcGxpZXIgPSB0eXBlb2YgcGFyYW1zLm1vZGlmaWVyID09PSAnZnVuY3Rpb24nID8gcGFyYW1zLm1vZGlmaWVyKGNlbnRlck9mZnNldCkgOiBjZW50ZXJPZmZzZXQgKiBwYXJhbXMubW9kaWZpZXI7XG4gICAgICBsZXQgcm90YXRlWSA9IGlzSG9yaXpvbnRhbCA/IHJvdGF0ZSAqIG9mZnNldE11bHRpcGxpZXIgOiAwO1xuICAgICAgbGV0IHJvdGF0ZVggPSBpc0hvcml6b250YWwgPyAwIDogcm90YXRlICogb2Zmc2V0TXVsdGlwbGllcjsgLy8gdmFyIHJvdGF0ZVogPSAwXG5cbiAgICAgIGxldCB0cmFuc2xhdGVaID0gLXRyYW5zbGF0ZSAqIE1hdGguYWJzKG9mZnNldE11bHRpcGxpZXIpO1xuICAgICAgbGV0IHN0cmV0Y2ggPSBwYXJhbXMuc3RyZXRjaDsgLy8gQWxsb3cgcGVyY2VudGFnZSB0byBtYWtlIGEgcmVsYXRpdmUgc3RyZXRjaCBmb3IgcmVzcG9uc2l2ZSBzbGlkZXJzXG5cbiAgICAgIGlmICh0eXBlb2Ygc3RyZXRjaCA9PT0gJ3N0cmluZycgJiYgc3RyZXRjaC5pbmRleE9mKCclJykgIT09IC0xKSB7XG4gICAgICAgIHN0cmV0Y2ggPSBwYXJzZUZsb2F0KHBhcmFtcy5zdHJldGNoKSAvIDEwMCAqIHNsaWRlU2l6ZTtcbiAgICAgIH1cblxuICAgICAgbGV0IHRyYW5zbGF0ZVkgPSBpc0hvcml6b250YWwgPyAwIDogc3RyZXRjaCAqIG9mZnNldE11bHRpcGxpZXI7XG4gICAgICBsZXQgdHJhbnNsYXRlWCA9IGlzSG9yaXpvbnRhbCA/IHN0cmV0Y2ggKiBvZmZzZXRNdWx0aXBsaWVyIDogMDtcbiAgICAgIGxldCBzY2FsZSA9IDEgLSAoMSAtIHBhcmFtcy5zY2FsZSkgKiBNYXRoLmFicyhvZmZzZXRNdWx0aXBsaWVyKTsgLy8gRml4IGZvciB1bHRyYSBzbWFsbCB2YWx1ZXNcblxuICAgICAgaWYgKE1hdGguYWJzKHRyYW5zbGF0ZVgpIDwgMC4wMDEpIHRyYW5zbGF0ZVggPSAwO1xuICAgICAgaWYgKE1hdGguYWJzKHRyYW5zbGF0ZVkpIDwgMC4wMDEpIHRyYW5zbGF0ZVkgPSAwO1xuICAgICAgaWYgKE1hdGguYWJzKHRyYW5zbGF0ZVopIDwgMC4wMDEpIHRyYW5zbGF0ZVogPSAwO1xuICAgICAgaWYgKE1hdGguYWJzKHJvdGF0ZVkpIDwgMC4wMDEpIHJvdGF0ZVkgPSAwO1xuICAgICAgaWYgKE1hdGguYWJzKHJvdGF0ZVgpIDwgMC4wMDEpIHJvdGF0ZVggPSAwO1xuICAgICAgaWYgKE1hdGguYWJzKHNjYWxlKSA8IDAuMDAxKSBzY2FsZSA9IDA7XG4gICAgICBjb25zdCBzbGlkZVRyYW5zZm9ybSA9IGB0cmFuc2xhdGUzZCgke3RyYW5zbGF0ZVh9cHgsJHt0cmFuc2xhdGVZfXB4LCR7dHJhbnNsYXRlWn1weCkgIHJvdGF0ZVgoJHtyb3RhdGVYfWRlZykgcm90YXRlWSgke3JvdGF0ZVl9ZGVnKSBzY2FsZSgke3NjYWxlfSlgO1xuICAgICAgY29uc3QgJHRhcmdldEVsID0gZWZmZWN0VGFyZ2V0KHBhcmFtcywgJHNsaWRlRWwpO1xuICAgICAgJHRhcmdldEVsLnRyYW5zZm9ybShzbGlkZVRyYW5zZm9ybSk7XG4gICAgICAkc2xpZGVFbFswXS5zdHlsZS56SW5kZXggPSAtTWF0aC5hYnMoTWF0aC5yb3VuZChvZmZzZXRNdWx0aXBsaWVyKSkgKyAxO1xuXG4gICAgICBpZiAocGFyYW1zLnNsaWRlU2hhZG93cykge1xuICAgICAgICAvLyBTZXQgc2hhZG93c1xuICAgICAgICBsZXQgJHNoYWRvd0JlZm9yZUVsID0gaXNIb3Jpem9udGFsID8gJHNsaWRlRWwuZmluZCgnLnN3aXBlci1zbGlkZS1zaGFkb3ctbGVmdCcpIDogJHNsaWRlRWwuZmluZCgnLnN3aXBlci1zbGlkZS1zaGFkb3ctdG9wJyk7XG4gICAgICAgIGxldCAkc2hhZG93QWZ0ZXJFbCA9IGlzSG9yaXpvbnRhbCA/ICRzbGlkZUVsLmZpbmQoJy5zd2lwZXItc2xpZGUtc2hhZG93LXJpZ2h0JykgOiAkc2xpZGVFbC5maW5kKCcuc3dpcGVyLXNsaWRlLXNoYWRvdy1ib3R0b20nKTtcblxuICAgICAgICBpZiAoJHNoYWRvd0JlZm9yZUVsLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICRzaGFkb3dCZWZvcmVFbCA9IGNyZWF0ZVNoYWRvdyhwYXJhbXMsICRzbGlkZUVsLCBpc0hvcml6b250YWwgPyAnbGVmdCcgOiAndG9wJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoJHNoYWRvd0FmdGVyRWwubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgJHNoYWRvd0FmdGVyRWwgPSBjcmVhdGVTaGFkb3cocGFyYW1zLCAkc2xpZGVFbCwgaXNIb3Jpem9udGFsID8gJ3JpZ2h0JyA6ICdib3R0b20nKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgkc2hhZG93QmVmb3JlRWwubGVuZ3RoKSAkc2hhZG93QmVmb3JlRWxbMF0uc3R5bGUub3BhY2l0eSA9IG9mZnNldE11bHRpcGxpZXIgPiAwID8gb2Zmc2V0TXVsdGlwbGllciA6IDA7XG4gICAgICAgIGlmICgkc2hhZG93QWZ0ZXJFbC5sZW5ndGgpICRzaGFkb3dBZnRlckVsWzBdLnN0eWxlLm9wYWNpdHkgPSAtb2Zmc2V0TXVsdGlwbGllciA+IDAgPyAtb2Zmc2V0TXVsdGlwbGllciA6IDA7XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIGNvbnN0IHNldFRyYW5zaXRpb24gPSBkdXJhdGlvbiA9PiB7XG4gICAgY29uc3Qge1xuICAgICAgdHJhbnNmb3JtRWxcbiAgICB9ID0gc3dpcGVyLnBhcmFtcy5jb3ZlcmZsb3dFZmZlY3Q7XG4gICAgY29uc3QgJHRyYW5zaXRpb25FbGVtZW50cyA9IHRyYW5zZm9ybUVsID8gc3dpcGVyLnNsaWRlcy5maW5kKHRyYW5zZm9ybUVsKSA6IHN3aXBlci5zbGlkZXM7XG4gICAgJHRyYW5zaXRpb25FbGVtZW50cy50cmFuc2l0aW9uKGR1cmF0aW9uKS5maW5kKCcuc3dpcGVyLXNsaWRlLXNoYWRvdy10b3AsIC5zd2lwZXItc2xpZGUtc2hhZG93LXJpZ2h0LCAuc3dpcGVyLXNsaWRlLXNoYWRvdy1ib3R0b20sIC5zd2lwZXItc2xpZGUtc2hhZG93LWxlZnQnKS50cmFuc2l0aW9uKGR1cmF0aW9uKTtcbiAgfTtcblxuICBlZmZlY3RJbml0KHtcbiAgICBlZmZlY3Q6ICdjb3ZlcmZsb3cnLFxuICAgIHN3aXBlcixcbiAgICBvbixcbiAgICBzZXRUcmFuc2xhdGUsXG4gICAgc2V0VHJhbnNpdGlvbixcbiAgICBwZXJzcGVjdGl2ZTogKCkgPT4gdHJ1ZSxcbiAgICBvdmVyd3JpdGVQYXJhbXM6ICgpID0+ICh7XG4gICAgICB3YXRjaFNsaWRlc1Byb2dyZXNzOiB0cnVlXG4gICAgfSlcbiAgfSk7XG59IiwiaW1wb3J0IGNyZWF0ZVNoYWRvdyBmcm9tICcuLi8uLi9zaGFyZWQvY3JlYXRlLXNoYWRvdy5qcyc7XG5pbXBvcnQgZWZmZWN0SW5pdCBmcm9tICcuLi8uLi9zaGFyZWQvZWZmZWN0LWluaXQuanMnO1xuaW1wb3J0IGVmZmVjdFRhcmdldCBmcm9tICcuLi8uLi9zaGFyZWQvZWZmZWN0LXRhcmdldC5qcyc7XG5pbXBvcnQgZWZmZWN0VmlydHVhbFRyYW5zaXRpb25FbmQgZnJvbSAnLi4vLi4vc2hhcmVkL2VmZmVjdC12aXJ0dWFsLXRyYW5zaXRpb24tZW5kLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIEVmZmVjdENyZWF0aXZlKHtcbiAgc3dpcGVyLFxuICBleHRlbmRQYXJhbXMsXG4gIG9uXG59KSB7XG4gIGV4dGVuZFBhcmFtcyh7XG4gICAgY3JlYXRpdmVFZmZlY3Q6IHtcbiAgICAgIHRyYW5zZm9ybUVsOiBudWxsLFxuICAgICAgbGltaXRQcm9ncmVzczogMSxcbiAgICAgIHNoYWRvd1BlclByb2dyZXNzOiBmYWxzZSxcbiAgICAgIHByb2dyZXNzTXVsdGlwbGllcjogMSxcbiAgICAgIHBlcnNwZWN0aXZlOiB0cnVlLFxuICAgICAgcHJldjoge1xuICAgICAgICB0cmFuc2xhdGU6IFswLCAwLCAwXSxcbiAgICAgICAgcm90YXRlOiBbMCwgMCwgMF0sXG4gICAgICAgIG9wYWNpdHk6IDEsXG4gICAgICAgIHNjYWxlOiAxXG4gICAgICB9LFxuICAgICAgbmV4dDoge1xuICAgICAgICB0cmFuc2xhdGU6IFswLCAwLCAwXSxcbiAgICAgICAgcm90YXRlOiBbMCwgMCwgMF0sXG4gICAgICAgIG9wYWNpdHk6IDEsXG4gICAgICAgIHNjYWxlOiAxXG4gICAgICB9XG4gICAgfVxuICB9KTtcblxuICBjb25zdCBnZXRUcmFuc2xhdGVWYWx1ZSA9IHZhbHVlID0+IHtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykgcmV0dXJuIHZhbHVlO1xuICAgIHJldHVybiBgJHt2YWx1ZX1weGA7XG4gIH07XG5cbiAgY29uc3Qgc2V0VHJhbnNsYXRlID0gKCkgPT4ge1xuICAgIGNvbnN0IHtcbiAgICAgIHNsaWRlcyxcbiAgICAgICR3cmFwcGVyRWwsXG4gICAgICBzbGlkZXNTaXplc0dyaWRcbiAgICB9ID0gc3dpcGVyO1xuICAgIGNvbnN0IHBhcmFtcyA9IHN3aXBlci5wYXJhbXMuY3JlYXRpdmVFZmZlY3Q7XG4gICAgY29uc3Qge1xuICAgICAgcHJvZ3Jlc3NNdWx0aXBsaWVyOiBtdWx0aXBsaWVyXG4gICAgfSA9IHBhcmFtcztcbiAgICBjb25zdCBpc0NlbnRlcmVkU2xpZGVzID0gc3dpcGVyLnBhcmFtcy5jZW50ZXJlZFNsaWRlcztcblxuICAgIGlmIChpc0NlbnRlcmVkU2xpZGVzKSB7XG4gICAgICBjb25zdCBtYXJnaW4gPSBzbGlkZXNTaXplc0dyaWRbMF0gLyAyIC0gc3dpcGVyLnBhcmFtcy5zbGlkZXNPZmZzZXRCZWZvcmUgfHwgMDtcbiAgICAgICR3cmFwcGVyRWwudHJhbnNmb3JtKGB0cmFuc2xhdGVYKGNhbGMoNTAlIC0gJHttYXJnaW59cHgpKWApO1xuICAgIH1cblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2xpZGVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICBjb25zdCAkc2xpZGVFbCA9IHNsaWRlcy5lcShpKTtcbiAgICAgIGNvbnN0IHNsaWRlUHJvZ3Jlc3MgPSAkc2xpZGVFbFswXS5wcm9ncmVzcztcbiAgICAgIGNvbnN0IHByb2dyZXNzID0gTWF0aC5taW4oTWF0aC5tYXgoJHNsaWRlRWxbMF0ucHJvZ3Jlc3MsIC1wYXJhbXMubGltaXRQcm9ncmVzcyksIHBhcmFtcy5saW1pdFByb2dyZXNzKTtcbiAgICAgIGxldCBvcmlnaW5hbFByb2dyZXNzID0gcHJvZ3Jlc3M7XG5cbiAgICAgIGlmICghaXNDZW50ZXJlZFNsaWRlcykge1xuICAgICAgICBvcmlnaW5hbFByb2dyZXNzID0gTWF0aC5taW4oTWF0aC5tYXgoJHNsaWRlRWxbMF0ub3JpZ2luYWxQcm9ncmVzcywgLXBhcmFtcy5saW1pdFByb2dyZXNzKSwgcGFyYW1zLmxpbWl0UHJvZ3Jlc3MpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBvZmZzZXQgPSAkc2xpZGVFbFswXS5zd2lwZXJTbGlkZU9mZnNldDtcbiAgICAgIGNvbnN0IHQgPSBbc3dpcGVyLnBhcmFtcy5jc3NNb2RlID8gLW9mZnNldCAtIHN3aXBlci50cmFuc2xhdGUgOiAtb2Zmc2V0LCAwLCAwXTtcbiAgICAgIGNvbnN0IHIgPSBbMCwgMCwgMF07XG4gICAgICBsZXQgY3VzdG9tID0gZmFsc2U7XG5cbiAgICAgIGlmICghc3dpcGVyLmlzSG9yaXpvbnRhbCgpKSB7XG4gICAgICAgIHRbMV0gPSB0WzBdO1xuICAgICAgICB0WzBdID0gMDtcbiAgICAgIH1cblxuICAgICAgbGV0IGRhdGEgPSB7XG4gICAgICAgIHRyYW5zbGF0ZTogWzAsIDAsIDBdLFxuICAgICAgICByb3RhdGU6IFswLCAwLCAwXSxcbiAgICAgICAgc2NhbGU6IDEsXG4gICAgICAgIG9wYWNpdHk6IDFcbiAgICAgIH07XG5cbiAgICAgIGlmIChwcm9ncmVzcyA8IDApIHtcbiAgICAgICAgZGF0YSA9IHBhcmFtcy5uZXh0O1xuICAgICAgICBjdXN0b20gPSB0cnVlO1xuICAgICAgfSBlbHNlIGlmIChwcm9ncmVzcyA+IDApIHtcbiAgICAgICAgZGF0YSA9IHBhcmFtcy5wcmV2O1xuICAgICAgICBjdXN0b20gPSB0cnVlO1xuICAgICAgfSAvLyBzZXQgdHJhbnNsYXRlXG5cblxuICAgICAgdC5mb3JFYWNoKCh2YWx1ZSwgaW5kZXgpID0+IHtcbiAgICAgICAgdFtpbmRleF0gPSBgY2FsYygke3ZhbHVlfXB4ICsgKCR7Z2V0VHJhbnNsYXRlVmFsdWUoZGF0YS50cmFuc2xhdGVbaW5kZXhdKX0gKiAke01hdGguYWJzKHByb2dyZXNzICogbXVsdGlwbGllcil9KSlgO1xuICAgICAgfSk7IC8vIHNldCByb3RhdGVzXG5cbiAgICAgIHIuZm9yRWFjaCgodmFsdWUsIGluZGV4KSA9PiB7XG4gICAgICAgIHJbaW5kZXhdID0gZGF0YS5yb3RhdGVbaW5kZXhdICogTWF0aC5hYnMocHJvZ3Jlc3MgKiBtdWx0aXBsaWVyKTtcbiAgICAgIH0pO1xuICAgICAgJHNsaWRlRWxbMF0uc3R5bGUuekluZGV4ID0gLU1hdGguYWJzKE1hdGgucm91bmQoc2xpZGVQcm9ncmVzcykpICsgc2xpZGVzLmxlbmd0aDtcbiAgICAgIGNvbnN0IHRyYW5zbGF0ZVN0cmluZyA9IHQuam9pbignLCAnKTtcbiAgICAgIGNvbnN0IHJvdGF0ZVN0cmluZyA9IGByb3RhdGVYKCR7clswXX1kZWcpIHJvdGF0ZVkoJHtyWzFdfWRlZykgcm90YXRlWigke3JbMl19ZGVnKWA7XG4gICAgICBjb25zdCBzY2FsZVN0cmluZyA9IG9yaWdpbmFsUHJvZ3Jlc3MgPCAwID8gYHNjYWxlKCR7MSArICgxIC0gZGF0YS5zY2FsZSkgKiBvcmlnaW5hbFByb2dyZXNzICogbXVsdGlwbGllcn0pYCA6IGBzY2FsZSgkezEgLSAoMSAtIGRhdGEuc2NhbGUpICogb3JpZ2luYWxQcm9ncmVzcyAqIG11bHRpcGxpZXJ9KWA7XG4gICAgICBjb25zdCBvcGFjaXR5U3RyaW5nID0gb3JpZ2luYWxQcm9ncmVzcyA8IDAgPyAxICsgKDEgLSBkYXRhLm9wYWNpdHkpICogb3JpZ2luYWxQcm9ncmVzcyAqIG11bHRpcGxpZXIgOiAxIC0gKDEgLSBkYXRhLm9wYWNpdHkpICogb3JpZ2luYWxQcm9ncmVzcyAqIG11bHRpcGxpZXI7XG4gICAgICBjb25zdCB0cmFuc2Zvcm0gPSBgdHJhbnNsYXRlM2QoJHt0cmFuc2xhdGVTdHJpbmd9KSAke3JvdGF0ZVN0cmluZ30gJHtzY2FsZVN0cmluZ31gOyAvLyBTZXQgc2hhZG93c1xuXG4gICAgICBpZiAoY3VzdG9tICYmIGRhdGEuc2hhZG93IHx8ICFjdXN0b20pIHtcbiAgICAgICAgbGV0ICRzaGFkb3dFbCA9ICRzbGlkZUVsLmNoaWxkcmVuKCcuc3dpcGVyLXNsaWRlLXNoYWRvdycpO1xuXG4gICAgICAgIGlmICgkc2hhZG93RWwubGVuZ3RoID09PSAwICYmIGRhdGEuc2hhZG93KSB7XG4gICAgICAgICAgJHNoYWRvd0VsID0gY3JlYXRlU2hhZG93KHBhcmFtcywgJHNsaWRlRWwpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCRzaGFkb3dFbC5sZW5ndGgpIHtcbiAgICAgICAgICBjb25zdCBzaGFkb3dPcGFjaXR5ID0gcGFyYW1zLnNoYWRvd1BlclByb2dyZXNzID8gcHJvZ3Jlc3MgKiAoMSAvIHBhcmFtcy5saW1pdFByb2dyZXNzKSA6IHByb2dyZXNzO1xuICAgICAgICAgICRzaGFkb3dFbFswXS5zdHlsZS5vcGFjaXR5ID0gTWF0aC5taW4oTWF0aC5tYXgoTWF0aC5hYnMoc2hhZG93T3BhY2l0eSksIDApLCAxKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCAkdGFyZ2V0RWwgPSBlZmZlY3RUYXJnZXQocGFyYW1zLCAkc2xpZGVFbCk7XG4gICAgICAkdGFyZ2V0RWwudHJhbnNmb3JtKHRyYW5zZm9ybSkuY3NzKHtcbiAgICAgICAgb3BhY2l0eTogb3BhY2l0eVN0cmluZ1xuICAgICAgfSk7XG5cbiAgICAgIGlmIChkYXRhLm9yaWdpbikge1xuICAgICAgICAkdGFyZ2V0RWwuY3NzKCd0cmFuc2Zvcm0tb3JpZ2luJywgZGF0YS5vcmlnaW4pO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICBjb25zdCBzZXRUcmFuc2l0aW9uID0gZHVyYXRpb24gPT4ge1xuICAgIGNvbnN0IHtcbiAgICAgIHRyYW5zZm9ybUVsXG4gICAgfSA9IHN3aXBlci5wYXJhbXMuY3JlYXRpdmVFZmZlY3Q7XG4gICAgY29uc3QgJHRyYW5zaXRpb25FbGVtZW50cyA9IHRyYW5zZm9ybUVsID8gc3dpcGVyLnNsaWRlcy5maW5kKHRyYW5zZm9ybUVsKSA6IHN3aXBlci5zbGlkZXM7XG4gICAgJHRyYW5zaXRpb25FbGVtZW50cy50cmFuc2l0aW9uKGR1cmF0aW9uKS5maW5kKCcuc3dpcGVyLXNsaWRlLXNoYWRvdycpLnRyYW5zaXRpb24oZHVyYXRpb24pO1xuICAgIGVmZmVjdFZpcnR1YWxUcmFuc2l0aW9uRW5kKHtcbiAgICAgIHN3aXBlcixcbiAgICAgIGR1cmF0aW9uLFxuICAgICAgdHJhbnNmb3JtRWwsXG4gICAgICBhbGxTbGlkZXM6IHRydWVcbiAgICB9KTtcbiAgfTtcblxuICBlZmZlY3RJbml0KHtcbiAgICBlZmZlY3Q6ICdjcmVhdGl2ZScsXG4gICAgc3dpcGVyLFxuICAgIG9uLFxuICAgIHNldFRyYW5zbGF0ZSxcbiAgICBzZXRUcmFuc2l0aW9uLFxuICAgIHBlcnNwZWN0aXZlOiAoKSA9PiBzd2lwZXIucGFyYW1zLmNyZWF0aXZlRWZmZWN0LnBlcnNwZWN0aXZlLFxuICAgIG92ZXJ3cml0ZVBhcmFtczogKCkgPT4gKHtcbiAgICAgIHdhdGNoU2xpZGVzUHJvZ3Jlc3M6IHRydWUsXG4gICAgICB2aXJ0dWFsVHJhbnNsYXRlOiAhc3dpcGVyLnBhcmFtcy5jc3NNb2RlXG4gICAgfSlcbiAgfSk7XG59IiwiaW1wb3J0IGNyZWF0ZVNoYWRvdyBmcm9tICcuLi8uLi9zaGFyZWQvY3JlYXRlLXNoYWRvdy5qcyc7XG5pbXBvcnQgZWZmZWN0SW5pdCBmcm9tICcuLi8uLi9zaGFyZWQvZWZmZWN0LWluaXQuanMnO1xuaW1wb3J0IGVmZmVjdFRhcmdldCBmcm9tICcuLi8uLi9zaGFyZWQvZWZmZWN0LXRhcmdldC5qcyc7XG5pbXBvcnQgZWZmZWN0VmlydHVhbFRyYW5zaXRpb25FbmQgZnJvbSAnLi4vLi4vc2hhcmVkL2VmZmVjdC12aXJ0dWFsLXRyYW5zaXRpb24tZW5kLmpzJztcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIEVmZmVjdENhcmRzKHtcbiAgc3dpcGVyLFxuICBleHRlbmRQYXJhbXMsXG4gIG9uXG59KSB7XG4gIGV4dGVuZFBhcmFtcyh7XG4gICAgY2FyZHNFZmZlY3Q6IHtcbiAgICAgIHNsaWRlU2hhZG93czogdHJ1ZSxcbiAgICAgIHRyYW5zZm9ybUVsOiBudWxsLFxuICAgICAgcm90YXRlOiB0cnVlLFxuICAgICAgcGVyU2xpZGVSb3RhdGU6IDIsXG4gICAgICBwZXJTbGlkZU9mZnNldDogOFxuICAgIH1cbiAgfSk7XG5cbiAgY29uc3Qgc2V0VHJhbnNsYXRlID0gKCkgPT4ge1xuICAgIGNvbnN0IHtcbiAgICAgIHNsaWRlcyxcbiAgICAgIGFjdGl2ZUluZGV4XG4gICAgfSA9IHN3aXBlcjtcbiAgICBjb25zdCBwYXJhbXMgPSBzd2lwZXIucGFyYW1zLmNhcmRzRWZmZWN0O1xuICAgIGNvbnN0IHtcbiAgICAgIHN0YXJ0VHJhbnNsYXRlLFxuICAgICAgaXNUb3VjaGVkXG4gICAgfSA9IHN3aXBlci50b3VjaEV2ZW50c0RhdGE7XG4gICAgY29uc3QgY3VycmVudFRyYW5zbGF0ZSA9IHN3aXBlci50cmFuc2xhdGU7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNsaWRlcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgY29uc3QgJHNsaWRlRWwgPSBzbGlkZXMuZXEoaSk7XG4gICAgICBjb25zdCBzbGlkZVByb2dyZXNzID0gJHNsaWRlRWxbMF0ucHJvZ3Jlc3M7XG4gICAgICBjb25zdCBwcm9ncmVzcyA9IE1hdGgubWluKE1hdGgubWF4KHNsaWRlUHJvZ3Jlc3MsIC00KSwgNCk7XG4gICAgICBsZXQgb2Zmc2V0ID0gJHNsaWRlRWxbMF0uc3dpcGVyU2xpZGVPZmZzZXQ7XG5cbiAgICAgIGlmIChzd2lwZXIucGFyYW1zLmNlbnRlcmVkU2xpZGVzICYmICFzd2lwZXIucGFyYW1zLmNzc01vZGUpIHtcbiAgICAgICAgc3dpcGVyLiR3cmFwcGVyRWwudHJhbnNmb3JtKGB0cmFuc2xhdGVYKCR7c3dpcGVyLm1pblRyYW5zbGF0ZSgpfXB4KWApO1xuICAgICAgfVxuXG4gICAgICBpZiAoc3dpcGVyLnBhcmFtcy5jZW50ZXJlZFNsaWRlcyAmJiBzd2lwZXIucGFyYW1zLmNzc01vZGUpIHtcbiAgICAgICAgb2Zmc2V0IC09IHNsaWRlc1swXS5zd2lwZXJTbGlkZU9mZnNldDtcbiAgICAgIH1cblxuICAgICAgbGV0IHRYID0gc3dpcGVyLnBhcmFtcy5jc3NNb2RlID8gLW9mZnNldCAtIHN3aXBlci50cmFuc2xhdGUgOiAtb2Zmc2V0O1xuICAgICAgbGV0IHRZID0gMDtcbiAgICAgIGNvbnN0IHRaID0gLTEwMCAqIE1hdGguYWJzKHByb2dyZXNzKTtcbiAgICAgIGxldCBzY2FsZSA9IDE7XG4gICAgICBsZXQgcm90YXRlID0gLXBhcmFtcy5wZXJTbGlkZVJvdGF0ZSAqIHByb2dyZXNzO1xuICAgICAgbGV0IHRYQWRkID0gcGFyYW1zLnBlclNsaWRlT2Zmc2V0IC0gTWF0aC5hYnMocHJvZ3Jlc3MpICogMC43NTtcbiAgICAgIGNvbnN0IHNsaWRlSW5kZXggPSBzd2lwZXIudmlydHVhbCAmJiBzd2lwZXIucGFyYW1zLnZpcnR1YWwuZW5hYmxlZCA/IHN3aXBlci52aXJ0dWFsLmZyb20gKyBpIDogaTtcbiAgICAgIGNvbnN0IGlzU3dpcGVUb05leHQgPSAoc2xpZGVJbmRleCA9PT0gYWN0aXZlSW5kZXggfHwgc2xpZGVJbmRleCA9PT0gYWN0aXZlSW5kZXggLSAxKSAmJiBwcm9ncmVzcyA+IDAgJiYgcHJvZ3Jlc3MgPCAxICYmIChpc1RvdWNoZWQgfHwgc3dpcGVyLnBhcmFtcy5jc3NNb2RlKSAmJiBjdXJyZW50VHJhbnNsYXRlIDwgc3RhcnRUcmFuc2xhdGU7XG4gICAgICBjb25zdCBpc1N3aXBlVG9QcmV2ID0gKHNsaWRlSW5kZXggPT09IGFjdGl2ZUluZGV4IHx8IHNsaWRlSW5kZXggPT09IGFjdGl2ZUluZGV4ICsgMSkgJiYgcHJvZ3Jlc3MgPCAwICYmIHByb2dyZXNzID4gLTEgJiYgKGlzVG91Y2hlZCB8fCBzd2lwZXIucGFyYW1zLmNzc01vZGUpICYmIGN1cnJlbnRUcmFuc2xhdGUgPiBzdGFydFRyYW5zbGF0ZTtcblxuICAgICAgaWYgKGlzU3dpcGVUb05leHQgfHwgaXNTd2lwZVRvUHJldikge1xuICAgICAgICBjb25zdCBzdWJQcm9ncmVzcyA9ICgxIC0gTWF0aC5hYnMoKE1hdGguYWJzKHByb2dyZXNzKSAtIDAuNSkgLyAwLjUpKSAqKiAwLjU7XG4gICAgICAgIHJvdGF0ZSArPSAtMjggKiBwcm9ncmVzcyAqIHN1YlByb2dyZXNzO1xuICAgICAgICBzY2FsZSArPSAtMC41ICogc3ViUHJvZ3Jlc3M7XG4gICAgICAgIHRYQWRkICs9IDk2ICogc3ViUHJvZ3Jlc3M7XG4gICAgICAgIHRZID0gYCR7LTI1ICogc3ViUHJvZ3Jlc3MgKiBNYXRoLmFicyhwcm9ncmVzcyl9JWA7XG4gICAgICB9XG5cbiAgICAgIGlmIChwcm9ncmVzcyA8IDApIHtcbiAgICAgICAgLy8gbmV4dFxuICAgICAgICB0WCA9IGBjYWxjKCR7dFh9cHggKyAoJHt0WEFkZCAqIE1hdGguYWJzKHByb2dyZXNzKX0lKSlgO1xuICAgICAgfSBlbHNlIGlmIChwcm9ncmVzcyA+IDApIHtcbiAgICAgICAgLy8gcHJldlxuICAgICAgICB0WCA9IGBjYWxjKCR7dFh9cHggKyAoLSR7dFhBZGQgKiBNYXRoLmFicyhwcm9ncmVzcyl9JSkpYDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRYID0gYCR7dFh9cHhgO1xuICAgICAgfVxuXG4gICAgICBpZiAoIXN3aXBlci5pc0hvcml6b250YWwoKSkge1xuICAgICAgICBjb25zdCBwcmV2WSA9IHRZO1xuICAgICAgICB0WSA9IHRYO1xuICAgICAgICB0WCA9IHByZXZZO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzY2FsZVN0cmluZyA9IHByb2dyZXNzIDwgMCA/IGAkezEgKyAoMSAtIHNjYWxlKSAqIHByb2dyZXNzfWAgOiBgJHsxIC0gKDEgLSBzY2FsZSkgKiBwcm9ncmVzc31gO1xuICAgICAgY29uc3QgdHJhbnNmb3JtID0gYFxuICAgICAgICB0cmFuc2xhdGUzZCgke3RYfSwgJHt0WX0sICR7dFp9cHgpXG4gICAgICAgIHJvdGF0ZVooJHtwYXJhbXMucm90YXRlID8gcm90YXRlIDogMH1kZWcpXG4gICAgICAgIHNjYWxlKCR7c2NhbGVTdHJpbmd9KVxuICAgICAgYDtcblxuICAgICAgaWYgKHBhcmFtcy5zbGlkZVNoYWRvd3MpIHtcbiAgICAgICAgLy8gU2V0IHNoYWRvd3NcbiAgICAgICAgbGV0ICRzaGFkb3dFbCA9ICRzbGlkZUVsLmZpbmQoJy5zd2lwZXItc2xpZGUtc2hhZG93Jyk7XG5cbiAgICAgICAgaWYgKCRzaGFkb3dFbC5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAkc2hhZG93RWwgPSBjcmVhdGVTaGFkb3cocGFyYW1zLCAkc2xpZGVFbCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoJHNoYWRvd0VsLmxlbmd0aCkgJHNoYWRvd0VsWzBdLnN0eWxlLm9wYWNpdHkgPSBNYXRoLm1pbihNYXRoLm1heCgoTWF0aC5hYnMocHJvZ3Jlc3MpIC0gMC41KSAvIDAuNSwgMCksIDEpO1xuICAgICAgfVxuXG4gICAgICAkc2xpZGVFbFswXS5zdHlsZS56SW5kZXggPSAtTWF0aC5hYnMoTWF0aC5yb3VuZChzbGlkZVByb2dyZXNzKSkgKyBzbGlkZXMubGVuZ3RoO1xuICAgICAgY29uc3QgJHRhcmdldEVsID0gZWZmZWN0VGFyZ2V0KHBhcmFtcywgJHNsaWRlRWwpO1xuICAgICAgJHRhcmdldEVsLnRyYW5zZm9ybSh0cmFuc2Zvcm0pO1xuICAgIH1cbiAgfTtcblxuICBjb25zdCBzZXRUcmFuc2l0aW9uID0gZHVyYXRpb24gPT4ge1xuICAgIGNvbnN0IHtcbiAgICAgIHRyYW5zZm9ybUVsXG4gICAgfSA9IHN3aXBlci5wYXJhbXMuY2FyZHNFZmZlY3Q7XG4gICAgY29uc3QgJHRyYW5zaXRpb25FbGVtZW50cyA9IHRyYW5zZm9ybUVsID8gc3dpcGVyLnNsaWRlcy5maW5kKHRyYW5zZm9ybUVsKSA6IHN3aXBlci5zbGlkZXM7XG4gICAgJHRyYW5zaXRpb25FbGVtZW50cy50cmFuc2l0aW9uKGR1cmF0aW9uKS5maW5kKCcuc3dpcGVyLXNsaWRlLXNoYWRvdycpLnRyYW5zaXRpb24oZHVyYXRpb24pO1xuICAgIGVmZmVjdFZpcnR1YWxUcmFuc2l0aW9uRW5kKHtcbiAgICAgIHN3aXBlcixcbiAgICAgIGR1cmF0aW9uLFxuICAgICAgdHJhbnNmb3JtRWxcbiAgICB9KTtcbiAgfTtcblxuICBlZmZlY3RJbml0KHtcbiAgICBlZmZlY3Q6ICdjYXJkcycsXG4gICAgc3dpcGVyLFxuICAgIG9uLFxuICAgIHNldFRyYW5zbGF0ZSxcbiAgICBzZXRUcmFuc2l0aW9uLFxuICAgIHBlcnNwZWN0aXZlOiAoKSA9PiB0cnVlLFxuICAgIG92ZXJ3cml0ZVBhcmFtczogKCkgPT4gKHtcbiAgICAgIHdhdGNoU2xpZGVzUHJvZ3Jlc3M6IHRydWUsXG4gICAgICB2aXJ0dWFsVHJhbnNsYXRlOiAhc3dpcGVyLnBhcmFtcy5jc3NNb2RlXG4gICAgfSlcbiAgfSk7XG59IiwiLyoqXG4gKiBTd2lwZXIgOC40LjdcbiAqIE1vc3QgbW9kZXJuIG1vYmlsZSB0b3VjaCBzbGlkZXIgYW5kIGZyYW1ld29yayB3aXRoIGhhcmR3YXJlIGFjY2VsZXJhdGVkIHRyYW5zaXRpb25zXG4gKiBodHRwczovL3N3aXBlcmpzLmNvbVxuICpcbiAqIENvcHlyaWdodCAyMDE0LTIwMjMgVmxhZGltaXIgS2hhcmxhbXBpZGlcbiAqXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2VcbiAqXG4gKiBSZWxlYXNlZCBvbjogSmFudWFyeSAzMCwgMjAyM1xuICovXG5cbmV4cG9ydCB7IGRlZmF1bHQgYXMgU3dpcGVyLCBkZWZhdWx0IH0gZnJvbSAnLi9jb3JlL2NvcmUuanMnO1xuZXhwb3J0IHsgZGVmYXVsdCBhcyBWaXJ0dWFsIH0gZnJvbSAnLi9tb2R1bGVzL3ZpcnR1YWwvdmlydHVhbC5qcyc7XG5leHBvcnQgeyBkZWZhdWx0IGFzIEtleWJvYXJkIH0gZnJvbSAnLi9tb2R1bGVzL2tleWJvYXJkL2tleWJvYXJkLmpzJztcbmV4cG9ydCB7IGRlZmF1bHQgYXMgTW91c2V3aGVlbCB9IGZyb20gJy4vbW9kdWxlcy9tb3VzZXdoZWVsL21vdXNld2hlZWwuanMnO1xuZXhwb3J0IHsgZGVmYXVsdCBhcyBOYXZpZ2F0aW9uIH0gZnJvbSAnLi9tb2R1bGVzL25hdmlnYXRpb24vbmF2aWdhdGlvbi5qcyc7XG5leHBvcnQgeyBkZWZhdWx0IGFzIFBhZ2luYXRpb24gfSBmcm9tICcuL21vZHVsZXMvcGFnaW5hdGlvbi9wYWdpbmF0aW9uLmpzJztcbmV4cG9ydCB7IGRlZmF1bHQgYXMgU2Nyb2xsYmFyIH0gZnJvbSAnLi9tb2R1bGVzL3Njcm9sbGJhci9zY3JvbGxiYXIuanMnO1xuZXhwb3J0IHsgZGVmYXVsdCBhcyBQYXJhbGxheCB9IGZyb20gJy4vbW9kdWxlcy9wYXJhbGxheC9wYXJhbGxheC5qcyc7XG5leHBvcnQgeyBkZWZhdWx0IGFzIFpvb20gfSBmcm9tICcuL21vZHVsZXMvem9vbS96b29tLmpzJztcbmV4cG9ydCB7IGRlZmF1bHQgYXMgTGF6eSB9IGZyb20gJy4vbW9kdWxlcy9sYXp5L2xhenkuanMnO1xuZXhwb3J0IHsgZGVmYXVsdCBhcyBDb250cm9sbGVyIH0gZnJvbSAnLi9tb2R1bGVzL2NvbnRyb2xsZXIvY29udHJvbGxlci5qcyc7XG5leHBvcnQgeyBkZWZhdWx0IGFzIEExMXkgfSBmcm9tICcuL21vZHVsZXMvYTExeS9hMTF5LmpzJztcbmV4cG9ydCB7IGRlZmF1bHQgYXMgSGlzdG9yeSB9IGZyb20gJy4vbW9kdWxlcy9oaXN0b3J5L2hpc3RvcnkuanMnO1xuZXhwb3J0IHsgZGVmYXVsdCBhcyBIYXNoTmF2aWdhdGlvbiB9IGZyb20gJy4vbW9kdWxlcy9oYXNoLW5hdmlnYXRpb24vaGFzaC1uYXZpZ2F0aW9uLmpzJztcbmV4cG9ydCB7IGRlZmF1bHQgYXMgQXV0b3BsYXkgfSBmcm9tICcuL21vZHVsZXMvYXV0b3BsYXkvYXV0b3BsYXkuanMnO1xuZXhwb3J0IHsgZGVmYXVsdCBhcyBUaHVtYnMgfSBmcm9tICcuL21vZHVsZXMvdGh1bWJzL3RodW1icy5qcyc7XG5leHBvcnQgeyBkZWZhdWx0IGFzIEZyZWVNb2RlIH0gZnJvbSAnLi9tb2R1bGVzL2ZyZWUtbW9kZS9mcmVlLW1vZGUuanMnO1xuZXhwb3J0IHsgZGVmYXVsdCBhcyBHcmlkIH0gZnJvbSAnLi9tb2R1bGVzL2dyaWQvZ3JpZC5qcyc7XG5leHBvcnQgeyBkZWZhdWx0IGFzIE1hbmlwdWxhdGlvbiB9IGZyb20gJy4vbW9kdWxlcy9tYW5pcHVsYXRpb24vbWFuaXB1bGF0aW9uLmpzJztcbmV4cG9ydCB7IGRlZmF1bHQgYXMgRWZmZWN0RmFkZSB9IGZyb20gJy4vbW9kdWxlcy9lZmZlY3QtZmFkZS9lZmZlY3QtZmFkZS5qcyc7XG5leHBvcnQgeyBkZWZhdWx0IGFzIEVmZmVjdEN1YmUgfSBmcm9tICcuL21vZHVsZXMvZWZmZWN0LWN1YmUvZWZmZWN0LWN1YmUuanMnO1xuZXhwb3J0IHsgZGVmYXVsdCBhcyBFZmZlY3RGbGlwIH0gZnJvbSAnLi9tb2R1bGVzL2VmZmVjdC1mbGlwL2VmZmVjdC1mbGlwLmpzJztcbmV4cG9ydCB7IGRlZmF1bHQgYXMgRWZmZWN0Q292ZXJmbG93IH0gZnJvbSAnLi9tb2R1bGVzL2VmZmVjdC1jb3ZlcmZsb3cvZWZmZWN0LWNvdmVyZmxvdy5qcyc7XG5leHBvcnQgeyBkZWZhdWx0IGFzIEVmZmVjdENyZWF0aXZlIH0gZnJvbSAnLi9tb2R1bGVzL2VmZmVjdC1jcmVhdGl2ZS9lZmZlY3QtY3JlYXRpdmUuanMnO1xuZXhwb3J0IHsgZGVmYXVsdCBhcyBFZmZlY3RDYXJkcyB9IGZyb20gJy4vbW9kdWxlcy9lZmZlY3QtY2FyZHMvZWZmZWN0LWNhcmRzLmpzJzsiLCIvL1ZlbmRvciBzY3JpcHRzXG5pbXBvcnQgc3dpcGVyLCB7IE5hdmlnYXRpb24gfSBmcm9tICdzd2lwZXInO1xuc3dpcGVyLnVzZShbTmF2aWdhdGlvbl0pO1xuY29uc3QgdncgPSB3aW5kb3cub3V0ZXJXaWR0aDtcbmxldCBzbGlkZXNNYXJrdXAgPSAnJztcbmxldCBzbGlkZXJJbml0O1xuY29uc3Qgc3dpcGVyQ29udGFpbmVyID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnNlY3Rpb25TbGlkZXJfc2xpZGVyJyk7XG5jb25zdCBzbGlkZUNsaWNrID0gKCkgPT4ge1xuICBjb25zdCBzd2lwZXJzbGlkZXMgPSBzd2lwZXJDb250YWluZXIucXVlcnlTZWxlY3RvckFsbCgnLnN3aXBlci1zbGlkZScpO1xuICBzd2lwZXJzbGlkZXMuZm9yRWFjaChzbGlkZSA9PiB7XG4gICAgY29uc3Qgc2xpZGVMaW5rID0gc2xpZGUucXVlcnlTZWxlY3RvcignLnNlY3Rpb25TbGlkZXJfc2xpZGVyLWxpbmsnKTtcbiAgICBzbGlkZS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsICgpID0+IHtcbiAgICAgIHNsaWRlTGluay5jbGljaygpO1xuICAgIH0pO1xuICB9KTtcbn07XG5jb25zdCBzd2lwZXJJbml0ID0gKCkgPT4ge1xuICBzbGlkZXJJbml0ID0gbmV3IHN3aXBlcihzd2lwZXJDb250YWluZXIsIHtcbiAgICBzbGlkZXNQZXJWaWV3OiAxLjIsXG4gICAgc3BhY2VCZXR3ZWVuOiAzMixcbiAgICAvLyBzaW11bGF0ZVRvdWNoOiBmYWxzZSxcbiAgICBicmVha3BvaW50czoge1xuICAgICAgNjQwOiB7XG4gICAgICAgIHNsaWRlc1BlclZpZXc6IDNcbiAgICAgIH0sXG4gICAgICA5OTI6IHtcbiAgICAgICAgc2xpZGVzUGVyVmlldzogNVxuICAgICAgfVxuICAgIH0sXG4gICAgbmF2aWdhdGlvbjoge1xuICAgICAgcHJldkVsOiAnLnNlY3Rpb25TbGlkZXJfc2xpZGVyLW5hdmlnYXRpb24tLXByZXYnLFxuICAgICAgbmV4dEVsOiAnLnNlY3Rpb25TbGlkZXJfc2xpZGVyLW5hdmlnYXRpb24tLW5leHQnLFxuICAgICAgZGlzYWJsZWRDbGFzczogJ2Rpc2FibGVkLWFycm93J1xuICAgIH0sXG4gICAgb246IHtcbiAgICAgIGluaXQ6IHNsaWRlQ2xpY2soKVxuICAgIH1cbiAgfSk7XG59O1xuaWYgKHN3aXBlckNvbnRhaW5lcikge1xuICBzd2lwZXJJbml0KCk7XG59IiwiLy9NYWluIHN0eWxlc1xuaW1wb3J0IFwiQmFzZVVybC9tYWluLnNjc3NcIjtcbi8vVmVuZG9yIHNjcmlwdHNcbmltcG9ydCAnbGF6eXNpemVzJztcbi8vQ29tbW9uIHNjcmlwdHNcbmltcG9ydCBcIkFzc2V0cy9qcy9jb21tb25cIjtcbi8vQ29tcG9uZW50cyBzY3JpcHRzXG5pbXBvcnQgXCJDb21wb25lbnRzL25hdmJhci9uYXZiYXJcIjtcbmltcG9ydCBcIkNvbXBvbmVudHMvdmlzdWFsL3Zpc3VhbFwiO1xuaW1wb3J0IFwiQ29tcG9uZW50cy9hbHRlcm5hdGUvYWx0ZXJuYXRlXCI7XG5pbXBvcnQgXCJDb21wb25lbnRzL21hcC9tYXBcIjtcbmltcG9ydCBcIkNvbXBvbmVudHMvc2xpZGVyL3NsaWRlclwiO1xuaW1wb3J0IFwiQ29tcG9uZW50cy9jcmVkaXRzL2NyZWRpdHNcIjtcbmltcG9ydCBcIkNvbXBvbmVudHMvY2hhcHRlci9jaGFwdGVyXCI7Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///848\n")},7:module=>{"use strict";eval("// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n\nvar R = typeof Reflect === 'object' ? Reflect : null\nvar ReflectApply = R && typeof R.apply === 'function'\n ? R.apply\n : function ReflectApply(target, receiver, args) {\n return Function.prototype.apply.call(target, receiver, args);\n }\n\nvar ReflectOwnKeys\nif (R && typeof R.ownKeys === 'function') {\n ReflectOwnKeys = R.ownKeys\n} else if (Object.getOwnPropertySymbols) {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target)\n .concat(Object.getOwnPropertySymbols(target));\n };\n} else {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target);\n };\n}\n\nfunction ProcessEmitWarning(warning) {\n if (console && console.warn) console.warn(warning);\n}\n\nvar NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {\n return value !== value;\n}\n\nfunction EventEmitter() {\n EventEmitter.init.call(this);\n}\nmodule.exports = EventEmitter;\nmodule.exports.once = once;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._eventsCount = 0;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nvar defaultMaxListeners = 10;\n\nfunction checkListener(listener) {\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n}\n\nObject.defineProperty(EventEmitter, 'defaultMaxListeners', {\n enumerable: true,\n get: function() {\n return defaultMaxListeners;\n },\n set: function(arg) {\n if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {\n throw new RangeError('The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received ' + arg + '.');\n }\n defaultMaxListeners = arg;\n }\n});\n\nEventEmitter.init = function() {\n\n if (this._events === undefined ||\n this._events === Object.getPrototypeOf(this)._events) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n }\n\n this._maxListeners = this._maxListeners || undefined;\n};\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {\n if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {\n throw new RangeError('The value of \"n\" is out of range. It must be a non-negative number. Received ' + n + '.');\n }\n this._maxListeners = n;\n return this;\n};\n\nfunction _getMaxListeners(that) {\n if (that._maxListeners === undefined)\n return EventEmitter.defaultMaxListeners;\n return that._maxListeners;\n}\n\nEventEmitter.prototype.getMaxListeners = function getMaxListeners() {\n return _getMaxListeners(this);\n};\n\nEventEmitter.prototype.emit = function emit(type) {\n var args = [];\n for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);\n var doError = (type === 'error');\n\n var events = this._events;\n if (events !== undefined)\n doError = (doError && events.error === undefined);\n else if (!doError)\n return false;\n\n // If there is no 'error' event listener then throw.\n if (doError) {\n var er;\n if (args.length > 0)\n er = args[0];\n if (er instanceof Error) {\n // Note: The comments on the `throw` lines are intentional, they show\n // up in Node's output if this results in an unhandled exception.\n throw er; // Unhandled 'error' event\n }\n // At least give some kind of context to the user\n var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));\n err.context = er;\n throw err; // Unhandled 'error' event\n }\n\n var handler = events[type];\n\n if (handler === undefined)\n return false;\n\n if (typeof handler === 'function') {\n ReflectApply(handler, this, args);\n } else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n ReflectApply(listeners[i], this, args);\n }\n\n return true;\n};\n\nfunction _addListener(target, type, listener, prepend) {\n var m;\n var events;\n var existing;\n\n checkListener(listener);\n\n events = target._events;\n if (events === undefined) {\n events = target._events = Object.create(null);\n target._eventsCount = 0;\n } else {\n // To avoid recursion in the case that type === \"newListener\"! Before\n // adding it to the listeners, first emit \"newListener\".\n if (events.newListener !== undefined) {\n target.emit('newListener', type,\n listener.listener ? listener.listener : listener);\n\n // Re-assign `events` because a newListener handler could have caused the\n // this._events to be assigned to a new object\n events = target._events;\n }\n existing = events[type];\n }\n\n if (existing === undefined) {\n // Optimize the case of one listener. Don't need the extra array object.\n existing = events[type] = listener;\n ++target._eventsCount;\n } else {\n if (typeof existing === 'function') {\n // Adding the second element, need to change to array.\n existing = events[type] =\n prepend ? [listener, existing] : [existing, listener];\n // If we've already got an array, just append.\n } else if (prepend) {\n existing.unshift(listener);\n } else {\n existing.push(listener);\n }\n\n // Check for listener leak\n m = _getMaxListeners(target);\n if (m > 0 && existing.length > m && !existing.warned) {\n existing.warned = true;\n // No error code for this since it is a Warning\n // eslint-disable-next-line no-restricted-syntax\n var w = new Error('Possible EventEmitter memory leak detected. ' +\n existing.length + ' ' + String(type) + ' listeners ' +\n 'added. Use emitter.setMaxListeners() to ' +\n 'increase limit');\n w.name = 'MaxListenersExceededWarning';\n w.emitter = target;\n w.type = type;\n w.count = existing.length;\n ProcessEmitWarning(w);\n }\n }\n\n return target;\n}\n\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n return _addListener(this, type, listener, false);\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.prependListener =\n function prependListener(type, listener) {\n return _addListener(this, type, listener, true);\n };\n\nfunction onceWrapper() {\n if (!this.fired) {\n this.target.removeListener(this.type, this.wrapFn);\n this.fired = true;\n if (arguments.length === 0)\n return this.listener.call(this.target);\n return this.listener.apply(this.target, arguments);\n }\n}\n\nfunction _onceWrap(target, type, listener) {\n var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };\n var wrapped = onceWrapper.bind(state);\n wrapped.listener = listener;\n state.wrapFn = wrapped;\n return wrapped;\n}\n\nEventEmitter.prototype.once = function once(type, listener) {\n checkListener(listener);\n this.on(type, _onceWrap(this, type, listener));\n return this;\n};\n\nEventEmitter.prototype.prependOnceListener =\n function prependOnceListener(type, listener) {\n checkListener(listener);\n this.prependListener(type, _onceWrap(this, type, listener));\n return this;\n };\n\n// Emits a 'removeListener' event if and only if the listener was removed.\nEventEmitter.prototype.removeListener =\n function removeListener(type, listener) {\n var list, events, position, i, originalListener;\n\n checkListener(listener);\n\n events = this._events;\n if (events === undefined)\n return this;\n\n list = events[type];\n if (list === undefined)\n return this;\n\n if (list === listener || list.listener === listener) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else {\n delete events[type];\n if (events.removeListener)\n this.emit('removeListener', type, list.listener || listener);\n }\n } else if (typeof list !== 'function') {\n position = -1;\n\n for (i = list.length - 1; i >= 0; i--) {\n if (list[i] === listener || list[i].listener === listener) {\n originalListener = list[i].listener;\n position = i;\n break;\n }\n }\n\n if (position < 0)\n return this;\n\n if (position === 0)\n list.shift();\n else {\n spliceOne(list, position);\n }\n\n if (list.length === 1)\n events[type] = list[0];\n\n if (events.removeListener !== undefined)\n this.emit('removeListener', type, originalListener || listener);\n }\n\n return this;\n };\n\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\n\nEventEmitter.prototype.removeAllListeners =\n function removeAllListeners(type) {\n var listeners, events, i;\n\n events = this._events;\n if (events === undefined)\n return this;\n\n // not listening for removeListener, no need to emit\n if (events.removeListener === undefined) {\n if (arguments.length === 0) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n } else if (events[type] !== undefined) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else\n delete events[type];\n }\n return this;\n }\n\n // emit removeListener for all listeners on all events\n if (arguments.length === 0) {\n var keys = Object.keys(events);\n var key;\n for (i = 0; i < keys.length; ++i) {\n key = keys[i];\n if (key === 'removeListener') continue;\n this.removeAllListeners(key);\n }\n this.removeAllListeners('removeListener');\n this._events = Object.create(null);\n this._eventsCount = 0;\n return this;\n }\n\n listeners = events[type];\n\n if (typeof listeners === 'function') {\n this.removeListener(type, listeners);\n } else if (listeners !== undefined) {\n // LIFO order\n for (i = listeners.length - 1; i >= 0; i--) {\n this.removeListener(type, listeners[i]);\n }\n }\n\n return this;\n };\n\nfunction _listeners(target, type, unwrap) {\n var events = target._events;\n\n if (events === undefined)\n return [];\n\n var evlistener = events[type];\n if (evlistener === undefined)\n return [];\n\n if (typeof evlistener === 'function')\n return unwrap ? [evlistener.listener || evlistener] : [evlistener];\n\n return unwrap ?\n unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);\n}\n\nEventEmitter.prototype.listeners = function listeners(type) {\n return _listeners(this, type, true);\n};\n\nEventEmitter.prototype.rawListeners = function rawListeners(type) {\n return _listeners(this, type, false);\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n if (typeof emitter.listenerCount === 'function') {\n return emitter.listenerCount(type);\n } else {\n return listenerCount.call(emitter, type);\n }\n};\n\nEventEmitter.prototype.listenerCount = listenerCount;\nfunction listenerCount(type) {\n var events = this._events;\n\n if (events !== undefined) {\n var evlistener = events[type];\n\n if (typeof evlistener === 'function') {\n return 1;\n } else if (evlistener !== undefined) {\n return evlistener.length;\n }\n }\n\n return 0;\n}\n\nEventEmitter.prototype.eventNames = function eventNames() {\n return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];\n};\n\nfunction arrayClone(arr, n) {\n var copy = new Array(n);\n for (var i = 0; i < n; ++i)\n copy[i] = arr[i];\n return copy;\n}\n\nfunction spliceOne(list, index) {\n for (; index + 1 < list.length; index++)\n list[index] = list[index + 1];\n list.pop();\n}\n\nfunction unwrapListeners(arr) {\n var ret = new Array(arr.length);\n for (var i = 0; i < ret.length; ++i) {\n ret[i] = arr[i].listener || arr[i];\n }\n return ret;\n}\n\nfunction once(emitter, name) {\n return new Promise(function (resolve, reject) {\n function errorListener(err) {\n emitter.removeListener(name, resolver);\n reject(err);\n }\n\n function resolver() {\n if (typeof emitter.removeListener === 'function') {\n emitter.removeListener('error', errorListener);\n }\n resolve([].slice.call(arguments));\n };\n\n eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });\n if (name !== 'error') {\n addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });\n }\n });\n}\n\nfunction addErrorHandlerIfEventEmitter(emitter, handler, flags) {\n if (typeof emitter.on === 'function') {\n eventTargetAgnosticAddListener(emitter, 'error', handler, flags);\n }\n}\n\nfunction eventTargetAgnosticAddListener(emitter, name, listener, flags) {\n if (typeof emitter.on === 'function') {\n if (flags.once) {\n emitter.once(name, listener);\n } else {\n emitter.on(name, listener);\n }\n } else if (typeof emitter.addEventListener === 'function') {\n // EventTarget does not have `error` event semantics like Node\n // EventEmitters, we do not listen for `error` events here.\n emitter.addEventListener(name, function wrapListener(arg) {\n // IE does not have builtin `{ once: true }` support so we\n // have to do it manually.\n if (flags.once) {\n emitter.removeEventListener(name, wrapListener);\n }\n listener(arg);\n });\n } else {\n throw new TypeError('The \"emitter\" argument must be of type EventEmitter. Received type ' + typeof emitter);\n }\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNy5qcyIsIm1hcHBpbmdzIjoiQUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9ldmVudHMvZXZlbnRzLmpzP2ZhYTEiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IEpveWVudCwgSW5jLiBhbmQgb3RoZXIgTm9kZSBjb250cmlidXRvcnMuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGFcbi8vIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGVcbi8vIFwiU29mdHdhcmVcIiksIHRvIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZ1xuLy8gd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLFxuLy8gZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdFxuLy8gcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlXG4vLyBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZFxuLy8gaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTU1xuLy8gT1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRlxuLy8gTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTlxuLy8gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sXG4vLyBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1Jcbi8vIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEVcbi8vIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIFIgPSB0eXBlb2YgUmVmbGVjdCA9PT0gJ29iamVjdCcgPyBSZWZsZWN0IDogbnVsbFxudmFyIFJlZmxlY3RBcHBseSA9IFIgJiYgdHlwZW9mIFIuYXBwbHkgPT09ICdmdW5jdGlvbidcbiAgPyBSLmFwcGx5XG4gIDogZnVuY3Rpb24gUmVmbGVjdEFwcGx5KHRhcmdldCwgcmVjZWl2ZXIsIGFyZ3MpIHtcbiAgICByZXR1cm4gRnVuY3Rpb24ucHJvdG90eXBlLmFwcGx5LmNhbGwodGFyZ2V0LCByZWNlaXZlciwgYXJncyk7XG4gIH1cblxudmFyIFJlZmxlY3RPd25LZXlzXG5pZiAoUiAmJiB0eXBlb2YgUi5vd25LZXlzID09PSAnZnVuY3Rpb24nKSB7XG4gIFJlZmxlY3RPd25LZXlzID0gUi5vd25LZXlzXG59IGVsc2UgaWYgKE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMpIHtcbiAgUmVmbGVjdE93bktleXMgPSBmdW5jdGlvbiBSZWZsZWN0T3duS2V5cyh0YXJnZXQpIHtcbiAgICByZXR1cm4gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXModGFyZ2V0KVxuICAgICAgLmNvbmNhdChPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKHRhcmdldCkpO1xuICB9O1xufSBlbHNlIHtcbiAgUmVmbGVjdE93bktleXMgPSBmdW5jdGlvbiBSZWZsZWN0T3duS2V5cyh0YXJnZXQpIHtcbiAgICByZXR1cm4gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXModGFyZ2V0KTtcbiAgfTtcbn1cblxuZnVuY3Rpb24gUHJvY2Vzc0VtaXRXYXJuaW5nKHdhcm5pbmcpIHtcbiAgaWYgKGNvbnNvbGUgJiYgY29uc29sZS53YXJuKSBjb25zb2xlLndhcm4od2FybmluZyk7XG59XG5cbnZhciBOdW1iZXJJc05hTiA9IE51bWJlci5pc05hTiB8fCBmdW5jdGlvbiBOdW1iZXJJc05hTih2YWx1ZSkge1xuICByZXR1cm4gdmFsdWUgIT09IHZhbHVlO1xufVxuXG5mdW5jdGlvbiBFdmVudEVtaXR0ZXIoKSB7XG4gIEV2ZW50RW1pdHRlci5pbml0LmNhbGwodGhpcyk7XG59XG5tb2R1bGUuZXhwb3J0cyA9IEV2ZW50RW1pdHRlcjtcbm1vZHVsZS5leHBvcnRzLm9uY2UgPSBvbmNlO1xuXG4vLyBCYWNrd2FyZHMtY29tcGF0IHdpdGggbm9kZSAwLjEwLnhcbkV2ZW50RW1pdHRlci5FdmVudEVtaXR0ZXIgPSBFdmVudEVtaXR0ZXI7XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuX2V2ZW50cyA9IHVuZGVmaW5lZDtcbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuX2V2ZW50c0NvdW50ID0gMDtcbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuX21heExpc3RlbmVycyA9IHVuZGVmaW5lZDtcblxuLy8gQnkgZGVmYXVsdCBFdmVudEVtaXR0ZXJzIHdpbGwgcHJpbnQgYSB3YXJuaW5nIGlmIG1vcmUgdGhhbiAxMCBsaXN0ZW5lcnMgYXJlXG4vLyBhZGRlZCB0byBpdC4gVGhpcyBpcyBhIHVzZWZ1bCBkZWZhdWx0IHdoaWNoIGhlbHBzIGZpbmRpbmcgbWVtb3J5IGxlYWtzLlxudmFyIGRlZmF1bHRNYXhMaXN0ZW5lcnMgPSAxMDtcblxuZnVuY3Rpb24gY2hlY2tMaXN0ZW5lcihsaXN0ZW5lcikge1xuICBpZiAodHlwZW9mIGxpc3RlbmVyICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignVGhlIFwibGlzdGVuZXJcIiBhcmd1bWVudCBtdXN0IGJlIG9mIHR5cGUgRnVuY3Rpb24uIFJlY2VpdmVkIHR5cGUgJyArIHR5cGVvZiBsaXN0ZW5lcik7XG4gIH1cbn1cblxuT2JqZWN0LmRlZmluZVByb3BlcnR5KEV2ZW50RW1pdHRlciwgJ2RlZmF1bHRNYXhMaXN0ZW5lcnMnLCB7XG4gIGVudW1lcmFibGU6IHRydWUsXG4gIGdldDogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIGRlZmF1bHRNYXhMaXN0ZW5lcnM7XG4gIH0sXG4gIHNldDogZnVuY3Rpb24oYXJnKSB7XG4gICAgaWYgKHR5cGVvZiBhcmcgIT09ICdudW1iZXInIHx8IGFyZyA8IDAgfHwgTnVtYmVySXNOYU4oYXJnKSkge1xuICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1RoZSB2YWx1ZSBvZiBcImRlZmF1bHRNYXhMaXN0ZW5lcnNcIiBpcyBvdXQgb2YgcmFuZ2UuIEl0IG11c3QgYmUgYSBub24tbmVnYXRpdmUgbnVtYmVyLiBSZWNlaXZlZCAnICsgYXJnICsgJy4nKTtcbiAgICB9XG4gICAgZGVmYXVsdE1heExpc3RlbmVycyA9IGFyZztcbiAgfVxufSk7XG5cbkV2ZW50RW1pdHRlci5pbml0ID0gZnVuY3Rpb24oKSB7XG5cbiAgaWYgKHRoaXMuX2V2ZW50cyA9PT0gdW5kZWZpbmVkIHx8XG4gICAgICB0aGlzLl9ldmVudHMgPT09IE9iamVjdC5nZXRQcm90b3R5cGVPZih0aGlzKS5fZXZlbnRzKSB7XG4gICAgdGhpcy5fZXZlbnRzID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcbiAgICB0aGlzLl9ldmVudHNDb3VudCA9IDA7XG4gIH1cblxuICB0aGlzLl9tYXhMaXN0ZW5lcnMgPSB0aGlzLl9tYXhMaXN0ZW5lcnMgfHwgdW5kZWZpbmVkO1xufTtcblxuLy8gT2J2aW91c2x5IG5vdCBhbGwgRW1pdHRlcnMgc2hvdWxkIGJlIGxpbWl0ZWQgdG8gMTAuIFRoaXMgZnVuY3Rpb24gYWxsb3dzXG4vLyB0aGF0IHRvIGJlIGluY3JlYXNlZC4gU2V0IHRvIHplcm8gZm9yIHVubGltaXRlZC5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuc2V0TWF4TGlzdGVuZXJzID0gZnVuY3Rpb24gc2V0TWF4TGlzdGVuZXJzKG4pIHtcbiAgaWYgKHR5cGVvZiBuICE9PSAnbnVtYmVyJyB8fCBuIDwgMCB8fCBOdW1iZXJJc05hTihuKSkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdUaGUgdmFsdWUgb2YgXCJuXCIgaXMgb3V0IG9mIHJhbmdlLiBJdCBtdXN0IGJlIGEgbm9uLW5lZ2F0aXZlIG51bWJlci4gUmVjZWl2ZWQgJyArIG4gKyAnLicpO1xuICB9XG4gIHRoaXMuX21heExpc3RlbmVycyA9IG47XG4gIHJldHVybiB0aGlzO1xufTtcblxuZnVuY3Rpb24gX2dldE1heExpc3RlbmVycyh0aGF0KSB7XG4gIGlmICh0aGF0Ll9tYXhMaXN0ZW5lcnMgPT09IHVuZGVmaW5lZClcbiAgICByZXR1cm4gRXZlbnRFbWl0dGVyLmRlZmF1bHRNYXhMaXN0ZW5lcnM7XG4gIHJldHVybiB0aGF0Ll9tYXhMaXN0ZW5lcnM7XG59XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuZ2V0TWF4TGlzdGVuZXJzID0gZnVuY3Rpb24gZ2V0TWF4TGlzdGVuZXJzKCkge1xuICByZXR1cm4gX2dldE1heExpc3RlbmVycyh0aGlzKTtcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuZW1pdCA9IGZ1bmN0aW9uIGVtaXQodHlwZSkge1xuICB2YXIgYXJncyA9IFtdO1xuICBmb3IgKHZhciBpID0gMTsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykgYXJncy5wdXNoKGFyZ3VtZW50c1tpXSk7XG4gIHZhciBkb0Vycm9yID0gKHR5cGUgPT09ICdlcnJvcicpO1xuXG4gIHZhciBldmVudHMgPSB0aGlzLl9ldmVudHM7XG4gIGlmIChldmVudHMgIT09IHVuZGVmaW5lZClcbiAgICBkb0Vycm9yID0gKGRvRXJyb3IgJiYgZXZlbnRzLmVycm9yID09PSB1bmRlZmluZWQpO1xuICBlbHNlIGlmICghZG9FcnJvcilcbiAgICByZXR1cm4gZmFsc2U7XG5cbiAgLy8gSWYgdGhlcmUgaXMgbm8gJ2Vycm9yJyBldmVudCBsaXN0ZW5lciB0aGVuIHRocm93LlxuICBpZiAoZG9FcnJvcikge1xuICAgIHZhciBlcjtcbiAgICBpZiAoYXJncy5sZW5ndGggPiAwKVxuICAgICAgZXIgPSBhcmdzWzBdO1xuICAgIGlmIChlciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICAvLyBOb3RlOiBUaGUgY29tbWVudHMgb24gdGhlIGB0aHJvd2AgbGluZXMgYXJlIGludGVudGlvbmFsLCB0aGV5IHNob3dcbiAgICAgIC8vIHVwIGluIE5vZGUncyBvdXRwdXQgaWYgdGhpcyByZXN1bHRzIGluIGFuIHVuaGFuZGxlZCBleGNlcHRpb24uXG4gICAgICB0aHJvdyBlcjsgLy8gVW5oYW5kbGVkICdlcnJvcicgZXZlbnRcbiAgICB9XG4gICAgLy8gQXQgbGVhc3QgZ2l2ZSBzb21lIGtpbmQgb2YgY29udGV4dCB0byB0aGUgdXNlclxuICAgIHZhciBlcnIgPSBuZXcgRXJyb3IoJ1VuaGFuZGxlZCBlcnJvci4nICsgKGVyID8gJyAoJyArIGVyLm1lc3NhZ2UgKyAnKScgOiAnJykpO1xuICAgIGVyci5jb250ZXh0ID0gZXI7XG4gICAgdGhyb3cgZXJyOyAvLyBVbmhhbmRsZWQgJ2Vycm9yJyBldmVudFxuICB9XG5cbiAgdmFyIGhhbmRsZXIgPSBldmVudHNbdHlwZV07XG5cbiAgaWYgKGhhbmRsZXIgPT09IHVuZGVmaW5lZClcbiAgICByZXR1cm4gZmFsc2U7XG5cbiAgaWYgKHR5cGVvZiBoYW5kbGVyID09PSAnZnVuY3Rpb24nKSB7XG4gICAgUmVmbGVjdEFwcGx5KGhhbmRsZXIsIHRoaXMsIGFyZ3MpO1xuICB9IGVsc2Uge1xuICAgIHZhciBsZW4gPSBoYW5kbGVyLmxlbmd0aDtcbiAgICB2YXIgbGlzdGVuZXJzID0gYXJyYXlDbG9uZShoYW5kbGVyLCBsZW4pO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuOyArK2kpXG4gICAgICBSZWZsZWN0QXBwbHkobGlzdGVuZXJzW2ldLCB0aGlzLCBhcmdzKTtcbiAgfVxuXG4gIHJldHVybiB0cnVlO1xufTtcblxuZnVuY3Rpb24gX2FkZExpc3RlbmVyKHRhcmdldCwgdHlwZSwgbGlzdGVuZXIsIHByZXBlbmQpIHtcbiAgdmFyIG07XG4gIHZhciBldmVudHM7XG4gIHZhciBleGlzdGluZztcblxuICBjaGVja0xpc3RlbmVyKGxpc3RlbmVyKTtcblxuICBldmVudHMgPSB0YXJnZXQuX2V2ZW50cztcbiAgaWYgKGV2ZW50cyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgZXZlbnRzID0gdGFyZ2V0Ll9ldmVudHMgPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuICAgIHRhcmdldC5fZXZlbnRzQ291bnQgPSAwO1xuICB9IGVsc2Uge1xuICAgIC8vIFRvIGF2b2lkIHJlY3Vyc2lvbiBpbiB0aGUgY2FzZSB0aGF0IHR5cGUgPT09IFwibmV3TGlzdGVuZXJcIiEgQmVmb3JlXG4gICAgLy8gYWRkaW5nIGl0IHRvIHRoZSBsaXN0ZW5lcnMsIGZpcnN0IGVtaXQgXCJuZXdMaXN0ZW5lclwiLlxuICAgIGlmIChldmVudHMubmV3TGlzdGVuZXIgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGFyZ2V0LmVtaXQoJ25ld0xpc3RlbmVyJywgdHlwZSxcbiAgICAgICAgICAgICAgICAgIGxpc3RlbmVyLmxpc3RlbmVyID8gbGlzdGVuZXIubGlzdGVuZXIgOiBsaXN0ZW5lcik7XG5cbiAgICAgIC8vIFJlLWFzc2lnbiBgZXZlbnRzYCBiZWNhdXNlIGEgbmV3TGlzdGVuZXIgaGFuZGxlciBjb3VsZCBoYXZlIGNhdXNlZCB0aGVcbiAgICAgIC8vIHRoaXMuX2V2ZW50cyB0byBiZSBhc3NpZ25lZCB0byBhIG5ldyBvYmplY3RcbiAgICAgIGV2ZW50cyA9IHRhcmdldC5fZXZlbnRzO1xuICAgIH1cbiAgICBleGlzdGluZyA9IGV2ZW50c1t0eXBlXTtcbiAgfVxuXG4gIGlmIChleGlzdGluZyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgLy8gT3B0aW1pemUgdGhlIGNhc2Ugb2Ygb25lIGxpc3RlbmVyLiBEb24ndCBuZWVkIHRoZSBleHRyYSBhcnJheSBvYmplY3QuXG4gICAgZXhpc3RpbmcgPSBldmVudHNbdHlwZV0gPSBsaXN0ZW5lcjtcbiAgICArK3RhcmdldC5fZXZlbnRzQ291bnQ7XG4gIH0gZWxzZSB7XG4gICAgaWYgKHR5cGVvZiBleGlzdGluZyA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgLy8gQWRkaW5nIHRoZSBzZWNvbmQgZWxlbWVudCwgbmVlZCB0byBjaGFuZ2UgdG8gYXJyYXkuXG4gICAgICBleGlzdGluZyA9IGV2ZW50c1t0eXBlXSA9XG4gICAgICAgIHByZXBlbmQgPyBbbGlzdGVuZXIsIGV4aXN0aW5nXSA6IFtleGlzdGluZywgbGlzdGVuZXJdO1xuICAgICAgLy8gSWYgd2UndmUgYWxyZWFkeSBnb3QgYW4gYXJyYXksIGp1c3QgYXBwZW5kLlxuICAgIH0gZWxzZSBpZiAocHJlcGVuZCkge1xuICAgICAgZXhpc3RpbmcudW5zaGlmdChsaXN0ZW5lcik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGV4aXN0aW5nLnB1c2gobGlzdGVuZXIpO1xuICAgIH1cblxuICAgIC8vIENoZWNrIGZvciBsaXN0ZW5lciBsZWFrXG4gICAgbSA9IF9nZXRNYXhMaXN0ZW5lcnModGFyZ2V0KTtcbiAgICBpZiAobSA+IDAgJiYgZXhpc3RpbmcubGVuZ3RoID4gbSAmJiAhZXhpc3Rpbmcud2FybmVkKSB7XG4gICAgICBleGlzdGluZy53YXJuZWQgPSB0cnVlO1xuICAgICAgLy8gTm8gZXJyb3IgY29kZSBmb3IgdGhpcyBzaW5jZSBpdCBpcyBhIFdhcm5pbmdcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1yZXN0cmljdGVkLXN5bnRheFxuICAgICAgdmFyIHcgPSBuZXcgRXJyb3IoJ1Bvc3NpYmxlIEV2ZW50RW1pdHRlciBtZW1vcnkgbGVhayBkZXRlY3RlZC4gJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGV4aXN0aW5nLmxlbmd0aCArICcgJyArIFN0cmluZyh0eXBlKSArICcgbGlzdGVuZXJzICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAnYWRkZWQuIFVzZSBlbWl0dGVyLnNldE1heExpc3RlbmVycygpIHRvICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAnaW5jcmVhc2UgbGltaXQnKTtcbiAgICAgIHcubmFtZSA9ICdNYXhMaXN0ZW5lcnNFeGNlZWRlZFdhcm5pbmcnO1xuICAgICAgdy5lbWl0dGVyID0gdGFyZ2V0O1xuICAgICAgdy50eXBlID0gdHlwZTtcbiAgICAgIHcuY291bnQgPSBleGlzdGluZy5sZW5ndGg7XG4gICAgICBQcm9jZXNzRW1pdFdhcm5pbmcodyk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRhcmdldDtcbn1cblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5hZGRMaXN0ZW5lciA9IGZ1bmN0aW9uIGFkZExpc3RlbmVyKHR5cGUsIGxpc3RlbmVyKSB7XG4gIHJldHVybiBfYWRkTGlzdGVuZXIodGhpcywgdHlwZSwgbGlzdGVuZXIsIGZhbHNlKTtcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub24gPSBFdmVudEVtaXR0ZXIucHJvdG90eXBlLmFkZExpc3RlbmVyO1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLnByZXBlbmRMaXN0ZW5lciA9XG4gICAgZnVuY3Rpb24gcHJlcGVuZExpc3RlbmVyKHR5cGUsIGxpc3RlbmVyKSB7XG4gICAgICByZXR1cm4gX2FkZExpc3RlbmVyKHRoaXMsIHR5cGUsIGxpc3RlbmVyLCB0cnVlKTtcbiAgICB9O1xuXG5mdW5jdGlvbiBvbmNlV3JhcHBlcigpIHtcbiAgaWYgKCF0aGlzLmZpcmVkKSB7XG4gICAgdGhpcy50YXJnZXQucmVtb3ZlTGlzdGVuZXIodGhpcy50eXBlLCB0aGlzLndyYXBGbik7XG4gICAgdGhpcy5maXJlZCA9IHRydWU7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDApXG4gICAgICByZXR1cm4gdGhpcy5saXN0ZW5lci5jYWxsKHRoaXMudGFyZ2V0KTtcbiAgICByZXR1cm4gdGhpcy5saXN0ZW5lci5hcHBseSh0aGlzLnRhcmdldCwgYXJndW1lbnRzKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBfb25jZVdyYXAodGFyZ2V0LCB0eXBlLCBsaXN0ZW5lcikge1xuICB2YXIgc3RhdGUgPSB7IGZpcmVkOiBmYWxzZSwgd3JhcEZuOiB1bmRlZmluZWQsIHRhcmdldDogdGFyZ2V0LCB0eXBlOiB0eXBlLCBsaXN0ZW5lcjogbGlzdGVuZXIgfTtcbiAgdmFyIHdyYXBwZWQgPSBvbmNlV3JhcHBlci5iaW5kKHN0YXRlKTtcbiAgd3JhcHBlZC5saXN0ZW5lciA9IGxpc3RlbmVyO1xuICBzdGF0ZS53cmFwRm4gPSB3cmFwcGVkO1xuICByZXR1cm4gd3JhcHBlZDtcbn1cblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5vbmNlID0gZnVuY3Rpb24gb25jZSh0eXBlLCBsaXN0ZW5lcikge1xuICBjaGVja0xpc3RlbmVyKGxpc3RlbmVyKTtcbiAgdGhpcy5vbih0eXBlLCBfb25jZVdyYXAodGhpcywgdHlwZSwgbGlzdGVuZXIpKTtcbiAgcmV0dXJuIHRoaXM7XG59O1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLnByZXBlbmRPbmNlTGlzdGVuZXIgPVxuICAgIGZ1bmN0aW9uIHByZXBlbmRPbmNlTGlzdGVuZXIodHlwZSwgbGlzdGVuZXIpIHtcbiAgICAgIGNoZWNrTGlzdGVuZXIobGlzdGVuZXIpO1xuICAgICAgdGhpcy5wcmVwZW5kTGlzdGVuZXIodHlwZSwgX29uY2VXcmFwKHRoaXMsIHR5cGUsIGxpc3RlbmVyKSk7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9O1xuXG4vLyBFbWl0cyBhICdyZW1vdmVMaXN0ZW5lcicgZXZlbnQgaWYgYW5kIG9ubHkgaWYgdGhlIGxpc3RlbmVyIHdhcyByZW1vdmVkLlxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVMaXN0ZW5lciA9XG4gICAgZnVuY3Rpb24gcmVtb3ZlTGlzdGVuZXIodHlwZSwgbGlzdGVuZXIpIHtcbiAgICAgIHZhciBsaXN0LCBldmVudHMsIHBvc2l0aW9uLCBpLCBvcmlnaW5hbExpc3RlbmVyO1xuXG4gICAgICBjaGVja0xpc3RlbmVyKGxpc3RlbmVyKTtcblxuICAgICAgZXZlbnRzID0gdGhpcy5fZXZlbnRzO1xuICAgICAgaWYgKGV2ZW50cyA9PT0gdW5kZWZpbmVkKVxuICAgICAgICByZXR1cm4gdGhpcztcblxuICAgICAgbGlzdCA9IGV2ZW50c1t0eXBlXTtcbiAgICAgIGlmIChsaXN0ID09PSB1bmRlZmluZWQpXG4gICAgICAgIHJldHVybiB0aGlzO1xuXG4gICAgICBpZiAobGlzdCA9PT0gbGlzdGVuZXIgfHwgbGlzdC5saXN0ZW5lciA9PT0gbGlzdGVuZXIpIHtcbiAgICAgICAgaWYgKC0tdGhpcy5fZXZlbnRzQ291bnQgPT09IDApXG4gICAgICAgICAgdGhpcy5fZXZlbnRzID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgZGVsZXRlIGV2ZW50c1t0eXBlXTtcbiAgICAgICAgICBpZiAoZXZlbnRzLnJlbW92ZUxpc3RlbmVyKVxuICAgICAgICAgICAgdGhpcy5lbWl0KCdyZW1vdmVMaXN0ZW5lcicsIHR5cGUsIGxpc3QubGlzdGVuZXIgfHwgbGlzdGVuZXIpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHR5cGVvZiBsaXN0ICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHBvc2l0aW9uID0gLTE7XG5cbiAgICAgICAgZm9yIChpID0gbGlzdC5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgICAgIGlmIChsaXN0W2ldID09PSBsaXN0ZW5lciB8fCBsaXN0W2ldLmxpc3RlbmVyID09PSBsaXN0ZW5lcikge1xuICAgICAgICAgICAgb3JpZ2luYWxMaXN0ZW5lciA9IGxpc3RbaV0ubGlzdGVuZXI7XG4gICAgICAgICAgICBwb3NpdGlvbiA9IGk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocG9zaXRpb24gPCAwKVxuICAgICAgICAgIHJldHVybiB0aGlzO1xuXG4gICAgICAgIGlmIChwb3NpdGlvbiA9PT0gMClcbiAgICAgICAgICBsaXN0LnNoaWZ0KCk7XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgIHNwbGljZU9uZShsaXN0LCBwb3NpdGlvbik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobGlzdC5sZW5ndGggPT09IDEpXG4gICAgICAgICAgZXZlbnRzW3R5cGVdID0gbGlzdFswXTtcblxuICAgICAgICBpZiAoZXZlbnRzLnJlbW92ZUxpc3RlbmVyICE9PSB1bmRlZmluZWQpXG4gICAgICAgICAgdGhpcy5lbWl0KCdyZW1vdmVMaXN0ZW5lcicsIHR5cGUsIG9yaWdpbmFsTGlzdGVuZXIgfHwgbGlzdGVuZXIpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9O1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLm9mZiA9IEV2ZW50RW1pdHRlci5wcm90b3R5cGUucmVtb3ZlTGlzdGVuZXI7XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUucmVtb3ZlQWxsTGlzdGVuZXJzID1cbiAgICBmdW5jdGlvbiByZW1vdmVBbGxMaXN0ZW5lcnModHlwZSkge1xuICAgICAgdmFyIGxpc3RlbmVycywgZXZlbnRzLCBpO1xuXG4gICAgICBldmVudHMgPSB0aGlzLl9ldmVudHM7XG4gICAgICBpZiAoZXZlbnRzID09PSB1bmRlZmluZWQpXG4gICAgICAgIHJldHVybiB0aGlzO1xuXG4gICAgICAvLyBub3QgbGlzdGVuaW5nIGZvciByZW1vdmVMaXN0ZW5lciwgbm8gbmVlZCB0byBlbWl0XG4gICAgICBpZiAoZXZlbnRzLnJlbW92ZUxpc3RlbmVyID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICB0aGlzLl9ldmVudHMgPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuICAgICAgICAgIHRoaXMuX2V2ZW50c0NvdW50ID0gMDtcbiAgICAgICAgfSBlbHNlIGlmIChldmVudHNbdHlwZV0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIGlmICgtLXRoaXMuX2V2ZW50c0NvdW50ID09PSAwKVxuICAgICAgICAgICAgdGhpcy5fZXZlbnRzID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcbiAgICAgICAgICBlbHNlXG4gICAgICAgICAgICBkZWxldGUgZXZlbnRzW3R5cGVdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgfVxuXG4gICAgICAvLyBlbWl0IHJlbW92ZUxpc3RlbmVyIGZvciBhbGwgbGlzdGVuZXJzIG9uIGFsbCBldmVudHNcbiAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHZhciBrZXlzID0gT2JqZWN0LmtleXMoZXZlbnRzKTtcbiAgICAgICAgdmFyIGtleTtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGtleXMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgICBrZXkgPSBrZXlzW2ldO1xuICAgICAgICAgIGlmIChrZXkgPT09ICdyZW1vdmVMaXN0ZW5lcicpIGNvbnRpbnVlO1xuICAgICAgICAgIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5yZW1vdmVBbGxMaXN0ZW5lcnMoJ3JlbW92ZUxpc3RlbmVyJyk7XG4gICAgICAgIHRoaXMuX2V2ZW50cyA9IE9iamVjdC5jcmVhdGUobnVsbCk7XG4gICAgICAgIHRoaXMuX2V2ZW50c0NvdW50ID0gMDtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICB9XG5cbiAgICAgIGxpc3RlbmVycyA9IGV2ZW50c1t0eXBlXTtcblxuICAgICAgaWYgKHR5cGVvZiBsaXN0ZW5lcnMgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcnMpO1xuICAgICAgfSBlbHNlIGlmIChsaXN0ZW5lcnMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAvLyBMSUZPIG9yZGVyXG4gICAgICAgIGZvciAoaSA9IGxpc3RlbmVycy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgICAgIHRoaXMucmVtb3ZlTGlzdGVuZXIodHlwZSwgbGlzdGVuZXJzW2ldKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9O1xuXG5mdW5jdGlvbiBfbGlzdGVuZXJzKHRhcmdldCwgdHlwZSwgdW53cmFwKSB7XG4gIHZhciBldmVudHMgPSB0YXJnZXQuX2V2ZW50cztcblxuICBpZiAoZXZlbnRzID09PSB1bmRlZmluZWQpXG4gICAgcmV0dXJuIFtdO1xuXG4gIHZhciBldmxpc3RlbmVyID0gZXZlbnRzW3R5cGVdO1xuICBpZiAoZXZsaXN0ZW5lciA9PT0gdW5kZWZpbmVkKVxuICAgIHJldHVybiBbXTtcblxuICBpZiAodHlwZW9mIGV2bGlzdGVuZXIgPT09ICdmdW5jdGlvbicpXG4gICAgcmV0dXJuIHVud3JhcCA/IFtldmxpc3RlbmVyLmxpc3RlbmVyIHx8IGV2bGlzdGVuZXJdIDogW2V2bGlzdGVuZXJdO1xuXG4gIHJldHVybiB1bndyYXAgP1xuICAgIHVud3JhcExpc3RlbmVycyhldmxpc3RlbmVyKSA6IGFycmF5Q2xvbmUoZXZsaXN0ZW5lciwgZXZsaXN0ZW5lci5sZW5ndGgpO1xufVxuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmxpc3RlbmVycyA9IGZ1bmN0aW9uIGxpc3RlbmVycyh0eXBlKSB7XG4gIHJldHVybiBfbGlzdGVuZXJzKHRoaXMsIHR5cGUsIHRydWUpO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yYXdMaXN0ZW5lcnMgPSBmdW5jdGlvbiByYXdMaXN0ZW5lcnModHlwZSkge1xuICByZXR1cm4gX2xpc3RlbmVycyh0aGlzLCB0eXBlLCBmYWxzZSk7XG59O1xuXG5FdmVudEVtaXR0ZXIubGlzdGVuZXJDb3VudCA9IGZ1bmN0aW9uKGVtaXR0ZXIsIHR5cGUpIHtcbiAgaWYgKHR5cGVvZiBlbWl0dGVyLmxpc3RlbmVyQ291bnQgPT09ICdmdW5jdGlvbicpIHtcbiAgICByZXR1cm4gZW1pdHRlci5saXN0ZW5lckNvdW50KHR5cGUpO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBsaXN0ZW5lckNvdW50LmNhbGwoZW1pdHRlciwgdHlwZSk7XG4gIH1cbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUubGlzdGVuZXJDb3VudCA9IGxpc3RlbmVyQ291bnQ7XG5mdW5jdGlvbiBsaXN0ZW5lckNvdW50KHR5cGUpIHtcbiAgdmFyIGV2ZW50cyA9IHRoaXMuX2V2ZW50cztcblxuICBpZiAoZXZlbnRzICE9PSB1bmRlZmluZWQpIHtcbiAgICB2YXIgZXZsaXN0ZW5lciA9IGV2ZW50c1t0eXBlXTtcblxuICAgIGlmICh0eXBlb2YgZXZsaXN0ZW5lciA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgcmV0dXJuIDE7XG4gICAgfSBlbHNlIGlmIChldmxpc3RlbmVyICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiBldmxpc3RlbmVyLmxlbmd0aDtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gMDtcbn1cblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5ldmVudE5hbWVzID0gZnVuY3Rpb24gZXZlbnROYW1lcygpIHtcbiAgcmV0dXJuIHRoaXMuX2V2ZW50c0NvdW50ID4gMCA/IFJlZmxlY3RPd25LZXlzKHRoaXMuX2V2ZW50cykgOiBbXTtcbn07XG5cbmZ1bmN0aW9uIGFycmF5Q2xvbmUoYXJyLCBuKSB7XG4gIHZhciBjb3B5ID0gbmV3IEFycmF5KG4pO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IG47ICsraSlcbiAgICBjb3B5W2ldID0gYXJyW2ldO1xuICByZXR1cm4gY29weTtcbn1cblxuZnVuY3Rpb24gc3BsaWNlT25lKGxpc3QsIGluZGV4KSB7XG4gIGZvciAoOyBpbmRleCArIDEgPCBsaXN0Lmxlbmd0aDsgaW5kZXgrKylcbiAgICBsaXN0W2luZGV4XSA9IGxpc3RbaW5kZXggKyAxXTtcbiAgbGlzdC5wb3AoKTtcbn1cblxuZnVuY3Rpb24gdW53cmFwTGlzdGVuZXJzKGFycikge1xuICB2YXIgcmV0ID0gbmV3IEFycmF5KGFyci5sZW5ndGgpO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IHJldC5sZW5ndGg7ICsraSkge1xuICAgIHJldFtpXSA9IGFycltpXS5saXN0ZW5lciB8fCBhcnJbaV07XG4gIH1cbiAgcmV0dXJuIHJldDtcbn1cblxuZnVuY3Rpb24gb25jZShlbWl0dGVyLCBuYW1lKSB7XG4gIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgZnVuY3Rpb24gZXJyb3JMaXN0ZW5lcihlcnIpIHtcbiAgICAgIGVtaXR0ZXIucmVtb3ZlTGlzdGVuZXIobmFtZSwgcmVzb2x2ZXIpO1xuICAgICAgcmVqZWN0KGVycik7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcmVzb2x2ZXIoKSB7XG4gICAgICBpZiAodHlwZW9mIGVtaXR0ZXIucmVtb3ZlTGlzdGVuZXIgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgZW1pdHRlci5yZW1vdmVMaXN0ZW5lcignZXJyb3InLCBlcnJvckxpc3RlbmVyKTtcbiAgICAgIH1cbiAgICAgIHJlc29sdmUoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKTtcbiAgICB9O1xuXG4gICAgZXZlbnRUYXJnZXRBZ25vc3RpY0FkZExpc3RlbmVyKGVtaXR0ZXIsIG5hbWUsIHJlc29sdmVyLCB7IG9uY2U6IHRydWUgfSk7XG4gICAgaWYgKG5hbWUgIT09ICdlcnJvcicpIHtcbiAgICAgIGFkZEVycm9ySGFuZGxlcklmRXZlbnRFbWl0dGVyKGVtaXR0ZXIsIGVycm9yTGlzdGVuZXIsIHsgb25jZTogdHJ1ZSB9KTtcbiAgICB9XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBhZGRFcnJvckhhbmRsZXJJZkV2ZW50RW1pdHRlcihlbWl0dGVyLCBoYW5kbGVyLCBmbGFncykge1xuICBpZiAodHlwZW9mIGVtaXR0ZXIub24gPT09ICdmdW5jdGlvbicpIHtcbiAgICBldmVudFRhcmdldEFnbm9zdGljQWRkTGlzdGVuZXIoZW1pdHRlciwgJ2Vycm9yJywgaGFuZGxlciwgZmxhZ3MpO1xuICB9XG59XG5cbmZ1bmN0aW9uIGV2ZW50VGFyZ2V0QWdub3N0aWNBZGRMaXN0ZW5lcihlbWl0dGVyLCBuYW1lLCBsaXN0ZW5lciwgZmxhZ3MpIHtcbiAgaWYgKHR5cGVvZiBlbWl0dGVyLm9uID09PSAnZnVuY3Rpb24nKSB7XG4gICAgaWYgKGZsYWdzLm9uY2UpIHtcbiAgICAgIGVtaXR0ZXIub25jZShuYW1lLCBsaXN0ZW5lcik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGVtaXR0ZXIub24obmFtZSwgbGlzdGVuZXIpO1xuICAgIH1cbiAgfSBlbHNlIGlmICh0eXBlb2YgZW1pdHRlci5hZGRFdmVudExpc3RlbmVyID09PSAnZnVuY3Rpb24nKSB7XG4gICAgLy8gRXZlbnRUYXJnZXQgZG9lcyBub3QgaGF2ZSBgZXJyb3JgIGV2ZW50IHNlbWFudGljcyBsaWtlIE5vZGVcbiAgICAvLyBFdmVudEVtaXR0ZXJzLCB3ZSBkbyBub3QgbGlzdGVuIGZvciBgZXJyb3JgIGV2ZW50cyBoZXJlLlxuICAgIGVtaXR0ZXIuYWRkRXZlbnRMaXN0ZW5lcihuYW1lLCBmdW5jdGlvbiB3cmFwTGlzdGVuZXIoYXJnKSB7XG4gICAgICAvLyBJRSBkb2VzIG5vdCBoYXZlIGJ1aWx0aW4gYHsgb25jZTogdHJ1ZSB9YCBzdXBwb3J0IHNvIHdlXG4gICAgICAvLyBoYXZlIHRvIGRvIGl0IG1hbnVhbGx5LlxuICAgICAgaWYgKGZsYWdzLm9uY2UpIHtcbiAgICAgICAgZW1pdHRlci5yZW1vdmVFdmVudExpc3RlbmVyKG5hbWUsIHdyYXBMaXN0ZW5lcik7XG4gICAgICB9XG4gICAgICBsaXN0ZW5lcihhcmcpO1xuICAgIH0pO1xuICB9IGVsc2Uge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1RoZSBcImVtaXR0ZXJcIiBhcmd1bWVudCBtdXN0IGJlIG9mIHR5cGUgRXZlbnRFbWl0dGVyLiBSZWNlaXZlZCB0eXBlICcgKyB0eXBlb2YgZW1pdHRlcik7XG4gIH1cbn1cbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///7\n")},879:module=>{eval("(function(window, factory) {\n\tvar lazySizes = factory(window, window.document, Date);\n\twindow.lazySizes = lazySizes;\n\tif( true && module.exports){\n\t\tmodule.exports = lazySizes;\n\t}\n}(typeof window != 'undefined' ?\n window : {}, \n/**\n * import(\"./types/global\")\n * @typedef { import(\"./types/lazysizes-config\").LazySizesConfigPartial } LazySizesConfigPartial\n */\nfunction l(window, document, Date) { // Pass in the window Date function also for SSR because the Date class can be lost\n\t'use strict';\n\t/*jshint eqnull:true */\n\n\tvar lazysizes,\n\t\t/**\n\t\t * @type { LazySizesConfigPartial }\n\t\t */\n\t\tlazySizesCfg;\n\n\t(function(){\n\t\tvar prop;\n\n\t\tvar lazySizesDefaults = {\n\t\t\tlazyClass: 'lazyload',\n\t\t\tloadedClass: 'lazyloaded',\n\t\t\tloadingClass: 'lazyloading',\n\t\t\tpreloadClass: 'lazypreload',\n\t\t\terrorClass: 'lazyerror',\n\t\t\t//strictClass: 'lazystrict',\n\t\t\tautosizesClass: 'lazyautosizes',\n\t\t\tfastLoadedClass: 'ls-is-cached',\n\t\t\tiframeLoadMode: 0,\n\t\t\tsrcAttr: 'data-src',\n\t\t\tsrcsetAttr: 'data-srcset',\n\t\t\tsizesAttr: 'data-sizes',\n\t\t\t//preloadAfterLoad: false,\n\t\t\tminSize: 40,\n\t\t\tcustomMedia: {},\n\t\t\tinit: true,\n\t\t\texpFactor: 1.5,\n\t\t\thFac: 0.8,\n\t\t\tloadMode: 2,\n\t\t\tloadHidden: true,\n\t\t\tricTimeout: 0,\n\t\t\tthrottleDelay: 125,\n\t\t};\n\n\t\tlazySizesCfg = window.lazySizesConfig || window.lazysizesConfig || {};\n\n\t\tfor(prop in lazySizesDefaults){\n\t\t\tif(!(prop in lazySizesCfg)){\n\t\t\t\tlazySizesCfg[prop] = lazySizesDefaults[prop];\n\t\t\t}\n\t\t}\n\t})();\n\n\tif (!document || !document.getElementsByClassName) {\n\t\treturn {\n\t\t\tinit: function () {},\n\t\t\t/**\n\t\t\t * @type { LazySizesConfigPartial }\n\t\t\t */\n\t\t\tcfg: lazySizesCfg,\n\t\t\t/**\n\t\t\t * @type { true }\n\t\t\t */\n\t\t\tnoSupport: true,\n\t\t};\n\t}\n\n\tvar docElem = document.documentElement;\n\n\tvar supportPicture = window.HTMLPictureElement;\n\n\tvar _addEventListener = 'addEventListener';\n\n\tvar _getAttribute = 'getAttribute';\n\n\t/**\n\t * Update to bind to window because 'this' becomes null during SSR\n\t * builds.\n\t */\n\tvar addEventListener = window[_addEventListener].bind(window);\n\n\tvar setTimeout = window.setTimeout;\n\n\tvar requestAnimationFrame = window.requestAnimationFrame || setTimeout;\n\n\tvar requestIdleCallback = window.requestIdleCallback;\n\n\tvar regPicture = /^picture$/i;\n\n\tvar loadEvents = ['load', 'error', 'lazyincluded', '_lazyloaded'];\n\n\tvar regClassCache = {};\n\n\tvar forEach = Array.prototype.forEach;\n\n\t/**\n\t * @param ele {Element}\n\t * @param cls {string}\n\t */\n\tvar hasClass = function(ele, cls) {\n\t\tif(!regClassCache[cls]){\n\t\t\tregClassCache[cls] = new RegExp('(\\\\s|^)'+cls+'(\\\\s|$)');\n\t\t}\n\t\treturn regClassCache[cls].test(ele[_getAttribute]('class') || '') && regClassCache[cls];\n\t};\n\n\t/**\n\t * @param ele {Element}\n\t * @param cls {string}\n\t */\n\tvar addClass = function(ele, cls) {\n\t\tif (!hasClass(ele, cls)){\n\t\t\tele.setAttribute('class', (ele[_getAttribute]('class') || '').trim() + ' ' + cls);\n\t\t}\n\t};\n\n\t/**\n\t * @param ele {Element}\n\t * @param cls {string}\n\t */\n\tvar removeClass = function(ele, cls) {\n\t\tvar reg;\n\t\tif ((reg = hasClass(ele,cls))) {\n\t\t\tele.setAttribute('class', (ele[_getAttribute]('class') || '').replace(reg, ' '));\n\t\t}\n\t};\n\n\tvar addRemoveLoadEvents = function(dom, fn, add){\n\t\tvar action = add ? _addEventListener : 'removeEventListener';\n\t\tif(add){\n\t\t\taddRemoveLoadEvents(dom, fn);\n\t\t}\n\t\tloadEvents.forEach(function(evt){\n\t\t\tdom[action](evt, fn);\n\t\t});\n\t};\n\n\t/**\n\t * @param elem { Element }\n\t * @param name { string }\n\t * @param detail { any }\n\t * @param noBubbles { boolean }\n\t * @param noCancelable { boolean }\n\t * @returns { CustomEvent }\n\t */\n\tvar triggerEvent = function(elem, name, detail, noBubbles, noCancelable){\n\t\tvar event = document.createEvent('Event');\n\n\t\tif(!detail){\n\t\t\tdetail = {};\n\t\t}\n\n\t\tdetail.instance = lazysizes;\n\n\t\tevent.initEvent(name, !noBubbles, !noCancelable);\n\n\t\tevent.detail = detail;\n\n\t\telem.dispatchEvent(event);\n\t\treturn event;\n\t};\n\n\tvar updatePolyfill = function (el, full){\n\t\tvar polyfill;\n\t\tif( !supportPicture && ( polyfill = (window.picturefill || lazySizesCfg.pf) ) ){\n\t\t\tif(full && full.src && !el[_getAttribute]('srcset')){\n\t\t\t\tel.setAttribute('srcset', full.src);\n\t\t\t}\n\t\t\tpolyfill({reevaluate: true, elements: [el]});\n\t\t} else if(full && full.src){\n\t\t\tel.src = full.src;\n\t\t}\n\t};\n\n\tvar getCSS = function (elem, style){\n\t\treturn (getComputedStyle(elem, null) || {})[style];\n\t};\n\n\t/**\n\t *\n\t * @param elem { Element }\n\t * @param parent { Element }\n\t * @param [width] {number}\n\t * @returns {number}\n\t */\n\tvar getWidth = function(elem, parent, width){\n\t\twidth = width || elem.offsetWidth;\n\n\t\twhile(width < lazySizesCfg.minSize && parent && !elem._lazysizesWidth){\n\t\t\twidth = parent.offsetWidth;\n\t\t\tparent = parent.parentNode;\n\t\t}\n\n\t\treturn width;\n\t};\n\n\tvar rAF = (function(){\n\t\tvar running, waiting;\n\t\tvar firstFns = [];\n\t\tvar secondFns = [];\n\t\tvar fns = firstFns;\n\n\t\tvar run = function(){\n\t\t\tvar runFns = fns;\n\n\t\t\tfns = firstFns.length ? secondFns : firstFns;\n\n\t\t\trunning = true;\n\t\t\twaiting = false;\n\n\t\t\twhile(runFns.length){\n\t\t\t\trunFns.shift()();\n\t\t\t}\n\n\t\t\trunning = false;\n\t\t};\n\n\t\tvar rafBatch = function(fn, queue){\n\t\t\tif(running && !queue){\n\t\t\t\tfn.apply(this, arguments);\n\t\t\t} else {\n\t\t\t\tfns.push(fn);\n\n\t\t\t\tif(!waiting){\n\t\t\t\t\twaiting = true;\n\t\t\t\t\t(document.hidden ? setTimeout : requestAnimationFrame)(run);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\trafBatch._lsFlush = run;\n\n\t\treturn rafBatch;\n\t})();\n\n\tvar rAFIt = function(fn, simple){\n\t\treturn simple ?\n\t\t\tfunction() {\n\t\t\t\trAF(fn);\n\t\t\t} :\n\t\t\tfunction(){\n\t\t\t\tvar that = this;\n\t\t\t\tvar args = arguments;\n\t\t\t\trAF(function(){\n\t\t\t\t\tfn.apply(that, args);\n\t\t\t\t});\n\t\t\t}\n\t\t;\n\t};\n\n\tvar throttle = function(fn){\n\t\tvar running;\n\t\tvar lastTime = 0;\n\t\tvar gDelay = lazySizesCfg.throttleDelay;\n\t\tvar rICTimeout = lazySizesCfg.ricTimeout;\n\t\tvar run = function(){\n\t\t\trunning = false;\n\t\t\tlastTime = Date.now();\n\t\t\tfn();\n\t\t};\n\t\tvar idleCallback = requestIdleCallback && rICTimeout > 49 ?\n\t\t\tfunction(){\n\t\t\t\trequestIdleCallback(run, {timeout: rICTimeout});\n\n\t\t\t\tif(rICTimeout !== lazySizesCfg.ricTimeout){\n\t\t\t\t\trICTimeout = lazySizesCfg.ricTimeout;\n\t\t\t\t}\n\t\t\t} :\n\t\t\trAFIt(function(){\n\t\t\t\tsetTimeout(run);\n\t\t\t}, true)\n\t\t;\n\n\t\treturn function(isPriority){\n\t\t\tvar delay;\n\n\t\t\tif((isPriority = isPriority === true)){\n\t\t\t\trICTimeout = 33;\n\t\t\t}\n\n\t\t\tif(running){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\trunning = true;\n\n\t\t\tdelay = gDelay - (Date.now() - lastTime);\n\n\t\t\tif(delay < 0){\n\t\t\t\tdelay = 0;\n\t\t\t}\n\n\t\t\tif(isPriority || delay < 9){\n\t\t\t\tidleCallback();\n\t\t\t} else {\n\t\t\t\tsetTimeout(idleCallback, delay);\n\t\t\t}\n\t\t};\n\t};\n\n\t//based on http://modernjavascript.blogspot.de/2013/08/building-better-debounce.html\n\tvar debounce = function(func) {\n\t\tvar timeout, timestamp;\n\t\tvar wait = 99;\n\t\tvar run = function(){\n\t\t\ttimeout = null;\n\t\t\tfunc();\n\t\t};\n\t\tvar later = function() {\n\t\t\tvar last = Date.now() - timestamp;\n\n\t\t\tif (last < wait) {\n\t\t\t\tsetTimeout(later, wait - last);\n\t\t\t} else {\n\t\t\t\t(requestIdleCallback || run)(run);\n\t\t\t}\n\t\t};\n\n\t\treturn function() {\n\t\t\ttimestamp = Date.now();\n\n\t\t\tif (!timeout) {\n\t\t\t\ttimeout = setTimeout(later, wait);\n\t\t\t}\n\t\t};\n\t};\n\n\tvar loader = (function(){\n\t\tvar preloadElems, isCompleted, resetPreloadingTimer, loadMode, started;\n\n\t\tvar eLvW, elvH, eLtop, eLleft, eLright, eLbottom, isBodyHidden;\n\n\t\tvar regImg = /^img$/i;\n\t\tvar regIframe = /^iframe$/i;\n\n\t\tvar supportScroll = ('onscroll' in window) && !(/(gle|ing)bot/.test(navigator.userAgent));\n\n\t\tvar shrinkExpand = 0;\n\t\tvar currentExpand = 0;\n\n\t\tvar isLoading = 0;\n\t\tvar lowRuns = -1;\n\n\t\tvar resetPreloading = function(e){\n\t\t\tisLoading--;\n\t\t\tif(!e || isLoading < 0 || !e.target){\n\t\t\t\tisLoading = 0;\n\t\t\t}\n\t\t};\n\n\t\tvar isVisible = function (elem) {\n\t\t\tif (isBodyHidden == null) {\n\t\t\t\tisBodyHidden = getCSS(document.body, 'visibility') == 'hidden';\n\t\t\t}\n\n\t\t\treturn isBodyHidden || !(getCSS(elem.parentNode, 'visibility') == 'hidden' && getCSS(elem, 'visibility') == 'hidden');\n\t\t};\n\n\t\tvar isNestedVisible = function(elem, elemExpand){\n\t\t\tvar outerRect;\n\t\t\tvar parent = elem;\n\t\t\tvar visible = isVisible(elem);\n\n\t\t\teLtop -= elemExpand;\n\t\t\teLbottom += elemExpand;\n\t\t\teLleft -= elemExpand;\n\t\t\teLright += elemExpand;\n\n\t\t\twhile(visible && (parent = parent.offsetParent) && parent != document.body && parent != docElem){\n\t\t\t\tvisible = ((getCSS(parent, 'opacity') || 1) > 0);\n\n\t\t\t\tif(visible && getCSS(parent, 'overflow') != 'visible'){\n\t\t\t\t\touterRect = parent.getBoundingClientRect();\n\t\t\t\t\tvisible = eLright > outerRect.left &&\n\t\t\t\t\t\teLleft < outerRect.right &&\n\t\t\t\t\t\teLbottom > outerRect.top - 1 &&\n\t\t\t\t\t\teLtop < outerRect.bottom + 1\n\t\t\t\t\t;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn visible;\n\t\t};\n\n\t\tvar checkElements = function() {\n\t\t\tvar eLlen, i, rect, autoLoadElem, loadedSomething, elemExpand, elemNegativeExpand, elemExpandVal,\n\t\t\t\tbeforeExpandVal, defaultExpand, preloadExpand, hFac;\n\t\t\tvar lazyloadElems = lazysizes.elements;\n\n\t\t\tif((loadMode = lazySizesCfg.loadMode) && isLoading < 8 && (eLlen = lazyloadElems.length)){\n\n\t\t\t\ti = 0;\n\n\t\t\t\tlowRuns++;\n\n\t\t\t\tfor(; i < eLlen; i++){\n\n\t\t\t\t\tif(!lazyloadElems[i] || lazyloadElems[i]._lazyRace){continue;}\n\n\t\t\t\t\tif(!supportScroll || (lazysizes.prematureUnveil && lazysizes.prematureUnveil(lazyloadElems[i]))){unveilElement(lazyloadElems[i]);continue;}\n\n\t\t\t\t\tif(!(elemExpandVal = lazyloadElems[i][_getAttribute]('data-expand')) || !(elemExpand = elemExpandVal * 1)){\n\t\t\t\t\t\telemExpand = currentExpand;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!defaultExpand) {\n\t\t\t\t\t\tdefaultExpand = (!lazySizesCfg.expand || lazySizesCfg.expand < 1) ?\n\t\t\t\t\t\t\tdocElem.clientHeight > 500 && docElem.clientWidth > 500 ? 500 : 370 :\n\t\t\t\t\t\t\tlazySizesCfg.expand;\n\n\t\t\t\t\t\tlazysizes._defEx = defaultExpand;\n\n\t\t\t\t\t\tpreloadExpand = defaultExpand * lazySizesCfg.expFactor;\n\t\t\t\t\t\thFac = lazySizesCfg.hFac;\n\t\t\t\t\t\tisBodyHidden = null;\n\n\t\t\t\t\t\tif(currentExpand < preloadExpand && isLoading < 1 && lowRuns > 2 && loadMode > 2 && !document.hidden){\n\t\t\t\t\t\t\tcurrentExpand = preloadExpand;\n\t\t\t\t\t\t\tlowRuns = 0;\n\t\t\t\t\t\t} else if(loadMode > 1 && lowRuns > 1 && isLoading < 6){\n\t\t\t\t\t\t\tcurrentExpand = defaultExpand;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcurrentExpand = shrinkExpand;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif(beforeExpandVal !== elemExpand){\n\t\t\t\t\t\teLvW = innerWidth + (elemExpand * hFac);\n\t\t\t\t\t\telvH = innerHeight + elemExpand;\n\t\t\t\t\t\telemNegativeExpand = elemExpand * -1;\n\t\t\t\t\t\tbeforeExpandVal = elemExpand;\n\t\t\t\t\t}\n\n\t\t\t\t\trect = lazyloadElems[i].getBoundingClientRect();\n\n\t\t\t\t\tif ((eLbottom = rect.bottom) >= elemNegativeExpand &&\n\t\t\t\t\t\t(eLtop = rect.top) <= elvH &&\n\t\t\t\t\t\t(eLright = rect.right) >= elemNegativeExpand * hFac &&\n\t\t\t\t\t\t(eLleft = rect.left) <= eLvW &&\n\t\t\t\t\t\t(eLbottom || eLright || eLleft || eLtop) &&\n\t\t\t\t\t\t(lazySizesCfg.loadHidden || isVisible(lazyloadElems[i])) &&\n\t\t\t\t\t\t((isCompleted && isLoading < 3 && !elemExpandVal && (loadMode < 3 || lowRuns < 4)) || isNestedVisible(lazyloadElems[i], elemExpand))){\n\t\t\t\t\t\tunveilElement(lazyloadElems[i]);\n\t\t\t\t\t\tloadedSomething = true;\n\t\t\t\t\t\tif(isLoading > 9){break;}\n\t\t\t\t\t} else if(!loadedSomething && isCompleted && !autoLoadElem &&\n\t\t\t\t\t\tisLoading < 4 && lowRuns < 4 && loadMode > 2 &&\n\t\t\t\t\t\t(preloadElems[0] || lazySizesCfg.preloadAfterLoad) &&\n\t\t\t\t\t\t(preloadElems[0] || (!elemExpandVal && ((eLbottom || eLright || eLleft || eLtop) || lazyloadElems[i][_getAttribute](lazySizesCfg.sizesAttr) != 'auto')))){\n\t\t\t\t\t\tautoLoadElem = preloadElems[0] || lazyloadElems[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif(autoLoadElem && !loadedSomething){\n\t\t\t\t\tunveilElement(autoLoadElem);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tvar throttledCheckElements = throttle(checkElements);\n\n\t\tvar switchLoadingClass = function(e){\n\t\t\tvar elem = e.target;\n\n\t\t\tif (elem._lazyCache) {\n\t\t\t\tdelete elem._lazyCache;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tresetPreloading(e);\n\t\t\taddClass(elem, lazySizesCfg.loadedClass);\n\t\t\tremoveClass(elem, lazySizesCfg.loadingClass);\n\t\t\taddRemoveLoadEvents(elem, rafSwitchLoadingClass);\n\t\t\ttriggerEvent(elem, 'lazyloaded');\n\t\t};\n\t\tvar rafedSwitchLoadingClass = rAFIt(switchLoadingClass);\n\t\tvar rafSwitchLoadingClass = function(e){\n\t\t\trafedSwitchLoadingClass({target: e.target});\n\t\t};\n\n\t\tvar changeIframeSrc = function(elem, src){\n\t\t\tvar loadMode = elem.getAttribute('data-load-mode') || lazySizesCfg.iframeLoadMode;\n\n\t\t\t// loadMode can be also a string!\n\t\t\tif (loadMode == 0) {\n\t\t\t\telem.contentWindow.location.replace(src);\n\t\t\t} else if (loadMode == 1) {\n\t\t\t\telem.src = src;\n\t\t\t}\n\t\t};\n\n\t\tvar handleSources = function(source){\n\t\t\tvar customMedia;\n\n\t\t\tvar sourceSrcset = source[_getAttribute](lazySizesCfg.srcsetAttr);\n\n\t\t\tif( (customMedia = lazySizesCfg.customMedia[source[_getAttribute]('data-media') || source[_getAttribute]('media')]) ){\n\t\t\t\tsource.setAttribute('media', customMedia);\n\t\t\t}\n\n\t\t\tif(sourceSrcset){\n\t\t\t\tsource.setAttribute('srcset', sourceSrcset);\n\t\t\t}\n\t\t};\n\n\t\tvar lazyUnveil = rAFIt(function (elem, detail, isAuto, sizes, isImg){\n\t\t\tvar src, srcset, parent, isPicture, event, firesLoad;\n\n\t\t\tif(!(event = triggerEvent(elem, 'lazybeforeunveil', detail)).defaultPrevented){\n\n\t\t\t\tif(sizes){\n\t\t\t\t\tif(isAuto){\n\t\t\t\t\t\taddClass(elem, lazySizesCfg.autosizesClass);\n\t\t\t\t\t} else {\n\t\t\t\t\t\telem.setAttribute('sizes', sizes);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tsrcset = elem[_getAttribute](lazySizesCfg.srcsetAttr);\n\t\t\t\tsrc = elem[_getAttribute](lazySizesCfg.srcAttr);\n\n\t\t\t\tif(isImg) {\n\t\t\t\t\tparent = elem.parentNode;\n\t\t\t\t\tisPicture = parent && regPicture.test(parent.nodeName || '');\n\t\t\t\t}\n\n\t\t\t\tfiresLoad = detail.firesLoad || (('src' in elem) && (srcset || src || isPicture));\n\n\t\t\t\tevent = {target: elem};\n\n\t\t\t\taddClass(elem, lazySizesCfg.loadingClass);\n\n\t\t\t\tif(firesLoad){\n\t\t\t\t\tclearTimeout(resetPreloadingTimer);\n\t\t\t\t\tresetPreloadingTimer = setTimeout(resetPreloading, 2500);\n\t\t\t\t\taddRemoveLoadEvents(elem, rafSwitchLoadingClass, true);\n\t\t\t\t}\n\n\t\t\t\tif(isPicture){\n\t\t\t\t\tforEach.call(parent.getElementsByTagName('source'), handleSources);\n\t\t\t\t}\n\n\t\t\t\tif(srcset){\n\t\t\t\t\telem.setAttribute('srcset', srcset);\n\t\t\t\t} else if(src && !isPicture){\n\t\t\t\t\tif(regIframe.test(elem.nodeName)){\n\t\t\t\t\t\tchangeIframeSrc(elem, src);\n\t\t\t\t\t} else {\n\t\t\t\t\t\telem.src = src;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif(isImg && (srcset || isPicture)){\n\t\t\t\t\tupdatePolyfill(elem, {src: src});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(elem._lazyRace){\n\t\t\t\tdelete elem._lazyRace;\n\t\t\t}\n\t\t\tremoveClass(elem, lazySizesCfg.lazyClass);\n\n\t\t\trAF(function(){\n\t\t\t\t// Part of this can be removed as soon as this fix is older: https://bugs.chromium.org/p/chromium/issues/detail?id=7731 (2015)\n\t\t\t\tvar isLoaded = elem.complete && elem.naturalWidth > 1;\n\n\t\t\t\tif( !firesLoad || isLoaded){\n\t\t\t\t\tif (isLoaded) {\n\t\t\t\t\t\taddClass(elem, lazySizesCfg.fastLoadedClass);\n\t\t\t\t\t}\n\t\t\t\t\tswitchLoadingClass(event);\n\t\t\t\t\telem._lazyCache = true;\n\t\t\t\t\tsetTimeout(function(){\n\t\t\t\t\t\tif ('_lazyCache' in elem) {\n\t\t\t\t\t\t\tdelete elem._lazyCache;\n\t\t\t\t\t\t}\n\t\t\t\t\t}, 9);\n\t\t\t\t}\n\t\t\t\tif (elem.loading == 'lazy') {\n\t\t\t\t\tisLoading--;\n\t\t\t\t}\n\t\t\t}, true);\n\t\t});\n\n\t\t/**\n\t\t *\n\t\t * @param elem { Element }\n\t\t */\n\t\tvar unveilElement = function (elem){\n\t\t\tif (elem._lazyRace) {return;}\n\t\t\tvar detail;\n\n\t\t\tvar isImg = regImg.test(elem.nodeName);\n\n\t\t\t//allow using sizes=\"auto\", but don't use. it's invalid. Use data-sizes=\"auto\" or a valid value for sizes instead (i.e.: sizes=\"80vw\")\n\t\t\tvar sizes = isImg && (elem[_getAttribute](lazySizesCfg.sizesAttr) || elem[_getAttribute]('sizes'));\n\t\t\tvar isAuto = sizes == 'auto';\n\n\t\t\tif( (isAuto || !isCompleted) && isImg && (elem[_getAttribute]('src') || elem.srcset) && !elem.complete && !hasClass(elem, lazySizesCfg.errorClass) && hasClass(elem, lazySizesCfg.lazyClass)){return;}\n\n\t\t\tdetail = triggerEvent(elem, 'lazyunveilread').detail;\n\n\t\t\tif(isAuto){\n\t\t\t\t autoSizer.updateElem(elem, true, elem.offsetWidth);\n\t\t\t}\n\n\t\t\telem._lazyRace = true;\n\t\t\tisLoading++;\n\n\t\t\tlazyUnveil(elem, detail, isAuto, sizes, isImg);\n\t\t};\n\n\t\tvar afterScroll = debounce(function(){\n\t\t\tlazySizesCfg.loadMode = 3;\n\t\t\tthrottledCheckElements();\n\t\t});\n\n\t\tvar altLoadmodeScrollListner = function(){\n\t\t\tif(lazySizesCfg.loadMode == 3){\n\t\t\t\tlazySizesCfg.loadMode = 2;\n\t\t\t}\n\t\t\tafterScroll();\n\t\t};\n\n\t\tvar onload = function(){\n\t\t\tif(isCompleted){return;}\n\t\t\tif(Date.now() - started < 999){\n\t\t\t\tsetTimeout(onload, 999);\n\t\t\t\treturn;\n\t\t\t}\n\n\n\t\t\tisCompleted = true;\n\n\t\t\tlazySizesCfg.loadMode = 3;\n\n\t\t\tthrottledCheckElements();\n\n\t\t\taddEventListener('scroll', altLoadmodeScrollListner, true);\n\t\t};\n\n\t\treturn {\n\t\t\t_: function(){\n\t\t\t\tstarted = Date.now();\n\n\t\t\t\tlazysizes.elements = document.getElementsByClassName(lazySizesCfg.lazyClass);\n\t\t\t\tpreloadElems = document.getElementsByClassName(lazySizesCfg.lazyClass + ' ' + lazySizesCfg.preloadClass);\n\n\t\t\t\taddEventListener('scroll', throttledCheckElements, true);\n\n\t\t\t\taddEventListener('resize', throttledCheckElements, true);\n\n\t\t\t\taddEventListener('pageshow', function (e) {\n\t\t\t\t\tif (e.persisted) {\n\t\t\t\t\t\tvar loadingElements = document.querySelectorAll('.' + lazySizesCfg.loadingClass);\n\n\t\t\t\t\t\tif (loadingElements.length && loadingElements.forEach) {\n\t\t\t\t\t\t\trequestAnimationFrame(function () {\n\t\t\t\t\t\t\t\tloadingElements.forEach( function (img) {\n\t\t\t\t\t\t\t\t\tif (img.complete) {\n\t\t\t\t\t\t\t\t\t\tunveilElement(img);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif(window.MutationObserver){\n\t\t\t\t\tnew MutationObserver( throttledCheckElements ).observe( docElem, {childList: true, subtree: true, attributes: true} );\n\t\t\t\t} else {\n\t\t\t\t\tdocElem[_addEventListener]('DOMNodeInserted', throttledCheckElements, true);\n\t\t\t\t\tdocElem[_addEventListener]('DOMAttrModified', throttledCheckElements, true);\n\t\t\t\t\tsetInterval(throttledCheckElements, 999);\n\t\t\t\t}\n\n\t\t\t\taddEventListener('hashchange', throttledCheckElements, true);\n\n\t\t\t\t//, 'fullscreenchange'\n\t\t\t\t['focus', 'mouseover', 'click', 'load', 'transitionend', 'animationend'].forEach(function(name){\n\t\t\t\t\tdocument[_addEventListener](name, throttledCheckElements, true);\n\t\t\t\t});\n\n\t\t\t\tif((/d$|^c/.test(document.readyState))){\n\t\t\t\t\tonload();\n\t\t\t\t} else {\n\t\t\t\t\taddEventListener('load', onload);\n\t\t\t\t\tdocument[_addEventListener]('DOMContentLoaded', throttledCheckElements);\n\t\t\t\t\tsetTimeout(onload, 20000);\n\t\t\t\t}\n\n\t\t\t\tif(lazysizes.elements.length){\n\t\t\t\t\tcheckElements();\n\t\t\t\t\trAF._lsFlush();\n\t\t\t\t} else {\n\t\t\t\t\tthrottledCheckElements();\n\t\t\t\t}\n\t\t\t},\n\t\t\tcheckElems: throttledCheckElements,\n\t\t\tunveil: unveilElement,\n\t\t\t_aLSL: altLoadmodeScrollListner,\n\t\t};\n\t})();\n\n\n\tvar autoSizer = (function(){\n\t\tvar autosizesElems;\n\n\t\tvar sizeElement = rAFIt(function(elem, parent, event, width){\n\t\t\tvar sources, i, len;\n\t\t\telem._lazysizesWidth = width;\n\t\t\twidth += 'px';\n\n\t\t\telem.setAttribute('sizes', width);\n\n\t\t\tif(regPicture.test(parent.nodeName || '')){\n\t\t\t\tsources = parent.getElementsByTagName('source');\n\t\t\t\tfor(i = 0, len = sources.length; i < len; i++){\n\t\t\t\t\tsources[i].setAttribute('sizes', width);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(!event.detail.dataAttr){\n\t\t\t\tupdatePolyfill(elem, event.detail);\n\t\t\t}\n\t\t});\n\t\t/**\n\t\t *\n\t\t * @param elem {Element}\n\t\t * @param dataAttr\n\t\t * @param [width] { number }\n\t\t */\n\t\tvar getSizeElement = function (elem, dataAttr, width){\n\t\t\tvar event;\n\t\t\tvar parent = elem.parentNode;\n\n\t\t\tif(parent){\n\t\t\t\twidth = getWidth(elem, parent, width);\n\t\t\t\tevent = triggerEvent(elem, 'lazybeforesizes', {width: width, dataAttr: !!dataAttr});\n\n\t\t\t\tif(!event.defaultPrevented){\n\t\t\t\t\twidth = event.detail.width;\n\n\t\t\t\t\tif(width && width !== elem._lazysizesWidth){\n\t\t\t\t\t\tsizeElement(elem, parent, event, width);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tvar updateElementsSizes = function(){\n\t\t\tvar i;\n\t\t\tvar len = autosizesElems.length;\n\t\t\tif(len){\n\t\t\t\ti = 0;\n\n\t\t\t\tfor(; i < len; i++){\n\t\t\t\t\tgetSizeElement(autosizesElems[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tvar debouncedUpdateElementsSizes = debounce(updateElementsSizes);\n\n\t\treturn {\n\t\t\t_: function(){\n\t\t\t\tautosizesElems = document.getElementsByClassName(lazySizesCfg.autosizesClass);\n\t\t\t\taddEventListener('resize', debouncedUpdateElementsSizes);\n\t\t\t},\n\t\t\tcheckElems: debouncedUpdateElementsSizes,\n\t\t\tupdateElem: getSizeElement\n\t\t};\n\t})();\n\n\tvar init = function(){\n\t\tif(!init.i && document.getElementsByClassName){\n\t\t\tinit.i = true;\n\t\t\tautoSizer._();\n\t\t\tloader._();\n\t\t}\n\t};\n\n\tsetTimeout(function(){\n\t\tif(lazySizesCfg.init){\n\t\t\tinit();\n\t\t}\n\t});\n\n\tlazysizes = {\n\t\t/**\n\t\t * @type { LazySizesConfigPartial }\n\t\t */\n\t\tcfg: lazySizesCfg,\n\t\tautoSizer: autoSizer,\n\t\tloader: loader,\n\t\tinit: init,\n\t\tuP: updatePolyfill,\n\t\taC: addClass,\n\t\trC: removeClass,\n\t\thC: hasClass,\n\t\tfire: triggerEvent,\n\t\tgW: getWidth,\n\t\trAF: rAF,\n\t};\n\n\treturn lazysizes;\n}\n));\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiODc5LmpzIiwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9sYXp5c2l6ZXMvbGF6eXNpemVzLmpzP2IzZTkiXSwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uKHdpbmRvdywgZmFjdG9yeSkge1xuXHR2YXIgbGF6eVNpemVzID0gZmFjdG9yeSh3aW5kb3csIHdpbmRvdy5kb2N1bWVudCwgRGF0ZSk7XG5cdHdpbmRvdy5sYXp5U2l6ZXMgPSBsYXp5U2l6ZXM7XG5cdGlmKHR5cGVvZiBtb2R1bGUgPT0gJ29iamVjdCcgJiYgbW9kdWxlLmV4cG9ydHMpe1xuXHRcdG1vZHVsZS5leHBvcnRzID0gbGF6eVNpemVzO1xuXHR9XG59KHR5cGVvZiB3aW5kb3cgIT0gJ3VuZGVmaW5lZCcgP1xuICAgICAgd2luZG93IDoge30sIFxuLyoqXG4gKiBpbXBvcnQoXCIuL3R5cGVzL2dsb2JhbFwiKVxuICogQHR5cGVkZWYgeyBpbXBvcnQoXCIuL3R5cGVzL2xhenlzaXplcy1jb25maWdcIikuTGF6eVNpemVzQ29uZmlnUGFydGlhbCB9IExhenlTaXplc0NvbmZpZ1BhcnRpYWxcbiAqL1xuZnVuY3Rpb24gbCh3aW5kb3csIGRvY3VtZW50LCBEYXRlKSB7IC8vIFBhc3MgaW4gdGhlIHdpbmRvdyBEYXRlIGZ1bmN0aW9uIGFsc28gZm9yIFNTUiBiZWNhdXNlIHRoZSBEYXRlIGNsYXNzIGNhbiBiZSBsb3N0XG5cdCd1c2Ugc3RyaWN0Jztcblx0Lypqc2hpbnQgZXFudWxsOnRydWUgKi9cblxuXHR2YXIgbGF6eXNpemVzLFxuXHRcdC8qKlxuXHRcdCAqIEB0eXBlIHsgTGF6eVNpemVzQ29uZmlnUGFydGlhbCB9XG5cdFx0ICovXG5cdFx0bGF6eVNpemVzQ2ZnO1xuXG5cdChmdW5jdGlvbigpe1xuXHRcdHZhciBwcm9wO1xuXG5cdFx0dmFyIGxhenlTaXplc0RlZmF1bHRzID0ge1xuXHRcdFx0bGF6eUNsYXNzOiAnbGF6eWxvYWQnLFxuXHRcdFx0bG9hZGVkQ2xhc3M6ICdsYXp5bG9hZGVkJyxcblx0XHRcdGxvYWRpbmdDbGFzczogJ2xhenlsb2FkaW5nJyxcblx0XHRcdHByZWxvYWRDbGFzczogJ2xhenlwcmVsb2FkJyxcblx0XHRcdGVycm9yQ2xhc3M6ICdsYXp5ZXJyb3InLFxuXHRcdFx0Ly9zdHJpY3RDbGFzczogJ2xhenlzdHJpY3QnLFxuXHRcdFx0YXV0b3NpemVzQ2xhc3M6ICdsYXp5YXV0b3NpemVzJyxcblx0XHRcdGZhc3RMb2FkZWRDbGFzczogJ2xzLWlzLWNhY2hlZCcsXG5cdFx0XHRpZnJhbWVMb2FkTW9kZTogMCxcblx0XHRcdHNyY0F0dHI6ICdkYXRhLXNyYycsXG5cdFx0XHRzcmNzZXRBdHRyOiAnZGF0YS1zcmNzZXQnLFxuXHRcdFx0c2l6ZXNBdHRyOiAnZGF0YS1zaXplcycsXG5cdFx0XHQvL3ByZWxvYWRBZnRlckxvYWQ6IGZhbHNlLFxuXHRcdFx0bWluU2l6ZTogNDAsXG5cdFx0XHRjdXN0b21NZWRpYToge30sXG5cdFx0XHRpbml0OiB0cnVlLFxuXHRcdFx0ZXhwRmFjdG9yOiAxLjUsXG5cdFx0XHRoRmFjOiAwLjgsXG5cdFx0XHRsb2FkTW9kZTogMixcblx0XHRcdGxvYWRIaWRkZW46IHRydWUsXG5cdFx0XHRyaWNUaW1lb3V0OiAwLFxuXHRcdFx0dGhyb3R0bGVEZWxheTogMTI1LFxuXHRcdH07XG5cblx0XHRsYXp5U2l6ZXNDZmcgPSB3aW5kb3cubGF6eVNpemVzQ29uZmlnIHx8IHdpbmRvdy5sYXp5c2l6ZXNDb25maWcgfHwge307XG5cblx0XHRmb3IocHJvcCBpbiBsYXp5U2l6ZXNEZWZhdWx0cyl7XG5cdFx0XHRpZighKHByb3AgaW4gbGF6eVNpemVzQ2ZnKSl7XG5cdFx0XHRcdGxhenlTaXplc0NmZ1twcm9wXSA9IGxhenlTaXplc0RlZmF1bHRzW3Byb3BdO1xuXHRcdFx0fVxuXHRcdH1cblx0fSkoKTtcblxuXHRpZiAoIWRvY3VtZW50IHx8ICFkb2N1bWVudC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdGluaXQ6IGZ1bmN0aW9uICgpIHt9LFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBAdHlwZSB7IExhenlTaXplc0NvbmZpZ1BhcnRpYWwgfVxuXHRcdFx0ICovXG5cdFx0XHRjZmc6IGxhenlTaXplc0NmZyxcblx0XHRcdC8qKlxuXHRcdFx0ICogQHR5cGUgeyB0cnVlIH1cblx0XHRcdCAqL1xuXHRcdFx0bm9TdXBwb3J0OiB0cnVlLFxuXHRcdH07XG5cdH1cblxuXHR2YXIgZG9jRWxlbSA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudDtcblxuXHR2YXIgc3VwcG9ydFBpY3R1cmUgPSB3aW5kb3cuSFRNTFBpY3R1cmVFbGVtZW50O1xuXG5cdHZhciBfYWRkRXZlbnRMaXN0ZW5lciA9ICdhZGRFdmVudExpc3RlbmVyJztcblxuXHR2YXIgX2dldEF0dHJpYnV0ZSA9ICdnZXRBdHRyaWJ1dGUnO1xuXG5cdC8qKlxuXHQgKiBVcGRhdGUgdG8gYmluZCB0byB3aW5kb3cgYmVjYXVzZSAndGhpcycgYmVjb21lcyBudWxsIGR1cmluZyBTU1Jcblx0ICogYnVpbGRzLlxuXHQgKi9cblx0dmFyIGFkZEV2ZW50TGlzdGVuZXIgPSB3aW5kb3dbX2FkZEV2ZW50TGlzdGVuZXJdLmJpbmQod2luZG93KTtcblxuXHR2YXIgc2V0VGltZW91dCA9IHdpbmRvdy5zZXRUaW1lb3V0O1xuXG5cdHZhciByZXF1ZXN0QW5pbWF0aW9uRnJhbWUgPSB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lIHx8IHNldFRpbWVvdXQ7XG5cblx0dmFyIHJlcXVlc3RJZGxlQ2FsbGJhY2sgPSB3aW5kb3cucmVxdWVzdElkbGVDYWxsYmFjaztcblxuXHR2YXIgcmVnUGljdHVyZSA9IC9ecGljdHVyZSQvaTtcblxuXHR2YXIgbG9hZEV2ZW50cyA9IFsnbG9hZCcsICdlcnJvcicsICdsYXp5aW5jbHVkZWQnLCAnX2xhenlsb2FkZWQnXTtcblxuXHR2YXIgcmVnQ2xhc3NDYWNoZSA9IHt9O1xuXG5cdHZhciBmb3JFYWNoID0gQXJyYXkucHJvdG90eXBlLmZvckVhY2g7XG5cblx0LyoqXG5cdCAqIEBwYXJhbSBlbGUge0VsZW1lbnR9XG5cdCAqIEBwYXJhbSBjbHMge3N0cmluZ31cblx0ICovXG5cdHZhciBoYXNDbGFzcyA9IGZ1bmN0aW9uKGVsZSwgY2xzKSB7XG5cdFx0aWYoIXJlZ0NsYXNzQ2FjaGVbY2xzXSl7XG5cdFx0XHRyZWdDbGFzc0NhY2hlW2Nsc10gPSBuZXcgUmVnRXhwKCcoXFxcXHN8XiknK2NscysnKFxcXFxzfCQpJyk7XG5cdFx0fVxuXHRcdHJldHVybiByZWdDbGFzc0NhY2hlW2Nsc10udGVzdChlbGVbX2dldEF0dHJpYnV0ZV0oJ2NsYXNzJykgfHwgJycpICYmIHJlZ0NsYXNzQ2FjaGVbY2xzXTtcblx0fTtcblxuXHQvKipcblx0ICogQHBhcmFtIGVsZSB7RWxlbWVudH1cblx0ICogQHBhcmFtIGNscyB7c3RyaW5nfVxuXHQgKi9cblx0dmFyIGFkZENsYXNzID0gZnVuY3Rpb24oZWxlLCBjbHMpIHtcblx0XHRpZiAoIWhhc0NsYXNzKGVsZSwgY2xzKSl7XG5cdFx0XHRlbGUuc2V0QXR0cmlidXRlKCdjbGFzcycsIChlbGVbX2dldEF0dHJpYnV0ZV0oJ2NsYXNzJykgfHwgJycpLnRyaW0oKSArICcgJyArIGNscyk7XG5cdFx0fVxuXHR9O1xuXG5cdC8qKlxuXHQgKiBAcGFyYW0gZWxlIHtFbGVtZW50fVxuXHQgKiBAcGFyYW0gY2xzIHtzdHJpbmd9XG5cdCAqL1xuXHR2YXIgcmVtb3ZlQ2xhc3MgPSBmdW5jdGlvbihlbGUsIGNscykge1xuXHRcdHZhciByZWc7XG5cdFx0aWYgKChyZWcgPSBoYXNDbGFzcyhlbGUsY2xzKSkpIHtcblx0XHRcdGVsZS5zZXRBdHRyaWJ1dGUoJ2NsYXNzJywgKGVsZVtfZ2V0QXR0cmlidXRlXSgnY2xhc3MnKSB8fCAnJykucmVwbGFjZShyZWcsICcgJykpO1xuXHRcdH1cblx0fTtcblxuXHR2YXIgYWRkUmVtb3ZlTG9hZEV2ZW50cyA9IGZ1bmN0aW9uKGRvbSwgZm4sIGFkZCl7XG5cdFx0dmFyIGFjdGlvbiA9IGFkZCA/IF9hZGRFdmVudExpc3RlbmVyIDogJ3JlbW92ZUV2ZW50TGlzdGVuZXInO1xuXHRcdGlmKGFkZCl7XG5cdFx0XHRhZGRSZW1vdmVMb2FkRXZlbnRzKGRvbSwgZm4pO1xuXHRcdH1cblx0XHRsb2FkRXZlbnRzLmZvckVhY2goZnVuY3Rpb24oZXZ0KXtcblx0XHRcdGRvbVthY3Rpb25dKGV2dCwgZm4pO1xuXHRcdH0pO1xuXHR9O1xuXG5cdC8qKlxuXHQgKiBAcGFyYW0gZWxlbSB7IEVsZW1lbnQgfVxuXHQgKiBAcGFyYW0gbmFtZSB7IHN0cmluZyB9XG5cdCAqIEBwYXJhbSBkZXRhaWwgeyBhbnkgfVxuXHQgKiBAcGFyYW0gbm9CdWJibGVzIHsgYm9vbGVhbiB9XG5cdCAqIEBwYXJhbSBub0NhbmNlbGFibGUgeyBib29sZWFuIH1cblx0ICogQHJldHVybnMgeyBDdXN0b21FdmVudCB9XG5cdCAqL1xuXHR2YXIgdHJpZ2dlckV2ZW50ID0gZnVuY3Rpb24oZWxlbSwgbmFtZSwgZGV0YWlsLCBub0J1YmJsZXMsIG5vQ2FuY2VsYWJsZSl7XG5cdFx0dmFyIGV2ZW50ID0gZG9jdW1lbnQuY3JlYXRlRXZlbnQoJ0V2ZW50Jyk7XG5cblx0XHRpZighZGV0YWlsKXtcblx0XHRcdGRldGFpbCA9IHt9O1xuXHRcdH1cblxuXHRcdGRldGFpbC5pbnN0YW5jZSA9IGxhenlzaXplcztcblxuXHRcdGV2ZW50LmluaXRFdmVudChuYW1lLCAhbm9CdWJibGVzLCAhbm9DYW5jZWxhYmxlKTtcblxuXHRcdGV2ZW50LmRldGFpbCA9IGRldGFpbDtcblxuXHRcdGVsZW0uZGlzcGF0Y2hFdmVudChldmVudCk7XG5cdFx0cmV0dXJuIGV2ZW50O1xuXHR9O1xuXG5cdHZhciB1cGRhdGVQb2x5ZmlsbCA9IGZ1bmN0aW9uIChlbCwgZnVsbCl7XG5cdFx0dmFyIHBvbHlmaWxsO1xuXHRcdGlmKCAhc3VwcG9ydFBpY3R1cmUgJiYgKCBwb2x5ZmlsbCA9ICh3aW5kb3cucGljdHVyZWZpbGwgfHwgbGF6eVNpemVzQ2ZnLnBmKSApICl7XG5cdFx0XHRpZihmdWxsICYmIGZ1bGwuc3JjICYmICFlbFtfZ2V0QXR0cmlidXRlXSgnc3Jjc2V0Jykpe1xuXHRcdFx0XHRlbC5zZXRBdHRyaWJ1dGUoJ3NyY3NldCcsIGZ1bGwuc3JjKTtcblx0XHRcdH1cblx0XHRcdHBvbHlmaWxsKHtyZWV2YWx1YXRlOiB0cnVlLCBlbGVtZW50czogW2VsXX0pO1xuXHRcdH0gZWxzZSBpZihmdWxsICYmIGZ1bGwuc3JjKXtcblx0XHRcdGVsLnNyYyA9IGZ1bGwuc3JjO1xuXHRcdH1cblx0fTtcblxuXHR2YXIgZ2V0Q1NTID0gZnVuY3Rpb24gKGVsZW0sIHN0eWxlKXtcblx0XHRyZXR1cm4gKGdldENvbXB1dGVkU3R5bGUoZWxlbSwgbnVsbCkgfHwge30pW3N0eWxlXTtcblx0fTtcblxuXHQvKipcblx0ICpcblx0ICogQHBhcmFtIGVsZW0geyBFbGVtZW50IH1cblx0ICogQHBhcmFtIHBhcmVudCB7IEVsZW1lbnQgfVxuXHQgKiBAcGFyYW0gW3dpZHRoXSB7bnVtYmVyfVxuXHQgKiBAcmV0dXJucyB7bnVtYmVyfVxuXHQgKi9cblx0dmFyIGdldFdpZHRoID0gZnVuY3Rpb24oZWxlbSwgcGFyZW50LCB3aWR0aCl7XG5cdFx0d2lkdGggPSB3aWR0aCB8fCBlbGVtLm9mZnNldFdpZHRoO1xuXG5cdFx0d2hpbGUod2lkdGggPCBsYXp5U2l6ZXNDZmcubWluU2l6ZSAmJiBwYXJlbnQgJiYgIWVsZW0uX2xhenlzaXplc1dpZHRoKXtcblx0XHRcdHdpZHRoID0gIHBhcmVudC5vZmZzZXRXaWR0aDtcblx0XHRcdHBhcmVudCA9IHBhcmVudC5wYXJlbnROb2RlO1xuXHRcdH1cblxuXHRcdHJldHVybiB3aWR0aDtcblx0fTtcblxuXHR2YXIgckFGID0gKGZ1bmN0aW9uKCl7XG5cdFx0dmFyIHJ1bm5pbmcsIHdhaXRpbmc7XG5cdFx0dmFyIGZpcnN0Rm5zID0gW107XG5cdFx0dmFyIHNlY29uZEZucyA9IFtdO1xuXHRcdHZhciBmbnMgPSBmaXJzdEZucztcblxuXHRcdHZhciBydW4gPSBmdW5jdGlvbigpe1xuXHRcdFx0dmFyIHJ1bkZucyA9IGZucztcblxuXHRcdFx0Zm5zID0gZmlyc3RGbnMubGVuZ3RoID8gc2Vjb25kRm5zIDogZmlyc3RGbnM7XG5cblx0XHRcdHJ1bm5pbmcgPSB0cnVlO1xuXHRcdFx0d2FpdGluZyA9IGZhbHNlO1xuXG5cdFx0XHR3aGlsZShydW5GbnMubGVuZ3RoKXtcblx0XHRcdFx0cnVuRm5zLnNoaWZ0KCkoKTtcblx0XHRcdH1cblxuXHRcdFx0cnVubmluZyA9IGZhbHNlO1xuXHRcdH07XG5cblx0XHR2YXIgcmFmQmF0Y2ggPSBmdW5jdGlvbihmbiwgcXVldWUpe1xuXHRcdFx0aWYocnVubmluZyAmJiAhcXVldWUpe1xuXHRcdFx0XHRmbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Zm5zLnB1c2goZm4pO1xuXG5cdFx0XHRcdGlmKCF3YWl0aW5nKXtcblx0XHRcdFx0XHR3YWl0aW5nID0gdHJ1ZTtcblx0XHRcdFx0XHQoZG9jdW1lbnQuaGlkZGVuID8gc2V0VGltZW91dCA6IHJlcXVlc3RBbmltYXRpb25GcmFtZSkocnVuKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH07XG5cblx0XHRyYWZCYXRjaC5fbHNGbHVzaCA9IHJ1bjtcblxuXHRcdHJldHVybiByYWZCYXRjaDtcblx0fSkoKTtcblxuXHR2YXIgckFGSXQgPSBmdW5jdGlvbihmbiwgc2ltcGxlKXtcblx0XHRyZXR1cm4gc2ltcGxlID9cblx0XHRcdGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRyQUYoZm4pO1xuXHRcdFx0fSA6XG5cdFx0XHRmdW5jdGlvbigpe1xuXHRcdFx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cdFx0XHRcdHZhciBhcmdzID0gYXJndW1lbnRzO1xuXHRcdFx0XHRyQUYoZnVuY3Rpb24oKXtcblx0XHRcdFx0XHRmbi5hcHBseSh0aGF0LCBhcmdzKTtcblx0XHRcdFx0fSk7XG5cdFx0XHR9XG5cdFx0O1xuXHR9O1xuXG5cdHZhciB0aHJvdHRsZSA9IGZ1bmN0aW9uKGZuKXtcblx0XHR2YXIgcnVubmluZztcblx0XHR2YXIgbGFzdFRpbWUgPSAwO1xuXHRcdHZhciBnRGVsYXkgPSBsYXp5U2l6ZXNDZmcudGhyb3R0bGVEZWxheTtcblx0XHR2YXIgcklDVGltZW91dCA9IGxhenlTaXplc0NmZy5yaWNUaW1lb3V0O1xuXHRcdHZhciBydW4gPSBmdW5jdGlvbigpe1xuXHRcdFx0cnVubmluZyA9IGZhbHNlO1xuXHRcdFx0bGFzdFRpbWUgPSBEYXRlLm5vdygpO1xuXHRcdFx0Zm4oKTtcblx0XHR9O1xuXHRcdHZhciBpZGxlQ2FsbGJhY2sgPSByZXF1ZXN0SWRsZUNhbGxiYWNrICYmIHJJQ1RpbWVvdXQgPiA0OSA/XG5cdFx0XHRmdW5jdGlvbigpe1xuXHRcdFx0XHRyZXF1ZXN0SWRsZUNhbGxiYWNrKHJ1biwge3RpbWVvdXQ6IHJJQ1RpbWVvdXR9KTtcblxuXHRcdFx0XHRpZihySUNUaW1lb3V0ICE9PSBsYXp5U2l6ZXNDZmcucmljVGltZW91dCl7XG5cdFx0XHRcdFx0cklDVGltZW91dCA9IGxhenlTaXplc0NmZy5yaWNUaW1lb3V0O1xuXHRcdFx0XHR9XG5cdFx0XHR9IDpcblx0XHRcdHJBRkl0KGZ1bmN0aW9uKCl7XG5cdFx0XHRcdHNldFRpbWVvdXQocnVuKTtcblx0XHRcdH0sIHRydWUpXG5cdFx0O1xuXG5cdFx0cmV0dXJuIGZ1bmN0aW9uKGlzUHJpb3JpdHkpe1xuXHRcdFx0dmFyIGRlbGF5O1xuXG5cdFx0XHRpZigoaXNQcmlvcml0eSA9IGlzUHJpb3JpdHkgPT09IHRydWUpKXtcblx0XHRcdFx0cklDVGltZW91dCA9IDMzO1xuXHRcdFx0fVxuXG5cdFx0XHRpZihydW5uaW5nKXtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRydW5uaW5nID0gIHRydWU7XG5cblx0XHRcdGRlbGF5ID0gZ0RlbGF5IC0gKERhdGUubm93KCkgLSBsYXN0VGltZSk7XG5cblx0XHRcdGlmKGRlbGF5IDwgMCl7XG5cdFx0XHRcdGRlbGF5ID0gMDtcblx0XHRcdH1cblxuXHRcdFx0aWYoaXNQcmlvcml0eSB8fCBkZWxheSA8IDkpe1xuXHRcdFx0XHRpZGxlQ2FsbGJhY2soKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHNldFRpbWVvdXQoaWRsZUNhbGxiYWNrLCBkZWxheSk7XG5cdFx0XHR9XG5cdFx0fTtcblx0fTtcblxuXHQvL2Jhc2VkIG9uIGh0dHA6Ly9tb2Rlcm5qYXZhc2NyaXB0LmJsb2dzcG90LmRlLzIwMTMvMDgvYnVpbGRpbmctYmV0dGVyLWRlYm91bmNlLmh0bWxcblx0dmFyIGRlYm91bmNlID0gZnVuY3Rpb24oZnVuYykge1xuXHRcdHZhciB0aW1lb3V0LCB0aW1lc3RhbXA7XG5cdFx0dmFyIHdhaXQgPSA5OTtcblx0XHR2YXIgcnVuID0gZnVuY3Rpb24oKXtcblx0XHRcdHRpbWVvdXQgPSBudWxsO1xuXHRcdFx0ZnVuYygpO1xuXHRcdH07XG5cdFx0dmFyIGxhdGVyID0gZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgbGFzdCA9IERhdGUubm93KCkgLSB0aW1lc3RhbXA7XG5cblx0XHRcdGlmIChsYXN0IDwgd2FpdCkge1xuXHRcdFx0XHRzZXRUaW1lb3V0KGxhdGVyLCB3YWl0IC0gbGFzdCk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHQocmVxdWVzdElkbGVDYWxsYmFjayB8fCBydW4pKHJ1bik7XG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdHJldHVybiBmdW5jdGlvbigpIHtcblx0XHRcdHRpbWVzdGFtcCA9IERhdGUubm93KCk7XG5cblx0XHRcdGlmICghdGltZW91dCkge1xuXHRcdFx0XHR0aW1lb3V0ID0gc2V0VGltZW91dChsYXRlciwgd2FpdCk7XG5cdFx0XHR9XG5cdFx0fTtcblx0fTtcblxuXHR2YXIgbG9hZGVyID0gKGZ1bmN0aW9uKCl7XG5cdFx0dmFyIHByZWxvYWRFbGVtcywgaXNDb21wbGV0ZWQsIHJlc2V0UHJlbG9hZGluZ1RpbWVyLCBsb2FkTW9kZSwgc3RhcnRlZDtcblxuXHRcdHZhciBlTHZXLCBlbHZILCBlTHRvcCwgZUxsZWZ0LCBlTHJpZ2h0LCBlTGJvdHRvbSwgaXNCb2R5SGlkZGVuO1xuXG5cdFx0dmFyIHJlZ0ltZyA9IC9eaW1nJC9pO1xuXHRcdHZhciByZWdJZnJhbWUgPSAvXmlmcmFtZSQvaTtcblxuXHRcdHZhciBzdXBwb3J0U2Nyb2xsID0gKCdvbnNjcm9sbCcgaW4gd2luZG93KSAmJiAhKC8oZ2xlfGluZylib3QvLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCkpO1xuXG5cdFx0dmFyIHNocmlua0V4cGFuZCA9IDA7XG5cdFx0dmFyIGN1cnJlbnRFeHBhbmQgPSAwO1xuXG5cdFx0dmFyIGlzTG9hZGluZyA9IDA7XG5cdFx0dmFyIGxvd1J1bnMgPSAtMTtcblxuXHRcdHZhciByZXNldFByZWxvYWRpbmcgPSBmdW5jdGlvbihlKXtcblx0XHRcdGlzTG9hZGluZy0tO1xuXHRcdFx0aWYoIWUgfHwgaXNMb2FkaW5nIDwgMCB8fCAhZS50YXJnZXQpe1xuXHRcdFx0XHRpc0xvYWRpbmcgPSAwO1xuXHRcdFx0fVxuXHRcdH07XG5cblx0XHR2YXIgaXNWaXNpYmxlID0gZnVuY3Rpb24gKGVsZW0pIHtcblx0XHRcdGlmIChpc0JvZHlIaWRkZW4gPT0gbnVsbCkge1xuXHRcdFx0XHRpc0JvZHlIaWRkZW4gPSBnZXRDU1MoZG9jdW1lbnQuYm9keSwgJ3Zpc2liaWxpdHknKSA9PSAnaGlkZGVuJztcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGlzQm9keUhpZGRlbiB8fCAhKGdldENTUyhlbGVtLnBhcmVudE5vZGUsICd2aXNpYmlsaXR5JykgPT0gJ2hpZGRlbicgJiYgZ2V0Q1NTKGVsZW0sICd2aXNpYmlsaXR5JykgPT0gJ2hpZGRlbicpO1xuXHRcdH07XG5cblx0XHR2YXIgaXNOZXN0ZWRWaXNpYmxlID0gZnVuY3Rpb24oZWxlbSwgZWxlbUV4cGFuZCl7XG5cdFx0XHR2YXIgb3V0ZXJSZWN0O1xuXHRcdFx0dmFyIHBhcmVudCA9IGVsZW07XG5cdFx0XHR2YXIgdmlzaWJsZSA9IGlzVmlzaWJsZShlbGVtKTtcblxuXHRcdFx0ZUx0b3AgLT0gZWxlbUV4cGFuZDtcblx0XHRcdGVMYm90dG9tICs9IGVsZW1FeHBhbmQ7XG5cdFx0XHRlTGxlZnQgLT0gZWxlbUV4cGFuZDtcblx0XHRcdGVMcmlnaHQgKz0gZWxlbUV4cGFuZDtcblxuXHRcdFx0d2hpbGUodmlzaWJsZSAmJiAocGFyZW50ID0gcGFyZW50Lm9mZnNldFBhcmVudCkgJiYgcGFyZW50ICE9IGRvY3VtZW50LmJvZHkgJiYgcGFyZW50ICE9IGRvY0VsZW0pe1xuXHRcdFx0XHR2aXNpYmxlID0gKChnZXRDU1MocGFyZW50LCAnb3BhY2l0eScpIHx8IDEpID4gMCk7XG5cblx0XHRcdFx0aWYodmlzaWJsZSAmJiBnZXRDU1MocGFyZW50LCAnb3ZlcmZsb3cnKSAhPSAndmlzaWJsZScpe1xuXHRcdFx0XHRcdG91dGVyUmVjdCA9IHBhcmVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcblx0XHRcdFx0XHR2aXNpYmxlID0gZUxyaWdodCA+IG91dGVyUmVjdC5sZWZ0ICYmXG5cdFx0XHRcdFx0XHRlTGxlZnQgPCBvdXRlclJlY3QucmlnaHQgJiZcblx0XHRcdFx0XHRcdGVMYm90dG9tID4gb3V0ZXJSZWN0LnRvcCAtIDEgJiZcblx0XHRcdFx0XHRcdGVMdG9wIDwgb3V0ZXJSZWN0LmJvdHRvbSArIDFcblx0XHRcdFx0XHQ7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHZpc2libGU7XG5cdFx0fTtcblxuXHRcdHZhciBjaGVja0VsZW1lbnRzID0gZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgZUxsZW4sIGksIHJlY3QsIGF1dG9Mb2FkRWxlbSwgbG9hZGVkU29tZXRoaW5nLCBlbGVtRXhwYW5kLCBlbGVtTmVnYXRpdmVFeHBhbmQsIGVsZW1FeHBhbmRWYWwsXG5cdFx0XHRcdGJlZm9yZUV4cGFuZFZhbCwgZGVmYXVsdEV4cGFuZCwgcHJlbG9hZEV4cGFuZCwgaEZhYztcblx0XHRcdHZhciBsYXp5bG9hZEVsZW1zID0gbGF6eXNpemVzLmVsZW1lbnRzO1xuXG5cdFx0XHRpZigobG9hZE1vZGUgPSBsYXp5U2l6ZXNDZmcubG9hZE1vZGUpICYmIGlzTG9hZGluZyA8IDggJiYgKGVMbGVuID0gbGF6eWxvYWRFbGVtcy5sZW5ndGgpKXtcblxuXHRcdFx0XHRpID0gMDtcblxuXHRcdFx0XHRsb3dSdW5zKys7XG5cblx0XHRcdFx0Zm9yKDsgaSA8IGVMbGVuOyBpKyspe1xuXG5cdFx0XHRcdFx0aWYoIWxhenlsb2FkRWxlbXNbaV0gfHwgbGF6eWxvYWRFbGVtc1tpXS5fbGF6eVJhY2Upe2NvbnRpbnVlO31cblxuXHRcdFx0XHRcdGlmKCFzdXBwb3J0U2Nyb2xsIHx8IChsYXp5c2l6ZXMucHJlbWF0dXJlVW52ZWlsICYmIGxhenlzaXplcy5wcmVtYXR1cmVVbnZlaWwobGF6eWxvYWRFbGVtc1tpXSkpKXt1bnZlaWxFbGVtZW50KGxhenlsb2FkRWxlbXNbaV0pO2NvbnRpbnVlO31cblxuXHRcdFx0XHRcdGlmKCEoZWxlbUV4cGFuZFZhbCA9IGxhenlsb2FkRWxlbXNbaV1bX2dldEF0dHJpYnV0ZV0oJ2RhdGEtZXhwYW5kJykpIHx8ICEoZWxlbUV4cGFuZCA9IGVsZW1FeHBhbmRWYWwgKiAxKSl7XG5cdFx0XHRcdFx0XHRlbGVtRXhwYW5kID0gY3VycmVudEV4cGFuZDtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoIWRlZmF1bHRFeHBhbmQpIHtcblx0XHRcdFx0XHRcdGRlZmF1bHRFeHBhbmQgPSAoIWxhenlTaXplc0NmZy5leHBhbmQgfHwgbGF6eVNpemVzQ2ZnLmV4cGFuZCA8IDEpID9cblx0XHRcdFx0XHRcdFx0ZG9jRWxlbS5jbGllbnRIZWlnaHQgPiA1MDAgJiYgZG9jRWxlbS5jbGllbnRXaWR0aCA+IDUwMCA/IDUwMCA6IDM3MCA6XG5cdFx0XHRcdFx0XHRcdGxhenlTaXplc0NmZy5leHBhbmQ7XG5cblx0XHRcdFx0XHRcdGxhenlzaXplcy5fZGVmRXggPSBkZWZhdWx0RXhwYW5kO1xuXG5cdFx0XHRcdFx0XHRwcmVsb2FkRXhwYW5kID0gZGVmYXVsdEV4cGFuZCAqIGxhenlTaXplc0NmZy5leHBGYWN0b3I7XG5cdFx0XHRcdFx0XHRoRmFjID0gbGF6eVNpemVzQ2ZnLmhGYWM7XG5cdFx0XHRcdFx0XHRpc0JvZHlIaWRkZW4gPSBudWxsO1xuXG5cdFx0XHRcdFx0XHRpZihjdXJyZW50RXhwYW5kIDwgcHJlbG9hZEV4cGFuZCAmJiBpc0xvYWRpbmcgPCAxICYmIGxvd1J1bnMgPiAyICYmIGxvYWRNb2RlID4gMiAmJiAhZG9jdW1lbnQuaGlkZGVuKXtcblx0XHRcdFx0XHRcdFx0Y3VycmVudEV4cGFuZCA9IHByZWxvYWRFeHBhbmQ7XG5cdFx0XHRcdFx0XHRcdGxvd1J1bnMgPSAwO1xuXHRcdFx0XHRcdFx0fSBlbHNlIGlmKGxvYWRNb2RlID4gMSAmJiBsb3dSdW5zID4gMSAmJiBpc0xvYWRpbmcgPCA2KXtcblx0XHRcdFx0XHRcdFx0Y3VycmVudEV4cGFuZCA9IGRlZmF1bHRFeHBhbmQ7XG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRjdXJyZW50RXhwYW5kID0gc2hyaW5rRXhwYW5kO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmKGJlZm9yZUV4cGFuZFZhbCAhPT0gZWxlbUV4cGFuZCl7XG5cdFx0XHRcdFx0XHRlTHZXID0gaW5uZXJXaWR0aCArIChlbGVtRXhwYW5kICogaEZhYyk7XG5cdFx0XHRcdFx0XHRlbHZIID0gaW5uZXJIZWlnaHQgKyBlbGVtRXhwYW5kO1xuXHRcdFx0XHRcdFx0ZWxlbU5lZ2F0aXZlRXhwYW5kID0gZWxlbUV4cGFuZCAqIC0xO1xuXHRcdFx0XHRcdFx0YmVmb3JlRXhwYW5kVmFsID0gZWxlbUV4cGFuZDtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRyZWN0ID0gbGF6eWxvYWRFbGVtc1tpXS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcblxuXHRcdFx0XHRcdGlmICgoZUxib3R0b20gPSByZWN0LmJvdHRvbSkgPj0gZWxlbU5lZ2F0aXZlRXhwYW5kICYmXG5cdFx0XHRcdFx0XHQoZUx0b3AgPSByZWN0LnRvcCkgPD0gZWx2SCAmJlxuXHRcdFx0XHRcdFx0KGVMcmlnaHQgPSByZWN0LnJpZ2h0KSA+PSBlbGVtTmVnYXRpdmVFeHBhbmQgKiBoRmFjICYmXG5cdFx0XHRcdFx0XHQoZUxsZWZ0ID0gcmVjdC5sZWZ0KSA8PSBlTHZXICYmXG5cdFx0XHRcdFx0XHQoZUxib3R0b20gfHwgZUxyaWdodCB8fCBlTGxlZnQgfHwgZUx0b3ApICYmXG5cdFx0XHRcdFx0XHQobGF6eVNpemVzQ2ZnLmxvYWRIaWRkZW4gfHwgaXNWaXNpYmxlKGxhenlsb2FkRWxlbXNbaV0pKSAmJlxuXHRcdFx0XHRcdFx0KChpc0NvbXBsZXRlZCAmJiBpc0xvYWRpbmcgPCAzICYmICFlbGVtRXhwYW5kVmFsICYmIChsb2FkTW9kZSA8IDMgfHwgbG93UnVucyA8IDQpKSB8fCBpc05lc3RlZFZpc2libGUobGF6eWxvYWRFbGVtc1tpXSwgZWxlbUV4cGFuZCkpKXtcblx0XHRcdFx0XHRcdHVudmVpbEVsZW1lbnQobGF6eWxvYWRFbGVtc1tpXSk7XG5cdFx0XHRcdFx0XHRsb2FkZWRTb21ldGhpbmcgPSB0cnVlO1xuXHRcdFx0XHRcdFx0aWYoaXNMb2FkaW5nID4gOSl7YnJlYWs7fVxuXHRcdFx0XHRcdH0gZWxzZSBpZighbG9hZGVkU29tZXRoaW5nICYmIGlzQ29tcGxldGVkICYmICFhdXRvTG9hZEVsZW0gJiZcblx0XHRcdFx0XHRcdGlzTG9hZGluZyA8IDQgJiYgbG93UnVucyA8IDQgJiYgbG9hZE1vZGUgPiAyICYmXG5cdFx0XHRcdFx0XHQocHJlbG9hZEVsZW1zWzBdIHx8IGxhenlTaXplc0NmZy5wcmVsb2FkQWZ0ZXJMb2FkKSAmJlxuXHRcdFx0XHRcdFx0KHByZWxvYWRFbGVtc1swXSB8fCAoIWVsZW1FeHBhbmRWYWwgJiYgKChlTGJvdHRvbSB8fCBlTHJpZ2h0IHx8IGVMbGVmdCB8fCBlTHRvcCkgfHwgbGF6eWxvYWRFbGVtc1tpXVtfZ2V0QXR0cmlidXRlXShsYXp5U2l6ZXNDZmcuc2l6ZXNBdHRyKSAhPSAnYXV0bycpKSkpe1xuXHRcdFx0XHRcdFx0YXV0b0xvYWRFbGVtID0gcHJlbG9hZEVsZW1zWzBdIHx8IGxhenlsb2FkRWxlbXNbaV07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYoYXV0b0xvYWRFbGVtICYmICFsb2FkZWRTb21ldGhpbmcpe1xuXHRcdFx0XHRcdHVudmVpbEVsZW1lbnQoYXV0b0xvYWRFbGVtKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH07XG5cblx0XHR2YXIgdGhyb3R0bGVkQ2hlY2tFbGVtZW50cyA9IHRocm90dGxlKGNoZWNrRWxlbWVudHMpO1xuXG5cdFx0dmFyIHN3aXRjaExvYWRpbmdDbGFzcyA9IGZ1bmN0aW9uKGUpe1xuXHRcdFx0dmFyIGVsZW0gPSBlLnRhcmdldDtcblxuXHRcdFx0aWYgKGVsZW0uX2xhenlDYWNoZSkge1xuXHRcdFx0XHRkZWxldGUgZWxlbS5fbGF6eUNhY2hlO1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdHJlc2V0UHJlbG9hZGluZyhlKTtcblx0XHRcdGFkZENsYXNzKGVsZW0sIGxhenlTaXplc0NmZy5sb2FkZWRDbGFzcyk7XG5cdFx0XHRyZW1vdmVDbGFzcyhlbGVtLCBsYXp5U2l6ZXNDZmcubG9hZGluZ0NsYXNzKTtcblx0XHRcdGFkZFJlbW92ZUxvYWRFdmVudHMoZWxlbSwgcmFmU3dpdGNoTG9hZGluZ0NsYXNzKTtcblx0XHRcdHRyaWdnZXJFdmVudChlbGVtLCAnbGF6eWxvYWRlZCcpO1xuXHRcdH07XG5cdFx0dmFyIHJhZmVkU3dpdGNoTG9hZGluZ0NsYXNzID0gckFGSXQoc3dpdGNoTG9hZGluZ0NsYXNzKTtcblx0XHR2YXIgcmFmU3dpdGNoTG9hZGluZ0NsYXNzID0gZnVuY3Rpb24oZSl7XG5cdFx0XHRyYWZlZFN3aXRjaExvYWRpbmdDbGFzcyh7dGFyZ2V0OiBlLnRhcmdldH0pO1xuXHRcdH07XG5cblx0XHR2YXIgY2hhbmdlSWZyYW1lU3JjID0gZnVuY3Rpb24oZWxlbSwgc3JjKXtcblx0XHRcdHZhciBsb2FkTW9kZSA9IGVsZW0uZ2V0QXR0cmlidXRlKCdkYXRhLWxvYWQtbW9kZScpIHx8IGxhenlTaXplc0NmZy5pZnJhbWVMb2FkTW9kZTtcblxuXHRcdFx0Ly8gbG9hZE1vZGUgY2FuIGJlIGFsc28gYSBzdHJpbmchXG5cdFx0XHRpZiAobG9hZE1vZGUgPT0gMCkge1xuXHRcdFx0XHRlbGVtLmNvbnRlbnRXaW5kb3cubG9jYXRpb24ucmVwbGFjZShzcmMpO1xuXHRcdFx0fSBlbHNlIGlmIChsb2FkTW9kZSA9PSAxKSB7XG5cdFx0XHRcdGVsZW0uc3JjID0gc3JjO1xuXHRcdFx0fVxuXHRcdH07XG5cblx0XHR2YXIgaGFuZGxlU291cmNlcyA9IGZ1bmN0aW9uKHNvdXJjZSl7XG5cdFx0XHR2YXIgY3VzdG9tTWVkaWE7XG5cblx0XHRcdHZhciBzb3VyY2VTcmNzZXQgPSBzb3VyY2VbX2dldEF0dHJpYnV0ZV0obGF6eVNpemVzQ2ZnLnNyY3NldEF0dHIpO1xuXG5cdFx0XHRpZiggKGN1c3RvbU1lZGlhID0gbGF6eVNpemVzQ2ZnLmN1c3RvbU1lZGlhW3NvdXJjZVtfZ2V0QXR0cmlidXRlXSgnZGF0YS1tZWRpYScpIHx8IHNvdXJjZVtfZ2V0QXR0cmlidXRlXSgnbWVkaWEnKV0pICl7XG5cdFx0XHRcdHNvdXJjZS5zZXRBdHRyaWJ1dGUoJ21lZGlhJywgY3VzdG9tTWVkaWEpO1xuXHRcdFx0fVxuXG5cdFx0XHRpZihzb3VyY2VTcmNzZXQpe1xuXHRcdFx0XHRzb3VyY2Uuc2V0QXR0cmlidXRlKCdzcmNzZXQnLCBzb3VyY2VTcmNzZXQpO1xuXHRcdFx0fVxuXHRcdH07XG5cblx0XHR2YXIgbGF6eVVudmVpbCA9IHJBRkl0KGZ1bmN0aW9uIChlbGVtLCBkZXRhaWwsIGlzQXV0bywgc2l6ZXMsIGlzSW1nKXtcblx0XHRcdHZhciBzcmMsIHNyY3NldCwgcGFyZW50LCBpc1BpY3R1cmUsIGV2ZW50LCBmaXJlc0xvYWQ7XG5cblx0XHRcdGlmKCEoZXZlbnQgPSB0cmlnZ2VyRXZlbnQoZWxlbSwgJ2xhenliZWZvcmV1bnZlaWwnLCBkZXRhaWwpKS5kZWZhdWx0UHJldmVudGVkKXtcblxuXHRcdFx0XHRpZihzaXplcyl7XG5cdFx0XHRcdFx0aWYoaXNBdXRvKXtcblx0XHRcdFx0XHRcdGFkZENsYXNzKGVsZW0sIGxhenlTaXplc0NmZy5hdXRvc2l6ZXNDbGFzcyk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdGVsZW0uc2V0QXR0cmlidXRlKCdzaXplcycsIHNpemVzKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRzcmNzZXQgPSBlbGVtW19nZXRBdHRyaWJ1dGVdKGxhenlTaXplc0NmZy5zcmNzZXRBdHRyKTtcblx0XHRcdFx0c3JjID0gZWxlbVtfZ2V0QXR0cmlidXRlXShsYXp5U2l6ZXNDZmcuc3JjQXR0cik7XG5cblx0XHRcdFx0aWYoaXNJbWcpIHtcblx0XHRcdFx0XHRwYXJlbnQgPSBlbGVtLnBhcmVudE5vZGU7XG5cdFx0XHRcdFx0aXNQaWN0dXJlID0gcGFyZW50ICYmIHJlZ1BpY3R1cmUudGVzdChwYXJlbnQubm9kZU5hbWUgfHwgJycpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0ZmlyZXNMb2FkID0gZGV0YWlsLmZpcmVzTG9hZCB8fCAoKCdzcmMnIGluIGVsZW0pICYmIChzcmNzZXQgfHwgc3JjIHx8IGlzUGljdHVyZSkpO1xuXG5cdFx0XHRcdGV2ZW50ID0ge3RhcmdldDogZWxlbX07XG5cblx0XHRcdFx0YWRkQ2xhc3MoZWxlbSwgbGF6eVNpemVzQ2ZnLmxvYWRpbmdDbGFzcyk7XG5cblx0XHRcdFx0aWYoZmlyZXNMb2FkKXtcblx0XHRcdFx0XHRjbGVhclRpbWVvdXQocmVzZXRQcmVsb2FkaW5nVGltZXIpO1xuXHRcdFx0XHRcdHJlc2V0UHJlbG9hZGluZ1RpbWVyID0gc2V0VGltZW91dChyZXNldFByZWxvYWRpbmcsIDI1MDApO1xuXHRcdFx0XHRcdGFkZFJlbW92ZUxvYWRFdmVudHMoZWxlbSwgcmFmU3dpdGNoTG9hZGluZ0NsYXNzLCB0cnVlKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmKGlzUGljdHVyZSl7XG5cdFx0XHRcdFx0Zm9yRWFjaC5jYWxsKHBhcmVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc291cmNlJyksIGhhbmRsZVNvdXJjZXMpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYoc3Jjc2V0KXtcblx0XHRcdFx0XHRlbGVtLnNldEF0dHJpYnV0ZSgnc3Jjc2V0Jywgc3Jjc2V0KTtcblx0XHRcdFx0fSBlbHNlIGlmKHNyYyAmJiAhaXNQaWN0dXJlKXtcblx0XHRcdFx0XHRpZihyZWdJZnJhbWUudGVzdChlbGVtLm5vZGVOYW1lKSl7XG5cdFx0XHRcdFx0XHRjaGFuZ2VJZnJhbWVTcmMoZWxlbSwgc3JjKTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0ZWxlbS5zcmMgPSBzcmM7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYoaXNJbWcgJiYgKHNyY3NldCB8fCBpc1BpY3R1cmUpKXtcblx0XHRcdFx0XHR1cGRhdGVQb2x5ZmlsbChlbGVtLCB7c3JjOiBzcmN9KTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHRpZihlbGVtLl9sYXp5UmFjZSl7XG5cdFx0XHRcdGRlbGV0ZSBlbGVtLl9sYXp5UmFjZTtcblx0XHRcdH1cblx0XHRcdHJlbW92ZUNsYXNzKGVsZW0sIGxhenlTaXplc0NmZy5sYXp5Q2xhc3MpO1xuXG5cdFx0XHRyQUYoZnVuY3Rpb24oKXtcblx0XHRcdFx0Ly8gUGFydCBvZiB0aGlzIGNhbiBiZSByZW1vdmVkIGFzIHNvb24gYXMgdGhpcyBmaXggaXMgb2xkZXI6IGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTc3MzEgKDIwMTUpXG5cdFx0XHRcdHZhciBpc0xvYWRlZCA9IGVsZW0uY29tcGxldGUgJiYgZWxlbS5uYXR1cmFsV2lkdGggPiAxO1xuXG5cdFx0XHRcdGlmKCAhZmlyZXNMb2FkIHx8IGlzTG9hZGVkKXtcblx0XHRcdFx0XHRpZiAoaXNMb2FkZWQpIHtcblx0XHRcdFx0XHRcdGFkZENsYXNzKGVsZW0sIGxhenlTaXplc0NmZy5mYXN0TG9hZGVkQ2xhc3MpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRzd2l0Y2hMb2FkaW5nQ2xhc3MoZXZlbnQpO1xuXHRcdFx0XHRcdGVsZW0uX2xhenlDYWNoZSA9IHRydWU7XG5cdFx0XHRcdFx0c2V0VGltZW91dChmdW5jdGlvbigpe1xuXHRcdFx0XHRcdFx0aWYgKCdfbGF6eUNhY2hlJyBpbiBlbGVtKSB7XG5cdFx0XHRcdFx0XHRcdGRlbGV0ZSBlbGVtLl9sYXp5Q2FjaGU7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSwgOSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKGVsZW0ubG9hZGluZyA9PSAnbGF6eScpIHtcblx0XHRcdFx0XHRpc0xvYWRpbmctLTtcblx0XHRcdFx0fVxuXHRcdFx0fSwgdHJ1ZSk7XG5cdFx0fSk7XG5cblx0XHQvKipcblx0XHQgKlxuXHRcdCAqIEBwYXJhbSBlbGVtIHsgRWxlbWVudCB9XG5cdFx0ICovXG5cdFx0dmFyIHVudmVpbEVsZW1lbnQgPSBmdW5jdGlvbiAoZWxlbSl7XG5cdFx0XHRpZiAoZWxlbS5fbGF6eVJhY2UpIHtyZXR1cm47fVxuXHRcdFx0dmFyIGRldGFpbDtcblxuXHRcdFx0dmFyIGlzSW1nID0gcmVnSW1nLnRlc3QoZWxlbS5ub2RlTmFtZSk7XG5cblx0XHRcdC8vYWxsb3cgdXNpbmcgc2l6ZXM9XCJhdXRvXCIsIGJ1dCBkb24ndCB1c2UuIGl0J3MgaW52YWxpZC4gVXNlIGRhdGEtc2l6ZXM9XCJhdXRvXCIgb3IgYSB2YWxpZCB2YWx1ZSBmb3Igc2l6ZXMgaW5zdGVhZCAoaS5lLjogc2l6ZXM9XCI4MHZ3XCIpXG5cdFx0XHR2YXIgc2l6ZXMgPSBpc0ltZyAmJiAoZWxlbVtfZ2V0QXR0cmlidXRlXShsYXp5U2l6ZXNDZmcuc2l6ZXNBdHRyKSB8fCBlbGVtW19nZXRBdHRyaWJ1dGVdKCdzaXplcycpKTtcblx0XHRcdHZhciBpc0F1dG8gPSBzaXplcyA9PSAnYXV0byc7XG5cblx0XHRcdGlmKCAoaXNBdXRvIHx8ICFpc0NvbXBsZXRlZCkgJiYgaXNJbWcgJiYgKGVsZW1bX2dldEF0dHJpYnV0ZV0oJ3NyYycpIHx8IGVsZW0uc3Jjc2V0KSAmJiAhZWxlbS5jb21wbGV0ZSAmJiAhaGFzQ2xhc3MoZWxlbSwgbGF6eVNpemVzQ2ZnLmVycm9yQ2xhc3MpICYmIGhhc0NsYXNzKGVsZW0sIGxhenlTaXplc0NmZy5sYXp5Q2xhc3MpKXtyZXR1cm47fVxuXG5cdFx0XHRkZXRhaWwgPSB0cmlnZ2VyRXZlbnQoZWxlbSwgJ2xhenl1bnZlaWxyZWFkJykuZGV0YWlsO1xuXG5cdFx0XHRpZihpc0F1dG8pe1xuXHRcdFx0XHQgYXV0b1NpemVyLnVwZGF0ZUVsZW0oZWxlbSwgdHJ1ZSwgZWxlbS5vZmZzZXRXaWR0aCk7XG5cdFx0XHR9XG5cblx0XHRcdGVsZW0uX2xhenlSYWNlID0gdHJ1ZTtcblx0XHRcdGlzTG9hZGluZysrO1xuXG5cdFx0XHRsYXp5VW52ZWlsKGVsZW0sIGRldGFpbCwgaXNBdXRvLCBzaXplcywgaXNJbWcpO1xuXHRcdH07XG5cblx0XHR2YXIgYWZ0ZXJTY3JvbGwgPSBkZWJvdW5jZShmdW5jdGlvbigpe1xuXHRcdFx0bGF6eVNpemVzQ2ZnLmxvYWRNb2RlID0gMztcblx0XHRcdHRocm90dGxlZENoZWNrRWxlbWVudHMoKTtcblx0XHR9KTtcblxuXHRcdHZhciBhbHRMb2FkbW9kZVNjcm9sbExpc3RuZXIgPSBmdW5jdGlvbigpe1xuXHRcdFx0aWYobGF6eVNpemVzQ2ZnLmxvYWRNb2RlID09IDMpe1xuXHRcdFx0XHRsYXp5U2l6ZXNDZmcubG9hZE1vZGUgPSAyO1xuXHRcdFx0fVxuXHRcdFx0YWZ0ZXJTY3JvbGwoKTtcblx0XHR9O1xuXG5cdFx0dmFyIG9ubG9hZCA9IGZ1bmN0aW9uKCl7XG5cdFx0XHRpZihpc0NvbXBsZXRlZCl7cmV0dXJuO31cblx0XHRcdGlmKERhdGUubm93KCkgLSBzdGFydGVkIDwgOTk5KXtcblx0XHRcdFx0c2V0VGltZW91dChvbmxvYWQsIDk5OSk7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXG5cdFx0XHRpc0NvbXBsZXRlZCA9IHRydWU7XG5cblx0XHRcdGxhenlTaXplc0NmZy5sb2FkTW9kZSA9IDM7XG5cblx0XHRcdHRocm90dGxlZENoZWNrRWxlbWVudHMoKTtcblxuXHRcdFx0YWRkRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgYWx0TG9hZG1vZGVTY3JvbGxMaXN0bmVyLCB0cnVlKTtcblx0XHR9O1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdF86IGZ1bmN0aW9uKCl7XG5cdFx0XHRcdHN0YXJ0ZWQgPSBEYXRlLm5vdygpO1xuXG5cdFx0XHRcdGxhenlzaXplcy5lbGVtZW50cyA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlDbGFzc05hbWUobGF6eVNpemVzQ2ZnLmxhenlDbGFzcyk7XG5cdFx0XHRcdHByZWxvYWRFbGVtcyA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlDbGFzc05hbWUobGF6eVNpemVzQ2ZnLmxhenlDbGFzcyArICcgJyArIGxhenlTaXplc0NmZy5wcmVsb2FkQ2xhc3MpO1xuXG5cdFx0XHRcdGFkZEV2ZW50TGlzdGVuZXIoJ3Njcm9sbCcsIHRocm90dGxlZENoZWNrRWxlbWVudHMsIHRydWUpO1xuXG5cdFx0XHRcdGFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIHRocm90dGxlZENoZWNrRWxlbWVudHMsIHRydWUpO1xuXG5cdFx0XHRcdGFkZEV2ZW50TGlzdGVuZXIoJ3BhZ2VzaG93JywgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRpZiAoZS5wZXJzaXN0ZWQpIHtcblx0XHRcdFx0XHRcdHZhciBsb2FkaW5nRWxlbWVudHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcuJyArIGxhenlTaXplc0NmZy5sb2FkaW5nQ2xhc3MpO1xuXG5cdFx0XHRcdFx0XHRpZiAobG9hZGluZ0VsZW1lbnRzLmxlbmd0aCAmJiBsb2FkaW5nRWxlbWVudHMuZm9yRWFjaCkge1xuXHRcdFx0XHRcdFx0XHRyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdFx0XHRcdGxvYWRpbmdFbGVtZW50cy5mb3JFYWNoKCBmdW5jdGlvbiAoaW1nKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAoaW1nLmNvbXBsZXRlKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHVudmVpbEVsZW1lbnQoaW1nKTtcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9KTtcblxuXHRcdFx0XHRpZih3aW5kb3cuTXV0YXRpb25PYnNlcnZlcil7XG5cdFx0XHRcdFx0bmV3IE11dGF0aW9uT2JzZXJ2ZXIoIHRocm90dGxlZENoZWNrRWxlbWVudHMgKS5vYnNlcnZlKCBkb2NFbGVtLCB7Y2hpbGRMaXN0OiB0cnVlLCBzdWJ0cmVlOiB0cnVlLCBhdHRyaWJ1dGVzOiB0cnVlfSApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGRvY0VsZW1bX2FkZEV2ZW50TGlzdGVuZXJdKCdET01Ob2RlSW5zZXJ0ZWQnLCB0aHJvdHRsZWRDaGVja0VsZW1lbnRzLCB0cnVlKTtcblx0XHRcdFx0XHRkb2NFbGVtW19hZGRFdmVudExpc3RlbmVyXSgnRE9NQXR0ck1vZGlmaWVkJywgdGhyb3R0bGVkQ2hlY2tFbGVtZW50cywgdHJ1ZSk7XG5cdFx0XHRcdFx0c2V0SW50ZXJ2YWwodGhyb3R0bGVkQ2hlY2tFbGVtZW50cywgOTk5KTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGFkZEV2ZW50TGlzdGVuZXIoJ2hhc2hjaGFuZ2UnLCB0aHJvdHRsZWRDaGVja0VsZW1lbnRzLCB0cnVlKTtcblxuXHRcdFx0XHQvLywgJ2Z1bGxzY3JlZW5jaGFuZ2UnXG5cdFx0XHRcdFsnZm9jdXMnLCAnbW91c2VvdmVyJywgJ2NsaWNrJywgJ2xvYWQnLCAndHJhbnNpdGlvbmVuZCcsICdhbmltYXRpb25lbmQnXS5mb3JFYWNoKGZ1bmN0aW9uKG5hbWUpe1xuXHRcdFx0XHRcdGRvY3VtZW50W19hZGRFdmVudExpc3RlbmVyXShuYW1lLCB0aHJvdHRsZWRDaGVja0VsZW1lbnRzLCB0cnVlKTtcblx0XHRcdFx0fSk7XG5cblx0XHRcdFx0aWYoKC9kJHxeYy8udGVzdChkb2N1bWVudC5yZWFkeVN0YXRlKSkpe1xuXHRcdFx0XHRcdG9ubG9hZCgpO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCBvbmxvYWQpO1xuXHRcdFx0XHRcdGRvY3VtZW50W19hZGRFdmVudExpc3RlbmVyXSgnRE9NQ29udGVudExvYWRlZCcsIHRocm90dGxlZENoZWNrRWxlbWVudHMpO1xuXHRcdFx0XHRcdHNldFRpbWVvdXQob25sb2FkLCAyMDAwMCk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZihsYXp5c2l6ZXMuZWxlbWVudHMubGVuZ3RoKXtcblx0XHRcdFx0XHRjaGVja0VsZW1lbnRzKCk7XG5cdFx0XHRcdFx0ckFGLl9sc0ZsdXNoKCk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0dGhyb3R0bGVkQ2hlY2tFbGVtZW50cygpO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0Y2hlY2tFbGVtczogdGhyb3R0bGVkQ2hlY2tFbGVtZW50cyxcblx0XHRcdHVudmVpbDogdW52ZWlsRWxlbWVudCxcblx0XHRcdF9hTFNMOiBhbHRMb2FkbW9kZVNjcm9sbExpc3RuZXIsXG5cdFx0fTtcblx0fSkoKTtcblxuXG5cdHZhciBhdXRvU2l6ZXIgPSAoZnVuY3Rpb24oKXtcblx0XHR2YXIgYXV0b3NpemVzRWxlbXM7XG5cblx0XHR2YXIgc2l6ZUVsZW1lbnQgPSByQUZJdChmdW5jdGlvbihlbGVtLCBwYXJlbnQsIGV2ZW50LCB3aWR0aCl7XG5cdFx0XHR2YXIgc291cmNlcywgaSwgbGVuO1xuXHRcdFx0ZWxlbS5fbGF6eXNpemVzV2lkdGggPSB3aWR0aDtcblx0XHRcdHdpZHRoICs9ICdweCc7XG5cblx0XHRcdGVsZW0uc2V0QXR0cmlidXRlKCdzaXplcycsIHdpZHRoKTtcblxuXHRcdFx0aWYocmVnUGljdHVyZS50ZXN0KHBhcmVudC5ub2RlTmFtZSB8fCAnJykpe1xuXHRcdFx0XHRzb3VyY2VzID0gcGFyZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzb3VyY2UnKTtcblx0XHRcdFx0Zm9yKGkgPSAwLCBsZW4gPSBzb3VyY2VzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKXtcblx0XHRcdFx0XHRzb3VyY2VzW2ldLnNldEF0dHJpYnV0ZSgnc2l6ZXMnLCB3aWR0aCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0aWYoIWV2ZW50LmRldGFpbC5kYXRhQXR0cil7XG5cdFx0XHRcdHVwZGF0ZVBvbHlmaWxsKGVsZW0sIGV2ZW50LmRldGFpbCk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdFx0LyoqXG5cdFx0ICpcblx0XHQgKiBAcGFyYW0gZWxlbSB7RWxlbWVudH1cblx0XHQgKiBAcGFyYW0gZGF0YUF0dHJcblx0XHQgKiBAcGFyYW0gW3dpZHRoXSB7IG51bWJlciB9XG5cdFx0ICovXG5cdFx0dmFyIGdldFNpemVFbGVtZW50ID0gZnVuY3Rpb24gKGVsZW0sIGRhdGFBdHRyLCB3aWR0aCl7XG5cdFx0XHR2YXIgZXZlbnQ7XG5cdFx0XHR2YXIgcGFyZW50ID0gZWxlbS5wYXJlbnROb2RlO1xuXG5cdFx0XHRpZihwYXJlbnQpe1xuXHRcdFx0XHR3aWR0aCA9IGdldFdpZHRoKGVsZW0sIHBhcmVudCwgd2lkdGgpO1xuXHRcdFx0XHRldmVudCA9IHRyaWdnZXJFdmVudChlbGVtLCAnbGF6eWJlZm9yZXNpemVzJywge3dpZHRoOiB3aWR0aCwgZGF0YUF0dHI6ICEhZGF0YUF0dHJ9KTtcblxuXHRcdFx0XHRpZighZXZlbnQuZGVmYXVsdFByZXZlbnRlZCl7XG5cdFx0XHRcdFx0d2lkdGggPSBldmVudC5kZXRhaWwud2lkdGg7XG5cblx0XHRcdFx0XHRpZih3aWR0aCAmJiB3aWR0aCAhPT0gZWxlbS5fbGF6eXNpemVzV2lkdGgpe1xuXHRcdFx0XHRcdFx0c2l6ZUVsZW1lbnQoZWxlbSwgcGFyZW50LCBldmVudCwgd2lkdGgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH07XG5cblx0XHR2YXIgdXBkYXRlRWxlbWVudHNTaXplcyA9IGZ1bmN0aW9uKCl7XG5cdFx0XHR2YXIgaTtcblx0XHRcdHZhciBsZW4gPSBhdXRvc2l6ZXNFbGVtcy5sZW5ndGg7XG5cdFx0XHRpZihsZW4pe1xuXHRcdFx0XHRpID0gMDtcblxuXHRcdFx0XHRmb3IoOyBpIDwgbGVuOyBpKyspe1xuXHRcdFx0XHRcdGdldFNpemVFbGVtZW50KGF1dG9zaXplc0VsZW1zW2ldKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH07XG5cblx0XHR2YXIgZGVib3VuY2VkVXBkYXRlRWxlbWVudHNTaXplcyA9IGRlYm91bmNlKHVwZGF0ZUVsZW1lbnRzU2l6ZXMpO1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdF86IGZ1bmN0aW9uKCl7XG5cdFx0XHRcdGF1dG9zaXplc0VsZW1zID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZShsYXp5U2l6ZXNDZmcuYXV0b3NpemVzQ2xhc3MpO1xuXHRcdFx0XHRhZGRFdmVudExpc3RlbmVyKCdyZXNpemUnLCBkZWJvdW5jZWRVcGRhdGVFbGVtZW50c1NpemVzKTtcblx0XHRcdH0sXG5cdFx0XHRjaGVja0VsZW1zOiBkZWJvdW5jZWRVcGRhdGVFbGVtZW50c1NpemVzLFxuXHRcdFx0dXBkYXRlRWxlbTogZ2V0U2l6ZUVsZW1lbnRcblx0XHR9O1xuXHR9KSgpO1xuXG5cdHZhciBpbml0ID0gZnVuY3Rpb24oKXtcblx0XHRpZighaW5pdC5pICYmIGRvY3VtZW50LmdldEVsZW1lbnRzQnlDbGFzc05hbWUpe1xuXHRcdFx0aW5pdC5pID0gdHJ1ZTtcblx0XHRcdGF1dG9TaXplci5fKCk7XG5cdFx0XHRsb2FkZXIuXygpO1xuXHRcdH1cblx0fTtcblxuXHRzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7XG5cdFx0aWYobGF6eVNpemVzQ2ZnLmluaXQpe1xuXHRcdFx0aW5pdCgpO1xuXHRcdH1cblx0fSk7XG5cblx0bGF6eXNpemVzID0ge1xuXHRcdC8qKlxuXHRcdCAqIEB0eXBlIHsgTGF6eVNpemVzQ29uZmlnUGFydGlhbCB9XG5cdFx0ICovXG5cdFx0Y2ZnOiBsYXp5U2l6ZXNDZmcsXG5cdFx0YXV0b1NpemVyOiBhdXRvU2l6ZXIsXG5cdFx0bG9hZGVyOiBsb2FkZXIsXG5cdFx0aW5pdDogaW5pdCxcblx0XHR1UDogdXBkYXRlUG9seWZpbGwsXG5cdFx0YUM6IGFkZENsYXNzLFxuXHRcdHJDOiByZW1vdmVDbGFzcyxcblx0XHRoQzogaGFzQ2xhc3MsXG5cdFx0ZmlyZTogdHJpZ2dlckV2ZW50LFxuXHRcdGdXOiBnZXRXaWR0aCxcblx0XHRyQUY6IHJBRixcblx0fTtcblxuXHRyZXR1cm4gbGF6eXNpemVzO1xufVxuKSk7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///879\n")},843:module=>{eval("/*! load-script2. MIT License. Feross Aboukhadijeh */\nmodule.exports = function loadScript2 (src, attrs, parentNode) {\n return new Promise((resolve, reject) => {\n const script = document.createElement('script')\n script.async = true\n script.src = src\n\n for (const [k, v] of Object.entries(attrs || {})) {\n script.setAttribute(k, v)\n }\n\n script.onload = () => {\n script.onerror = script.onload = null\n resolve(script)\n }\n\n script.onerror = () => {\n script.onerror = script.onload = null\n reject(new Error(`Failed to load ${src}`))\n }\n\n const node = parentNode || document.head || document.getElementsByTagName('head')[0]\n node.appendChild(script)\n })\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiODQzLmpzIiwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vcGlyZWxsaV9iZWNjYXJpYS8uL25vZGVfbW9kdWxlcy9sb2FkLXNjcmlwdDIvaW5kZXguanM/MGNhYiJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiEgbG9hZC1zY3JpcHQyLiBNSVQgTGljZW5zZS4gRmVyb3NzIEFib3VraGFkaWplaCA8aHR0cHM6Ly9mZXJvc3Mub3JnL29wZW5zb3VyY2U+ICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGxvYWRTY3JpcHQyIChzcmMsIGF0dHJzLCBwYXJlbnROb2RlKSB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgY29uc3Qgc2NyaXB0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc2NyaXB0JylcbiAgICBzY3JpcHQuYXN5bmMgPSB0cnVlXG4gICAgc2NyaXB0LnNyYyA9IHNyY1xuXG4gICAgZm9yIChjb25zdCBbaywgdl0gb2YgT2JqZWN0LmVudHJpZXMoYXR0cnMgfHwge30pKSB7XG4gICAgICBzY3JpcHQuc2V0QXR0cmlidXRlKGssIHYpXG4gICAgfVxuXG4gICAgc2NyaXB0Lm9ubG9hZCA9ICgpID0+IHtcbiAgICAgIHNjcmlwdC5vbmVycm9yID0gc2NyaXB0Lm9ubG9hZCA9IG51bGxcbiAgICAgIHJlc29sdmUoc2NyaXB0KVxuICAgIH1cblxuICAgIHNjcmlwdC5vbmVycm9yID0gKCkgPT4ge1xuICAgICAgc2NyaXB0Lm9uZXJyb3IgPSBzY3JpcHQub25sb2FkID0gbnVsbFxuICAgICAgcmVqZWN0KG5ldyBFcnJvcihgRmFpbGVkIHRvIGxvYWQgJHtzcmN9YCkpXG4gICAgfVxuXG4gICAgY29uc3Qgbm9kZSA9IHBhcmVudE5vZGUgfHwgZG9jdW1lbnQuaGVhZCB8fCBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnaGVhZCcpWzBdXG4gICAgbm9kZS5hcHBlbmRDaGlsZChzY3JpcHQpXG4gIH0pXG59XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///843\n")},19:module=>{eval('/*!\n * @file ScrollMagic GSAP Animation Plugin.\n *\n * requires: GSAP ~1.14\n * Powered by the Greensock Animation Platform (GSAP): http://www.greensock.com/js\n * Greensock License info at http://www.greensock.com/licensing/\n */\n/**\n * This plugin is meant to be used in conjunction with the Greensock Animation Plattform.\n * It offers an easy API to trigger Tweens or synchronize them to the scrollbar movement.\n *\n * Both the `lite` and the `max` versions of the GSAP library are supported.\n * The most basic requirement is `TweenLite`.\n *\n * To have access to this extension, please include `plugins/animation.gsap.js`.\n * @requires {@link http://greensock.com/gsap|GSAP ~1.14.x}\n * @mixin animation.GSAP\n */\nvar ScrollMagicPluginGsap = function(ScrollMagic, TweenMax, Timeline) {\n var Tween = TweenMax;\n var NAMESPACE = "animation.gsap";\n\n // (BUILD) - REMOVE IN MINIFY - START\n var console = window.console || {},\n err = Function.prototype.bind.call(\n console.error || console.log || function() {},\n console\n );\n if (!ScrollMagic) {\n err(\n "(" +\n NAMESPACE +\n ") -> ERROR: The ScrollMagic main module could not be found. Please make sure it\'s loaded before this plugin or use an asynchronous loader like requirejs."\n );\n }\n if (!Tween) {\n err(\n "(" +\n NAMESPACE +\n ") -> ERROR: TweenLite or TweenMax could not be found. Please make sure GSAP is loaded before ScrollMagic or use an asynchronous loader like requirejs."\n );\n }\n // (BUILD) - REMOVE IN MINIFY - END\n\n /*\n * ----------------------------------------------------------------\n * Extensions for Scene\n * ----------------------------------------------------------------\n */\n /**\n * Every instance of ScrollMagic.Scene now accepts an additional option. \n * See {@link ScrollMagic.Scene} for a complete list of the standard options.\n * @memberof! animation.GSAP#\n * @method new ScrollMagic.Scene(options)\n * @example\n * var scene = new ScrollMagic.Scene({tweenChanges: true});\n *\n * @param {object} [options] - Options for the Scene. The options can be updated at any time.\n * @param {boolean} [options.tweenChanges=false] - Tweens Animation to the progress target instead of setting it. \n Does not affect animations where duration is `0`.\n */\n /**\n * **Get** or **Set** the tweenChanges option value.\n * This only affects scenes with a duration. If `tweenChanges` is `true`, the progress update when scrolling will not be immediate, but instead the animation will smoothly animate to the target state.\n * For a better understanding, try enabling and disabling this option in the [Scene Manipulation Example](../examples/basic/scene_manipulation.html).\n * @memberof! animation.GSAP#\n * @method Scene.tweenChanges\n *\n * @example\n * // get the current tweenChanges option\n * var tweenChanges = scene.tweenChanges();\n *\n * // set new tweenChanges option\n * scene.tweenChanges(true);\n *\n * @fires {@link Scene.change}, when used as setter\n * @param {boolean} [newTweenChanges] - The new tweenChanges setting of the scene.\n * @returns {boolean} `get` - Current tweenChanges option value.\n * @returns {Scene} `set` - Parent object for chaining.\n */\n // add option (TODO: DOC (private for dev))\n ScrollMagic.Scene.addOption(\n "tweenChanges", // name\n false, // default\n function(val) {\n // validation callback\n return !!val;\n }\n );\n // extend scene\n ScrollMagic.Scene.extend(function() {\n var Scene = this,\n _tween;\n\n // (BUILD) - REMOVE IN MINIFY - START\n var log = function() {\n if (Scene._log) {\n // not available, when main source minified\n Array.prototype.splice.call(\n arguments,\n 1,\n 0,\n "(" + NAMESPACE + ")",\n "->"\n );\n Scene._log.apply(this, arguments);\n }\n };\n // (BUILD) - REMOVE IN MINIFY - END\n\n // set listeners\n Scene.on("progress.plugin_gsap", function() {\n updateTweenProgress();\n });\n Scene.on("destroy.plugin_gsap", function(e) {\n Scene.removeTween(e.reset);\n });\n\n /**\n * Update the tween progress to current position.\n * @private\n */\n var updateTweenProgress = function() {\n if (_tween) {\n var progress = Scene.progress(),\n state = Scene.state();\n if (_tween.repeat && _tween.repeat() === -1) {\n // infinite loop, so not in relation to progress\n if (state === "DURING" && _tween.paused()) {\n _tween.play();\n } else if (state !== "DURING" && !_tween.paused()) {\n _tween.pause();\n }\n } else if (progress != _tween.progress()) {\n // do we even need to update the progress?\n // no infinite loop - so should we just play or go to a specific point in time?\n if (Scene.duration() === 0) {\n // play the animation\n if (progress > 0) {\n // play from 0 to 1\n _tween.play();\n } else {\n // play from 1 to 0\n _tween.reverse();\n }\n } else {\n // go to a specific point in time\n if (Scene.tweenChanges() && _tween.tweenTo) {\n // go smooth\n _tween.tweenTo(progress * _tween.duration());\n } else {\n // just hard set it\n _tween.progress(progress).pause();\n }\n }\n }\n }\n };\n\n /**\n * Add a tween to the scene.\n * If you want to add multiple tweens, add them into a GSAP Timeline object and supply it instead (see example below).\n *\n * If the scene has a duration, the tween\'s duration will be projected to the scroll distance of the scene, meaning its progress will be synced to scrollbar movement.\n * For a scene with a duration of `0`, the tween will be triggered when scrolling forward past the scene\'s trigger position and reversed, when scrolling back.\n * To gain better understanding, check out the [Simple Tweening example](../examples/basic/simple_tweening.html).\n *\n * Instead of supplying a tween this method can also be used as a shorthand for `TweenMax.to()` (see example below).\n * @memberof! animation.GSAP#\n *\n * @example\n * // add a single tween directly\n * scene.setTween(TweenMax.to("obj"), 1, {x: 100});\n *\n * // add a single tween via variable\n * var tween = TweenMax.to("obj"), 1, {x: 100};\n * scene.setTween(tween);\n *\n * // add multiple tweens, wrapped in a timeline.\n * var timeline = new TimelineMax();\n * var tween1 = TweenMax.from("obj1", 1, {x: 100});\n * var tween2 = TweenMax.to("obj2", 1, {y: 100});\n * timeline\n * .add(tween1)\n * .add(tween2);\n * scene.addTween(timeline);\n *\n * // short hand to add a TweenMax.to() tween\n * scene.setTween("obj3", 0.5, {y: 100});\n *\n * // short hand to add a TweenMax.to() tween for 1 second\n * // this is useful, when the scene has a duration and the tween duration isn\'t important anyway\n * scene.setTween("obj3", {y: 100});\n *\n * @param {(object|string)} TweenObject - A TweenMax, TweenLite, TimelineMax or TimelineLite object that should be animated in the scene. Can also be a Dom Element or Selector, when using direct tween definition (see examples).\n * @param {(number|object)} duration - A duration for the tween, or tween parameters. If an object containing parameters are supplied, a default duration of 1 will be used.\n * @param {object} params - The parameters for the tween\n * @returns {Scene} Parent object for chaining.\n */\n Scene.setTween = function(TweenObject, duration, params) {\n var newTween;\n if (arguments.length > 1) {\n if (arguments.length < 3) {\n params = duration;\n duration = 1;\n }\n TweenObject = Tween.to(TweenObject, duration, params);\n }\n try {\n // wrap Tween into a Timeline Object if available to include delay and repeats in the duration and standardize methods.\n if (Timeline) {\n newTween = new Timeline({ smoothChildTiming: true }).add(\n TweenObject\n );\n } else {\n newTween = TweenObject;\n }\n newTween.pause();\n } catch (e) {\n log(\n 1,\n "ERROR calling method \'setTween()\': Supplied argument is not a valid TweenObject"\n );\n return Scene;\n }\n if (_tween) {\n // kill old tween?\n Scene.removeTween();\n }\n _tween = newTween;\n\n // some properties need to be transferred it to the wrapper, otherwise they would get lost.\n if (TweenObject.repeat && TweenObject.repeat() === -1) {\n // TweenMax or TimelineMax Object?\n _tween.repeat(-1);\n _tween.yoyo(TweenObject.yoyo());\n }\n // (BUILD) - REMOVE IN MINIFY - START\n // Some tween validations and debugging helpers\n\n if (Scene.tweenChanges() && !_tween.tweenTo) {\n log(\n 2,\n "WARNING: tweenChanges will only work if the TimelineMax object is available for ScrollMagic."\n );\n }\n\n // check if there are position tweens defined for the trigger and warn about it :)\n if (\n _tween &&\n Scene.controller() &&\n Scene.triggerElement() &&\n Scene.loglevel() >= 2\n ) {\n // controller is needed to know scroll direction.\n var triggerTweens = Tween.getTweensOf(Scene.triggerElement()),\n vertical = Scene.controller().info("vertical");\n triggerTweens.forEach(function(value, index) {\n var tweenvars = value.vars.css || value.vars,\n condition = vertical\n ? tweenvars.top !== undefined ||\n tweenvars.bottom !== undefined\n : tweenvars.left !== undefined ||\n tweenvars.right !== undefined;\n if (condition) {\n log(\n 2,\n "WARNING: Tweening the position of the trigger element affects the scene timing and should be avoided!"\n );\n return false;\n }\n });\n }\n\n // warn about tween overwrites, when an element is tweened multiple times\n if (parseFloat(Tween.version) >= 1.14) {\n // onOverwrite only present since GSAP v1.14.0\n var list = _tween.getChildren\n ? _tween.getChildren(true, true, false)\n : [_tween], // get all nested tween objects\n newCallback = function() {\n log(\n 2,\n "WARNING: tween was overwritten by another. To learn how to avoid this issue see here: https://github.com/janpaepke/ScrollMagic/wiki/WARNING:-tween-was-overwritten-by-another"\n );\n };\n for (var i = 0, thisTween, oldCallback; i < list.length; i++) {\n /*jshint loopfunc: true */\n thisTween = list[i];\n if (oldCallback !== newCallback) {\n // if tweens is added more than once\n oldCallback = thisTween.vars.onOverwrite;\n thisTween.vars.onOverwrite = function() {\n if (oldCallback) {\n oldCallback.apply(this, arguments);\n }\n newCallback.apply(this, arguments);\n };\n }\n }\n }\n // (BUILD) - REMOVE IN MINIFY - END\n log(3, "added tween");\n\n updateTweenProgress();\n return Scene;\n };\n\n /**\n * Remove the tween from the scene.\n * This will terminate the control of the Scene over the tween.\n *\n * Using the reset option you can decide if the tween should remain in the current state or be rewound to set the target elements back to the state they were in before the tween was added to the scene.\n * @memberof! animation.GSAP#\n *\n * @example\n * // remove the tween from the scene without resetting it\n * scene.removeTween();\n *\n * // remove the tween from the scene and reset it to initial position\n * scene.removeTween(true);\n *\n * @param {boolean} [reset=false] - If `true` the tween will be reset to its initial values.\n * @returns {Scene} Parent object for chaining.\n */\n Scene.removeTween = function(reset) {\n if (_tween) {\n if (reset) {\n _tween.progress(0).pause();\n }\n _tween.kill();\n _tween = undefined;\n log(\n 3,\n "removed tween (reset: " + (reset ? "true" : "false") + ")"\n );\n }\n return Scene;\n };\n });\n};\n\nmodule.exports = { ScrollMagicPluginGsap : ScrollMagicPluginGsap };\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMTkuanMiLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3Njcm9sbG1hZ2ljLXBsdWdpbi1nc2FwL2luZGV4LmpzP2UzNDUiXSwic291cmNlc0NvbnRlbnQiOlsiLyohXG4gKiBAZmlsZSBTY3JvbGxNYWdpYyBHU0FQIEFuaW1hdGlvbiBQbHVnaW4uXG4gKlxuICogcmVxdWlyZXM6IEdTQVAgfjEuMTRcbiAqIFBvd2VyZWQgYnkgdGhlIEdyZWVuc29jayBBbmltYXRpb24gUGxhdGZvcm0gKEdTQVApOiBodHRwOi8vd3d3LmdyZWVuc29jay5jb20vanNcbiAqIEdyZWVuc29jayBMaWNlbnNlIGluZm8gYXQgaHR0cDovL3d3dy5ncmVlbnNvY2suY29tL2xpY2Vuc2luZy9cbiAqL1xuLyoqXG4gKiBUaGlzIHBsdWdpbiBpcyBtZWFudCB0byBiZSB1c2VkIGluIGNvbmp1bmN0aW9uIHdpdGggdGhlIEdyZWVuc29jayBBbmltYXRpb24gUGxhdHRmb3JtLlxuICogSXQgb2ZmZXJzIGFuIGVhc3kgQVBJIHRvIHRyaWdnZXIgVHdlZW5zIG9yIHN5bmNocm9uaXplIHRoZW0gdG8gdGhlIHNjcm9sbGJhciBtb3ZlbWVudC5cbiAqXG4gKiBCb3RoIHRoZSBgbGl0ZWAgYW5kIHRoZSBgbWF4YCB2ZXJzaW9ucyBvZiB0aGUgR1NBUCBsaWJyYXJ5IGFyZSBzdXBwb3J0ZWQuXG4gKiBUaGUgbW9zdCBiYXNpYyByZXF1aXJlbWVudCBpcyBgVHdlZW5MaXRlYC5cbiAqXG4gKiBUbyBoYXZlIGFjY2VzcyB0byB0aGlzIGV4dGVuc2lvbiwgcGxlYXNlIGluY2x1ZGUgYHBsdWdpbnMvYW5pbWF0aW9uLmdzYXAuanNgLlxuICogQHJlcXVpcmVzIHtAbGluayBodHRwOi8vZ3JlZW5zb2NrLmNvbS9nc2FwfEdTQVAgfjEuMTQueH1cbiAqIEBtaXhpbiBhbmltYXRpb24uR1NBUFxuICovXG52YXIgU2Nyb2xsTWFnaWNQbHVnaW5Hc2FwID0gZnVuY3Rpb24oU2Nyb2xsTWFnaWMsIFR3ZWVuTWF4LCBUaW1lbGluZSkge1xuICAgIHZhciBUd2VlbiA9IFR3ZWVuTWF4O1xuICAgIHZhciBOQU1FU1BBQ0UgPSBcImFuaW1hdGlvbi5nc2FwXCI7XG5cbiAgICAvLyAoQlVJTEQpIC0gUkVNT1ZFIElOIE1JTklGWSAtIFNUQVJUXG4gICAgdmFyIGNvbnNvbGUgPSB3aW5kb3cuY29uc29sZSB8fCB7fSxcbiAgICAgICAgZXJyID0gRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQuY2FsbChcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IgfHwgY29uc29sZS5sb2cgfHwgZnVuY3Rpb24oKSB7fSxcbiAgICAgICAgICAgIGNvbnNvbGVcbiAgICAgICAgKTtcbiAgICBpZiAoIVNjcm9sbE1hZ2ljKSB7XG4gICAgICAgIGVycihcbiAgICAgICAgICAgIFwiKFwiICtcbiAgICAgICAgICAgICAgICBOQU1FU1BBQ0UgK1xuICAgICAgICAgICAgICAgIFwiKSAtPiBFUlJPUjogVGhlIFNjcm9sbE1hZ2ljIG1haW4gbW9kdWxlIGNvdWxkIG5vdCBiZSBmb3VuZC4gUGxlYXNlIG1ha2Ugc3VyZSBpdCdzIGxvYWRlZCBiZWZvcmUgdGhpcyBwbHVnaW4gb3IgdXNlIGFuIGFzeW5jaHJvbm91cyBsb2FkZXIgbGlrZSByZXF1aXJlanMuXCJcbiAgICAgICAgKTtcbiAgICB9XG4gICAgaWYgKCFUd2Vlbikge1xuICAgICAgICBlcnIoXG4gICAgICAgICAgICBcIihcIiArXG4gICAgICAgICAgICAgICAgTkFNRVNQQUNFICtcbiAgICAgICAgICAgICAgICBcIikgLT4gRVJST1I6IFR3ZWVuTGl0ZSBvciBUd2Vlbk1heCBjb3VsZCBub3QgYmUgZm91bmQuIFBsZWFzZSBtYWtlIHN1cmUgR1NBUCBpcyBsb2FkZWQgYmVmb3JlIFNjcm9sbE1hZ2ljIG9yIHVzZSBhbiBhc3luY2hyb25vdXMgbG9hZGVyIGxpa2UgcmVxdWlyZWpzLlwiXG4gICAgICAgICk7XG4gICAgfVxuICAgIC8vIChCVUlMRCkgLSBSRU1PVkUgSU4gTUlOSUZZIC0gRU5EXG5cbiAgICAvKlxuICAgICAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAgKiBFeHRlbnNpb25zIGZvciBTY2VuZVxuICAgICAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAgKi9cbiAgICAvKipcbiAgICAgKiBFdmVyeSBpbnN0YW5jZSBvZiBTY3JvbGxNYWdpYy5TY2VuZSBub3cgYWNjZXB0cyBhbiBhZGRpdGlvbmFsIG9wdGlvbi4gIFxuICAgICAqIFNlZSB7QGxpbmsgU2Nyb2xsTWFnaWMuU2NlbmV9IGZvciBhIGNvbXBsZXRlIGxpc3Qgb2YgdGhlIHN0YW5kYXJkIG9wdGlvbnMuXG4gICAgICogQG1lbWJlcm9mISBhbmltYXRpb24uR1NBUCNcbiAgICAgKiBAbWV0aG9kIG5ldyBTY3JvbGxNYWdpYy5TY2VuZShvcHRpb25zKVxuICAgICAqIEBleGFtcGxlXG4gICAgICogdmFyIHNjZW5lID0gbmV3IFNjcm9sbE1hZ2ljLlNjZW5lKHt0d2VlbkNoYW5nZXM6IHRydWV9KTtcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBbb3B0aW9uc10gLSBPcHRpb25zIGZvciB0aGUgU2NlbmUuIFRoZSBvcHRpb25zIGNhbiBiZSB1cGRhdGVkIGF0IGFueSB0aW1lLlxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMudHdlZW5DaGFuZ2VzPWZhbHNlXSAtIFR3ZWVucyBBbmltYXRpb24gdG8gdGhlIHByb2dyZXNzIHRhcmdldCBpbnN0ZWFkIG9mIHNldHRpbmcgaXQuICBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERvZXMgbm90IGFmZmVjdCBhbmltYXRpb25zIHdoZXJlIGR1cmF0aW9uIGlzIGAwYC5cbiAgICAgKi9cbiAgICAvKipcbiAgICAgKiAqKkdldCoqIG9yICoqU2V0KiogdGhlIHR3ZWVuQ2hhbmdlcyBvcHRpb24gdmFsdWUuXG4gICAgICogVGhpcyBvbmx5IGFmZmVjdHMgc2NlbmVzIHdpdGggYSBkdXJhdGlvbi4gSWYgYHR3ZWVuQ2hhbmdlc2AgaXMgYHRydWVgLCB0aGUgcHJvZ3Jlc3MgdXBkYXRlIHdoZW4gc2Nyb2xsaW5nIHdpbGwgbm90IGJlIGltbWVkaWF0ZSwgYnV0IGluc3RlYWQgdGhlIGFuaW1hdGlvbiB3aWxsIHNtb290aGx5IGFuaW1hdGUgdG8gdGhlIHRhcmdldCBzdGF0ZS5cbiAgICAgKiBGb3IgYSBiZXR0ZXIgdW5kZXJzdGFuZGluZywgdHJ5IGVuYWJsaW5nIGFuZCBkaXNhYmxpbmcgdGhpcyBvcHRpb24gaW4gdGhlIFtTY2VuZSBNYW5pcHVsYXRpb24gRXhhbXBsZV0oLi4vZXhhbXBsZXMvYmFzaWMvc2NlbmVfbWFuaXB1bGF0aW9uLmh0bWwpLlxuICAgICAqIEBtZW1iZXJvZiEgYW5pbWF0aW9uLkdTQVAjXG4gICAgICogQG1ldGhvZCBTY2VuZS50d2VlbkNoYW5nZXNcbiAgICAgKlxuICAgICAqIEBleGFtcGxlXG4gICAgICogLy8gZ2V0IHRoZSBjdXJyZW50IHR3ZWVuQ2hhbmdlcyBvcHRpb25cbiAgICAgKiB2YXIgdHdlZW5DaGFuZ2VzID0gc2NlbmUudHdlZW5DaGFuZ2VzKCk7XG4gICAgICpcbiAgICAgKiAvLyBzZXQgbmV3IHR3ZWVuQ2hhbmdlcyBvcHRpb25cbiAgICAgKiBzY2VuZS50d2VlbkNoYW5nZXModHJ1ZSk7XG4gICAgICpcbiAgICAgKiBAZmlyZXMge0BsaW5rIFNjZW5lLmNoYW5nZX0sIHdoZW4gdXNlZCBhcyBzZXR0ZXJcbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtuZXdUd2VlbkNoYW5nZXNdIC0gVGhlIG5ldyB0d2VlbkNoYW5nZXMgc2V0dGluZyBvZiB0aGUgc2NlbmUuXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IGBnZXRgIC0gIEN1cnJlbnQgdHdlZW5DaGFuZ2VzIG9wdGlvbiB2YWx1ZS5cbiAgICAgKiBAcmV0dXJucyB7U2NlbmV9IGBzZXRgIC0gIFBhcmVudCBvYmplY3QgZm9yIGNoYWluaW5nLlxuICAgICAqL1xuICAgIC8vIGFkZCBvcHRpb24gKFRPRE86IERPQyAocHJpdmF0ZSBmb3IgZGV2KSlcbiAgICBTY3JvbGxNYWdpYy5TY2VuZS5hZGRPcHRpb24oXG4gICAgICAgIFwidHdlZW5DaGFuZ2VzXCIsIC8vIG5hbWVcbiAgICAgICAgZmFsc2UsIC8vIGRlZmF1bHRcbiAgICAgICAgZnVuY3Rpb24odmFsKSB7XG4gICAgICAgICAgICAvLyB2YWxpZGF0aW9uIGNhbGxiYWNrXG4gICAgICAgICAgICByZXR1cm4gISF2YWw7XG4gICAgICAgIH1cbiAgICApO1xuICAgIC8vIGV4dGVuZCBzY2VuZVxuICAgIFNjcm9sbE1hZ2ljLlNjZW5lLmV4dGVuZChmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIFNjZW5lID0gdGhpcyxcbiAgICAgICAgICAgIF90d2VlbjtcblxuICAgICAgICAvLyAoQlVJTEQpIC0gUkVNT1ZFIElOIE1JTklGWSAtIFNUQVJUXG4gICAgICAgIHZhciBsb2cgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIGlmIChTY2VuZS5fbG9nKSB7XG4gICAgICAgICAgICAgICAgLy8gbm90IGF2YWlsYWJsZSwgd2hlbiBtYWluIHNvdXJjZSBtaW5pZmllZFxuICAgICAgICAgICAgICAgIEFycmF5LnByb3RvdHlwZS5zcGxpY2UuY2FsbChcbiAgICAgICAgICAgICAgICAgICAgYXJndW1lbnRzLFxuICAgICAgICAgICAgICAgICAgICAxLFxuICAgICAgICAgICAgICAgICAgICAwLFxuICAgICAgICAgICAgICAgICAgICBcIihcIiArIE5BTUVTUEFDRSArIFwiKVwiLFxuICAgICAgICAgICAgICAgICAgICBcIi0+XCJcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIFNjZW5lLl9sb2cuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgLy8gKEJVSUxEKSAtIFJFTU9WRSBJTiBNSU5JRlkgLSBFTkRcblxuICAgICAgICAvLyBzZXQgbGlzdGVuZXJzXG4gICAgICAgIFNjZW5lLm9uKFwicHJvZ3Jlc3MucGx1Z2luX2dzYXBcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB1cGRhdGVUd2VlblByb2dyZXNzKCk7XG4gICAgICAgIH0pO1xuICAgICAgICBTY2VuZS5vbihcImRlc3Ryb3kucGx1Z2luX2dzYXBcIiwgZnVuY3Rpb24oZSkge1xuICAgICAgICAgICAgU2NlbmUucmVtb3ZlVHdlZW4oZS5yZXNldCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBVcGRhdGUgdGhlIHR3ZWVuIHByb2dyZXNzIHRvIGN1cnJlbnQgcG9zaXRpb24uXG4gICAgICAgICAqIEBwcml2YXRlXG4gICAgICAgICAqL1xuICAgICAgICB2YXIgdXBkYXRlVHdlZW5Qcm9ncmVzcyA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgaWYgKF90d2Vlbikge1xuICAgICAgICAgICAgICAgIHZhciBwcm9ncmVzcyA9IFNjZW5lLnByb2dyZXNzKCksXG4gICAgICAgICAgICAgICAgICAgIHN0YXRlID0gU2NlbmUuc3RhdGUoKTtcbiAgICAgICAgICAgICAgICBpZiAoX3R3ZWVuLnJlcGVhdCAmJiBfdHdlZW4ucmVwZWF0KCkgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGluZmluaXRlIGxvb3AsIHNvIG5vdCBpbiByZWxhdGlvbiB0byBwcm9ncmVzc1xuICAgICAgICAgICAgICAgICAgICBpZiAoc3RhdGUgPT09IFwiRFVSSU5HXCIgJiYgX3R3ZWVuLnBhdXNlZCgpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBfdHdlZW4ucGxheSgpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHN0YXRlICE9PSBcIkRVUklOR1wiICYmICFfdHdlZW4ucGF1c2VkKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIF90d2Vlbi5wYXVzZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChwcm9ncmVzcyAhPSBfdHdlZW4ucHJvZ3Jlc3MoKSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBkbyB3ZSBldmVuIG5lZWQgdG8gdXBkYXRlIHRoZSBwcm9ncmVzcz9cbiAgICAgICAgICAgICAgICAgICAgLy8gbm8gaW5maW5pdGUgbG9vcCAtIHNvIHNob3VsZCB3ZSBqdXN0IHBsYXkgb3IgZ28gdG8gYSBzcGVjaWZpYyBwb2ludCBpbiB0aW1lP1xuICAgICAgICAgICAgICAgICAgICBpZiAoU2NlbmUuZHVyYXRpb24oKSA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcGxheSB0aGUgYW5pbWF0aW9uXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAocHJvZ3Jlc3MgPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcGxheSBmcm9tIDAgdG8gMVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIF90d2Vlbi5wbGF5KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHBsYXkgZnJvbSAxIHRvIDBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBfdHdlZW4ucmV2ZXJzZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZ28gdG8gYSBzcGVjaWZpYyBwb2ludCBpbiB0aW1lXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoU2NlbmUudHdlZW5DaGFuZ2VzKCkgJiYgX3R3ZWVuLnR3ZWVuVG8pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBnbyBzbW9vdGhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBfdHdlZW4udHdlZW5Ubyhwcm9ncmVzcyAqIF90d2Vlbi5kdXJhdGlvbigpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8ganVzdCBoYXJkIHNldCBpdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIF90d2Vlbi5wcm9ncmVzcyhwcm9ncmVzcykucGF1c2UoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogQWRkIGEgdHdlZW4gdG8gdGhlIHNjZW5lLlxuICAgICAgICAgKiBJZiB5b3Ugd2FudCB0byBhZGQgbXVsdGlwbGUgdHdlZW5zLCBhZGQgdGhlbSBpbnRvIGEgR1NBUCBUaW1lbGluZSBvYmplY3QgYW5kIHN1cHBseSBpdCBpbnN0ZWFkIChzZWUgZXhhbXBsZSBiZWxvdykuXG4gICAgICAgICAqXG4gICAgICAgICAqIElmIHRoZSBzY2VuZSBoYXMgYSBkdXJhdGlvbiwgdGhlIHR3ZWVuJ3MgZHVyYXRpb24gd2lsbCBiZSBwcm9qZWN0ZWQgdG8gdGhlIHNjcm9sbCBkaXN0YW5jZSBvZiB0aGUgc2NlbmUsIG1lYW5pbmcgaXRzIHByb2dyZXNzIHdpbGwgYmUgc3luY2VkIHRvIHNjcm9sbGJhciBtb3ZlbWVudC5cbiAgICAgICAgICogRm9yIGEgc2NlbmUgd2l0aCBhIGR1cmF0aW9uIG9mIGAwYCwgdGhlIHR3ZWVuIHdpbGwgYmUgdHJpZ2dlcmVkIHdoZW4gc2Nyb2xsaW5nIGZvcndhcmQgcGFzdCB0aGUgc2NlbmUncyB0cmlnZ2VyIHBvc2l0aW9uIGFuZCByZXZlcnNlZCwgd2hlbiBzY3JvbGxpbmcgYmFjay5cbiAgICAgICAgICogVG8gZ2FpbiBiZXR0ZXIgdW5kZXJzdGFuZGluZywgY2hlY2sgb3V0IHRoZSBbU2ltcGxlIFR3ZWVuaW5nIGV4YW1wbGVdKC4uL2V4YW1wbGVzL2Jhc2ljL3NpbXBsZV90d2VlbmluZy5odG1sKS5cbiAgICAgICAgICpcbiAgICAgICAgICogSW5zdGVhZCBvZiBzdXBwbHlpbmcgYSB0d2VlbiB0aGlzIG1ldGhvZCBjYW4gYWxzbyBiZSB1c2VkIGFzIGEgc2hvcnRoYW5kIGZvciBgVHdlZW5NYXgudG8oKWAgKHNlZSBleGFtcGxlIGJlbG93KS5cbiAgICAgICAgICogQG1lbWJlcm9mISBhbmltYXRpb24uR1NBUCNcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogLy8gYWRkIGEgc2luZ2xlIHR3ZWVuIGRpcmVjdGx5XG4gICAgICAgICAqIHNjZW5lLnNldFR3ZWVuKFR3ZWVuTWF4LnRvKFwib2JqXCIpLCAxLCB7eDogMTAwfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqIC8vIGFkZCBhIHNpbmdsZSB0d2VlbiB2aWEgdmFyaWFibGVcbiAgICAgICAgICogdmFyIHR3ZWVuID0gVHdlZW5NYXgudG8oXCJvYmpcIiksIDEsIHt4OiAxMDB9O1xuICAgICAgICAgKiBzY2VuZS5zZXRUd2Vlbih0d2Vlbik7XG4gICAgICAgICAqXG4gICAgICAgICAqIC8vIGFkZCBtdWx0aXBsZSB0d2VlbnMsIHdyYXBwZWQgaW4gYSB0aW1lbGluZS5cbiAgICAgICAgICogdmFyIHRpbWVsaW5lID0gbmV3IFRpbWVsaW5lTWF4KCk7XG4gICAgICAgICAqIHZhciB0d2VlbjEgPSBUd2Vlbk1heC5mcm9tKFwib2JqMVwiLCAxLCB7eDogMTAwfSk7XG4gICAgICAgICAqIHZhciB0d2VlbjIgPSBUd2Vlbk1heC50byhcIm9iajJcIiwgMSwge3k6IDEwMH0pO1xuICAgICAgICAgKiB0aW1lbGluZVxuICAgICAgICAgKiAgICAgIC5hZGQodHdlZW4xKVxuICAgICAgICAgKiAgICAgIC5hZGQodHdlZW4yKTtcbiAgICAgICAgICogc2NlbmUuYWRkVHdlZW4odGltZWxpbmUpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAvLyBzaG9ydCBoYW5kIHRvIGFkZCBhIFR3ZWVuTWF4LnRvKCkgdHdlZW5cbiAgICAgICAgICogc2NlbmUuc2V0VHdlZW4oXCJvYmozXCIsIDAuNSwge3k6IDEwMH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAvLyBzaG9ydCBoYW5kIHRvIGFkZCBhIFR3ZWVuTWF4LnRvKCkgdHdlZW4gZm9yIDEgc2Vjb25kXG4gICAgICAgICAqIC8vIHRoaXMgaXMgdXNlZnVsLCB3aGVuIHRoZSBzY2VuZSBoYXMgYSBkdXJhdGlvbiBhbmQgdGhlIHR3ZWVuIGR1cmF0aW9uIGlzbid0IGltcG9ydGFudCBhbnl3YXlcbiAgICAgICAgICogc2NlbmUuc2V0VHdlZW4oXCJvYmozXCIsIHt5OiAxMDB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogQHBhcmFtIHsob2JqZWN0fHN0cmluZyl9IFR3ZWVuT2JqZWN0IC0gQSBUd2Vlbk1heCwgVHdlZW5MaXRlLCBUaW1lbGluZU1heCBvciBUaW1lbGluZUxpdGUgb2JqZWN0IHRoYXQgc2hvdWxkIGJlIGFuaW1hdGVkIGluIHRoZSBzY2VuZS4gQ2FuIGFsc28gYmUgYSBEb20gRWxlbWVudCBvciBTZWxlY3Rvciwgd2hlbiB1c2luZyBkaXJlY3QgdHdlZW4gZGVmaW5pdGlvbiAoc2VlIGV4YW1wbGVzKS5cbiAgICAgICAgICogQHBhcmFtIHsobnVtYmVyfG9iamVjdCl9IGR1cmF0aW9uIC0gQSBkdXJhdGlvbiBmb3IgdGhlIHR3ZWVuLCBvciB0d2VlbiBwYXJhbWV0ZXJzLiBJZiBhbiBvYmplY3QgY29udGFpbmluZyBwYXJhbWV0ZXJzIGFyZSBzdXBwbGllZCwgYSBkZWZhdWx0IGR1cmF0aW9uIG9mIDEgd2lsbCBiZSB1c2VkLlxuICAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gcGFyYW1zIC0gVGhlIHBhcmFtZXRlcnMgZm9yIHRoZSB0d2VlblxuICAgICAgICAgKiBAcmV0dXJucyB7U2NlbmV9IFBhcmVudCBvYmplY3QgZm9yIGNoYWluaW5nLlxuICAgICAgICAgKi9cbiAgICAgICAgU2NlbmUuc2V0VHdlZW4gPSBmdW5jdGlvbihUd2Vlbk9iamVjdCwgZHVyYXRpb24sIHBhcmFtcykge1xuICAgICAgICAgICAgdmFyIG5ld1R3ZWVuO1xuICAgICAgICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPCAzKSB7XG4gICAgICAgICAgICAgICAgICAgIHBhcmFtcyA9IGR1cmF0aW9uO1xuICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbiA9IDE7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIFR3ZWVuT2JqZWN0ID0gVHdlZW4udG8oVHdlZW5PYmplY3QsIGR1cmF0aW9uLCBwYXJhbXMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAvLyB3cmFwIFR3ZWVuIGludG8gYSBUaW1lbGluZSBPYmplY3QgaWYgYXZhaWxhYmxlIHRvIGluY2x1ZGUgZGVsYXkgYW5kIHJlcGVhdHMgaW4gdGhlIGR1cmF0aW9uIGFuZCBzdGFuZGFyZGl6ZSBtZXRob2RzLlxuICAgICAgICAgICAgICAgIGlmIChUaW1lbGluZSkge1xuICAgICAgICAgICAgICAgICAgICBuZXdUd2VlbiA9IG5ldyBUaW1lbGluZSh7IHNtb290aENoaWxkVGltaW5nOiB0cnVlIH0pLmFkZChcbiAgICAgICAgICAgICAgICAgICAgICAgIFR3ZWVuT2JqZWN0XG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgbmV3VHdlZW4gPSBUd2Vlbk9iamVjdDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbmV3VHdlZW4ucGF1c2UoKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBsb2coXG4gICAgICAgICAgICAgICAgICAgIDEsXG4gICAgICAgICAgICAgICAgICAgIFwiRVJST1IgY2FsbGluZyBtZXRob2QgJ3NldFR3ZWVuKCknOiBTdXBwbGllZCBhcmd1bWVudCBpcyBub3QgYSB2YWxpZCBUd2Vlbk9iamVjdFwiXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gU2NlbmU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoX3R3ZWVuKSB7XG4gICAgICAgICAgICAgICAgLy8ga2lsbCBvbGQgdHdlZW4/XG4gICAgICAgICAgICAgICAgU2NlbmUucmVtb3ZlVHdlZW4oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIF90d2VlbiA9IG5ld1R3ZWVuO1xuXG4gICAgICAgICAgICAvLyBzb21lIHByb3BlcnRpZXMgbmVlZCB0byBiZSB0cmFuc2ZlcnJlZCBpdCB0byB0aGUgd3JhcHBlciwgb3RoZXJ3aXNlIHRoZXkgd291bGQgZ2V0IGxvc3QuXG4gICAgICAgICAgICBpZiAoVHdlZW5PYmplY3QucmVwZWF0ICYmIFR3ZWVuT2JqZWN0LnJlcGVhdCgpID09PSAtMSkge1xuICAgICAgICAgICAgICAgIC8vIFR3ZWVuTWF4IG9yIFRpbWVsaW5lTWF4IE9iamVjdD9cbiAgICAgICAgICAgICAgICBfdHdlZW4ucmVwZWF0KC0xKTtcbiAgICAgICAgICAgICAgICBfdHdlZW4ueW95byhUd2Vlbk9iamVjdC55b3lvKCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gKEJVSUxEKSAtIFJFTU9WRSBJTiBNSU5JRlkgLSBTVEFSVFxuICAgICAgICAgICAgLy8gU29tZSB0d2VlbiB2YWxpZGF0aW9ucyBhbmQgZGVidWdnaW5nIGhlbHBlcnNcblxuICAgICAgICAgICAgaWYgKFNjZW5lLnR3ZWVuQ2hhbmdlcygpICYmICFfdHdlZW4udHdlZW5Ubykge1xuICAgICAgICAgICAgICAgIGxvZyhcbiAgICAgICAgICAgICAgICAgICAgMixcbiAgICAgICAgICAgICAgICAgICAgXCJXQVJOSU5HOiB0d2VlbkNoYW5nZXMgd2lsbCBvbmx5IHdvcmsgaWYgdGhlIFRpbWVsaW5lTWF4IG9iamVjdCBpcyBhdmFpbGFibGUgZm9yIFNjcm9sbE1hZ2ljLlwiXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gY2hlY2sgaWYgdGhlcmUgYXJlIHBvc2l0aW9uIHR3ZWVucyBkZWZpbmVkIGZvciB0aGUgdHJpZ2dlciBhbmQgd2FybiBhYm91dCBpdCA6KVxuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgIF90d2VlbiAmJlxuICAgICAgICAgICAgICAgIFNjZW5lLmNvbnRyb2xsZXIoKSAmJlxuICAgICAgICAgICAgICAgIFNjZW5lLnRyaWdnZXJFbGVtZW50KCkgJiZcbiAgICAgICAgICAgICAgICBTY2VuZS5sb2dsZXZlbCgpID49IDJcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIC8vIGNvbnRyb2xsZXIgaXMgbmVlZGVkIHRvIGtub3cgc2Nyb2xsIGRpcmVjdGlvbi5cbiAgICAgICAgICAgICAgICB2YXIgdHJpZ2dlclR3ZWVucyA9IFR3ZWVuLmdldFR3ZWVuc09mKFNjZW5lLnRyaWdnZXJFbGVtZW50KCkpLFxuICAgICAgICAgICAgICAgICAgICB2ZXJ0aWNhbCA9IFNjZW5lLmNvbnRyb2xsZXIoKS5pbmZvKFwidmVydGljYWxcIik7XG4gICAgICAgICAgICAgICAgdHJpZ2dlclR3ZWVucy5mb3JFYWNoKGZ1bmN0aW9uKHZhbHVlLCBpbmRleCkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdHdlZW52YXJzID0gdmFsdWUudmFycy5jc3MgfHwgdmFsdWUudmFycyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmRpdGlvbiA9IHZlcnRpY2FsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPyB0d2VlbnZhcnMudG9wICE9PSB1bmRlZmluZWQgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR3ZWVudmFycy5ib3R0b20gIT09IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogdHdlZW52YXJzLmxlZnQgIT09IHVuZGVmaW5lZCB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHdlZW52YXJzLnJpZ2h0ICE9PSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgICAgIGlmIChjb25kaXRpb24pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxvZyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiV0FSTklORzogVHdlZW5pbmcgdGhlIHBvc2l0aW9uIG9mIHRoZSB0cmlnZ2VyIGVsZW1lbnQgYWZmZWN0cyB0aGUgc2NlbmUgdGltaW5nIGFuZCBzaG91bGQgYmUgYXZvaWRlZCFcIlxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyB3YXJuIGFib3V0IHR3ZWVuIG92ZXJ3cml0ZXMsIHdoZW4gYW4gZWxlbWVudCBpcyB0d2VlbmVkIG11bHRpcGxlIHRpbWVzXG4gICAgICAgICAgICBpZiAocGFyc2VGbG9hdChUd2Vlbi52ZXJzaW9uKSA+PSAxLjE0KSB7XG4gICAgICAgICAgICAgICAgLy8gb25PdmVyd3JpdGUgb25seSBwcmVzZW50IHNpbmNlIEdTQVAgdjEuMTQuMFxuICAgICAgICAgICAgICAgIHZhciBsaXN0ID0gX3R3ZWVuLmdldENoaWxkcmVuXG4gICAgICAgICAgICAgICAgICAgICAgICA/IF90d2Vlbi5nZXRDaGlsZHJlbih0cnVlLCB0cnVlLCBmYWxzZSlcbiAgICAgICAgICAgICAgICAgICAgICAgIDogW190d2Vlbl0sIC8vIGdldCBhbGwgbmVzdGVkIHR3ZWVuIG9iamVjdHNcbiAgICAgICAgICAgICAgICAgICAgbmV3Q2FsbGJhY2sgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxvZyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiV0FSTklORzogdHdlZW4gd2FzIG92ZXJ3cml0dGVuIGJ5IGFub3RoZXIuIFRvIGxlYXJuIGhvdyB0byBhdm9pZCB0aGlzIGlzc3VlIHNlZSBoZXJlOiBodHRwczovL2dpdGh1Yi5jb20vamFucGFlcGtlL1Njcm9sbE1hZ2ljL3dpa2kvV0FSTklORzotdHdlZW4td2FzLW92ZXJ3cml0dGVuLWJ5LWFub3RoZXJcIlxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMCwgdGhpc1R3ZWVuLCBvbGRDYWxsYmFjazsgaSA8IGxpc3QubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgLypqc2hpbnQgbG9vcGZ1bmM6IHRydWUgKi9cbiAgICAgICAgICAgICAgICAgICAgdGhpc1R3ZWVuID0gbGlzdFtpXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9sZENhbGxiYWNrICE9PSBuZXdDYWxsYmFjaykge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaWYgdHdlZW5zIGlzIGFkZGVkIG1vcmUgdGhhbiBvbmNlXG4gICAgICAgICAgICAgICAgICAgICAgICBvbGRDYWxsYmFjayA9IHRoaXNUd2Vlbi52YXJzLm9uT3ZlcndyaXRlO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpc1R3ZWVuLnZhcnMub25PdmVyd3JpdGUgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAob2xkQ2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkQ2FsbGJhY2suYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3Q2FsbGJhY2suYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyAoQlVJTEQpIC0gUkVNT1ZFIElOIE1JTklGWSAtIEVORFxuICAgICAgICAgICAgbG9nKDMsIFwiYWRkZWQgdHdlZW5cIik7XG5cbiAgICAgICAgICAgIHVwZGF0ZVR3ZWVuUHJvZ3Jlc3MoKTtcbiAgICAgICAgICAgIHJldHVybiBTY2VuZTtcbiAgICAgICAgfTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlIHRoZSB0d2VlbiBmcm9tIHRoZSBzY2VuZS5cbiAgICAgICAgICogVGhpcyB3aWxsIHRlcm1pbmF0ZSB0aGUgY29udHJvbCBvZiB0aGUgU2NlbmUgb3ZlciB0aGUgdHdlZW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIFVzaW5nIHRoZSByZXNldCBvcHRpb24geW91IGNhbiBkZWNpZGUgaWYgdGhlIHR3ZWVuIHNob3VsZCByZW1haW4gaW4gdGhlIGN1cnJlbnQgc3RhdGUgb3IgYmUgcmV3b3VuZCB0byBzZXQgdGhlIHRhcmdldCBlbGVtZW50cyBiYWNrIHRvIHRoZSBzdGF0ZSB0aGV5IHdlcmUgaW4gYmVmb3JlIHRoZSB0d2VlbiB3YXMgYWRkZWQgdG8gdGhlIHNjZW5lLlxuICAgICAgICAgKiBAbWVtYmVyb2YhIGFuaW1hdGlvbi5HU0FQI1xuICAgICAgICAgKlxuICAgICAgICAgKiBAZXhhbXBsZVxuICAgICAgICAgKiAvLyByZW1vdmUgdGhlIHR3ZWVuIGZyb20gdGhlIHNjZW5lIHdpdGhvdXQgcmVzZXR0aW5nIGl0XG4gICAgICAgICAqIHNjZW5lLnJlbW92ZVR3ZWVuKCk7XG4gICAgICAgICAqXG4gICAgICAgICAqIC8vIHJlbW92ZSB0aGUgdHdlZW4gZnJvbSB0aGUgc2NlbmUgYW5kIHJlc2V0IGl0IHRvIGluaXRpYWwgcG9zaXRpb25cbiAgICAgICAgICogc2NlbmUucmVtb3ZlVHdlZW4odHJ1ZSk7XG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3Jlc2V0PWZhbHNlXSAtIElmIGB0cnVlYCB0aGUgdHdlZW4gd2lsbCBiZSByZXNldCB0byBpdHMgaW5pdGlhbCB2YWx1ZXMuXG4gICAgICAgICAqIEByZXR1cm5zIHtTY2VuZX0gUGFyZW50IG9iamVjdCBmb3IgY2hhaW5pbmcuXG4gICAgICAgICAqL1xuICAgICAgICBTY2VuZS5yZW1vdmVUd2VlbiA9IGZ1bmN0aW9uKHJlc2V0KSB7XG4gICAgICAgICAgICBpZiAoX3R3ZWVuKSB7XG4gICAgICAgICAgICAgICAgaWYgKHJlc2V0KSB7XG4gICAgICAgICAgICAgICAgICAgIF90d2Vlbi5wcm9ncmVzcygwKS5wYXVzZSgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBfdHdlZW4ua2lsbCgpO1xuICAgICAgICAgICAgICAgIF90d2VlbiA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICBsb2coXG4gICAgICAgICAgICAgICAgICAgIDMsXG4gICAgICAgICAgICAgICAgICAgIFwicmVtb3ZlZCB0d2VlbiAocmVzZXQ6IFwiICsgKHJlc2V0ID8gXCJ0cnVlXCIgOiBcImZhbHNlXCIpICsgXCIpXCJcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIFNjZW5lO1xuICAgICAgICB9O1xuICAgIH0pO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSB7IFNjcm9sbE1hZ2ljUGx1Z2luR3NhcCA6IFNjcm9sbE1hZ2ljUGx1Z2luR3NhcCB9O1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///19\n')},131:function(module,exports,__webpack_require__){eval('var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!\r\n * ScrollMagic v2.0.8 (2020-08-14)\r\n * The javascript library for magical scroll interactions.\r\n * (c) 2020 Jan Paepke (@janpaepke)\r\n * Project Website: http://scrollmagic.io\r\n * \r\n * @version 2.0.8\r\n * @license Dual licensed under MIT license and GPL.\r\n * @author Jan Paepke - e-mail@janpaepke.de\r\n *\r\n * @file ScrollMagic main library.\r\n */\r\n/**\r\n * @namespace ScrollMagic\r\n */\r\n(function (root, factory) {\r\n\tif (true) {\r\n\t\t// AMD. Register as an anonymous module.\r\n\t\t!(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory),\n\t\t__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === \'function\' ?\n\t\t(__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) :\n\t\t__WEBPACK_AMD_DEFINE_FACTORY__),\n\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\r\n\t} else {}\r\n}(this, function () {\r\n\t"use strict";\r\n\r\n\tvar ScrollMagic = function () {\r\n\t\t_util.log(2, \'(COMPATIBILITY NOTICE) -> As of ScrollMagic 2.0.0 you need to use \\\'new ScrollMagic.Controller()\\\' to create a new controller instance. Use \\\'new ScrollMagic.Scene()\\\' to instance a scene.\');\r\n\t};\r\n\r\n\tScrollMagic.version = "2.0.8";\r\n\r\n\t// TODO: temporary workaround for chrome\'s scroll jitter bug\r\n\tif (typeof (window) !== \'undefined\') {\r\n\t\twindow.addEventListener("mousewheel", void(0));\r\n\t}\r\n\r\n\t// global const\r\n\tvar PIN_SPACER_ATTRIBUTE = "data-scrollmagic-pin-spacer";\r\n\r\n\t/**\r\n\t * The main class that is needed once per scroll container.\r\n\t *\r\n\t * @class\r\n\t *\r\n\t * @example\r\n\t * // basic initialization\r\n\t * var controller = new ScrollMagic.Controller();\r\n\t *\r\n\t * // passing options\r\n\t * var controller = new ScrollMagic.Controller({container: "#myContainer", loglevel: 3});\r\n\t *\r\n\t * @param {object} [options] - An object containing one or more options for the controller.\r\n\t * @param {(string|object)} [options.container=window] - A selector, DOM object that references the main container for scrolling.\r\n\t * @param {boolean} [options.vertical=true] - Sets the scroll mode to vertical (`true`) or horizontal (`false`) scrolling.\r\n\t * @param {object} [options.globalSceneOptions={}] - These options will be passed to every Scene that is added to the controller using the addScene method. For more information on Scene options see {@link ScrollMagic.Scene}.\r\n\t * @param {number} [options.loglevel=2] Loglevel for debugging. Note that logging is disabled in the minified version of ScrollMagic.\r\n\t\t\t\t\t\t\t\t\t\t\t ** `0` => silent\r\n\t\t\t\t\t\t\t\t\t\t\t ** `1` => errors\r\n\t\t\t\t\t\t\t\t\t\t\t ** `2` => errors, warnings\r\n\t\t\t\t\t\t\t\t\t\t\t ** `3` => errors, warnings, debuginfo\r\n\t * @param {boolean} [options.refreshInterval=100] - Some changes don\'t call events by default, like changing the container size or moving a scene trigger element. \r\n\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t This interval polls these parameters to fire the necessary events. \r\n\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t If you don\'t use custom containers, trigger elements or have static layouts, where the positions of the trigger elements don\'t change, you can set this to 0 disable interval checking and improve performance.\r\n\t *\r\n\t */\r\n\tScrollMagic.Controller = function (options) {\r\n\t\t/*\r\n\t\t * ----------------------------------------------------------------\r\n\t\t * settings\r\n\t\t * ----------------------------------------------------------------\r\n\t\t */\r\n\t\tvar\r\n\t\t\tNAMESPACE = \'ScrollMagic.Controller\',\r\n\t\t\tSCROLL_DIRECTION_FORWARD = \'FORWARD\',\r\n\t\t\tSCROLL_DIRECTION_REVERSE = \'REVERSE\',\r\n\t\t\tSCROLL_DIRECTION_PAUSED = \'PAUSED\',\r\n\t\t\tDEFAULT_OPTIONS = CONTROLLER_OPTIONS.defaults;\r\n\r\n\t\t/*\r\n\t\t * ----------------------------------------------------------------\r\n\t\t * private vars\r\n\t\t * ----------------------------------------------------------------\r\n\t\t */\r\n\t\tvar\r\n\t\t\tController = this,\r\n\t\t\t_options = _util.extend({}, DEFAULT_OPTIONS, options),\r\n\t\t\t_sceneObjects = [],\r\n\t\t\t_updateScenesOnNextCycle = false, // can be boolean (true => all scenes) or an array of scenes to be updated\r\n\t\t\t_scrollPos = 0,\r\n\t\t\t_scrollDirection = SCROLL_DIRECTION_PAUSED,\r\n\t\t\t_isDocument = true,\r\n\t\t\t_viewPortSize = 0,\r\n\t\t\t_enabled = true,\r\n\t\t\t_updateTimeout,\r\n\t\t\t_refreshTimeout;\r\n\r\n\t\t/*\r\n\t\t * ----------------------------------------------------------------\r\n\t\t * private functions\r\n\t\t * ----------------------------------------------------------------\r\n\t\t */\r\n\r\n\t\t/**\r\n\t\t * Internal constructor function of the ScrollMagic Controller\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar construct = function () {\r\n\t\t\tfor (var key in _options) {\r\n\t\t\t\tif (!DEFAULT_OPTIONS.hasOwnProperty(key)) {\r\n\t\t\t\t\tlog(2, "WARNING: Unknown option \\"" + key + "\\"");\r\n\t\t\t\t\tdelete _options[key];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t_options.container = _util.get.elements(_options.container)[0];\r\n\t\t\t// check ScrollContainer\r\n\t\t\tif (!_options.container) {\r\n\t\t\t\tlog(1, "ERROR creating object " + NAMESPACE + ": No valid scroll container supplied");\r\n\t\t\t\tthrow NAMESPACE + " init failed."; // cancel\r\n\t\t\t}\r\n\t\t\t_isDocument = _options.container === window || _options.container === document.body || !document.body.contains(_options.container);\r\n\t\t\t// normalize to window\r\n\t\t\tif (_isDocument) {\r\n\t\t\t\t_options.container = window;\r\n\t\t\t}\r\n\t\t\t// update container size immediately\r\n\t\t\t_viewPortSize = getViewportSize();\r\n\t\t\t// set event handlers\r\n\t\t\t_options.container.addEventListener("resize", onChange);\r\n\t\t\t_options.container.addEventListener("scroll", onChange);\r\n\r\n\t\t\tvar ri = parseInt(_options.refreshInterval, 10);\r\n\t\t\t_options.refreshInterval = _util.type.Number(ri) ? ri : DEFAULT_OPTIONS.refreshInterval;\r\n\t\t\tscheduleRefresh();\r\n\r\n\t\t\tlog(3, "added new " + NAMESPACE + " controller (v" + ScrollMagic.version + ")");\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Schedule the next execution of the refresh function\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar scheduleRefresh = function () {\r\n\t\t\tif (_options.refreshInterval > 0) {\r\n\t\t\t\t_refreshTimeout = window.setTimeout(refresh, _options.refreshInterval);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Default function to get scroll pos - overwriteable using `Controller.scrollPos(newFunction)`\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar getScrollPos = function () {\r\n\t\t\treturn _options.vertical ? _util.get.scrollTop(_options.container) : _util.get.scrollLeft(_options.container);\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Returns the current viewport Size (width vor horizontal, height for vertical)\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar getViewportSize = function () {\r\n\t\t\treturn _options.vertical ? _util.get.height(_options.container) : _util.get.width(_options.container);\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Default function to set scroll pos - overwriteable using `Controller.scrollTo(newFunction)`\r\n\t\t * Make available publicly for pinned mousewheel workaround.\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar setScrollPos = this._setScrollPos = function (pos) {\r\n\t\t\tif (_options.vertical) {\r\n\t\t\t\tif (_isDocument) {\r\n\t\t\t\t\twindow.scrollTo(_util.get.scrollLeft(), pos);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t_options.container.scrollTop = pos;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (_isDocument) {\r\n\t\t\t\t\twindow.scrollTo(pos, _util.get.scrollTop());\r\n\t\t\t\t} else {\r\n\t\t\t\t\t_options.container.scrollLeft = pos;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Handle updates in cycles instead of on scroll (performance)\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar updateScenes = function () {\r\n\t\t\tif (_enabled && _updateScenesOnNextCycle) {\r\n\t\t\t\t// determine scenes to update\r\n\t\t\t\tvar scenesToUpdate = _util.type.Array(_updateScenesOnNextCycle) ? _updateScenesOnNextCycle : _sceneObjects.slice(0);\r\n\t\t\t\t// reset scenes\r\n\t\t\t\t_updateScenesOnNextCycle = false;\r\n\t\t\t\tvar oldScrollPos = _scrollPos;\r\n\t\t\t\t// update scroll pos now instead of onChange, as it might have changed since scheduling (i.e. in-browser smooth scroll)\r\n\t\t\t\t_scrollPos = Controller.scrollPos();\r\n\t\t\t\tvar deltaScroll = _scrollPos - oldScrollPos;\r\n\t\t\t\tif (deltaScroll !== 0) { // scroll position changed?\r\n\t\t\t\t\t_scrollDirection = (deltaScroll > 0) ? SCROLL_DIRECTION_FORWARD : SCROLL_DIRECTION_REVERSE;\r\n\t\t\t\t}\r\n\t\t\t\t// reverse order of scenes if scrolling reverse\r\n\t\t\t\tif (_scrollDirection === SCROLL_DIRECTION_REVERSE) {\r\n\t\t\t\t\tscenesToUpdate.reverse();\r\n\t\t\t\t}\r\n\t\t\t\t// update scenes\r\n\t\t\t\tscenesToUpdate.forEach(function (scene, index) {\r\n\t\t\t\t\tlog(3, "updating Scene " + (index + 1) + "/" + scenesToUpdate.length + " (" + _sceneObjects.length + " total)");\r\n\t\t\t\t\tscene.update(true);\r\n\t\t\t\t});\r\n\t\t\t\tif (scenesToUpdate.length === 0 && _options.loglevel >= 3) {\r\n\t\t\t\t\tlog(3, "updating 0 Scenes (nothing added to controller)");\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Initializes rAF callback\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar debounceUpdate = function () {\r\n\t\t\t_updateTimeout = _util.rAF(updateScenes);\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Handles Container changes\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar onChange = function (e) {\r\n\t\t\tlog(3, "event fired causing an update:", e.type);\r\n\t\t\tif (e.type == "resize") {\r\n\t\t\t\t// resize\r\n\t\t\t\t_viewPortSize = getViewportSize();\r\n\t\t\t\t_scrollDirection = SCROLL_DIRECTION_PAUSED;\r\n\t\t\t}\r\n\t\t\t// schedule update\r\n\t\t\tif (_updateScenesOnNextCycle !== true) {\r\n\t\t\t\t_updateScenesOnNextCycle = true;\r\n\t\t\t\tdebounceUpdate();\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tvar refresh = function () {\r\n\t\t\tif (!_isDocument) {\r\n\t\t\t\t// simulate resize event. Only works for viewport relevant param (performance)\r\n\t\t\t\tif (_viewPortSize != getViewportSize()) {\r\n\t\t\t\t\tvar resizeEvent;\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tresizeEvent = new Event(\'resize\', {\r\n\t\t\t\t\t\t\tbubbles: false,\r\n\t\t\t\t\t\t\tcancelable: false\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t} catch (e) { // stupid IE\r\n\t\t\t\t\t\tresizeEvent = document.createEvent("Event");\r\n\t\t\t\t\t\tresizeEvent.initEvent("resize", false, false);\r\n\t\t\t\t\t}\r\n\t\t\t\t\t_options.container.dispatchEvent(resizeEvent);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t_sceneObjects.forEach(function (scene, index) { // refresh all scenes\r\n\t\t\t\tscene.refresh();\r\n\t\t\t});\r\n\t\t\tscheduleRefresh();\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Send a debug message to the console.\r\n\t\t * provided publicly with _log for plugins\r\n\t\t * @private\r\n\t\t *\r\n\t\t * @param {number} loglevel - The loglevel required to initiate output for the message.\r\n\t\t * @param {...mixed} output - One or more variables that should be passed to the console.\r\n\t\t */\r\n\t\tvar log = this._log = function (loglevel, output) {\r\n\t\t\tif (_options.loglevel >= loglevel) {\r\n\t\t\t\tArray.prototype.splice.call(arguments, 1, 0, "(" + NAMESPACE + ") ->");\r\n\t\t\t\t_util.log.apply(window, arguments);\r\n\t\t\t}\r\n\t\t};\r\n\t\t// for scenes we have getters for each option, but for the controller we don\'t, so we need to make it available externally for plugins\r\n\t\tthis._options = _options;\r\n\r\n\t\t/**\r\n\t\t * Sort scenes in ascending order of their start offset.\r\n\t\t * @private\r\n\t\t *\r\n\t\t * @param {array} ScenesArray - an array of ScrollMagic Scenes that should be sorted\r\n\t\t * @return {array} The sorted array of Scenes.\r\n\t\t */\r\n\t\tvar sortScenes = function (ScenesArray) {\r\n\t\t\tif (ScenesArray.length <= 1) {\r\n\t\t\t\treturn ScenesArray;\r\n\t\t\t} else {\r\n\t\t\t\tvar scenes = ScenesArray.slice(0);\r\n\t\t\t\tscenes.sort(function (a, b) {\r\n\t\t\t\t\treturn a.scrollOffset() > b.scrollOffset() ? 1 : -1;\r\n\t\t\t\t});\r\n\t\t\t\treturn scenes;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * ----------------------------------------------------------------\r\n\t\t * public functions\r\n\t\t * ----------------------------------------------------------------\r\n\t\t */\r\n\r\n\t\t/**\r\n\t\t * Add one ore more scene(s) to the controller. \r\n\t\t * This is the equivalent to `Scene.addTo(controller)`.\r\n\t\t * @public\r\n\t\t * @example\r\n\t\t * // with a previously defined scene\r\n\t\t * controller.addScene(scene);\r\n\t\t *\r\n\t\t * // with a newly created scene.\r\n\t\t * controller.addScene(new ScrollMagic.Scene({duration : 0}));\r\n\t\t *\r\n\t\t * // adding multiple scenes\r\n\t\t * controller.addScene([scene, scene2, new ScrollMagic.Scene({duration : 0})]);\r\n\t\t *\r\n\t\t * @param {(ScrollMagic.Scene|array)} newScene - ScrollMagic Scene or Array of Scenes to be added to the controller.\r\n\t\t * @return {Controller} Parent object for chaining.\r\n\t\t */\r\n\t\tthis.addScene = function (newScene) {\r\n\t\t\tif (_util.type.Array(newScene)) {\r\n\t\t\t\tnewScene.forEach(function (scene, index) {\r\n\t\t\t\t\tController.addScene(scene);\r\n\t\t\t\t});\r\n\t\t\t} else if (newScene instanceof ScrollMagic.Scene) {\r\n\t\t\t\tif (newScene.controller() !== Controller) {\r\n\t\t\t\t\tnewScene.addTo(Controller);\r\n\t\t\t\t} else if (_sceneObjects.indexOf(newScene) < 0) {\r\n\t\t\t\t\t// new scene\r\n\t\t\t\t\t_sceneObjects.push(newScene); // add to array\r\n\t\t\t\t\t_sceneObjects = sortScenes(_sceneObjects); // sort\r\n\t\t\t\t\tnewScene.on("shift.controller_sort", function () { // resort whenever scene moves\r\n\t\t\t\t\t\t_sceneObjects = sortScenes(_sceneObjects);\r\n\t\t\t\t\t});\r\n\t\t\t\t\t// insert Global defaults.\r\n\t\t\t\t\tfor (var key in _options.globalSceneOptions) {\r\n\t\t\t\t\t\tif (newScene[key]) {\r\n\t\t\t\t\t\t\tnewScene[key].call(newScene, _options.globalSceneOptions[key]);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tlog(3, "adding Scene (now " + _sceneObjects.length + " total)");\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tlog(1, "ERROR: invalid argument supplied for \'.addScene()\'");\r\n\t\t\t}\r\n\t\t\treturn Controller;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Remove one ore more scene(s) from the controller. \r\n\t\t * This is the equivalent to `Scene.remove()`.\r\n\t\t * @public\r\n\t\t * @example\r\n\t\t * // remove a scene from the controller\r\n\t\t * controller.removeScene(scene);\r\n\t\t *\r\n\t\t * // remove multiple scenes from the controller\r\n\t\t * controller.removeScene([scene, scene2, scene3]);\r\n\t\t *\r\n\t\t * @param {(ScrollMagic.Scene|array)} Scene - ScrollMagic Scene or Array of Scenes to be removed from the controller.\r\n\t\t * @returns {Controller} Parent object for chaining.\r\n\t\t */\r\n\t\tthis.removeScene = function (Scene) {\r\n\t\t\tif (_util.type.Array(Scene)) {\r\n\t\t\t\tScene.forEach(function (scene, index) {\r\n\t\t\t\t\tController.removeScene(scene);\r\n\t\t\t\t});\r\n\t\t\t} else {\r\n\t\t\t\tvar index = _sceneObjects.indexOf(Scene);\r\n\t\t\t\tif (index > -1) {\r\n\t\t\t\t\tScene.off("shift.controller_sort");\r\n\t\t\t\t\t_sceneObjects.splice(index, 1);\r\n\t\t\t\t\tlog(3, "removing Scene (now " + _sceneObjects.length + " left)");\r\n\t\t\t\t\tScene.remove();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn Controller;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t * Update one ore more scene(s) according to the scroll position of the container. \r\n\t * This is the equivalent to `Scene.update()`. \r\n\t * The update method calculates the scene\'s start and end position (based on the trigger element, trigger hook, duration and offset) and checks it against the current scroll position of the container. \r\n\t * It then updates the current scene state accordingly (or does nothing, if the state is already correct) – Pins will be set to their correct position and tweens will be updated to their correct progress. \r\n\t * _**Note:** This method gets called constantly whenever Controller detects a change. The only application for you is if you change something outside of the realm of ScrollMagic, like moving the trigger or changing tween parameters._\r\n\t * @public\r\n\t * @example\r\n\t * // update a specific scene on next cycle\r\n \t * controller.updateScene(scene);\r\n \t *\r\n\t * // update a specific scene immediately\r\n\t * controller.updateScene(scene, true);\r\n \t *\r\n\t * // update multiple scenes scene on next cycle\r\n\t * controller.updateScene([scene1, scene2, scene3]);\r\n\t *\r\n\t * @param {ScrollMagic.Scene} Scene - ScrollMagic Scene or Array of Scenes that is/are supposed to be updated.\r\n\t * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next update cycle. \r\n\t \t\t\t\t\t\t\t\t\t\t This is useful when changing multiple properties of the scene - this way it will only be updated once all new properties are set (updateScenes).\r\n\t * @return {Controller} Parent object for chaining.\r\n\t */\r\n\t\tthis.updateScene = function (Scene, immediately) {\r\n\t\t\tif (_util.type.Array(Scene)) {\r\n\t\t\t\tScene.forEach(function (scene, index) {\r\n\t\t\t\t\tController.updateScene(scene, immediately);\r\n\t\t\t\t});\r\n\t\t\t} else {\r\n\t\t\t\tif (immediately) {\r\n\t\t\t\t\tScene.update(true);\r\n\t\t\t\t} else if (_updateScenesOnNextCycle !== true && Scene instanceof ScrollMagic.Scene) { // if _updateScenesOnNextCycle is true, all connected scenes are already scheduled for update\r\n\t\t\t\t\t// prep array for next update cycle\r\n\t\t\t\t\t_updateScenesOnNextCycle = _updateScenesOnNextCycle || [];\r\n\t\t\t\t\tif (_updateScenesOnNextCycle.indexOf(Scene) == -1) {\r\n\t\t\t\t\t\t_updateScenesOnNextCycle.push(Scene);\r\n\t\t\t\t\t}\r\n\t\t\t\t\t_updateScenesOnNextCycle = sortScenes(_updateScenesOnNextCycle); // sort\r\n\t\t\t\t\tdebounceUpdate();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn Controller;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Updates the controller params and calls updateScene on every scene, that is attached to the controller. \r\n\t\t * See `Controller.updateScene()` for more information about what this means. \r\n\t\t * In most cases you will not need this function, as it is called constantly, whenever ScrollMagic detects a state change event, like resize or scroll. \r\n\t\t * The only application for this method is when ScrollMagic fails to detect these events. \r\n\t\t * One application is with some external scroll libraries (like iScroll) that move an internal container to a negative offset instead of actually scrolling. In this case the update on the controller needs to be called whenever the child container\'s position changes.\r\n\t\t * For this case there will also be the need to provide a custom function to calculate the correct scroll position. See `Controller.scrollPos()` for details.\r\n\t\t * @public\r\n\t\t * @example\r\n\t\t * // update the controller on next cycle (saves performance due to elimination of redundant updates)\r\n\t\t * controller.update();\r\n\t\t *\r\n\t\t * // update the controller immediately\r\n\t\t * controller.update(true);\r\n\t\t *\r\n\t\t * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next update cycle (better performance)\r\n\t\t * @return {Controller} Parent object for chaining.\r\n\t\t */\r\n\t\tthis.update = function (immediately) {\r\n\t\t\tonChange({\r\n\t\t\t\ttype: "resize"\r\n\t\t\t}); // will update size and set _updateScenesOnNextCycle to true\r\n\t\t\tif (immediately) {\r\n\t\t\t\tupdateScenes();\r\n\t\t\t}\r\n\t\t\treturn Controller;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Scroll to a numeric scroll offset, a DOM element, the start of a scene or provide an alternate method for scrolling. \r\n\t\t * For vertical controllers it will change the top scroll offset and for horizontal applications it will change the left offset.\r\n\t\t * @public\r\n\t\t *\r\n\t\t * @since 1.1.0\r\n\t\t * @example\r\n\t\t * // scroll to an offset of 100\r\n\t\t * controller.scrollTo(100);\r\n\t\t *\r\n\t\t * // scroll to a DOM element\r\n\t\t * controller.scrollTo("#anchor");\r\n\t\t *\r\n\t\t * // scroll to the beginning of a scene\r\n\t\t * var scene = new ScrollMagic.Scene({offset: 200});\r\n\t\t * controller.scrollTo(scene);\r\n\t\t *\r\n\t\t * // define a new scroll position modification function (jQuery animate instead of jump)\r\n\t\t * controller.scrollTo(function (newScrollPos) {\r\n\t\t *\t$("html, body").animate({scrollTop: newScrollPos});\r\n\t\t * });\r\n\t\t * controller.scrollTo(100); // call as usual, but the new function will be used instead\r\n\t\t *\r\n\t\t * // define a new scroll function with an additional parameter\r\n\t\t * controller.scrollTo(function (newScrollPos, message) {\r\n\t\t * console.log(message);\r\n\t\t *\t$(this).animate({scrollTop: newScrollPos});\r\n\t\t * });\r\n\t\t * // call as usual, but supply an extra parameter to the defined custom function\r\n\t\t * controller.scrollTo(100, "my message");\r\n\t\t *\r\n\t\t * // define a new scroll function with an additional parameter containing multiple variables\r\n\t\t * controller.scrollTo(function (newScrollPos, options) {\r\n\t\t * someGlobalVar = options.a + options.b;\r\n\t\t *\t$(this).animate({scrollTop: newScrollPos});\r\n\t\t * });\r\n\t\t * // call as usual, but supply an extra parameter containing multiple options\r\n\t\t * controller.scrollTo(100, {a: 1, b: 2});\r\n\t\t *\r\n\t\t * // define a new scroll function with a callback supplied as an additional parameter\r\n\t\t * controller.scrollTo(function (newScrollPos, callback) {\r\n\t\t *\t$(this).animate({scrollTop: newScrollPos}, 400, "swing", callback);\r\n\t\t * });\r\n\t\t * // call as usual, but supply an extra parameter, which is used as a callback in the previously defined custom scroll function\r\n\t\t * controller.scrollTo(100, function() {\r\n\t\t *\tconsole.log("scroll has finished.");\r\n\t\t * });\r\n\t\t *\r\n\t\t * @param {mixed} scrollTarget - The supplied argument can be one of these types:\r\n\t\t * 1. `number` -> The container will scroll to this new scroll offset.\r\n\t\t * 2. `string` or `object` -> Can be a selector or a DOM object. \r\n\t\t * The container will scroll to the position of this element.\r\n\t\t * 3. `ScrollMagic Scene` -> The container will scroll to the start of this scene.\r\n\t\t * 4. `function` -> This function will be used for future scroll position modifications. \r\n\t\t * This provides a way for you to change the behaviour of scrolling and adding new behaviour like animation. The function receives the new scroll position as a parameter and a reference to the container element using `this`. \r\n\t\t * It may also optionally receive an optional additional parameter (see below) \r\n\t\t * _**NOTE:** \r\n\t\t * All other options will still work as expected, using the new function to scroll._\r\n\t\t * @param {mixed} [additionalParameter] - If a custom scroll function was defined (see above 4.), you may want to supply additional parameters to it, when calling it. You can do this using this parameter – see examples for details. Please note, that this parameter will have no effect, if you use the default scrolling function.\r\n\t\t * @returns {Controller} Parent object for chaining.\r\n\t\t */\r\n\t\tthis.scrollTo = function (scrollTarget, additionalParameter) {\r\n\t\t\tif (_util.type.Number(scrollTarget)) { // excecute\r\n\t\t\t\tsetScrollPos.call(_options.container, scrollTarget, additionalParameter);\r\n\t\t\t} else if (scrollTarget instanceof ScrollMagic.Scene) { // scroll to scene\r\n\t\t\t\tif (scrollTarget.controller() === Controller) { // check if the controller is associated with this scene\r\n\t\t\t\t\tController.scrollTo(scrollTarget.scrollOffset(), additionalParameter);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlog(2, "scrollTo(): The supplied scene does not belong to this controller. Scroll cancelled.", scrollTarget);\r\n\t\t\t\t}\r\n\t\t\t} else if (_util.type.Function(scrollTarget)) { // assign new scroll function\r\n\t\t\t\tsetScrollPos = scrollTarget;\r\n\t\t\t} else { // scroll to element\r\n\t\t\t\tvar elem = _util.get.elements(scrollTarget)[0];\r\n\t\t\t\tif (elem) {\r\n\t\t\t\t\t// if parent is pin spacer, use spacer position instead so correct start position is returned for pinned elements.\r\n\t\t\t\t\twhile (elem.parentNode.hasAttribute(PIN_SPACER_ATTRIBUTE)) {\r\n\t\t\t\t\t\telem = elem.parentNode;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tvar\r\n\t\t\t\t\t\tparam = _options.vertical ? "top" : "left", // which param is of interest ?\r\n\t\t\t\t\t\tcontainerOffset = _util.get.offset(_options.container), // container position is needed because element offset is returned in relation to document, not in relation to container.\r\n\t\t\t\t\t\telementOffset = _util.get.offset(elem);\r\n\r\n\t\t\t\t\tif (!_isDocument) { // container is not the document root, so substract scroll Position to get correct trigger element position relative to scrollcontent\r\n\t\t\t\t\t\tcontainerOffset[param] -= Controller.scrollPos();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tController.scrollTo(elementOffset[param] - containerOffset[param], additionalParameter);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlog(2, "scrollTo(): The supplied argument is invalid. Scroll cancelled.", scrollTarget);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn Controller;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * **Get** the current scrollPosition or **Set** a new method to calculate it. \r\n\t\t * -> **GET**:\r\n\t\t * When used as a getter this function will return the current scroll position. \r\n\t\t * To get a cached value use Controller.info("scrollPos"), which will be updated in the update cycle. \r\n\t\t * For vertical controllers it will return the top scroll offset and for horizontal applications it will return the left offset.\r\n\t\t *\r\n\t\t * -> **SET**:\r\n\t\t * When used as a setter this method prodes a way to permanently overwrite the controller\'s scroll position calculation. \r\n\t\t * A typical usecase is when the scroll position is not reflected by the containers scrollTop or scrollLeft values, but for example by the inner offset of a child container. \r\n\t\t * Moving a child container inside a parent is a commonly used method for several scrolling frameworks, including iScroll. \r\n\t\t * By providing an alternate calculation function you can make sure ScrollMagic receives the correct scroll position. \r\n\t\t * Please also bear in mind that your function should return y values for vertical scrolls an x for horizontals.\r\n\t\t *\r\n\t\t * To change the current scroll position please use `Controller.scrollTo()`.\r\n\t\t * @public\r\n\t\t *\r\n\t\t * @example\r\n\t\t * // get the current scroll Position\r\n\t\t * var scrollPos = controller.scrollPos();\r\n\t\t *\r\n\t\t * // set a new scroll position calculation method\r\n\t\t * controller.scrollPos(function () {\r\n\t\t *\treturn this.info("vertical") ? -mychildcontainer.y : -mychildcontainer.x\r\n\t\t * });\r\n\t\t *\r\n\t\t * @param {function} [scrollPosMethod] - The function to be used for the scroll position calculation of the container.\r\n\t\t * @returns {(number|Controller)} Current scroll position or parent object for chaining.\r\n\t\t */\r\n\t\tthis.scrollPos = function (scrollPosMethod) {\r\n\t\t\tif (!arguments.length) { // get\r\n\t\t\t\treturn getScrollPos.call(Controller);\r\n\t\t\t} else { // set\r\n\t\t\t\tif (_util.type.Function(scrollPosMethod)) {\r\n\t\t\t\t\tgetScrollPos = scrollPosMethod;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlog(2, "Provided value for method \'scrollPos\' is not a function. To change the current scroll position use \'scrollTo()\'.");\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn Controller;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * **Get** all infos or one in particular about the controller.\r\n\t\t * @public\r\n\t\t * @example\r\n\t\t * // returns the current scroll position (number)\r\n\t\t * var scrollPos = controller.info("scrollPos");\r\n\t\t *\r\n\t\t * // returns all infos as an object\r\n\t\t * var infos = controller.info();\r\n\t\t *\r\n\t\t * @param {string} [about] - If passed only this info will be returned instead of an object containing all. \r\n\t\t \t\t\t\t\t\t\t Valid options are:\r\n\t\t \t\t\t\t\t\t\t ** `"size"` => the current viewport size of the container\r\n\t\t \t\t\t\t\t\t\t ** `"vertical"` => true if vertical scrolling, otherwise false\r\n\t\t \t\t\t\t\t\t\t ** `"scrollPos"` => the current scroll position\r\n\t\t \t\t\t\t\t\t\t ** `"scrollDirection"` => the last known direction of the scroll\r\n\t\t \t\t\t\t\t\t\t ** `"container"` => the container element\r\n\t\t \t\t\t\t\t\t\t ** `"isDocument"` => true if container element is the document.\r\n\t\t * @returns {(mixed|object)} The requested info(s).\r\n\t\t */\r\n\t\tthis.info = function (about) {\r\n\t\t\tvar values = {\r\n\t\t\t\tsize: _viewPortSize, // contains height or width (in regard to orientation);\r\n\t\t\t\tvertical: _options.vertical,\r\n\t\t\t\tscrollPos: _scrollPos,\r\n\t\t\t\tscrollDirection: _scrollDirection,\r\n\t\t\t\tcontainer: _options.container,\r\n\t\t\t\tisDocument: _isDocument\r\n\t\t\t};\r\n\t\t\tif (!arguments.length) { // get all as an object\r\n\t\t\t\treturn values;\r\n\t\t\t} else if (values[about] !== undefined) {\r\n\t\t\t\treturn values[about];\r\n\t\t\t} else {\r\n\t\t\t\tlog(1, "ERROR: option \\"" + about + "\\" is not available");\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * **Get** or **Set** the current loglevel option value.\r\n\t\t * @public\r\n\t\t *\r\n\t\t * @example\r\n\t\t * // get the current value\r\n\t\t * var loglevel = controller.loglevel();\r\n\t\t *\r\n\t\t * // set a new value\r\n\t\t * controller.loglevel(3);\r\n\t\t *\r\n\t\t * @param {number} [newLoglevel] - The new loglevel setting of the Controller. `[0-3]`\r\n\t\t * @returns {(number|Controller)} Current loglevel or parent object for chaining.\r\n\t\t */\r\n\t\tthis.loglevel = function (newLoglevel) {\r\n\t\t\tif (!arguments.length) { // get\r\n\t\t\t\treturn _options.loglevel;\r\n\t\t\t} else if (_options.loglevel != newLoglevel) { // set\r\n\t\t\t\t_options.loglevel = newLoglevel;\r\n\t\t\t}\r\n\t\t\treturn Controller;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * **Get** or **Set** the current enabled state of the controller. \r\n\t\t * This can be used to disable all Scenes connected to the controller without destroying or removing them.\r\n\t\t * @public\r\n\t\t *\r\n\t\t * @example\r\n\t\t * // get the current value\r\n\t\t * var enabled = controller.enabled();\r\n\t\t *\r\n\t\t * // disable the controller\r\n\t\t * controller.enabled(false);\r\n\t\t *\r\n\t\t * @param {boolean} [newState] - The new enabled state of the controller `true` or `false`.\r\n\t\t * @returns {(boolean|Controller)} Current enabled state or parent object for chaining.\r\n\t\t */\r\n\t\tthis.enabled = function (newState) {\r\n\t\t\tif (!arguments.length) { // get\r\n\t\t\t\treturn _enabled;\r\n\t\t\t} else if (_enabled != newState) { // set\r\n\t\t\t\t_enabled = !!newState;\r\n\t\t\t\tController.updateScene(_sceneObjects, true);\r\n\t\t\t}\r\n\t\t\treturn Controller;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Destroy the Controller, all Scenes and everything.\r\n\t\t * @public\r\n\t\t *\r\n\t\t * @example\r\n\t\t * // without resetting the scenes\r\n\t\t * controller = controller.destroy();\r\n\t\t *\r\n\t\t * // with scene reset\r\n\t\t * controller = controller.destroy(true);\r\n\t\t *\r\n\t\t * @param {boolean} [resetScenes=false] - If `true` the pins and tweens (if existent) of all scenes will be reset.\r\n\t\t * @returns {null} Null to unset handler variables.\r\n\t\t */\r\n\t\tthis.destroy = function (resetScenes) {\r\n\t\t\twindow.clearTimeout(_refreshTimeout);\r\n\t\t\tvar i = _sceneObjects.length;\r\n\t\t\twhile (i--) {\r\n\t\t\t\t_sceneObjects[i].destroy(resetScenes);\r\n\t\t\t}\r\n\t\t\t_options.container.removeEventListener("resize", onChange);\r\n\t\t\t_options.container.removeEventListener("scroll", onChange);\r\n\t\t\t_util.cAF(_updateTimeout);\r\n\t\t\tlog(3, "destroyed " + NAMESPACE + " (reset: " + (resetScenes ? "true" : "false") + ")");\r\n\t\t\treturn null;\r\n\t\t};\r\n\r\n\t\t// INIT\r\n\t\tconstruct();\r\n\t\treturn Controller;\r\n\t};\r\n\r\n\t// store pagewide controller options\r\n\tvar CONTROLLER_OPTIONS = {\r\n\t\tdefaults: {\r\n\t\t\tcontainer: window,\r\n\t\t\tvertical: true,\r\n\t\t\tglobalSceneOptions: {},\r\n\t\t\tloglevel: 2,\r\n\t\t\trefreshInterval: 100\r\n\t\t}\r\n\t};\r\n\t/*\r\n\t * method used to add an option to ScrollMagic Scenes.\r\n\t */\r\n\tScrollMagic.Controller.addOption = function (name, defaultValue) {\r\n\t\tCONTROLLER_OPTIONS.defaults[name] = defaultValue;\r\n\t};\r\n\t// instance extension function for plugins\r\n\tScrollMagic.Controller.extend = function (extension) {\r\n\t\tvar oldClass = this;\r\n\t\tScrollMagic.Controller = function () {\r\n\t\t\toldClass.apply(this, arguments);\r\n\t\t\tthis.$super = _util.extend({}, this); // copy parent state\r\n\t\t\treturn extension.apply(this, arguments) || this;\r\n\t\t};\r\n\t\t_util.extend(ScrollMagic.Controller, oldClass); // copy properties\r\n\t\tScrollMagic.Controller.prototype = oldClass.prototype; // copy prototype\r\n\t\tScrollMagic.Controller.prototype.constructor = ScrollMagic.Controller; // restore constructor\r\n\t};\r\n\r\n\r\n\t/**\r\n\t * A Scene defines where the controller should react and how.\r\n\t *\r\n\t * @class\r\n\t *\r\n\t * @example\r\n\t * // create a standard scene and add it to a controller\r\n\t * new ScrollMagic.Scene()\r\n\t *\t\t.addTo(controller);\r\n\t *\r\n\t * // create a scene with custom options and assign a handler to it.\r\n\t * var scene = new ScrollMagic.Scene({\r\n\t * \t\tduration: 100,\r\n\t *\t\toffset: 200,\r\n\t *\t\ttriggerHook: "onEnter",\r\n\t *\t\treverse: false\r\n\t * });\r\n\t *\r\n\t * @param {object} [options] - Options for the Scene. The options can be updated at any time. \r\n\t \t\t\t\t\t\t\t Instead of setting the options for each scene individually you can also set them globally in the controller as the controllers `globalSceneOptions` option. The object accepts the same properties as the ones below. \r\n\t \t\t\t\t\t\t\t When a scene is added to the controller the options defined using the Scene constructor will be overwritten by those set in `globalSceneOptions`.\r\n\t * @param {(number|string|function)} [options.duration=0] - The duration of the scene. \r\n\t \t\t\t\t\tPlease see `Scene.duration()` for details.\r\n\t * @param {number} [options.offset=0] - Offset Value for the Trigger Position. If no triggerElement is defined this will be the scroll distance from the start of the page, after which the scene will start.\r\n\t * @param {(string|object)} [options.triggerElement=null] - Selector or DOM object that defines the start of the scene. If undefined the scene will start right at the start of the page (unless an offset is set).\r\n\t * @param {(number|string)} [options.triggerHook="onCenter"] - Can be a number between 0 and 1 defining the position of the trigger Hook in relation to the viewport. \r\n\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t Can also be defined using a string:\r\n\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ** `"onEnter"` => `1`\r\n\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ** `"onCenter"` => `0.5`\r\n\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ** `"onLeave"` => `0`\r\n\t * @param {boolean} [options.reverse=true] - Should the scene reverse, when scrolling up?\r\n\t * @param {number} [options.loglevel=2] - Loglevel for debugging. Note that logging is disabled in the minified version of ScrollMagic.\r\n\t \t\t\t\t\t\t\t\t\t\t ** `0` => silent\r\n\t \t\t\t\t\t\t\t\t\t\t ** `1` => errors\r\n\t \t\t\t\t\t\t\t\t\t\t ** `2` => errors, warnings\r\n\t \t\t\t\t\t\t\t\t\t\t ** `3` => errors, warnings, debuginfo\r\n\t * \r\n\t */\r\n\tScrollMagic.Scene = function (options) {\r\n\r\n\t\t/*\r\n\t\t * ----------------------------------------------------------------\r\n\t\t * settings\r\n\t\t * ----------------------------------------------------------------\r\n\t\t */\r\n\r\n\t\tvar\r\n\t\t\tNAMESPACE = \'ScrollMagic.Scene\',\r\n\t\t\tSCENE_STATE_BEFORE = \'BEFORE\',\r\n\t\t\tSCENE_STATE_DURING = \'DURING\',\r\n\t\t\tSCENE_STATE_AFTER = \'AFTER\',\r\n\t\t\tDEFAULT_OPTIONS = SCENE_OPTIONS.defaults;\r\n\r\n\t\t/*\r\n\t\t * ----------------------------------------------------------------\r\n\t\t * private vars\r\n\t\t * ----------------------------------------------------------------\r\n\t\t */\r\n\r\n\t\tvar\r\n\t\t\tScene = this,\r\n\t\t\t_options = _util.extend({}, DEFAULT_OPTIONS, options),\r\n\t\t\t_state = SCENE_STATE_BEFORE,\r\n\t\t\t_progress = 0,\r\n\t\t\t_scrollOffset = {\r\n\t\t\t\tstart: 0,\r\n\t\t\t\tend: 0\r\n\t\t\t}, // reflects the controllers\'s scroll position for the start and end of the scene respectively\r\n\t\t\t_triggerPos = 0,\r\n\t\t\t_enabled = true,\r\n\t\t\t_durationUpdateMethod,\r\n\t\t\t_controller;\r\n\r\n\t\t/**\r\n\t\t * Internal constructor function of the ScrollMagic Scene\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar construct = function () {\r\n\t\t\tfor (var key in _options) { // check supplied options\r\n\t\t\t\tif (!DEFAULT_OPTIONS.hasOwnProperty(key)) {\r\n\t\t\t\t\tlog(2, "WARNING: Unknown option \\"" + key + "\\"");\r\n\t\t\t\t\tdelete _options[key];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// add getters/setters for all possible options\r\n\t\t\tfor (var optionName in DEFAULT_OPTIONS) {\r\n\t\t\t\taddSceneOption(optionName);\r\n\t\t\t}\r\n\t\t\t// validate all options\r\n\t\t\tvalidateOption();\r\n\t\t};\r\n\r\n\t\t/*\r\n\t\t * ----------------------------------------------------------------\r\n\t\t * Event Management\r\n\t\t * ----------------------------------------------------------------\r\n\t\t */\r\n\r\n\t\tvar _listeners = {};\r\n\t\t/**\r\n\t\t * Scene start event. \r\n\t\t * Fires whenever the scroll position its the starting point of the scene. \r\n\t\t * It will also fire when scrolling back up going over the start position of the scene. If you want something to happen only when scrolling down/right, use the scrollDirection parameter passed to the callback.\r\n\t\t *\r\n\t\t * For details on this event and the order in which it is fired, please review the {@link Scene.progress} method.\r\n\t\t *\r\n\t\t * @event ScrollMagic.Scene#start\r\n\t\t *\r\n\t\t * @example\r\n\t\t * scene.on("start", function (event) {\r\n\t\t * \tconsole.log("Hit start point of scene.");\r\n\t\t * });\r\n\t\t *\r\n\t\t * @property {object} event - The event Object passed to each callback\r\n\t\t * @property {string} event.type - The name of the event\r\n\t\t * @property {Scene} event.target - The Scene object that triggered this event\r\n\t\t * @property {number} event.progress - Reflects the current progress of the scene\r\n\t\t * @property {string} event.state - The current state of the scene `"BEFORE"` or `"DURING"`\r\n\t\t * @property {string} event.scrollDirection - Indicates which way we are scrolling `"PAUSED"`, `"FORWARD"` or `"REVERSE"`\r\n\t\t */\r\n\t\t/**\r\n\t\t * Scene end event. \r\n\t\t * Fires whenever the scroll position its the ending point of the scene. \r\n\t\t * It will also fire when scrolling back up from after the scene and going over its end position. If you want something to happen only when scrolling down/right, use the scrollDirection parameter passed to the callback.\r\n\t\t *\r\n\t\t * For details on this event and the order in which it is fired, please review the {@link Scene.progress} method.\r\n\t\t *\r\n\t\t * @event ScrollMagic.Scene#end\r\n\t\t *\r\n\t\t * @example\r\n\t\t * scene.on("end", function (event) {\r\n\t\t * \tconsole.log("Hit end point of scene.");\r\n\t\t * });\r\n\t\t *\r\n\t\t * @property {object} event - The event Object passed to each callback\r\n\t\t * @property {string} event.type - The name of the event\r\n\t\t * @property {Scene} event.target - The Scene object that triggered this event\r\n\t\t * @property {number} event.progress - Reflects the current progress of the scene\r\n\t\t * @property {string} event.state - The current state of the scene `"DURING"` or `"AFTER"`\r\n\t\t * @property {string} event.scrollDirection - Indicates which way we are scrolling `"PAUSED"`, `"FORWARD"` or `"REVERSE"`\r\n\t\t */\r\n\t\t/**\r\n\t\t * Scene enter event. \r\n\t\t * Fires whenever the scene enters the "DURING" state. \r\n\t\t * Keep in mind that it doesn\'t matter if the scene plays forward or backward: This event always fires when the scene enters its active scroll timeframe, regardless of the scroll-direction.\r\n\t\t *\r\n\t\t * For details on this event and the order in which it is fired, please review the {@link Scene.progress} method.\r\n\t\t *\r\n\t\t * @event ScrollMagic.Scene#enter\r\n\t\t *\r\n\t\t * @example\r\n\t\t * scene.on("enter", function (event) {\r\n\t\t * \tconsole.log("Scene entered.");\r\n\t\t * });\r\n\t\t *\r\n\t\t * @property {object} event - The event Object passed to each callback\r\n\t\t * @property {string} event.type - The name of the event\r\n\t\t * @property {Scene} event.target - The Scene object that triggered this event\r\n\t\t * @property {number} event.progress - Reflects the current progress of the scene\r\n\t\t * @property {string} event.state - The current state of the scene - always `"DURING"`\r\n\t\t * @property {string} event.scrollDirection - Indicates which way we are scrolling `"PAUSED"`, `"FORWARD"` or `"REVERSE"`\r\n\t\t */\r\n\t\t/**\r\n\t\t * Scene leave event. \r\n\t\t * Fires whenever the scene\'s state goes from "DURING" to either "BEFORE" or "AFTER". \r\n\t\t * Keep in mind that it doesn\'t matter if the scene plays forward or backward: This event always fires when the scene leaves its active scroll timeframe, regardless of the scroll-direction.\r\n\t\t *\r\n\t\t * For details on this event and the order in which it is fired, please review the {@link Scene.progress} method.\r\n\t\t *\r\n\t\t * @event ScrollMagic.Scene#leave\r\n\t\t *\r\n\t\t * @example\r\n\t\t * scene.on("leave", function (event) {\r\n\t\t * \tconsole.log("Scene left.");\r\n\t\t * });\r\n\t\t *\r\n\t\t * @property {object} event - The event Object passed to each callback\r\n\t\t * @property {string} event.type - The name of the event\r\n\t\t * @property {Scene} event.target - The Scene object that triggered this event\r\n\t\t * @property {number} event.progress - Reflects the current progress of the scene\r\n\t\t * @property {string} event.state - The current state of the scene `"BEFORE"` or `"AFTER"`\r\n\t\t * @property {string} event.scrollDirection - Indicates which way we are scrolling `"PAUSED"`, `"FORWARD"` or `"REVERSE"`\r\n\t\t */\r\n\t\t/**\r\n\t\t * Scene update event. \r\n\t\t * Fires whenever the scene is updated (but not necessarily changes the progress).\r\n\t\t *\r\n\t\t * @event ScrollMagic.Scene#update\r\n\t\t *\r\n\t\t * @example\r\n\t\t * scene.on("update", function (event) {\r\n\t\t * \tconsole.log("Scene updated.");\r\n\t\t * });\r\n\t\t *\r\n\t\t * @property {object} event - The event Object passed to each callback\r\n\t\t * @property {string} event.type - The name of the event\r\n\t\t * @property {Scene} event.target - The Scene object that triggered this event\r\n\t\t * @property {number} event.startPos - The starting position of the scene (in relation to the conainer)\r\n\t\t * @property {number} event.endPos - The ending position of the scene (in relation to the conainer)\r\n\t\t * @property {number} event.scrollPos - The current scroll position of the container\r\n\t\t */\r\n\t\t/**\r\n\t\t * Scene progress event. \r\n\t\t * Fires whenever the progress of the scene changes.\r\n\t\t *\r\n\t\t * For details on this event and the order in which it is fired, please review the {@link Scene.progress} method.\r\n\t\t *\r\n\t\t * @event ScrollMagic.Scene#progress\r\n\t\t *\r\n\t\t * @example\r\n\t\t * scene.on("progress", function (event) {\r\n\t\t * \tconsole.log("Scene progress changed to " + event.progress);\r\n\t\t * });\r\n\t\t *\r\n\t\t * @property {object} event - The event Object passed to each callback\r\n\t\t * @property {string} event.type - The name of the event\r\n\t\t * @property {Scene} event.target - The Scene object that triggered this event\r\n\t\t * @property {number} event.progress - Reflects the current progress of the scene\r\n\t\t * @property {string} event.state - The current state of the scene `"BEFORE"`, `"DURING"` or `"AFTER"`\r\n\t\t * @property {string} event.scrollDirection - Indicates which way we are scrolling `"PAUSED"`, `"FORWARD"` or `"REVERSE"`\r\n\t\t */\r\n\t\t/**\r\n\t\t * Scene change event. \r\n\t\t * Fires whenvever a property of the scene is changed.\r\n\t\t *\r\n\t\t * @event ScrollMagic.Scene#change\r\n\t\t *\r\n\t\t * @example\r\n\t\t * scene.on("change", function (event) {\r\n\t\t * \tconsole.log("Scene Property \\"" + event.what + "\\" changed to " + event.newval);\r\n\t\t * });\r\n\t\t *\r\n\t\t * @property {object} event - The event Object passed to each callback\r\n\t\t * @property {string} event.type - The name of the event\r\n\t\t * @property {Scene} event.target - The Scene object that triggered this event\r\n\t\t * @property {string} event.what - Indicates what value has been changed\r\n\t\t * @property {mixed} event.newval - The new value of the changed property\r\n\t\t */\r\n\t\t/**\r\n\t\t * Scene shift event. \r\n\t\t * Fires whenvever the start or end **scroll offset** of the scene change.\r\n\t\t * This happens explicitely, when one of these values change: `offset`, `duration` or `triggerHook`.\r\n\t\t * It will fire implicitly when the `triggerElement` changes, if the new element has a different position (most cases).\r\n\t\t * It will also fire implicitly when the size of the container changes and the triggerHook is anything other than `onLeave`.\r\n\t\t *\r\n\t\t * @event ScrollMagic.Scene#shift\r\n\t\t * @since 1.1.0\r\n\t\t *\r\n\t\t * @example\r\n\t\t * scene.on("shift", function (event) {\r\n\t\t * \tconsole.log("Scene moved, because the " + event.reason + " has changed.)");\r\n\t\t * });\r\n\t\t *\r\n\t\t * @property {object} event - The event Object passed to each callback\r\n\t\t * @property {string} event.type - The name of the event\r\n\t\t * @property {Scene} event.target - The Scene object that triggered this event\r\n\t\t * @property {string} event.reason - Indicates why the scene has shifted\r\n\t\t */\r\n\t\t/**\r\n\t\t * Scene destroy event. \r\n\t\t * Fires whenvever the scene is destroyed.\r\n\t\t * This can be used to tidy up custom behaviour used in events.\r\n\t\t *\r\n\t\t * @event ScrollMagic.Scene#destroy\r\n\t\t * @since 1.1.0\r\n\t\t *\r\n\t\t * @example\r\n\t\t * scene.on("enter", function (event) {\r\n\t\t * // add custom action\r\n\t\t * $("#my-elem").left("200");\r\n\t\t * })\r\n\t\t * .on("destroy", function (event) {\r\n\t\t * // reset my element to start position\r\n\t\t * if (event.reset) {\r\n\t\t * $("#my-elem").left("0");\r\n\t\t * }\r\n\t\t * });\r\n\t\t *\r\n\t\t * @property {object} event - The event Object passed to each callback\r\n\t\t * @property {string} event.type - The name of the event\r\n\t\t * @property {Scene} event.target - The Scene object that triggered this event\r\n\t\t * @property {boolean} event.reset - Indicates if the destroy method was called with reset `true` or `false`.\r\n\t\t */\r\n\t\t/**\r\n\t\t * Scene add event. \r\n\t\t * Fires when the scene is added to a controller.\r\n\t\t * This is mostly used by plugins to know that change might be due.\r\n\t\t *\r\n\t\t * @event ScrollMagic.Scene#add\r\n\t\t * @since 2.0.0\r\n\t\t *\r\n\t\t * @example\r\n\t\t * scene.on("add", function (event) {\r\n\t\t * \tconsole.log(\'Scene was added to a new controller.\');\r\n\t\t * });\r\n\t\t *\r\n\t\t * @property {object} event - The event Object passed to each callback\r\n\t\t * @property {string} event.type - The name of the event\r\n\t\t * @property {Scene} event.target - The Scene object that triggered this event\r\n\t\t * @property {boolean} event.controller - The controller object the scene was added to.\r\n\t\t */\r\n\t\t/**\r\n\t\t * Scene remove event. \r\n\t\t * Fires when the scene is removed from a controller.\r\n\t\t * This is mostly used by plugins to know that change might be due.\r\n\t\t *\r\n\t\t * @event ScrollMagic.Scene#remove\r\n\t\t * @since 2.0.0\r\n\t\t *\r\n\t\t * @example\r\n\t\t * scene.on("remove", function (event) {\r\n\t\t * \tconsole.log(\'Scene was removed from its controller.\');\r\n\t\t * });\r\n\t\t *\r\n\t\t * @property {object} event - The event Object passed to each callback\r\n\t\t * @property {string} event.type - The name of the event\r\n\t\t * @property {Scene} event.target - The Scene object that triggered this event\r\n\t\t */\r\n\r\n\t\t/**\r\n\t\t * Add one ore more event listener. \r\n\t\t * The callback function will be fired at the respective event, and an object containing relevant data will be passed to the callback.\r\n\t\t * @method ScrollMagic.Scene#on\r\n\t\t *\r\n\t\t * @example\r\n\t\t * function callback (event) {\r\n\t\t * \t\tconsole.log("Event fired! (" + event.type + ")");\r\n\t\t * }\r\n\t\t * // add listeners\r\n\t\t * scene.on("change update progress start end enter leave", callback);\r\n\t\t *\r\n\t\t * @param {string} names - The name or names of the event the callback should be attached to.\r\n\t\t * @param {function} callback - A function that should be executed, when the event is dispatched. An event object will be passed to the callback.\r\n\t\t * @returns {Scene} Parent object for chaining.\r\n\t\t */\r\n\t\tthis.on = function (names, callback) {\r\n\t\t\tif (_util.type.Function(callback)) {\r\n\t\t\t\tnames = names.trim().split(\' \');\r\n\t\t\t\tnames.forEach(function (fullname) {\r\n\t\t\t\t\tvar\r\n\t\t\t\t\t\tnameparts = fullname.split(\'.\'),\r\n\t\t\t\t\t\teventname = nameparts[0],\r\n\t\t\t\t\t\tnamespace = nameparts[1];\r\n\t\t\t\t\tif (eventname != "*") { // disallow wildcards\r\n\t\t\t\t\t\tif (!_listeners[eventname]) {\r\n\t\t\t\t\t\t\t_listeners[eventname] = [];\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\t_listeners[eventname].push({\r\n\t\t\t\t\t\t\tnamespace: namespace || \'\',\r\n\t\t\t\t\t\t\tcallback: callback\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t} else {\r\n\t\t\t\tlog(1, "ERROR when calling \'.on()\': Supplied callback for \'" + names + "\' is not a valid function!");\r\n\t\t\t}\r\n\t\t\treturn Scene;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Remove one or more event listener.\r\n\t\t * @method ScrollMagic.Scene#off\r\n\t\t *\r\n\t\t * @example\r\n\t\t * function callback (event) {\r\n\t\t * \t\tconsole.log("Event fired! (" + event.type + ")");\r\n\t\t * }\r\n\t\t * // add listeners\r\n\t\t * scene.on("change update", callback);\r\n\t\t * // remove listeners\r\n\t\t * scene.off("change update", callback);\r\n\t\t *\r\n\t\t * @param {string} names - The name or names of the event that should be removed.\r\n\t\t * @param {function} [callback] - A specific callback function that should be removed. If none is passed all callbacks to the event listener will be removed.\r\n\t\t * @returns {Scene} Parent object for chaining.\r\n\t\t */\r\n\t\tthis.off = function (names, callback) {\r\n\t\t\tif (!names) {\r\n\t\t\t\tlog(1, "ERROR: Invalid event name supplied.");\r\n\t\t\t\treturn Scene;\r\n\t\t\t}\r\n\t\t\tnames = names.trim().split(\' \');\r\n\t\t\tnames.forEach(function (fullname, key) {\r\n\t\t\t\tvar\r\n\t\t\t\t\tnameparts = fullname.split(\'.\'),\r\n\t\t\t\t\teventname = nameparts[0],\r\n\t\t\t\t\tnamespace = nameparts[1] || \'\',\r\n\t\t\t\t\tremoveList = eventname === \'*\' ? Object.keys(_listeners) : [eventname];\r\n\t\t\t\tremoveList.forEach(function (remove) {\r\n\t\t\t\t\tvar\r\n\t\t\t\t\t\tlist = _listeners[remove] || [],\r\n\t\t\t\t\t\ti = list.length;\r\n\t\t\t\t\twhile (i--) {\r\n\t\t\t\t\t\tvar listener = list[i];\r\n\t\t\t\t\t\tif (listener && (namespace === listener.namespace || namespace === \'*\') && (!callback || callback == listener.callback)) {\r\n\t\t\t\t\t\t\tlist.splice(i, 1);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (!list.length) {\r\n\t\t\t\t\t\tdelete _listeners[remove];\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t\treturn Scene;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Trigger an event.\r\n\t\t * @method ScrollMagic.Scene#trigger\r\n\t\t *\r\n\t\t * @example\r\n\t\t * this.trigger("change");\r\n\t\t *\r\n\t\t * @param {string} name - The name of the event that should be triggered.\r\n\t\t * @param {object} [vars] - An object containing info that should be passed to the callback.\r\n\t\t * @returns {Scene} Parent object for chaining.\r\n\t\t */\r\n\t\tthis.trigger = function (name, vars) {\r\n\t\t\tif (name) {\r\n\t\t\t\tvar\r\n\t\t\t\t\tnameparts = name.trim().split(\'.\'),\r\n\t\t\t\t\teventname = nameparts[0],\r\n\t\t\t\t\tnamespace = nameparts[1],\r\n\t\t\t\t\tlisteners = _listeners[eventname];\r\n\t\t\t\tlog(3, \'event fired:\', eventname, vars ? "->" : \'\', vars || \'\');\r\n\t\t\t\tif (listeners) {\r\n\t\t\t\t\tlisteners.forEach(function (listener, key) {\r\n\t\t\t\t\t\tif (!namespace || namespace === listener.namespace) {\r\n\t\t\t\t\t\t\tlistener.callback.call(Scene, new ScrollMagic.Event(eventname, listener.namespace, Scene, vars));\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tlog(1, "ERROR: Invalid event name supplied.");\r\n\t\t\t}\r\n\t\t\treturn Scene;\r\n\t\t};\r\n\r\n\t\t// set event listeners\r\n\t\tScene\r\n\t\t\t.on("change.internal", function (e) {\r\n\t\t\t\tif (e.what !== "loglevel" && e.what !== "tweenChanges") { // no need for a scene update scene with these options...\r\n\t\t\t\t\tif (e.what === "triggerElement") {\r\n\t\t\t\t\t\tupdateTriggerElementPosition();\r\n\t\t\t\t\t} else if (e.what === "reverse") { // the only property left that may have an impact on the current scene state. Everything else is handled by the shift event.\r\n\t\t\t\t\t\tScene.update();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\t.on("shift.internal", function (e) {\r\n\t\t\t\tupdateScrollOffset();\r\n\t\t\t\tScene.update(); // update scene to reflect new position\r\n\t\t\t});\r\n\r\n\t\t/**\r\n\t\t * Send a debug message to the console.\r\n\t\t * @private\r\n\t\t * but provided publicly with _log for plugins\r\n\t\t *\r\n\t\t * @param {number} loglevel - The loglevel required to initiate output for the message.\r\n\t\t * @param {...mixed} output - One or more variables that should be passed to the console.\r\n\t\t */\r\n\t\tvar log = this._log = function (loglevel, output) {\r\n\t\t\tif (_options.loglevel >= loglevel) {\r\n\t\t\t\tArray.prototype.splice.call(arguments, 1, 0, "(" + NAMESPACE + ") ->");\r\n\t\t\t\t_util.log.apply(window, arguments);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Add the scene to a controller. \r\n\t\t * This is the equivalent to `Controller.addScene(scene)`.\r\n\t\t * @method ScrollMagic.Scene#addTo\r\n\t\t *\r\n\t\t * @example\r\n\t\t * // add a scene to a ScrollMagic Controller\r\n\t\t * scene.addTo(controller);\r\n\t\t *\r\n\t\t * @param {ScrollMagic.Controller} controller - The controller to which the scene should be added.\r\n\t\t * @returns {Scene} Parent object for chaining.\r\n\t\t */\r\n\t\tthis.addTo = function (controller) {\r\n\t\t\tif (!(controller instanceof ScrollMagic.Controller)) {\r\n\t\t\t\tlog(1, "ERROR: supplied argument of \'addTo()\' is not a valid ScrollMagic Controller");\r\n\t\t\t} else if (_controller != controller) {\r\n\t\t\t\t// new controller\r\n\t\t\t\tif (_controller) { // was associated to a different controller before, so remove it...\r\n\t\t\t\t\t_controller.removeScene(Scene);\r\n\t\t\t\t}\r\n\t\t\t\t_controller = controller;\r\n\t\t\t\tvalidateOption();\r\n\t\t\t\tupdateDuration(true);\r\n\t\t\t\tupdateTriggerElementPosition(true);\r\n\t\t\t\tupdateScrollOffset();\r\n\t\t\t\t_controller.info("container").addEventListener(\'resize\', onContainerResize);\r\n\t\t\t\tcontroller.addScene(Scene);\r\n\t\t\t\tScene.trigger("add", {\r\n\t\t\t\t\tcontroller: _controller\r\n\t\t\t\t});\r\n\t\t\t\tlog(3, "added " + NAMESPACE + " to controller");\r\n\t\t\t\tScene.update();\r\n\t\t\t}\r\n\t\t\treturn Scene;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * **Get** or **Set** the current enabled state of the scene. \r\n\t\t * This can be used to disable this scene without removing or destroying it.\r\n\t\t * @method ScrollMagic.Scene#enabled\r\n\t\t *\r\n\t\t * @example\r\n\t\t * // get the current value\r\n\t\t * var enabled = scene.enabled();\r\n\t\t *\r\n\t\t * // disable the scene\r\n\t\t * scene.enabled(false);\r\n\t\t *\r\n\t\t * @param {boolean} [newState] - The new enabled state of the scene `true` or `false`.\r\n\t\t * @returns {(boolean|Scene)} Current enabled state or parent object for chaining.\r\n\t\t */\r\n\t\tthis.enabled = function (newState) {\r\n\t\t\tif (!arguments.length) { // get\r\n\t\t\t\treturn _enabled;\r\n\t\t\t} else if (_enabled != newState) { // set\r\n\t\t\t\t_enabled = !!newState;\r\n\t\t\t\tScene.update(true);\r\n\t\t\t}\r\n\t\t\treturn Scene;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Remove the scene from the controller. \r\n\t\t * This is the equivalent to `Controller.removeScene(scene)`.\r\n\t\t * The scene will not be updated anymore until you readd it to a controller.\r\n\t\t * To remove the pin or the tween you need to call removeTween() or removePin() respectively.\r\n\t\t * @method ScrollMagic.Scene#remove\r\n\t\t * @example\r\n\t\t * // remove the scene from its controller\r\n\t\t * scene.remove();\r\n\t\t *\r\n\t\t * @returns {Scene} Parent object for chaining.\r\n\t\t */\r\n\t\tthis.remove = function () {\r\n\t\t\tif (_controller) {\r\n\t\t\t\t_controller.info("container").removeEventListener(\'resize\', onContainerResize);\r\n\t\t\t\tvar tmpParent = _controller;\r\n\t\t\t\t_controller = undefined;\r\n\t\t\t\ttmpParent.removeScene(Scene);\r\n\t\t\t\tScene.trigger("remove");\r\n\t\t\t\tlog(3, "removed " + NAMESPACE + " from controller");\r\n\t\t\t}\r\n\t\t\treturn Scene;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Destroy the scene and everything.\r\n\t\t * @method ScrollMagic.Scene#destroy\r\n\t\t * @example\r\n\t\t * // destroy the scene without resetting the pin and tween to their initial positions\r\n\t\t * scene = scene.destroy();\r\n\t\t *\r\n\t\t * // destroy the scene and reset the pin and tween\r\n\t\t * scene = scene.destroy(true);\r\n\t\t *\r\n\t\t * @param {boolean} [reset=false] - If `true` the pin and tween (if existent) will be reset.\r\n\t\t * @returns {null} Null to unset handler variables.\r\n\t\t */\r\n\t\tthis.destroy = function (reset) {\r\n\t\t\tScene.trigger("destroy", {\r\n\t\t\t\treset: reset\r\n\t\t\t});\r\n\t\t\tScene.remove();\r\n\t\t\tScene.off("*.*");\r\n\t\t\tlog(3, "destroyed " + NAMESPACE + " (reset: " + (reset ? "true" : "false") + ")");\r\n\t\t\treturn null;\r\n\t\t};\r\n\r\n\r\n\t\t/**\r\n\t\t * Updates the Scene to reflect the current state. \r\n\t\t * This is the equivalent to `Controller.updateScene(scene, immediately)`. \r\n\t\t * The update method calculates the scene\'s start and end position (based on the trigger element, trigger hook, duration and offset) and checks it against the current scroll position of the container. \r\n\t\t * It then updates the current scene state accordingly (or does nothing, if the state is already correct) – Pins will be set to their correct position and tweens will be updated to their correct progress.\r\n\t\t * This means an update doesn\'t necessarily result in a progress change. The `progress` event will be fired if the progress has indeed changed between this update and the last. \r\n\t\t * _**NOTE:** This method gets called constantly whenever ScrollMagic detects a change. The only application for you is if you change something outside of the realm of ScrollMagic, like moving the trigger or changing tween parameters._\r\n\t\t * @method ScrollMagic.Scene#update\r\n\t\t * @example\r\n\t\t * // update the scene on next tick\r\n\t\t * scene.update();\r\n\t\t *\r\n\t\t * // update the scene immediately\r\n\t\t * scene.update(true);\r\n\t\t *\r\n\t\t * @fires Scene.update\r\n\t\t *\r\n\t\t * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next update cycle (better performance).\r\n\t\t * @returns {Scene} Parent object for chaining.\r\n\t\t */\r\n\t\tthis.update = function (immediately) {\r\n\t\t\tif (_controller) {\r\n\t\t\t\tif (immediately) {\r\n\t\t\t\t\tif (_controller.enabled() && _enabled) {\r\n\t\t\t\t\t\tvar\r\n\t\t\t\t\t\t\tscrollPos = _controller.info("scrollPos"),\r\n\t\t\t\t\t\t\tnewProgress;\r\n\r\n\t\t\t\t\t\tif (_options.duration > 0) {\r\n\t\t\t\t\t\t\tnewProgress = (scrollPos - _scrollOffset.start) / (_scrollOffset.end - _scrollOffset.start);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tnewProgress = scrollPos >= _scrollOffset.start ? 1 : 0;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tScene.trigger("update", {\r\n\t\t\t\t\t\t\tstartPos: _scrollOffset.start,\r\n\t\t\t\t\t\t\tendPos: _scrollOffset.end,\r\n\t\t\t\t\t\t\tscrollPos: scrollPos\r\n\t\t\t\t\t\t});\r\n\r\n\t\t\t\t\t\tScene.progress(newProgress);\r\n\t\t\t\t\t} else if (_pin && _state === SCENE_STATE_DURING) {\r\n\t\t\t\t\t\tupdatePinState(true); // unpin in position\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\t_controller.updateScene(Scene, false);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn Scene;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Updates dynamic scene variables like the trigger element position or the duration.\r\n\t\t * This method is automatically called in regular intervals from the controller. See {@link ScrollMagic.Controller} option `refreshInterval`.\r\n\t\t * \r\n\t\t * You can call it to minimize lag, for example when you intentionally change the position of the triggerElement.\r\n\t\t * If you don\'t it will simply be updated in the next refresh interval of the container, which is usually sufficient.\r\n\t\t *\r\n\t\t * @method ScrollMagic.Scene#refresh\r\n\t\t * @since 1.1.0\r\n\t\t * @example\r\n\t\t * scene = new ScrollMagic.Scene({triggerElement: "#trigger"});\r\n\t\t * \r\n\t\t * // change the position of the trigger\r\n\t\t * $("#trigger").css("top", 500);\r\n\t\t * // immediately let the scene know of this change\r\n\t\t * scene.refresh();\r\n\t\t *\r\n\t\t * @fires {@link Scene.shift}, if the trigger element position or the duration changed\r\n\t\t * @fires {@link Scene.change}, if the duration changed\r\n\t\t *\r\n\t\t * @returns {Scene} Parent object for chaining.\r\n\t\t */\r\n\t\tthis.refresh = function () {\r\n\t\t\tupdateDuration();\r\n\t\t\tupdateTriggerElementPosition();\r\n\t\t\t// update trigger element position\r\n\t\t\treturn Scene;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * **Get** or **Set** the scene\'s progress. \r\n\t\t * Usually it shouldn\'t be necessary to use this as a setter, as it is set automatically by scene.update(). \r\n\t\t * The order in which the events are fired depends on the duration of the scene:\r\n\t\t * 1. Scenes with `duration == 0`: \r\n\t\t * Scenes that have no duration by definition have no ending. Thus the `end` event will never be fired. \r\n\t\t * When the trigger position of the scene is passed the events are always fired in this order: \r\n\t\t * `enter`, `start`, `progress` when scrolling forward \r\n\t\t * and \r\n\t\t * `progress`, `start`, `leave` when scrolling in reverse\r\n\t\t * 2. Scenes with `duration > 0`: \r\n\t\t * Scenes with a set duration have a defined start and end point. \r\n\t\t * When scrolling past the start position of the scene it will fire these events in this order: \r\n\t\t * `enter`, `start`, `progress` \r\n\t\t * When continuing to scroll and passing the end point it will fire these events: \r\n\t\t * `progress`, `end`, `leave` \r\n\t\t * When reversing through the end point these events are fired: \r\n\t\t * `enter`, `end`, `progress` \r\n\t\t * And when continuing to scroll past the start position in reverse it will fire: \r\n\t\t * `progress`, `start`, `leave` \r\n\t\t * In between start and end the `progress` event will be called constantly, whenever the progress changes.\r\n\t\t * \r\n\t\t * In short: \r\n\t\t * `enter` events will always trigger **before** the progress update and `leave` envents will trigger **after** the progress update. \r\n\t\t * `start` and `end` will always trigger at their respective position.\r\n\t\t * \r\n\t\t * Please review the event descriptions for details on the events and the event object that is passed to the callback.\r\n\t\t * \r\n\t\t * @method ScrollMagic.Scene#progress\r\n\t\t * @example\r\n\t\t * // get the current scene progress\r\n\t\t * var progress = scene.progress();\r\n\t\t *\r\n\t\t * // set new scene progress\r\n\t\t * scene.progress(0.3);\r\n\t\t *\r\n\t\t * @fires {@link Scene.enter}, when used as setter\r\n\t\t * @fires {@link Scene.start}, when used as setter\r\n\t\t * @fires {@link Scene.progress}, when used as setter\r\n\t\t * @fires {@link Scene.end}, when used as setter\r\n\t\t * @fires {@link Scene.leave}, when used as setter\r\n\t\t *\r\n\t\t * @param {number} [progress] - The new progress value of the scene `[0-1]`.\r\n\t\t * @returns {number} `get` - Current scene progress.\r\n\t\t * @returns {Scene} `set` - Parent object for chaining.\r\n\t\t */\r\n\t\tthis.progress = function (progress) {\r\n\t\t\tif (!arguments.length) { // get\r\n\t\t\t\treturn _progress;\r\n\t\t\t} else { // set\r\n\t\t\t\tvar\r\n\t\t\t\t\tdoUpdate = false,\r\n\t\t\t\t\toldState = _state,\r\n\t\t\t\t\tscrollDirection = _controller ? _controller.info("scrollDirection") : \'PAUSED\',\r\n\t\t\t\t\treverseOrForward = _options.reverse || progress >= _progress;\r\n\t\t\t\tif (_options.duration === 0) {\r\n\t\t\t\t\t// zero duration scenes\r\n\t\t\t\t\tdoUpdate = _progress != progress;\r\n\t\t\t\t\t_progress = progress < 1 && reverseOrForward ? 0 : 1;\r\n\t\t\t\t\t_state = _progress === 0 ? SCENE_STATE_BEFORE : SCENE_STATE_DURING;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// scenes with start and end\r\n\t\t\t\t\tif (progress < 0 && _state !== SCENE_STATE_BEFORE && reverseOrForward) {\r\n\t\t\t\t\t\t// go back to initial state\r\n\t\t\t\t\t\t_progress = 0;\r\n\t\t\t\t\t\t_state = SCENE_STATE_BEFORE;\r\n\t\t\t\t\t\tdoUpdate = true;\r\n\t\t\t\t\t} else if (progress >= 0 && progress < 1 && reverseOrForward) {\r\n\t\t\t\t\t\t_progress = progress;\r\n\t\t\t\t\t\t_state = SCENE_STATE_DURING;\r\n\t\t\t\t\t\tdoUpdate = true;\r\n\t\t\t\t\t} else if (progress >= 1 && _state !== SCENE_STATE_AFTER) {\r\n\t\t\t\t\t\t_progress = 1;\r\n\t\t\t\t\t\t_state = SCENE_STATE_AFTER;\r\n\t\t\t\t\t\tdoUpdate = true;\r\n\t\t\t\t\t} else if (_state === SCENE_STATE_DURING && !reverseOrForward) {\r\n\t\t\t\t\t\tupdatePinState(); // in case we scrolled backwards mid-scene and reverse is disabled => update the pin position, so it doesn\'t move back as well.\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (doUpdate) {\r\n\t\t\t\t\t// fire events\r\n\t\t\t\t\tvar\r\n\t\t\t\t\t\teventVars = {\r\n\t\t\t\t\t\t\tprogress: _progress,\r\n\t\t\t\t\t\t\tstate: _state,\r\n\t\t\t\t\t\t\tscrollDirection: scrollDirection\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\tstateChanged = _state != oldState;\r\n\r\n\t\t\t\t\tvar trigger = function (eventName) { // tmp helper to simplify code\r\n\t\t\t\t\t\tScene.trigger(eventName, eventVars);\r\n\t\t\t\t\t};\r\n\r\n\t\t\t\t\tif (stateChanged) { // enter events\r\n\t\t\t\t\t\tif (oldState !== SCENE_STATE_DURING) {\r\n\t\t\t\t\t\t\ttrigger("enter");\r\n\t\t\t\t\t\t\ttrigger(oldState === SCENE_STATE_BEFORE ? "start" : "end");\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\ttrigger("progress");\r\n\t\t\t\t\tif (stateChanged) { // leave events\r\n\t\t\t\t\t\tif (_state !== SCENE_STATE_DURING) {\r\n\t\t\t\t\t\t\ttrigger(_state === SCENE_STATE_BEFORE ? "start" : "end");\r\n\t\t\t\t\t\t\ttrigger("leave");\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn Scene;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\r\n\t\t/**\r\n\t\t * Update the start and end scrollOffset of the container.\r\n\t\t * The positions reflect what the controller\'s scroll position will be at the start and end respectively.\r\n\t\t * Is called, when:\r\n\t\t * - Scene event "change" is called with: offset, triggerHook, duration \r\n\t\t * - scroll container event "resize" is called\r\n\t\t * - the position of the triggerElement changes\r\n\t\t * - the controller changes -> addTo()\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar updateScrollOffset = function () {\r\n\t\t\t_scrollOffset = {\r\n\t\t\t\tstart: _triggerPos + _options.offset\r\n\t\t\t};\r\n\t\t\tif (_controller && _options.triggerElement) {\r\n\t\t\t\t// take away triggerHook portion to get relative to top\r\n\t\t\t\t_scrollOffset.start -= _controller.info("size") * _options.triggerHook;\r\n\t\t\t}\r\n\t\t\t_scrollOffset.end = _scrollOffset.start + _options.duration;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Updates the duration if set to a dynamic function.\r\n\t\t * This method is called when the scene is added to a controller and in regular intervals from the controller through scene.refresh().\r\n\t\t * \r\n\t\t * @fires {@link Scene.change}, if the duration changed\r\n\t\t * @fires {@link Scene.shift}, if the duration changed\r\n\t\t *\r\n\t\t * @param {boolean} [suppressEvents=false] - If true the shift event will be suppressed.\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar updateDuration = function (suppressEvents) {\r\n\t\t\t// update duration\r\n\t\t\tif (_durationUpdateMethod) {\r\n\t\t\t\tvar varname = "duration";\r\n\t\t\t\tif (changeOption(varname, _durationUpdateMethod.call(Scene)) && !suppressEvents) { // set\r\n\t\t\t\t\tScene.trigger("change", {\r\n\t\t\t\t\t\twhat: varname,\r\n\t\t\t\t\t\tnewval: _options[varname]\r\n\t\t\t\t\t});\r\n\t\t\t\t\tScene.trigger("shift", {\r\n\t\t\t\t\t\treason: varname\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Updates the position of the triggerElement, if present.\r\n\t\t * This method is called ...\r\n\t\t * - ... when the triggerElement is changed\r\n\t\t * - ... when the scene is added to a (new) controller\r\n\t\t * - ... in regular intervals from the controller through scene.refresh().\r\n\t\t * \r\n\t\t * @fires {@link Scene.shift}, if the position changed\r\n\t\t *\r\n\t\t * @param {boolean} [suppressEvents=false] - If true the shift event will be suppressed.\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar updateTriggerElementPosition = function (suppressEvents) {\r\n\t\t\tvar\r\n\t\t\t\telementPos = 0,\r\n\t\t\t\ttelem = _options.triggerElement;\r\n\t\t\tif (_controller && (telem || _triggerPos > 0)) { // either an element exists or was removed and the triggerPos is still > 0\r\n\t\t\t\tif (telem) { // there currently a triggerElement set\r\n\t\t\t\t\tif (telem.parentNode) { // check if element is still attached to DOM\r\n\t\t\t\t\t\tvar\r\n\t\t\t\t\t\t\tcontrollerInfo = _controller.info(),\r\n\t\t\t\t\t\t\tcontainerOffset = _util.get.offset(controllerInfo.container), // container position is needed because element offset is returned in relation to document, not in relation to container.\r\n\t\t\t\t\t\t\tparam = controllerInfo.vertical ? "top" : "left"; // which param is of interest ?\r\n\r\n\t\t\t\t\t\t// if parent is spacer, use spacer position instead so correct start position is returned for pinned elements.\r\n\t\t\t\t\t\twhile (telem.parentNode.hasAttribute(PIN_SPACER_ATTRIBUTE)) {\r\n\t\t\t\t\t\t\ttelem = telem.parentNode;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tvar elementOffset = _util.get.offset(telem);\r\n\r\n\t\t\t\t\t\tif (!controllerInfo.isDocument) { // container is not the document root, so substract scroll Position to get correct trigger element position relative to scrollcontent\r\n\t\t\t\t\t\t\tcontainerOffset[param] -= _controller.scrollPos();\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\telementPos = elementOffset[param] - containerOffset[param];\r\n\r\n\t\t\t\t\t} else { // there was an element, but it was removed from DOM\r\n\t\t\t\t\t\tlog(2, "WARNING: triggerElement was removed from DOM and will be reset to", undefined);\r\n\t\t\t\t\t\tScene.triggerElement(undefined); // unset, so a change event is triggered\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar changed = elementPos != _triggerPos;\r\n\t\t\t\t_triggerPos = elementPos;\r\n\t\t\t\tif (changed && !suppressEvents) {\r\n\t\t\t\t\tScene.trigger("shift", {\r\n\t\t\t\t\t\treason: "triggerElementPosition"\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Trigger a shift event, when the container is resized and the triggerHook is > 1.\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar onContainerResize = function (e) {\r\n\t\t\tif (_options.triggerHook > 0) {\r\n\t\t\t\tScene.trigger("shift", {\r\n\t\t\t\t\treason: "containerResize"\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t};\r\n\r\n\r\n\t\tvar _validate = _util.extend(SCENE_OPTIONS.validate, {\r\n\t\t\t// validation for duration handled internally for reference to private var _durationMethod\r\n\t\t\tduration: function (val) {\r\n\t\t\t\tif (_util.type.String(val) && val.match(/^(\\.|\\d)*\\d+%$/)) {\r\n\t\t\t\t\t// percentage value\r\n\t\t\t\t\tvar perc = parseFloat(val) / 100;\r\n\t\t\t\t\tval = function () {\r\n\t\t\t\t\t\treturn _controller ? _controller.info("size") * perc : 0;\r\n\t\t\t\t\t};\r\n\t\t\t\t}\r\n\t\t\t\tif (_util.type.Function(val)) {\r\n\t\t\t\t\t// function\r\n\t\t\t\t\t_durationUpdateMethod = val;\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tval = parseFloat(_durationUpdateMethod.call(Scene));\r\n\t\t\t\t\t} catch (e) {\r\n\t\t\t\t\t\tval = -1; // will cause error below\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t// val has to be float\r\n\t\t\t\tval = parseFloat(val);\r\n\t\t\t\tif (!_util.type.Number(val) || val < 0) {\r\n\t\t\t\t\tif (_durationUpdateMethod) {\r\n\t\t\t\t\t\t_durationUpdateMethod = undefined;\r\n\t\t\t\t\t\tthrow ["Invalid return value of supplied function for option \\"duration\\":", val];\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthrow ["Invalid value for option \\"duration\\":", val];\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\treturn val;\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t/**\r\n\t\t * Checks the validity of a specific or all options and reset to default if neccessary.\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar validateOption = function (check) {\r\n\t\t\tcheck = arguments.length ? [check] : Object.keys(_validate);\r\n\t\t\tcheck.forEach(function (optionName, key) {\r\n\t\t\t\tvar value;\r\n\t\t\t\tif (_validate[optionName]) { // there is a validation method for this option\r\n\t\t\t\t\ttry { // validate value\r\n\t\t\t\t\t\tvalue = _validate[optionName](_options[optionName]);\r\n\t\t\t\t\t} catch (e) { // validation failed -> reset to default\r\n\t\t\t\t\t\tvalue = DEFAULT_OPTIONS[optionName];\r\n\t\t\t\t\t\tvar logMSG = _util.type.String(e) ? [e] : e;\r\n\t\t\t\t\t\tif (_util.type.Array(logMSG)) {\r\n\t\t\t\t\t\t\tlogMSG[0] = "ERROR: " + logMSG[0];\r\n\t\t\t\t\t\t\tlogMSG.unshift(1); // loglevel 1 for error msg\r\n\t\t\t\t\t\t\tlog.apply(this, logMSG);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tlog(1, "ERROR: Problem executing validation callback for option \'" + optionName + "\':", e.message);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} finally {\r\n\t\t\t\t\t\t_options[optionName] = value;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Helper used by the setter/getters for scene options\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar changeOption = function (varname, newval) {\r\n\t\t\tvar\r\n\t\t\t\tchanged = false,\r\n\t\t\t\toldval = _options[varname];\r\n\t\t\tif (_options[varname] != newval) {\r\n\t\t\t\t_options[varname] = newval;\r\n\t\t\t\tvalidateOption(varname); // resets to default if necessary\r\n\t\t\t\tchanged = oldval != _options[varname];\r\n\t\t\t}\r\n\t\t\treturn changed;\r\n\t\t};\r\n\r\n\t\t// generate getters/setters for all options\r\n\t\tvar addSceneOption = function (optionName) {\r\n\t\t\tif (!Scene[optionName]) {\r\n\t\t\t\tScene[optionName] = function (newVal) {\r\n\t\t\t\t\tif (!arguments.length) { // get\r\n\t\t\t\t\t\treturn _options[optionName];\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tif (optionName === "duration") { // new duration is set, so any previously set function must be unset\r\n\t\t\t\t\t\t\t_durationUpdateMethod = undefined;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (changeOption(optionName, newVal)) { // set\r\n\t\t\t\t\t\t\tScene.trigger("change", {\r\n\t\t\t\t\t\t\t\twhat: optionName,\r\n\t\t\t\t\t\t\t\tnewval: _options[optionName]\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\tif (SCENE_OPTIONS.shifts.indexOf(optionName) > -1) {\r\n\t\t\t\t\t\t\t\tScene.trigger("shift", {\r\n\t\t\t\t\t\t\t\t\treason: optionName\r\n\t\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn Scene;\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * **Get** or **Set** the duration option value.\r\n\t\t *\r\n\t\t * As a **setter** it accepts three types of parameters:\r\n\t\t * 1. `number`: Sets the duration of the scene to exactly this amount of pixels. \r\n\t\t * This means the scene will last for exactly this amount of pixels scrolled. Sub-Pixels are also valid.\r\n\t\t * A value of `0` means that the scene is \'open end\' and no end will be triggered. Pins will never unpin and animations will play independently of scroll progress.\r\n\t\t * 2. `string`: Always updates the duration relative to parent scroll container. \r\n\t\t * For example `"100%"` will keep the duration always exactly at the inner height of the scroll container.\r\n\t\t * When scrolling vertically the width is used for reference respectively.\r\n\t\t * 3. `function`: The supplied function will be called to return the scene duration.\r\n\t\t * This is useful in setups where the duration depends on other elements who might change size. By supplying a function you can return a value instead of updating potentially multiple scene durations. \r\n\t\t * The scene can be referenced inside the callback using `this`.\r\n\t\t * _**WARNING:** This is an easy way to kill performance, as the callback will be executed every time `Scene.refresh()` is called, which happens a lot. The interval is defined by the controller (see ScrollMagic.Controller option `refreshInterval`). \r\n\t\t * It\'s recomended to avoid calculations within the function and use cached variables as return values. \r\n\t\t * This counts double if you use the same function for multiple scenes._\r\n\t\t *\r\n\t\t * @method ScrollMagic.Scene#duration\r\n\t\t * @example\r\n\t\t * // get the current duration value\r\n\t\t * var duration = scene.duration();\r\n\t\t *\r\n\t\t * // set a new duration\r\n\t\t * scene.duration(300);\r\n\t\t *\r\n\t\t * // set duration responsively to container size\r\n\t\t * scene.duration("100%");\r\n\t\t *\r\n\t\t * // use a function to randomize the duration for some reason.\r\n\t\t * var durationValueCache;\r\n\t\t * function durationCallback () {\r\n\t\t * return durationValueCache;\r\n\t\t * }\r\n\t\t * function updateDuration () {\r\n\t\t * durationValueCache = Math.random() * 100;\r\n\t\t * }\r\n\t\t * updateDuration(); // set to initial value\r\n\t\t * scene.duration(durationCallback); // set duration callback\r\n\t\t *\r\n\t\t * @fires {@link Scene.change}, when used as setter\r\n\t\t * @fires {@link Scene.shift}, when used as setter\r\n\t\t * @param {(number|string|function)} [newDuration] - The new duration setting for the scene.\r\n\t\t * @returns {number} `get` - Current scene duration.\r\n\t\t * @returns {Scene} `set` - Parent object for chaining.\r\n\t\t */\r\n\r\n\t\t/**\r\n\t\t * **Get** or **Set** the offset option value.\r\n\t\t * @method ScrollMagic.Scene#offset\r\n\t\t * @example\r\n\t\t * // get the current offset\r\n\t\t * var offset = scene.offset();\r\n\t\t *\r\n\t\t * // set a new offset\r\n\t\t * scene.offset(100);\r\n\t\t *\r\n\t\t * @fires {@link Scene.change}, when used as setter\r\n\t\t * @fires {@link Scene.shift}, when used as setter\r\n\t\t * @param {number} [newOffset] - The new offset of the scene.\r\n\t\t * @returns {number} `get` - Current scene offset.\r\n\t\t * @returns {Scene} `set` - Parent object for chaining.\r\n\t\t */\r\n\r\n\t\t/**\r\n\t\t * **Get** or **Set** the triggerElement option value.\r\n\t\t * Does **not** fire `Scene.shift`, because changing the trigger Element doesn\'t necessarily mean the start position changes. This will be determined in `Scene.refresh()`, which is automatically triggered.\r\n\t\t * @method ScrollMagic.Scene#triggerElement\r\n\t\t * @example\r\n\t\t * // get the current triggerElement\r\n\t\t * var triggerElement = scene.triggerElement();\r\n\t\t *\r\n\t\t * // set a new triggerElement using a selector\r\n\t\t * scene.triggerElement("#trigger");\r\n\t\t * // set a new triggerElement using a DOM object\r\n\t\t * scene.triggerElement(document.getElementById("trigger"));\r\n\t\t *\r\n\t\t * @fires {@link Scene.change}, when used as setter\r\n\t\t * @param {(string|object)} [newTriggerElement] - The new trigger element for the scene.\r\n\t\t * @returns {(string|object)} `get` - Current triggerElement.\r\n\t\t * @returns {Scene} `set` - Parent object for chaining.\r\n\t\t */\r\n\r\n\t\t/**\r\n\t\t * **Get** or **Set** the triggerHook option value.\r\n\t\t * @method ScrollMagic.Scene#triggerHook\r\n\t\t * @example\r\n\t\t * // get the current triggerHook value\r\n\t\t * var triggerHook = scene.triggerHook();\r\n\t\t *\r\n\t\t * // set a new triggerHook using a string\r\n\t\t * scene.triggerHook("onLeave");\r\n\t\t * // set a new triggerHook using a number\r\n\t\t * scene.triggerHook(0.7);\r\n\t\t *\r\n\t\t * @fires {@link Scene.change}, when used as setter\r\n\t\t * @fires {@link Scene.shift}, when used as setter\r\n\t\t * @param {(number|string)} [newTriggerHook] - The new triggerHook of the scene. See {@link Scene} parameter description for value options.\r\n\t\t * @returns {number} `get` - Current triggerHook (ALWAYS numerical).\r\n\t\t * @returns {Scene} `set` - Parent object for chaining.\r\n\t\t */\r\n\r\n\t\t/**\r\n\t\t * **Get** or **Set** the reverse option value.\r\n\t\t * @method ScrollMagic.Scene#reverse\r\n\t\t * @example\r\n\t\t * // get the current reverse option\r\n\t\t * var reverse = scene.reverse();\r\n\t\t *\r\n\t\t * // set new reverse option\r\n\t\t * scene.reverse(false);\r\n\t\t *\r\n\t\t * @fires {@link Scene.change}, when used as setter\r\n\t\t * @param {boolean} [newReverse] - The new reverse setting of the scene.\r\n\t\t * @returns {boolean} `get` - Current reverse option value.\r\n\t\t * @returns {Scene} `set` - Parent object for chaining.\r\n\t\t */\r\n\r\n\t\t/**\r\n\t\t * **Get** or **Set** the loglevel option value.\r\n\t\t * @method ScrollMagic.Scene#loglevel\r\n\t\t * @example\r\n\t\t * // get the current loglevel\r\n\t\t * var loglevel = scene.loglevel();\r\n\t\t *\r\n\t\t * // set new loglevel\r\n\t\t * scene.loglevel(3);\r\n\t\t *\r\n\t\t * @fires {@link Scene.change}, when used as setter\r\n\t\t * @param {number} [newLoglevel] - The new loglevel setting of the scene. `[0-3]`\r\n\t\t * @returns {number} `get` - Current loglevel.\r\n\t\t * @returns {Scene} `set` - Parent object for chaining.\r\n\t\t */\r\n\r\n\t\t/**\r\n\t\t * **Get** the associated controller.\r\n\t\t * @method ScrollMagic.Scene#controller\r\n\t\t * @example\r\n\t\t * // get the controller of a scene\r\n\t\t * var controller = scene.controller();\r\n\t\t *\r\n\t\t * @returns {ScrollMagic.Controller} Parent controller or `undefined`\r\n\t\t */\r\n\t\tthis.controller = function () {\r\n\t\t\treturn _controller;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * **Get** the current state.\r\n\t\t * @method ScrollMagic.Scene#state\r\n\t\t * @example\r\n\t\t * // get the current state\r\n\t\t * var state = scene.state();\r\n\t\t *\r\n\t\t * @returns {string} `"BEFORE"`, `"DURING"` or `"AFTER"`\r\n\t\t */\r\n\t\tthis.state = function () {\r\n\t\t\treturn _state;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * **Get** the current scroll offset for the start of the scene. \r\n\t\t * Mind, that the scrollOffset is related to the size of the container, if `triggerHook` is bigger than `0` (or `"onLeave"`). \r\n\t\t * This means, that resizing the container or changing the `triggerHook` will influence the scene\'s start offset.\r\n\t\t * @method ScrollMagic.Scene#scrollOffset\r\n\t\t * @example\r\n\t\t * // get the current scroll offset for the start and end of the scene.\r\n\t\t * var start = scene.scrollOffset();\r\n\t\t * var end = scene.scrollOffset() + scene.duration();\r\n\t\t * console.log("the scene starts at", start, "and ends at", end);\r\n\t\t *\r\n\t\t * @returns {number} The scroll offset (of the container) at which the scene will trigger. Y value for vertical and X value for horizontal scrolls.\r\n\t\t */\r\n\t\tthis.scrollOffset = function () {\r\n\t\t\treturn _scrollOffset.start;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * **Get** the trigger position of the scene (including the value of the `offset` option). \r\n\t\t * @method ScrollMagic.Scene#triggerPosition\r\n\t\t * @example\r\n\t\t * // get the scene\'s trigger position\r\n\t\t * var triggerPosition = scene.triggerPosition();\r\n\t\t *\r\n\t\t * @returns {number} Start position of the scene. Top position value for vertical and left position value for horizontal scrolls.\r\n\t\t */\r\n\t\tthis.triggerPosition = function () {\r\n\t\t\tvar pos = _options.offset; // the offset is the basis\r\n\t\t\tif (_controller) {\r\n\t\t\t\t// get the trigger position\r\n\t\t\t\tif (_options.triggerElement) {\r\n\t\t\t\t\t// Element as trigger\r\n\t\t\t\t\tpos += _triggerPos;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// return the height of the triggerHook to start at the beginning\r\n\t\t\t\t\tpos += _controller.info("size") * Scene.triggerHook();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn pos;\r\n\t\t};\r\n\r\n\r\n\t\tvar\r\n\t\t\t_pin,\r\n\t\t\t_pinOptions;\r\n\r\n\t\tScene\r\n\t\t\t.on("shift.internal", function (e) {\r\n\t\t\t\tvar durationChanged = e.reason === "duration";\r\n\t\t\t\tif ((_state === SCENE_STATE_AFTER && durationChanged) || (_state === SCENE_STATE_DURING && _options.duration === 0)) {\r\n\t\t\t\t\t// if [duration changed after a scene (inside scene progress updates pin position)] or [duration is 0, we are in pin phase and some other value changed].\r\n\t\t\t\t\tupdatePinState();\r\n\t\t\t\t}\r\n\t\t\t\tif (durationChanged) {\r\n\t\t\t\t\tupdatePinDimensions();\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\t.on("progress.internal", function (e) {\r\n\t\t\t\tupdatePinState();\r\n\t\t\t})\r\n\t\t\t.on("add.internal", function (e) {\r\n\t\t\t\tupdatePinDimensions();\r\n\t\t\t})\r\n\t\t\t.on("destroy.internal", function (e) {\r\n\t\t\t\tScene.removePin(e.reset);\r\n\t\t\t});\r\n\t\t/**\r\n\t\t * Update the pin state.\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar updatePinState = function (forceUnpin) {\r\n\t\t\tif (_pin && _controller) {\r\n\t\t\t\tvar\r\n\t\t\t\t\tcontainerInfo = _controller.info(),\r\n\t\t\t\t\tpinTarget = _pinOptions.spacer.firstChild; // may be pin element or another spacer, if cascading pins\r\n\r\n\t\t\t\tif (!forceUnpin && _state === SCENE_STATE_DURING) { // during scene or if duration is 0 and we are past the trigger\r\n\t\t\t\t\t// pinned state\r\n\t\t\t\t\tif (_util.css(pinTarget, "position") != "fixed") {\r\n\t\t\t\t\t\t// change state before updating pin spacer (position changes due to fixed collapsing might occur.)\r\n\t\t\t\t\t\t_util.css(pinTarget, {\r\n\t\t\t\t\t\t\t"position": "fixed"\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t\t// update pin spacer\r\n\t\t\t\t\t\tupdatePinDimensions();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tvar\r\n\t\t\t\t\t\tfixedPos = _util.get.offset(_pinOptions.spacer, true), // get viewport position of spacer\r\n\t\t\t\t\t\tscrollDistance = _options.reverse || _options.duration === 0 ?\r\n\t\t\t\t\t\tcontainerInfo.scrollPos - _scrollOffset.start // quicker\r\n\t\t\t\t\t\t:\r\n\t\t\t\t\t\tMath.round(_progress * _options.duration * 10) / 10; // if no reverse and during pin the position needs to be recalculated using the progress\r\n\r\n\t\t\t\t\t// add scrollDistance\r\n\t\t\t\t\tfixedPos[containerInfo.vertical ? "top" : "left"] += scrollDistance;\r\n\r\n\t\t\t\t\t// set new values\r\n\t\t\t\t\t_util.css(_pinOptions.spacer.firstChild, {\r\n\t\t\t\t\t\ttop: fixedPos.top,\r\n\t\t\t\t\t\tleft: fixedPos.left\r\n\t\t\t\t\t});\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// unpinned state\r\n\t\t\t\t\tvar\r\n\t\t\t\t\t\tnewCSS = {\r\n\t\t\t\t\t\t\tposition: _pinOptions.inFlow ? "relative" : "absolute",\r\n\t\t\t\t\t\t\ttop: 0,\r\n\t\t\t\t\t\t\tleft: 0\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\tchange = _util.css(pinTarget, "position") != newCSS.position;\r\n\r\n\t\t\t\t\tif (!_pinOptions.pushFollowers) {\r\n\t\t\t\t\t\tnewCSS[containerInfo.vertical ? "top" : "left"] = _options.duration * _progress;\r\n\t\t\t\t\t} else if (_options.duration > 0) { // only concerns scenes with duration\r\n\t\t\t\t\t\tif (_state === SCENE_STATE_AFTER && parseFloat(_util.css(_pinOptions.spacer, "padding-top")) === 0) {\r\n\t\t\t\t\t\t\tchange = true; // if in after state but havent updated spacer yet (jumped past pin)\r\n\t\t\t\t\t\t} else if (_state === SCENE_STATE_BEFORE && parseFloat(_util.css(_pinOptions.spacer, "padding-bottom")) === 0) { // before\r\n\t\t\t\t\t\t\tchange = true; // jumped past fixed state upward direction\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t// set new values\r\n\t\t\t\t\t_util.css(pinTarget, newCSS);\r\n\t\t\t\t\tif (change) {\r\n\t\t\t\t\t\t// update pin spacer if state changed\r\n\t\t\t\t\t\tupdatePinDimensions();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Update the pin spacer and/or element size.\r\n\t\t * The size of the spacer needs to be updated whenever the duration of the scene changes, if it is to push down following elements.\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar updatePinDimensions = function () {\r\n\t\t\tif (_pin && _controller && _pinOptions.inFlow) { // no spacerresize, if original position is absolute\r\n\t\t\t\tvar\r\n\t\t\t\t\tafter = (_state === SCENE_STATE_AFTER),\r\n\t\t\t\t\tbefore = (_state === SCENE_STATE_BEFORE),\r\n\t\t\t\t\tduring = (_state === SCENE_STATE_DURING),\r\n\t\t\t\t\tvertical = _controller.info("vertical"),\r\n\t\t\t\t\tpinTarget = _pinOptions.spacer.firstChild, // usually the pined element but can also be another spacer (cascaded pins)\r\n\t\t\t\t\tmarginCollapse = _util.isMarginCollapseType(_util.css(_pinOptions.spacer, "display")),\r\n\t\t\t\t\tcss = {};\r\n\r\n\t\t\t\t// set new size\r\n\t\t\t\t// if relsize: spacer -> pin | else: pin -> spacer\r\n\t\t\t\tif (_pinOptions.relSize.width || _pinOptions.relSize.autoFullWidth) {\r\n\t\t\t\t\tif (during) {\r\n\t\t\t\t\t\t_util.css(_pin, {\r\n\t\t\t\t\t\t\t"width": _util.get.width(_pinOptions.spacer)\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t_util.css(_pin, {\r\n\t\t\t\t\t\t\t"width": "100%"\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// minwidth is needed for cascaded pins.\r\n\t\t\t\t\tcss["min-width"] = _util.get.width(vertical ? _pin : pinTarget, true, true);\r\n\t\t\t\t\tcss.width = during ? css["min-width"] : "auto";\r\n\t\t\t\t}\r\n\t\t\t\tif (_pinOptions.relSize.height) {\r\n\t\t\t\t\tif (during) {\r\n\t\t\t\t\t\t// the only padding the spacer should ever include is the duration (if pushFollowers = true), so we need to substract that.\r\n\t\t\t\t\t\t_util.css(_pin, {\r\n\t\t\t\t\t\t\t"height": _util.get.height(_pinOptions.spacer) - (_pinOptions.pushFollowers ? _options.duration : 0)\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t_util.css(_pin, {\r\n\t\t\t\t\t\t\t"height": "100%"\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// margin is only included if it\'s a cascaded pin to resolve an IE9 bug\r\n\t\t\t\t\tcss["min-height"] = _util.get.height(vertical ? pinTarget : _pin, true, !marginCollapse); // needed for cascading pins\r\n\t\t\t\t\tcss.height = during ? css["min-height"] : "auto";\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// add space for duration if pushFollowers is true\r\n\t\t\t\tif (_pinOptions.pushFollowers) {\r\n\t\t\t\t\tcss["padding" + (vertical ? "Top" : "Left")] = _options.duration * _progress;\r\n\t\t\t\t\tcss["padding" + (vertical ? "Bottom" : "Right")] = _options.duration * (1 - _progress);\r\n\t\t\t\t}\r\n\t\t\t\t_util.css(_pinOptions.spacer, css);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Updates the Pin state (in certain scenarios)\r\n\t\t * If the controller container is not the document and we are mid-pin-phase scrolling or resizing the main document can result to wrong pin positions.\r\n\t\t * So this function is called on resize and scroll of the document.\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar updatePinInContainer = function () {\r\n\t\t\tif (_controller && _pin && _state === SCENE_STATE_DURING && !_controller.info("isDocument")) {\r\n\t\t\t\tupdatePinState();\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Updates the Pin spacer size state (in certain scenarios)\r\n\t\t * If container is resized during pin and relatively sized the size of the pin might need to be updated...\r\n\t\t * So this function is called on resize of the container.\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar updateRelativePinSpacer = function () {\r\n\t\t\tif (_controller && _pin && // well, duh\r\n\t\t\t\t_state === SCENE_STATE_DURING && // element in pinned state?\r\n\t\t\t\t( // is width or height relatively sized, but not in relation to body? then we need to recalc.\r\n\t\t\t\t\t((_pinOptions.relSize.width || _pinOptions.relSize.autoFullWidth) && _util.get.width(window) != _util.get.width(_pinOptions.spacer.parentNode)) ||\r\n\t\t\t\t\t(_pinOptions.relSize.height && _util.get.height(window) != _util.get.height(_pinOptions.spacer.parentNode))\r\n\t\t\t\t)\r\n\t\t\t) {\r\n\t\t\t\tupdatePinDimensions();\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Is called, when the mousewhel is used while over a pinned element inside a div container.\r\n\t\t * If the scene is in fixed state scroll events would be counted towards the body. This forwards the event to the scroll container.\r\n\t\t * @private\r\n\t\t */\r\n\t\tvar onMousewheelOverPin = function (e) {\r\n\t\t\tif (_controller && _pin && _state === SCENE_STATE_DURING && !_controller.info("isDocument")) { // in pin state\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\t_controller._setScrollPos(_controller.info("scrollPos") - ((e.wheelDelta || e[_controller.info("vertical") ? "wheelDeltaY" : "wheelDeltaX"]) / 3 || -e.detail * 30));\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Pin an element for the duration of the scene.\r\n\t\t * If the scene duration is 0 the element will only be unpinned, if the user scrolls back past the start position. \r\n\t\t * Make sure only one pin is applied to an element at the same time.\r\n\t\t * An element can be pinned multiple times, but only successively.\r\n\t\t * _**NOTE:** The option `pushFollowers` has no effect, when the scene duration is 0._\r\n\t\t * @method ScrollMagic.Scene#setPin\r\n\t\t * @example\r\n\t\t * // pin element and push all following elements down by the amount of the pin duration.\r\n\t\t * scene.setPin("#pin");\r\n\t\t *\r\n\t\t * // pin element and keeping all following elements in their place. The pinned element will move past them.\r\n\t\t * scene.setPin("#pin", {pushFollowers: false});\r\n\t\t *\r\n\t\t * @param {(string|object)} element - A Selector targeting an element or a DOM object that is supposed to be pinned.\r\n\t\t * @param {object} [settings] - settings for the pin\r\n\t\t * @param {boolean} [settings.pushFollowers=true] - If `true` following elements will be "pushed" down for the duration of the pin, if `false` the pinned element will just scroll past them. \r\n\t\t \t\t\t\t\t\t\t\t\t\t\t\t Ignored, when duration is `0`.\r\n\t\t * @param {string} [settings.spacerClass="scrollmagic-pin-spacer"] - Classname of the pin spacer element, which is used to replace the element.\r\n\t\t *\r\n\t\t * @returns {Scene} Parent object for chaining.\r\n\t\t */\r\n\t\tthis.setPin = function (element, settings) {\r\n\t\t\tvar\r\n\t\t\t\tdefaultSettings = {\r\n\t\t\t\t\tpushFollowers: true,\r\n\t\t\t\t\tspacerClass: "scrollmagic-pin-spacer"\r\n\t\t\t\t};\r\n\t\t\tvar pushFollowersActivelySet = settings && settings.hasOwnProperty(\'pushFollowers\');\r\n\t\t\tsettings = _util.extend({}, defaultSettings, settings);\r\n\r\n\t\t\t// validate Element\r\n\t\t\telement = _util.get.elements(element)[0];\r\n\t\t\tif (!element) {\r\n\t\t\t\tlog(1, "ERROR calling method \'setPin()\': Invalid pin element supplied.");\r\n\t\t\t\treturn Scene; // cancel\r\n\t\t\t} else if (_util.css(element, "position") === "fixed") {\r\n\t\t\t\tlog(1, "ERROR calling method \'setPin()\': Pin does not work with elements that are positioned \'fixed\'.");\r\n\t\t\t\treturn Scene; // cancel\r\n\t\t\t}\r\n\r\n\t\t\tif (_pin) { // preexisting pin?\r\n\t\t\t\tif (_pin === element) {\r\n\t\t\t\t\t// same pin we already have -> do nothing\r\n\t\t\t\t\treturn Scene; // cancel\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// kill old pin\r\n\t\t\t\t\tScene.removePin();\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\t\t\t_pin = element;\r\n\r\n\t\t\tvar\r\n\t\t\t\tparentDisplay = _pin.parentNode.style.display,\r\n\t\t\t\tboundsParams = ["top", "left", "bottom", "right", "margin", "marginLeft", "marginRight", "marginTop", "marginBottom"];\r\n\r\n\t\t\t_pin.parentNode.style.display = \'none\'; // hack start to force css to return stylesheet values instead of calculated px values.\r\n\t\t\tvar\r\n\t\t\t\tinFlow = _util.css(_pin, "position") != "absolute",\r\n\t\t\t\tpinCSS = _util.css(_pin, boundsParams.concat(["display"])),\r\n\t\t\t\tsizeCSS = _util.css(_pin, ["width", "height"]);\r\n\t\t\t_pin.parentNode.style.display = parentDisplay; // hack end.\r\n\r\n\t\t\tif (!inFlow && settings.pushFollowers) {\r\n\t\t\t\tlog(2, "WARNING: If the pinned element is positioned absolutely pushFollowers will be disabled.");\r\n\t\t\t\tsettings.pushFollowers = false;\r\n\t\t\t}\r\n\t\t\twindow.setTimeout(function () { // wait until all finished, because with responsive duration it will only be set after scene is added to controller\r\n\t\t\t\tif (_pin && _options.duration === 0 && pushFollowersActivelySet && settings.pushFollowers) {\r\n\t\t\t\t\tlog(2, "WARNING: pushFollowers =", true, "has no effect, when scene duration is 0.");\r\n\t\t\t\t}\r\n\t\t\t}, 0);\r\n\r\n\t\t\t// create spacer and insert\r\n\t\t\tvar\r\n\t\t\t\tspacer = _pin.parentNode.insertBefore(document.createElement(\'div\'), _pin),\r\n\t\t\t\tspacerCSS = _util.extend(pinCSS, {\r\n\t\t\t\t\tposition: inFlow ? "relative" : "absolute",\r\n\t\t\t\t\tboxSizing: "content-box",\r\n\t\t\t\t\tmozBoxSizing: "content-box",\r\n\t\t\t\t\twebkitBoxSizing: "content-box"\r\n\t\t\t\t});\r\n\r\n\t\t\tif (!inFlow) { // copy size if positioned absolutely, to work for bottom/right positioned elements.\r\n\t\t\t\t_util.extend(spacerCSS, _util.css(_pin, ["width", "height"]));\r\n\t\t\t}\r\n\r\n\t\t\t_util.css(spacer, spacerCSS);\r\n\t\t\tspacer.setAttribute(PIN_SPACER_ATTRIBUTE, "");\r\n\t\t\t_util.addClass(spacer, settings.spacerClass);\r\n\r\n\t\t\t// set the pin Options\r\n\t\t\t_pinOptions = {\r\n\t\t\t\tspacer: spacer,\r\n\t\t\t\trelSize: { // save if size is defined using % values. if so, handle spacer resize differently...\r\n\t\t\t\t\twidth: sizeCSS.width.slice(-1) === "%",\r\n\t\t\t\t\theight: sizeCSS.height.slice(-1) === "%",\r\n\t\t\t\t\tautoFullWidth: sizeCSS.width === "auto" && inFlow && _util.isMarginCollapseType(pinCSS.display)\r\n\t\t\t\t},\r\n\t\t\t\tpushFollowers: settings.pushFollowers,\r\n\t\t\t\tinFlow: inFlow, // stores if the element takes up space in the document flow\r\n\t\t\t};\r\n\r\n\t\t\tif (!_pin.___origStyle) {\r\n\t\t\t\t_pin.___origStyle = {};\r\n\t\t\t\tvar\r\n\t\t\t\t\tpinInlineCSS = _pin.style,\r\n\t\t\t\t\tcopyStyles = boundsParams.concat(["width", "height", "position", "boxSizing", "mozBoxSizing", "webkitBoxSizing"]);\r\n\t\t\t\tcopyStyles.forEach(function (val) {\r\n\t\t\t\t\t_pin.___origStyle[val] = pinInlineCSS[val] || "";\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\t// if relative size, transfer it to spacer and make pin calculate it...\r\n\t\t\tif (_pinOptions.relSize.width) {\r\n\t\t\t\t_util.css(spacer, {\r\n\t\t\t\t\twidth: sizeCSS.width\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t\tif (_pinOptions.relSize.height) {\r\n\t\t\t\t_util.css(spacer, {\r\n\t\t\t\t\theight: sizeCSS.height\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\t// now place the pin element inside the spacer\t\r\n\t\t\tspacer.appendChild(_pin);\r\n\t\t\t// and set new css\r\n\t\t\t_util.css(_pin, {\r\n\t\t\t\tposition: inFlow ? "relative" : "absolute",\r\n\t\t\t\tmargin: "auto",\r\n\t\t\t\ttop: "auto",\r\n\t\t\t\tleft: "auto",\r\n\t\t\t\tbottom: "auto",\r\n\t\t\t\tright: "auto"\r\n\t\t\t});\r\n\r\n\t\t\tif (_pinOptions.relSize.width || _pinOptions.relSize.autoFullWidth) {\r\n\t\t\t\t_util.css(_pin, {\r\n\t\t\t\t\tboxSizing: "border-box",\r\n\t\t\t\t\tmozBoxSizing: "border-box",\r\n\t\t\t\t\twebkitBoxSizing: "border-box"\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\t// add listener to document to update pin position in case controller is not the document.\r\n\t\t\twindow.addEventListener(\'scroll\', updatePinInContainer);\r\n\t\t\twindow.addEventListener(\'resize\', updatePinInContainer);\r\n\t\t\twindow.addEventListener(\'resize\', updateRelativePinSpacer);\r\n\t\t\t// add mousewheel listener to catch scrolls over fixed elements\r\n\t\t\t_pin.addEventListener("mousewheel", onMousewheelOverPin);\r\n\t\t\t_pin.addEventListener("DOMMouseScroll", onMousewheelOverPin);\r\n\r\n\t\t\tlog(3, "added pin");\r\n\r\n\t\t\t// finally update the pin to init\r\n\t\t\tupdatePinState();\r\n\r\n\t\t\treturn Scene;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Remove the pin from the scene.\r\n\t\t * @method ScrollMagic.Scene#removePin\r\n\t\t * @example\r\n\t\t * // remove the pin from the scene without resetting it (the spacer is not removed)\r\n\t\t * scene.removePin();\r\n\t\t *\r\n\t\t * // remove the pin from the scene and reset the pin element to its initial position (spacer is removed)\r\n\t\t * scene.removePin(true);\r\n\t\t *\r\n\t\t * @param {boolean} [reset=false] - If `false` the spacer will not be removed and the element\'s position will not be reset.\r\n\t\t * @returns {Scene} Parent object for chaining.\r\n\t\t */\r\n\t\tthis.removePin = function (reset) {\r\n\t\t\tif (_pin) {\r\n\t\t\t\tif (_state === SCENE_STATE_DURING) {\r\n\t\t\t\t\tupdatePinState(true); // force unpin at position\r\n\t\t\t\t}\r\n\t\t\t\tif (reset || !_controller) { // if there\'s no controller no progress was made anyway...\r\n\t\t\t\t\tvar pinTarget = _pinOptions.spacer.firstChild; // usually the pin element, but may be another spacer (cascaded pins)...\r\n\t\t\t\t\tif (pinTarget.hasAttribute(PIN_SPACER_ATTRIBUTE)) { // copy margins to child spacer\r\n\t\t\t\t\t\tvar\r\n\t\t\t\t\t\t\tstyle = _pinOptions.spacer.style,\r\n\t\t\t\t\t\t\tvalues = ["margin", "marginLeft", "marginRight", "marginTop", "marginBottom"],\r\n\t\t\t\t\t\t\tmargins = {};\r\n\t\t\t\t\t\tvalues.forEach(function (val) {\r\n\t\t\t\t\t\t\tmargins[val] = style[val] || "";\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t\t_util.css(pinTarget, margins);\r\n\t\t\t\t\t}\r\n\t\t\t\t\t_pinOptions.spacer.parentNode.insertBefore(pinTarget, _pinOptions.spacer);\r\n\t\t\t\t\t_pinOptions.spacer.parentNode.removeChild(_pinOptions.spacer);\r\n\t\t\t\t\tif (!_pin.parentNode.hasAttribute(PIN_SPACER_ATTRIBUTE)) { // if it\'s the last pin for this element -> restore inline styles\r\n\t\t\t\t\t\t// TODO: only correctly set for first pin (when cascading) - how to fix?\r\n\t\t\t\t\t\t_util.css(_pin, _pin.___origStyle);\r\n\t\t\t\t\t\tdelete _pin.___origStyle;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\twindow.removeEventListener(\'scroll\', updatePinInContainer);\r\n\t\t\t\twindow.removeEventListener(\'resize\', updatePinInContainer);\r\n\t\t\t\twindow.removeEventListener(\'resize\', updateRelativePinSpacer);\r\n\t\t\t\t_pin.removeEventListener("mousewheel", onMousewheelOverPin);\r\n\t\t\t\t_pin.removeEventListener("DOMMouseScroll", onMousewheelOverPin);\r\n\t\t\t\t_pin = undefined;\r\n\t\t\t\tlog(3, "removed pin (reset: " + (reset ? "true" : "false") + ")");\r\n\t\t\t}\r\n\t\t\treturn Scene;\r\n\t\t};\r\n\r\n\r\n\t\tvar\r\n\t\t\t_cssClasses,\r\n\t\t\t_cssClassElems = [];\r\n\r\n\t\tScene\r\n\t\t\t.on("destroy.internal", function (e) {\r\n\t\t\t\tScene.removeClassToggle(e.reset);\r\n\t\t\t});\r\n\t\t/**\r\n\t\t * Define a css class modification while the scene is active. \r\n\t\t * When the scene triggers the classes will be added to the supplied element and removed, when the scene is over.\r\n\t\t * If the scene duration is 0 the classes will only be removed if the user scrolls back past the start position.\r\n\t\t * @method ScrollMagic.Scene#setClassToggle\r\n\t\t * @example\r\n\t\t * // add the class \'myclass\' to the element with the id \'my-elem\' for the duration of the scene\r\n\t\t * scene.setClassToggle("#my-elem", "myclass");\r\n\t\t *\r\n\t\t * // add multiple classes to multiple elements defined by the selector \'.classChange\'\r\n\t\t * scene.setClassToggle(".classChange", "class1 class2 class3");\r\n\t\t *\r\n\t\t * @param {(string|object)} element - A Selector targeting one or more elements or a DOM object that is supposed to be modified.\r\n\t\t * @param {string} classes - One or more Classnames (separated by space) that should be added to the element during the scene.\r\n\t\t *\r\n\t\t * @returns {Scene} Parent object for chaining.\r\n\t\t */\r\n\t\tthis.setClassToggle = function (element, classes) {\r\n\t\t\tvar elems = _util.get.elements(element);\r\n\t\t\tif (elems.length === 0 || !_util.type.String(classes)) {\r\n\t\t\t\tlog(1, "ERROR calling method \'setClassToggle()\': Invalid " + (elems.length === 0 ? "element" : "classes") + " supplied.");\r\n\t\t\t\treturn Scene;\r\n\t\t\t}\r\n\t\t\tif (_cssClassElems.length > 0) {\r\n\t\t\t\t// remove old ones\r\n\t\t\t\tScene.removeClassToggle();\r\n\t\t\t}\r\n\t\t\t_cssClasses = classes;\r\n\t\t\t_cssClassElems = elems;\r\n\t\t\tScene.on("enter.internal_class leave.internal_class", function (e) {\r\n\t\t\t\tvar toggle = e.type === "enter" ? _util.addClass : _util.removeClass;\r\n\t\t\t\t_cssClassElems.forEach(function (elem, key) {\r\n\t\t\t\t\ttoggle(elem, _cssClasses);\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t\treturn Scene;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Remove the class binding from the scene.\r\n\t\t * @method ScrollMagic.Scene#removeClassToggle\r\n\t\t * @example\r\n\t\t * // remove class binding from the scene without reset\r\n\t\t * scene.removeClassToggle();\r\n\t\t *\r\n\t\t * // remove class binding and remove the changes it caused\r\n\t\t * scene.removeClassToggle(true);\r\n\t\t *\r\n\t\t * @param {boolean} [reset=false] - If `false` and the classes are currently active, they will remain on the element. If `true` they will be removed.\r\n\t\t * @returns {Scene} Parent object for chaining.\r\n\t\t */\r\n\t\tthis.removeClassToggle = function (reset) {\r\n\t\t\tif (reset) {\r\n\t\t\t\t_cssClassElems.forEach(function (elem, key) {\r\n\t\t\t\t\t_util.removeClass(elem, _cssClasses);\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t\tScene.off("start.internal_class end.internal_class");\r\n\t\t\t_cssClasses = undefined;\r\n\t\t\t_cssClassElems = [];\r\n\t\t\treturn Scene;\r\n\t\t};\r\n\r\n\t\t// INIT\r\n\t\tconstruct();\r\n\t\treturn Scene;\r\n\t};\r\n\r\n\t// store pagewide scene options\r\n\tvar SCENE_OPTIONS = {\r\n\t\tdefaults: {\r\n\t\t\tduration: 0,\r\n\t\t\toffset: 0,\r\n\t\t\ttriggerElement: undefined,\r\n\t\t\ttriggerHook: 0.5,\r\n\t\t\treverse: true,\r\n\t\t\tloglevel: 2\r\n\t\t},\r\n\t\tvalidate: {\r\n\t\t\toffset: function (val) {\r\n\t\t\t\tval = parseFloat(val);\r\n\t\t\t\tif (!_util.type.Number(val)) {\r\n\t\t\t\t\tthrow ["Invalid value for option \\"offset\\":", val];\r\n\t\t\t\t}\r\n\t\t\t\treturn val;\r\n\t\t\t},\r\n\t\t\ttriggerElement: function (val) {\r\n\t\t\t\tval = val || undefined;\r\n\t\t\t\tif (val) {\r\n\t\t\t\t\tvar elem = _util.get.elements(val)[0];\r\n\t\t\t\t\tif (elem && elem.parentNode) {\r\n\t\t\t\t\t\tval = elem;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthrow ["Element defined in option \\"triggerElement\\" was not found:", val];\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\treturn val;\r\n\t\t\t},\r\n\t\t\ttriggerHook: function (val) {\r\n\t\t\t\tvar translate = {\r\n\t\t\t\t\t"onCenter": 0.5,\r\n\t\t\t\t\t"onEnter": 1,\r\n\t\t\t\t\t"onLeave": 0\r\n\t\t\t\t};\r\n\t\t\t\tif (_util.type.Number(val)) {\r\n\t\t\t\t\tval = Math.max(0, Math.min(parseFloat(val), 1)); // make sure its betweeen 0 and 1\r\n\t\t\t\t} else if (val in translate) {\r\n\t\t\t\t\tval = translate[val];\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthrow ["Invalid value for option \\"triggerHook\\": ", val];\r\n\t\t\t\t}\r\n\t\t\t\treturn val;\r\n\t\t\t},\r\n\t\t\treverse: function (val) {\r\n\t\t\t\treturn !!val; // force boolean\r\n\t\t\t},\r\n\t\t\tloglevel: function (val) {\r\n\t\t\t\tval = parseInt(val);\r\n\t\t\t\tif (!_util.type.Number(val) || val < 0 || val > 3) {\r\n\t\t\t\t\tthrow ["Invalid value for option \\"loglevel\\":", val];\r\n\t\t\t\t}\r\n\t\t\t\treturn val;\r\n\t\t\t}\r\n\t\t}, // holder for validation methods. duration validation is handled in \'getters-setters.js\'\r\n\t\tshifts: ["duration", "offset", "triggerHook"], // list of options that trigger a `shift` event\r\n\t};\r\n\t/*\r\n\t * method used to add an option to ScrollMagic Scenes.\r\n\t * TODO: DOC (private for dev)\r\n\t */\r\n\tScrollMagic.Scene.addOption = function (name, defaultValue, validationCallback, shifts) {\r\n\t\tif (!(name in SCENE_OPTIONS.defaults)) {\r\n\t\t\tSCENE_OPTIONS.defaults[name] = defaultValue;\r\n\t\t\tSCENE_OPTIONS.validate[name] = validationCallback;\r\n\t\t\tif (shifts) {\r\n\t\t\t\tSCENE_OPTIONS.shifts.push(name);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tScrollMagic._util.log(1, "[static] ScrollMagic.Scene -> Cannot add Scene option \'" + name + "\', because it already exists.");\r\n\t\t}\r\n\t};\r\n\t// instance extension function for plugins\r\n\t// TODO: DOC (private for dev)\r\n\tScrollMagic.Scene.extend = function (extension) {\r\n\t\tvar oldClass = this;\r\n\t\tScrollMagic.Scene = function () {\r\n\t\t\toldClass.apply(this, arguments);\r\n\t\t\tthis.$super = _util.extend({}, this); // copy parent state\r\n\t\t\treturn extension.apply(this, arguments) || this;\r\n\t\t};\r\n\t\t_util.extend(ScrollMagic.Scene, oldClass); // copy properties\r\n\t\tScrollMagic.Scene.prototype = oldClass.prototype; // copy prototype\r\n\t\tScrollMagic.Scene.prototype.constructor = ScrollMagic.Scene; // restore constructor\r\n\t};\r\n\r\n\r\n\r\n\t/**\r\n\t * TODO: DOCS (private for dev)\r\n\t * @class\r\n\t * @private\r\n\t */\r\n\r\n\tScrollMagic.Event = function (type, namespace, target, vars) {\r\n\t\tvars = vars || {};\r\n\t\tfor (var key in vars) {\r\n\t\t\tthis[key] = vars[key];\r\n\t\t}\r\n\t\tthis.type = type;\r\n\t\tthis.target = this.currentTarget = target;\r\n\t\tthis.namespace = namespace || \'\';\r\n\t\tthis.timeStamp = this.timestamp = Date.now();\r\n\t\treturn this;\r\n\t};\r\n\r\n\t/*\r\n\t * TODO: DOCS (private for dev)\r\n\t */\r\n\r\n\tvar _util = ScrollMagic._util = (function (window) {\r\n\t\tvar U = {},\r\n\t\t\ti;\r\n\r\n\t\t/**\r\n\t\t * ------------------------------\r\n\t\t * internal helpers\r\n\t\t * ------------------------------\r\n\t\t */\r\n\r\n\t\t// parse float and fall back to 0.\r\n\t\tvar floatval = function (number) {\r\n\t\t\treturn parseFloat(number) || 0;\r\n\t\t};\r\n\t\t// get current style IE safe (otherwise IE would return calculated values for \'auto\')\r\n\t\tvar _getComputedStyle = function (elem) {\r\n\t\t\treturn elem.currentStyle ? elem.currentStyle : window.getComputedStyle(elem);\r\n\t\t};\r\n\r\n\t\t// get element dimension (width or height)\r\n\t\tvar _dimension = function (which, elem, outer, includeMargin) {\r\n\t\t\telem = (elem === document) ? window : elem;\r\n\t\t\tif (elem === window) {\r\n\t\t\t\tincludeMargin = false;\r\n\t\t\t} else if (!_type.DomElement(elem)) {\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t\twhich = which.charAt(0).toUpperCase() + which.substr(1).toLowerCase();\r\n\t\t\tvar dimension = (outer ? elem[\'offset\' + which] || elem[\'outer\' + which] : elem[\'client\' + which] || elem[\'inner\' + which]) || 0;\r\n\t\t\tif (outer && includeMargin) {\r\n\t\t\t\tvar style = _getComputedStyle(elem);\r\n\t\t\t\tdimension += which === \'Height\' ? floatval(style.marginTop) + floatval(style.marginBottom) : floatval(style.marginLeft) + floatval(style.marginRight);\r\n\t\t\t}\r\n\t\t\treturn dimension;\r\n\t\t};\r\n\t\t// converts \'margin-top\' into \'marginTop\'\r\n\t\tvar _camelCase = function (str) {\r\n\t\t\treturn str.replace(/^[^a-z]+([a-z])/g, \'$1\').replace(/-([a-z])/g, function (g) {\r\n\t\t\t\treturn g[1].toUpperCase();\r\n\t\t\t});\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * ------------------------------\r\n\t\t * external helpers\r\n\t\t * ------------------------------\r\n\t\t */\r\n\r\n\t\t// extend obj – same as jQuery.extend({}, objA, objB)\r\n\t\tU.extend = function (obj) {\r\n\t\t\tobj = obj || {};\r\n\t\t\tfor (i = 1; i < arguments.length; i++) {\r\n\t\t\t\tif (!arguments[i]) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tfor (var key in arguments[i]) {\r\n\t\t\t\t\tif (arguments[i].hasOwnProperty(key)) {\r\n\t\t\t\t\t\tobj[key] = arguments[i][key];\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn obj;\r\n\t\t};\r\n\r\n\t\t// check if a css display type results in margin-collapse or not\r\n\t\tU.isMarginCollapseType = function (str) {\r\n\t\t\treturn ["block", "flex", "list-item", "table", "-webkit-box"].indexOf(str) > -1;\r\n\t\t};\r\n\r\n\t\t// implementation of requestAnimationFrame\r\n\t\t// based on https://gist.github.com/paulirish/1579671\r\n\t\tvar\r\n\t\t\tlastTime = 0,\r\n\t\t\tvendors = [\'ms\', \'moz\', \'webkit\', \'o\'];\r\n\t\tvar _requestAnimationFrame = window.requestAnimationFrame;\r\n\t\tvar _cancelAnimationFrame = window.cancelAnimationFrame;\r\n\t\t// try vendor prefixes if the above doesn\'t work\r\n\t\tfor (i = 0; !_requestAnimationFrame && i < vendors.length; ++i) {\r\n\t\t\t_requestAnimationFrame = window[vendors[i] + \'RequestAnimationFrame\'];\r\n\t\t\t_cancelAnimationFrame = window[vendors[i] + \'CancelAnimationFrame\'] || window[vendors[i] + \'CancelRequestAnimationFrame\'];\r\n\t\t}\r\n\r\n\t\t// fallbacks\r\n\t\tif (!_requestAnimationFrame) {\r\n\t\t\t_requestAnimationFrame = function (callback) {\r\n\t\t\t\tvar\r\n\t\t\t\t\tcurrTime = new Date().getTime(),\r\n\t\t\t\t\ttimeToCall = Math.max(0, 16 - (currTime - lastTime)),\r\n\t\t\t\t\tid = window.setTimeout(function () {\r\n\t\t\t\t\t\tcallback(currTime + timeToCall);\r\n\t\t\t\t\t}, timeToCall);\r\n\t\t\t\tlastTime = currTime + timeToCall;\r\n\t\t\t\treturn id;\r\n\t\t\t};\r\n\t\t}\r\n\t\tif (!_cancelAnimationFrame) {\r\n\t\t\t_cancelAnimationFrame = function (id) {\r\n\t\t\t\twindow.clearTimeout(id);\r\n\t\t\t};\r\n\t\t}\r\n\t\tU.rAF = _requestAnimationFrame.bind(window);\r\n\t\tU.cAF = _cancelAnimationFrame.bind(window);\r\n\r\n\t\tvar\r\n\t\t\tloglevels = ["error", "warn", "log"],\r\n\t\t\tconsole = window.console || {};\r\n\r\n\t\tconsole.log = console.log || function () {}; // no console log, well - do nothing then...\r\n\t\t// make sure methods for all levels exist.\r\n\t\tfor (i = 0; i < loglevels.length; i++) {\r\n\t\t\tvar method = loglevels[i];\r\n\t\t\tif (!console[method]) {\r\n\t\t\t\tconsole[method] = console.log; // prefer .log over nothing\r\n\t\t\t}\r\n\t\t}\r\n\t\tU.log = function (loglevel) {\r\n\t\t\tif (loglevel > loglevels.length || loglevel <= 0) loglevel = loglevels.length;\r\n\t\t\tvar now = new Date(),\r\n\t\t\t\ttime = ("0" + now.getHours()).slice(-2) + ":" + ("0" + now.getMinutes()).slice(-2) + ":" + ("0" + now.getSeconds()).slice(-2) + ":" + ("00" + now.getMilliseconds()).slice(-3),\r\n\t\t\t\tmethod = loglevels[loglevel - 1],\r\n\t\t\t\targs = Array.prototype.splice.call(arguments, 1),\r\n\t\t\t\tfunc = Function.prototype.bind.call(console[method], console);\r\n\t\t\targs.unshift(time);\r\n\t\t\tfunc.apply(console, args);\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * ------------------------------\r\n\t\t * type testing\r\n\t\t * ------------------------------\r\n\t\t */\r\n\r\n\t\tvar _type = U.type = function (v) {\r\n\t\t\treturn Object.prototype.toString.call(v).replace(/^\\[object (.+)\\]$/, "$1").toLowerCase();\r\n\t\t};\r\n\t\t_type.String = function (v) {\r\n\t\t\treturn _type(v) === \'string\';\r\n\t\t};\r\n\t\t_type.Function = function (v) {\r\n\t\t\treturn _type(v) === \'function\';\r\n\t\t};\r\n\t\t_type.Array = function (v) {\r\n\t\t\treturn Array.isArray(v);\r\n\t\t};\r\n\t\t_type.Number = function (v) {\r\n\t\t\treturn !_type.Array(v) && (v - parseFloat(v) + 1) >= 0;\r\n\t\t};\r\n\t\t_type.DomElement = function (o) {\r\n\t\t\treturn (\r\n\t\t\t\ttypeof HTMLElement === "object" || typeof HTMLElement === "function" ? o instanceof HTMLElement || o instanceof SVGElement : //DOM2\r\n\t\t\t\to && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName === "string"\r\n\t\t\t);\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * ------------------------------\r\n\t\t * DOM Element info\r\n\t\t * ------------------------------\r\n\t\t */\r\n\t\t// always returns a list of matching DOM elements, from a selector, a DOM element or an list of elements or even an array of selectors\r\n\t\tvar _get = U.get = {};\r\n\t\t_get.elements = function (selector) {\r\n\t\t\tvar arr = [];\r\n\t\t\tif (_type.String(selector)) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tselector = document.querySelectorAll(selector);\r\n\t\t\t\t} catch (e) { // invalid selector\r\n\t\t\t\t\treturn arr;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (_type(selector) === \'nodelist\' || _type.Array(selector) || selector instanceof NodeList) {\r\n\t\t\t\tfor (var i = 0, ref = arr.length = selector.length; i < ref; i++) { // list of elements\r\n\t\t\t\t\tvar elem = selector[i];\r\n\t\t\t\t\tarr[i] = _type.DomElement(elem) ? elem : _get.elements(elem); // if not an element, try to resolve recursively\r\n\t\t\t\t}\r\n\t\t\t} else if (_type.DomElement(selector) || selector === document || selector === window) {\r\n\t\t\t\tarr = [selector]; // only the element\r\n\t\t\t}\r\n\t\t\treturn arr;\r\n\t\t};\r\n\t\t// get scroll top value\r\n\t\t_get.scrollTop = function (elem) {\r\n\t\t\treturn (elem && typeof elem.scrollTop === \'number\') ? elem.scrollTop : window.pageYOffset || 0;\r\n\t\t};\r\n\t\t// get scroll left value\r\n\t\t_get.scrollLeft = function (elem) {\r\n\t\t\treturn (elem && typeof elem.scrollLeft === \'number\') ? elem.scrollLeft : window.pageXOffset || 0;\r\n\t\t};\r\n\t\t// get element height\r\n\t\t_get.width = function (elem, outer, includeMargin) {\r\n\t\t\treturn _dimension(\'width\', elem, outer, includeMargin);\r\n\t\t};\r\n\t\t// get element width\r\n\t\t_get.height = function (elem, outer, includeMargin) {\r\n\t\t\treturn _dimension(\'height\', elem, outer, includeMargin);\r\n\t\t};\r\n\r\n\t\t// get element position (optionally relative to viewport)\r\n\t\t_get.offset = function (elem, relativeToViewport) {\r\n\t\t\tvar offset = {\r\n\t\t\t\ttop: 0,\r\n\t\t\t\tleft: 0\r\n\t\t\t};\r\n\t\t\tif (elem && elem.getBoundingClientRect) { // check if available\r\n\t\t\t\tvar rect = elem.getBoundingClientRect();\r\n\t\t\t\toffset.top = rect.top;\r\n\t\t\t\toffset.left = rect.left;\r\n\t\t\t\tif (!relativeToViewport) { // clientRect is by default relative to viewport...\r\n\t\t\t\t\toffset.top += _get.scrollTop();\r\n\t\t\t\t\toffset.left += _get.scrollLeft();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn offset;\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * ------------------------------\r\n\t\t * DOM Element manipulation\r\n\t\t * ------------------------------\r\n\t\t */\r\n\r\n\t\tU.addClass = function (elem, classname) {\r\n\t\t\tif (classname) {\r\n\t\t\t\tif (elem.classList)\r\n\t\t\t\t\telem.classList.add(classname);\r\n\t\t\t\telse\r\n\t\t\t\t\telem.className += \' \' + classname;\r\n\t\t\t}\r\n\t\t};\r\n\t\tU.removeClass = function (elem, classname) {\r\n\t\t\tif (classname) {\r\n\t\t\t\tif (elem.classList)\r\n\t\t\t\t\telem.classList.remove(classname);\r\n\t\t\t\telse\r\n\t\t\t\t\telem.className = elem.className.replace(new RegExp(\'(^|\\\\b)\' + classname.split(\' \').join(\'|\') + \'(\\\\b|$)\', \'gi\'), \' \');\r\n\t\t\t}\r\n\t\t};\r\n\t\t// if options is string -> returns css value\r\n\t\t// if options is array -> returns object with css value pairs\r\n\t\t// if options is object -> set new css values\r\n\t\tU.css = function (elem, options) {\r\n\t\t\tif (_type.String(options)) {\r\n\t\t\t\treturn _getComputedStyle(elem)[_camelCase(options)];\r\n\t\t\t} else if (_type.Array(options)) {\r\n\t\t\t\tvar\r\n\t\t\t\t\tobj = {},\r\n\t\t\t\t\tstyle = _getComputedStyle(elem);\r\n\t\t\t\toptions.forEach(function (option, key) {\r\n\t\t\t\t\tobj[option] = style[_camelCase(option)];\r\n\t\t\t\t});\r\n\t\t\t\treturn obj;\r\n\t\t\t} else {\r\n\t\t\t\tfor (var option in options) {\r\n\t\t\t\t\tvar val = options[option];\r\n\t\t\t\t\tif (val == parseFloat(val)) { // assume pixel for seemingly numerical values\r\n\t\t\t\t\t\tval += \'px\';\r\n\t\t\t\t\t}\r\n\t\t\t\t\telem.style[_camelCase(option)] = val;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\treturn U;\r\n\t}(window || {}));\r\n\r\n\r\n\tScrollMagic.Scene.prototype.addIndicators = function () {\r\n\t\tScrollMagic._util.log(1, \'(ScrollMagic.Scene) -> ERROR calling addIndicators() due to missing Plugin \\\'debug.addIndicators\\\'. Please make sure to include plugins/debug.addIndicators.js\');\r\n\t\treturn this;\r\n\t}\r\n\tScrollMagic.Scene.prototype.removeIndicators = function () {\r\n\t\tScrollMagic._util.log(1, \'(ScrollMagic.Scene) -> ERROR calling removeIndicators() due to missing Plugin \\\'debug.addIndicators\\\'. Please make sure to include plugins/debug.addIndicators.js\');\r\n\t\treturn this;\r\n\t}\r\n\tScrollMagic.Scene.prototype.setTween = function () {\r\n\t\tScrollMagic._util.log(1, \'(ScrollMagic.Scene) -> ERROR calling setTween() due to missing Plugin \\\'animation.gsap\\\'. Please make sure to include plugins/animation.gsap.js\');\r\n\t\treturn this;\r\n\t}\r\n\tScrollMagic.Scene.prototype.removeTween = function () {\r\n\t\tScrollMagic._util.log(1, \'(ScrollMagic.Scene) -> ERROR calling removeTween() due to missing Plugin \\\'animation.gsap\\\'. Please make sure to include plugins/animation.gsap.js\');\r\n\t\treturn this;\r\n\t}\r\n\tScrollMagic.Scene.prototype.setVelocity = function () {\r\n\t\tScrollMagic._util.log(1, \'(ScrollMagic.Scene) -> ERROR calling setVelocity() due to missing Plugin \\\'animation.velocity\\\'. Please make sure to include plugins/animation.velocity.js\');\r\n\t\treturn this;\r\n\t}\r\n\tScrollMagic.Scene.prototype.removeVelocity = function () {\r\n\t\tScrollMagic._util.log(1, \'(ScrollMagic.Scene) -> ERROR calling removeVelocity() due to missing Plugin \\\'animation.velocity\\\'. Please make sure to include plugins/animation.velocity.js\');\r\n\t\treturn this;\r\n\t}\r\n\r\n\treturn ScrollMagic;\r\n}));//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMTMxLmpzIiwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQU9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9waXJlbGxpX2JlY2NhcmlhLy4vbm9kZV9tb2R1bGVzL3Njcm9sbG1hZ2ljL3Njcm9sbG1hZ2ljL3VuY29tcHJlc3NlZC9TY3JvbGxNYWdpYy5qcz9jZDI5Il0sInNvdXJjZXNDb250ZW50IjpbIi8qIVxyXG4gKiBTY3JvbGxNYWdpYyB2Mi4wLjggKDIwMjAtMDgtMTQpXHJcbiAqIFRoZSBqYXZhc2NyaXB0IGxpYnJhcnkgZm9yIG1hZ2ljYWwgc2Nyb2xsIGludGVyYWN0aW9ucy5cclxuICogKGMpIDIwMjAgSmFuIFBhZXBrZSAoQGphbnBhZXBrZSlcclxuICogUHJvamVjdCBXZWJzaXRlOiBodHRwOi8vc2Nyb2xsbWFnaWMuaW9cclxuICogXHJcbiAqIEB2ZXJzaW9uIDIuMC44XHJcbiAqIEBsaWNlbnNlIER1YWwgbGljZW5zZWQgdW5kZXIgTUlUIGxpY2Vuc2UgYW5kIEdQTC5cclxuICogQGF1dGhvciBKYW4gUGFlcGtlIC0gZS1tYWlsQGphbnBhZXBrZS5kZVxyXG4gKlxyXG4gKiBAZmlsZSBTY3JvbGxNYWdpYyBtYWluIGxpYnJhcnkuXHJcbiAqL1xyXG4vKipcclxuICogQG5hbWVzcGFjZSBTY3JvbGxNYWdpY1xyXG4gKi9cclxuKGZ1bmN0aW9uIChyb290LCBmYWN0b3J5KSB7XHJcblx0aWYgKHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCkge1xyXG5cdFx0Ly8gQU1ELiBSZWdpc3RlciBhcyBhbiBhbm9ueW1vdXMgbW9kdWxlLlxyXG5cdFx0ZGVmaW5lKGZhY3RvcnkpO1xyXG5cdH0gZWxzZSBpZiAodHlwZW9mIGV4cG9ydHMgPT09ICdvYmplY3QnKSB7XHJcblx0XHQvLyBDb21tb25KU1xyXG5cdFx0bW9kdWxlLmV4cG9ydHMgPSBmYWN0b3J5KCk7XHJcblx0fSBlbHNlIHtcclxuXHRcdC8vIEJyb3dzZXIgZ2xvYmFsXHJcblx0XHRyb290LlNjcm9sbE1hZ2ljID0gZmFjdG9yeSgpO1xyXG5cdH1cclxufSh0aGlzLCBmdW5jdGlvbiAoKSB7XHJcblx0XCJ1c2Ugc3RyaWN0XCI7XHJcblxyXG5cdHZhciBTY3JvbGxNYWdpYyA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdF91dGlsLmxvZygyLCAnKENPTVBBVElCSUxJVFkgTk9USUNFKSAtPiBBcyBvZiBTY3JvbGxNYWdpYyAyLjAuMCB5b3UgbmVlZCB0byB1c2UgXFwnbmV3IFNjcm9sbE1hZ2ljLkNvbnRyb2xsZXIoKVxcJyB0byBjcmVhdGUgYSBuZXcgY29udHJvbGxlciBpbnN0YW5jZS4gVXNlIFxcJ25ldyBTY3JvbGxNYWdpYy5TY2VuZSgpXFwnIHRvIGluc3RhbmNlIGEgc2NlbmUuJyk7XHJcblx0fTtcclxuXHJcblx0U2Nyb2xsTWFnaWMudmVyc2lvbiA9IFwiMi4wLjhcIjtcclxuXHJcblx0Ly8gVE9ETzogdGVtcG9yYXJ5IHdvcmthcm91bmQgZm9yIGNocm9tZSdzIHNjcm9sbCBqaXR0ZXIgYnVnXHJcblx0aWYgKHR5cGVvZiAod2luZG93KSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuXHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwibW91c2V3aGVlbFwiLCB2b2lkKDApKTtcclxuXHR9XHJcblxyXG5cdC8vIGdsb2JhbCBjb25zdFxyXG5cdHZhciBQSU5fU1BBQ0VSX0FUVFJJQlVURSA9IFwiZGF0YS1zY3JvbGxtYWdpYy1waW4tc3BhY2VyXCI7XHJcblxyXG5cdC8qKlxyXG5cdCAqIFRoZSBtYWluIGNsYXNzIHRoYXQgaXMgbmVlZGVkIG9uY2UgcGVyIHNjcm9sbCBjb250YWluZXIuXHJcblx0ICpcclxuXHQgKiBAY2xhc3NcclxuXHQgKlxyXG5cdCAqIEBleGFtcGxlXHJcblx0ICogLy8gYmFzaWMgaW5pdGlhbGl6YXRpb25cclxuXHQgKiB2YXIgY29udHJvbGxlciA9IG5ldyBTY3JvbGxNYWdpYy5Db250cm9sbGVyKCk7XHJcblx0ICpcclxuXHQgKiAvLyBwYXNzaW5nIG9wdGlvbnNcclxuXHQgKiB2YXIgY29udHJvbGxlciA9IG5ldyBTY3JvbGxNYWdpYy5Db250cm9sbGVyKHtjb250YWluZXI6IFwiI215Q29udGFpbmVyXCIsIGxvZ2xldmVsOiAzfSk7XHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge29iamVjdH0gW29wdGlvbnNdIC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgb25lIG9yIG1vcmUgb3B0aW9ucyBmb3IgdGhlIGNvbnRyb2xsZXIuXHJcblx0ICogQHBhcmFtIHsoc3RyaW5nfG9iamVjdCl9IFtvcHRpb25zLmNvbnRhaW5lcj13aW5kb3ddIC0gQSBzZWxlY3RvciwgRE9NIG9iamVjdCB0aGF0IHJlZmVyZW5jZXMgdGhlIG1haW4gY29udGFpbmVyIGZvciBzY3JvbGxpbmcuXHJcblx0ICogQHBhcmFtIHtib29sZWFufSBbb3B0aW9ucy52ZXJ0aWNhbD10cnVlXSAtIFNldHMgdGhlIHNjcm9sbCBtb2RlIHRvIHZlcnRpY2FsIChgdHJ1ZWApIG9yIGhvcml6b250YWwgKGBmYWxzZWApIHNjcm9sbGluZy5cclxuXHQgKiBAcGFyYW0ge29iamVjdH0gW29wdGlvbnMuZ2xvYmFsU2NlbmVPcHRpb25zPXt9XSAtIFRoZXNlIG9wdGlvbnMgd2lsbCBiZSBwYXNzZWQgdG8gZXZlcnkgU2NlbmUgdGhhdCBpcyBhZGRlZCB0byB0aGUgY29udHJvbGxlciB1c2luZyB0aGUgYWRkU2NlbmUgbWV0aG9kLiBGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBTY2VuZSBvcHRpb25zIHNlZSB7QGxpbmsgU2Nyb2xsTWFnaWMuU2NlbmV9LlxyXG5cdCAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy5sb2dsZXZlbD0yXSBMb2dsZXZlbCBmb3IgZGVidWdnaW5nLiBOb3RlIHRoYXQgbG9nZ2luZyBpcyBkaXNhYmxlZCBpbiB0aGUgbWluaWZpZWQgdmVyc2lvbiBvZiBTY3JvbGxNYWdpYy5cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAqKiBgMGAgPT4gc2lsZW50XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgKiogYDFgID0+IGVycm9yc1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICoqIGAyYCA9PiBlcnJvcnMsIHdhcm5pbmdzXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgKiogYDNgID0+IGVycm9ycywgd2FybmluZ3MsIGRlYnVnaW5mb1xyXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMucmVmcmVzaEludGVydmFsPTEwMF0gLSBTb21lIGNoYW5nZXMgZG9uJ3QgY2FsbCBldmVudHMgYnkgZGVmYXVsdCwgbGlrZSBjaGFuZ2luZyB0aGUgY29udGFpbmVyIHNpemUgb3IgbW92aW5nIGEgc2NlbmUgdHJpZ2dlciBlbGVtZW50LiAgXHJcblx0IFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgVGhpcyBpbnRlcnZhbCBwb2xscyB0aGVzZSBwYXJhbWV0ZXJzIHRvIGZpcmUgdGhlIG5lY2Vzc2FyeSBldmVudHMuICBcclxuXHQgXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCBJZiB5b3UgZG9uJ3QgdXNlIGN1c3RvbSBjb250YWluZXJzLCB0cmlnZ2VyIGVsZW1lbnRzIG9yIGhhdmUgc3RhdGljIGxheW91dHMsIHdoZXJlIHRoZSBwb3NpdGlvbnMgb2YgdGhlIHRyaWdnZXIgZWxlbWVudHMgZG9uJ3QgY2hhbmdlLCB5b3UgY2FuIHNldCB0aGlzIHRvIDAgZGlzYWJsZSBpbnRlcnZhbCBjaGVja2luZyBhbmQgaW1wcm92ZSBwZXJmb3JtYW5jZS5cclxuXHQgKlxyXG5cdCAqL1xyXG5cdFNjcm9sbE1hZ2ljLkNvbnRyb2xsZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xyXG5cdFx0LypcclxuXHRcdCAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdCAqIHNldHRpbmdzXHJcblx0XHQgKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHQgKi9cclxuXHRcdHZhclxyXG5cdFx0XHROQU1FU1BBQ0UgPSAnU2Nyb2xsTWFnaWMuQ29udHJvbGxlcicsXHJcblx0XHRcdFNDUk9MTF9ESVJFQ1RJT05fRk9SV0FSRCA9ICdGT1JXQVJEJyxcclxuXHRcdFx0U0NST0xMX0RJUkVDVElPTl9SRVZFUlNFID0gJ1JFVkVSU0UnLFxyXG5cdFx0XHRTQ1JPTExfRElSRUNUSU9OX1BBVVNFRCA9ICdQQVVTRUQnLFxyXG5cdFx0XHRERUZBVUxUX09QVElPTlMgPSBDT05UUk9MTEVSX09QVElPTlMuZGVmYXVsdHM7XHJcblxyXG5cdFx0LypcclxuXHRcdCAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdCAqIHByaXZhdGUgdmFyc1xyXG5cdFx0ICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0ICovXHJcblx0XHR2YXJcclxuXHRcdFx0Q29udHJvbGxlciA9IHRoaXMsXHJcblx0XHRcdF9vcHRpb25zID0gX3V0aWwuZXh0ZW5kKHt9LCBERUZBVUxUX09QVElPTlMsIG9wdGlvbnMpLFxyXG5cdFx0XHRfc2NlbmVPYmplY3RzID0gW10sXHJcblx0XHRcdF91cGRhdGVTY2VuZXNPbk5leHRDeWNsZSA9IGZhbHNlLCAvLyBjYW4gYmUgYm9vbGVhbiAodHJ1ZSA9PiBhbGwgc2NlbmVzKSBvciBhbiBhcnJheSBvZiBzY2VuZXMgdG8gYmUgdXBkYXRlZFxyXG5cdFx0XHRfc2Nyb2xsUG9zID0gMCxcclxuXHRcdFx0X3Njcm9sbERpcmVjdGlvbiA9IFNDUk9MTF9ESVJFQ1RJT05fUEFVU0VELFxyXG5cdFx0XHRfaXNEb2N1bWVudCA9IHRydWUsXHJcblx0XHRcdF92aWV3UG9ydFNpemUgPSAwLFxyXG5cdFx0XHRfZW5hYmxlZCA9IHRydWUsXHJcblx0XHRcdF91cGRhdGVUaW1lb3V0LFxyXG5cdFx0XHRfcmVmcmVzaFRpbWVvdXQ7XHJcblxyXG5cdFx0LypcclxuXHRcdCAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdCAqIHByaXZhdGUgZnVuY3Rpb25zXHJcblx0XHQgKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHQgKi9cclxuXHJcblx0XHQvKipcclxuXHRcdCAqIEludGVybmFsIGNvbnN0cnVjdG9yIGZ1bmN0aW9uIG9mIHRoZSBTY3JvbGxNYWdpYyBDb250cm9sbGVyXHJcblx0XHQgKiBAcHJpdmF0ZVxyXG5cdFx0ICovXHJcblx0XHR2YXIgY29uc3RydWN0ID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRmb3IgKHZhciBrZXkgaW4gX29wdGlvbnMpIHtcclxuXHRcdFx0XHRpZiAoIURFRkFVTFRfT1BUSU9OUy5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XHJcblx0XHRcdFx0XHRsb2coMiwgXCJXQVJOSU5HOiBVbmtub3duIG9wdGlvbiBcXFwiXCIgKyBrZXkgKyBcIlxcXCJcIik7XHJcblx0XHRcdFx0XHRkZWxldGUgX29wdGlvbnNba2V5XTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdFx0X29wdGlvbnMuY29udGFpbmVyID0gX3V0aWwuZ2V0LmVsZW1lbnRzKF9vcHRpb25zLmNvbnRhaW5lcilbMF07XHJcblx0XHRcdC8vIGNoZWNrIFNjcm9sbENvbnRhaW5lclxyXG5cdFx0XHRpZiAoIV9vcHRpb25zLmNvbnRhaW5lcikge1xyXG5cdFx0XHRcdGxvZygxLCBcIkVSUk9SIGNyZWF0aW5nIG9iamVjdCBcIiArIE5BTUVTUEFDRSArIFwiOiBObyB2YWxpZCBzY3JvbGwgY29udGFpbmVyIHN1cHBsaWVkXCIpO1xyXG5cdFx0XHRcdHRocm93IE5BTUVTUEFDRSArIFwiIGluaXQgZmFpbGVkLlwiOyAvLyBjYW5jZWxcclxuXHRcdFx0fVxyXG5cdFx0XHRfaXNEb2N1bWVudCA9IF9vcHRpb25zLmNvbnRhaW5lciA9PT0gd2luZG93IHx8IF9vcHRpb25zLmNvbnRhaW5lciA9PT0gZG9jdW1lbnQuYm9keSB8fCAhZG9jdW1lbnQuYm9keS5jb250YWlucyhfb3B0aW9ucy5jb250YWluZXIpO1xyXG5cdFx0XHQvLyBub3JtYWxpemUgdG8gd2luZG93XHJcblx0XHRcdGlmIChfaXNEb2N1bWVudCkge1xyXG5cdFx0XHRcdF9vcHRpb25zLmNvbnRhaW5lciA9IHdpbmRvdztcclxuXHRcdFx0fVxyXG5cdFx0XHQvLyB1cGRhdGUgY29udGFpbmVyIHNpemUgaW1tZWRpYXRlbHlcclxuXHRcdFx0X3ZpZXdQb3J0U2l6ZSA9IGdldFZpZXdwb3J0U2l6ZSgpO1xyXG5cdFx0XHQvLyBzZXQgZXZlbnQgaGFuZGxlcnNcclxuXHRcdFx0X29wdGlvbnMuY29udGFpbmVyLmFkZEV2ZW50TGlzdGVuZXIoXCJyZXNpemVcIiwgb25DaGFuZ2UpO1xyXG5cdFx0XHRfb3B0aW9ucy5jb250YWluZXIuYWRkRXZlbnRMaXN0ZW5lcihcInNjcm9sbFwiLCBvbkNoYW5nZSk7XHJcblxyXG5cdFx0XHR2YXIgcmkgPSBwYXJzZUludChfb3B0aW9ucy5yZWZyZXNoSW50ZXJ2YWwsIDEwKTtcclxuXHRcdFx0X29wdGlvbnMucmVmcmVzaEludGVydmFsID0gX3V0aWwudHlwZS5OdW1iZXIocmkpID8gcmkgOiBERUZBVUxUX09QVElPTlMucmVmcmVzaEludGVydmFsO1xyXG5cdFx0XHRzY2hlZHVsZVJlZnJlc2goKTtcclxuXHJcblx0XHRcdGxvZygzLCBcImFkZGVkIG5ldyBcIiArIE5BTUVTUEFDRSArIFwiIGNvbnRyb2xsZXIgKHZcIiArIFNjcm9sbE1hZ2ljLnZlcnNpb24gKyBcIilcIik7XHJcblx0XHR9O1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogU2NoZWR1bGUgdGhlIG5leHQgZXhlY3V0aW9uIG9mIHRoZSByZWZyZXNoIGZ1bmN0aW9uXHJcblx0XHQgKiBAcHJpdmF0ZVxyXG5cdFx0ICovXHJcblx0XHR2YXIgc2NoZWR1bGVSZWZyZXNoID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRpZiAoX29wdGlvbnMucmVmcmVzaEludGVydmFsID4gMCkge1xyXG5cdFx0XHRcdF9yZWZyZXNoVGltZW91dCA9IHdpbmRvdy5zZXRUaW1lb3V0KHJlZnJlc2gsIF9vcHRpb25zLnJlZnJlc2hJbnRlcnZhbCk7XHJcblx0XHRcdH1cclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBEZWZhdWx0IGZ1bmN0aW9uIHRvIGdldCBzY3JvbGwgcG9zIC0gb3ZlcndyaXRlYWJsZSB1c2luZyBgQ29udHJvbGxlci5zY3JvbGxQb3MobmV3RnVuY3Rpb24pYFxyXG5cdFx0ICogQHByaXZhdGVcclxuXHRcdCAqL1xyXG5cdFx0dmFyIGdldFNjcm9sbFBvcyA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0cmV0dXJuIF9vcHRpb25zLnZlcnRpY2FsID8gX3V0aWwuZ2V0LnNjcm9sbFRvcChfb3B0aW9ucy5jb250YWluZXIpIDogX3V0aWwuZ2V0LnNjcm9sbExlZnQoX29wdGlvbnMuY29udGFpbmVyKTtcclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHZpZXdwb3J0IFNpemUgKHdpZHRoIHZvciBob3Jpem9udGFsLCBoZWlnaHQgZm9yIHZlcnRpY2FsKVxyXG5cdFx0ICogQHByaXZhdGVcclxuXHRcdCAqL1xyXG5cdFx0dmFyIGdldFZpZXdwb3J0U2l6ZSA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0cmV0dXJuIF9vcHRpb25zLnZlcnRpY2FsID8gX3V0aWwuZ2V0LmhlaWdodChfb3B0aW9ucy5jb250YWluZXIpIDogX3V0aWwuZ2V0LndpZHRoKF9vcHRpb25zLmNvbnRhaW5lcik7XHJcblx0XHR9O1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogRGVmYXVsdCBmdW5jdGlvbiB0byBzZXQgc2Nyb2xsIHBvcyAtIG92ZXJ3cml0ZWFibGUgdXNpbmcgYENvbnRyb2xsZXIuc2Nyb2xsVG8obmV3RnVuY3Rpb24pYFxyXG5cdFx0ICogTWFrZSBhdmFpbGFibGUgcHVibGljbHkgZm9yIHBpbm5lZCBtb3VzZXdoZWVsIHdvcmthcm91bmQuXHJcblx0XHQgKiBAcHJpdmF0ZVxyXG5cdFx0ICovXHJcblx0XHR2YXIgc2V0U2Nyb2xsUG9zID0gdGhpcy5fc2V0U2Nyb2xsUG9zID0gZnVuY3Rpb24gKHBvcykge1xyXG5cdFx0XHRpZiAoX29wdGlvbnMudmVydGljYWwpIHtcclxuXHRcdFx0XHRpZiAoX2lzRG9jdW1lbnQpIHtcclxuXHRcdFx0XHRcdHdpbmRvdy5zY3JvbGxUbyhfdXRpbC5nZXQuc2Nyb2xsTGVmdCgpLCBwb3MpO1xyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHRfb3B0aW9ucy5jb250YWluZXIuc2Nyb2xsVG9wID0gcG9zO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRpZiAoX2lzRG9jdW1lbnQpIHtcclxuXHRcdFx0XHRcdHdpbmRvdy5zY3JvbGxUbyhwb3MsIF91dGlsLmdldC5zY3JvbGxUb3AoKSk7XHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdF9vcHRpb25zLmNvbnRhaW5lci5zY3JvbGxMZWZ0ID0gcG9zO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0fTtcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIEhhbmRsZSB1cGRhdGVzIGluIGN5Y2xlcyBpbnN0ZWFkIG9mIG9uIHNjcm9sbCAocGVyZm9ybWFuY2UpXHJcblx0XHQgKiBAcHJpdmF0ZVxyXG5cdFx0ICovXHJcblx0XHR2YXIgdXBkYXRlU2NlbmVzID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRpZiAoX2VuYWJsZWQgJiYgX3VwZGF0ZVNjZW5lc09uTmV4dEN5Y2xlKSB7XHJcblx0XHRcdFx0Ly8gZGV0ZXJtaW5lIHNjZW5lcyB0byB1cGRhdGVcclxuXHRcdFx0XHR2YXIgc2NlbmVzVG9VcGRhdGUgPSBfdXRpbC50eXBlLkFycmF5KF91cGRhdGVTY2VuZXNPbk5leHRDeWNsZSkgPyBfdXBkYXRlU2NlbmVzT25OZXh0Q3ljbGUgOiBfc2NlbmVPYmplY3RzLnNsaWNlKDApO1xyXG5cdFx0XHRcdC8vIHJlc2V0IHNjZW5lc1xyXG5cdFx0XHRcdF91cGRhdGVTY2VuZXNPbk5leHRDeWNsZSA9IGZhbHNlO1xyXG5cdFx0XHRcdHZhciBvbGRTY3JvbGxQb3MgPSBfc2Nyb2xsUG9zO1xyXG5cdFx0XHRcdC8vIHVwZGF0ZSBzY3JvbGwgcG9zIG5vdyBpbnN0ZWFkIG9mIG9uQ2hhbmdlLCBhcyBpdCBtaWdodCBoYXZlIGNoYW5nZWQgc2luY2Ugc2NoZWR1bGluZyAoaS5lLiBpbi1icm93c2VyIHNtb290aCBzY3JvbGwpXHJcblx0XHRcdFx0X3Njcm9sbFBvcyA9IENvbnRyb2xsZXIuc2Nyb2xsUG9zKCk7XHJcblx0XHRcdFx0dmFyIGRlbHRhU2Nyb2xsID0gX3Njcm9sbFBvcyAtIG9sZFNjcm9sbFBvcztcclxuXHRcdFx0XHRpZiAoZGVsdGFTY3JvbGwgIT09IDApIHsgLy8gc2Nyb2xsIHBvc2l0aW9uIGNoYW5nZWQ/XHJcblx0XHRcdFx0XHRfc2Nyb2xsRGlyZWN0aW9uID0gKGRlbHRhU2Nyb2xsID4gMCkgPyBTQ1JPTExfRElSRUNUSU9OX0ZPUldBUkQgOiBTQ1JPTExfRElSRUNUSU9OX1JFVkVSU0U7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdC8vIHJldmVyc2Ugb3JkZXIgb2Ygc2NlbmVzIGlmIHNjcm9sbGluZyByZXZlcnNlXHJcblx0XHRcdFx0aWYgKF9zY3JvbGxEaXJlY3Rpb24gPT09IFNDUk9MTF9ESVJFQ1RJT05fUkVWRVJTRSkge1xyXG5cdFx0XHRcdFx0c2NlbmVzVG9VcGRhdGUucmV2ZXJzZSgpO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHQvLyB1cGRhdGUgc2NlbmVzXHJcblx0XHRcdFx0c2NlbmVzVG9VcGRhdGUuZm9yRWFjaChmdW5jdGlvbiAoc2NlbmUsIGluZGV4KSB7XHJcblx0XHRcdFx0XHRsb2coMywgXCJ1cGRhdGluZyBTY2VuZSBcIiArIChpbmRleCArIDEpICsgXCIvXCIgKyBzY2VuZXNUb1VwZGF0ZS5sZW5ndGggKyBcIiAoXCIgKyBfc2NlbmVPYmplY3RzLmxlbmd0aCArIFwiIHRvdGFsKVwiKTtcclxuXHRcdFx0XHRcdHNjZW5lLnVwZGF0ZSh0cnVlKTtcclxuXHRcdFx0XHR9KTtcclxuXHRcdFx0XHRpZiAoc2NlbmVzVG9VcGRhdGUubGVuZ3RoID09PSAwICYmIF9vcHRpb25zLmxvZ2xldmVsID49IDMpIHtcclxuXHRcdFx0XHRcdGxvZygzLCBcInVwZGF0aW5nIDAgU2NlbmVzIChub3RoaW5nIGFkZGVkIHRvIGNvbnRyb2xsZXIpXCIpO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0fTtcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIEluaXRpYWxpemVzIHJBRiBjYWxsYmFja1xyXG5cdFx0ICogQHByaXZhdGVcclxuXHRcdCAqL1xyXG5cdFx0dmFyIGRlYm91bmNlVXBkYXRlID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRfdXBkYXRlVGltZW91dCA9IF91dGlsLnJBRih1cGRhdGVTY2VuZXMpO1xyXG5cdFx0fTtcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIEhhbmRsZXMgQ29udGFpbmVyIGNoYW5nZXNcclxuXHRcdCAqIEBwcml2YXRlXHJcblx0XHQgKi9cclxuXHRcdHZhciBvbkNoYW5nZSA9IGZ1bmN0aW9uIChlKSB7XHJcblx0XHRcdGxvZygzLCBcImV2ZW50IGZpcmVkIGNhdXNpbmcgYW4gdXBkYXRlOlwiLCBlLnR5cGUpO1xyXG5cdFx0XHRpZiAoZS50eXBlID09IFwicmVzaXplXCIpIHtcclxuXHRcdFx0XHQvLyByZXNpemVcclxuXHRcdFx0XHRfdmlld1BvcnRTaXplID0gZ2V0Vmlld3BvcnRTaXplKCk7XHJcblx0XHRcdFx0X3Njcm9sbERpcmVjdGlvbiA9IFNDUk9MTF9ESVJFQ1RJT05fUEFVU0VEO1xyXG5cdFx0XHR9XHJcblx0XHRcdC8vIHNjaGVkdWxlIHVwZGF0ZVxyXG5cdFx0XHRpZiAoX3VwZGF0ZVNjZW5lc09uTmV4dEN5Y2xlICE9PSB0cnVlKSB7XHJcblx0XHRcdFx0X3VwZGF0ZVNjZW5lc09uTmV4dEN5Y2xlID0gdHJ1ZTtcclxuXHRcdFx0XHRkZWJvdW5jZVVwZGF0ZSgpO1xyXG5cdFx0XHR9XHJcblx0XHR9O1xyXG5cclxuXHRcdHZhciByZWZyZXNoID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRpZiAoIV9pc0RvY3VtZW50KSB7XHJcblx0XHRcdFx0Ly8gc2ltdWxhdGUgcmVzaXplIGV2ZW50LiBPbmx5IHdvcmtzIGZvciB2aWV3cG9ydCByZWxldmFudCBwYXJhbSAocGVyZm9ybWFuY2UpXHJcblx0XHRcdFx0aWYgKF92aWV3UG9ydFNpemUgIT0gZ2V0Vmlld3BvcnRTaXplKCkpIHtcclxuXHRcdFx0XHRcdHZhciByZXNpemVFdmVudDtcclxuXHRcdFx0XHRcdHRyeSB7XHJcblx0XHRcdFx0XHRcdHJlc2l6ZUV2ZW50ID0gbmV3IEV2ZW50KCdyZXNpemUnLCB7XHJcblx0XHRcdFx0XHRcdFx0YnViYmxlczogZmFsc2UsXHJcblx0XHRcdFx0XHRcdFx0Y2FuY2VsYWJsZTogZmFsc2VcclxuXHRcdFx0XHRcdFx0fSk7XHJcblx0XHRcdFx0XHR9IGNhdGNoIChlKSB7IC8vIHN0dXBpZCBJRVxyXG5cdFx0XHRcdFx0XHRyZXNpemVFdmVudCA9IGRvY3VtZW50LmNyZWF0ZUV2ZW50KFwiRXZlbnRcIik7XHJcblx0XHRcdFx0XHRcdHJlc2l6ZUV2ZW50LmluaXRFdmVudChcInJlc2l6ZVwiLCBmYWxzZSwgZmFsc2UpO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0X29wdGlvbnMuY29udGFpbmVyLmRpc3BhdGNoRXZlbnQocmVzaXplRXZlbnQpO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0XHRfc2NlbmVPYmplY3RzLmZvckVhY2goZnVuY3Rpb24gKHNjZW5lLCBpbmRleCkgeyAvLyByZWZyZXNoIGFsbCBzY2VuZXNcclxuXHRcdFx0XHRzY2VuZS5yZWZyZXNoKCk7XHJcblx0XHRcdH0pO1xyXG5cdFx0XHRzY2hlZHVsZVJlZnJlc2goKTtcclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBTZW5kIGEgZGVidWcgbWVzc2FnZSB0byB0aGUgY29uc29sZS5cclxuXHRcdCAqIHByb3ZpZGVkIHB1YmxpY2x5IHdpdGggX2xvZyBmb3IgcGx1Z2luc1xyXG5cdFx0ICogQHByaXZhdGVcclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0ge251bWJlcn0gbG9nbGV2ZWwgLSBUaGUgbG9nbGV2ZWwgcmVxdWlyZWQgdG8gaW5pdGlhdGUgb3V0cHV0IGZvciB0aGUgbWVzc2FnZS5cclxuXHRcdCAqIEBwYXJhbSB7Li4ubWl4ZWR9IG91dHB1dCAtIE9uZSBvciBtb3JlIHZhcmlhYmxlcyB0aGF0IHNob3VsZCBiZSBwYXNzZWQgdG8gdGhlIGNvbnNvbGUuXHJcblx0XHQgKi9cclxuXHRcdHZhciBsb2cgPSB0aGlzLl9sb2cgPSBmdW5jdGlvbiAobG9nbGV2ZWwsIG91dHB1dCkge1xyXG5cdFx0XHRpZiAoX29wdGlvbnMubG9nbGV2ZWwgPj0gbG9nbGV2ZWwpIHtcclxuXHRcdFx0XHRBcnJheS5wcm90b3R5cGUuc3BsaWNlLmNhbGwoYXJndW1lbnRzLCAxLCAwLCBcIihcIiArIE5BTUVTUEFDRSArIFwiKSAtPlwiKTtcclxuXHRcdFx0XHRfdXRpbC5sb2cuYXBwbHkod2luZG93LCBhcmd1bWVudHMpO1xyXG5cdFx0XHR9XHJcblx0XHR9O1xyXG5cdFx0Ly8gZm9yIHNjZW5lcyB3ZSBoYXZlIGdldHRlcnMgZm9yIGVhY2ggb3B0aW9uLCBidXQgZm9yIHRoZSBjb250cm9sbGVyIHdlIGRvbid0LCBzbyB3ZSBuZWVkIHRvIG1ha2UgaXQgYXZhaWxhYmxlIGV4dGVybmFsbHkgZm9yIHBsdWdpbnNcclxuXHRcdHRoaXMuX29wdGlvbnMgPSBfb3B0aW9ucztcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIFNvcnQgc2NlbmVzIGluIGFzY2VuZGluZyBvcmRlciBvZiB0aGVpciBzdGFydCBvZmZzZXQuXHJcblx0XHQgKiBAcHJpdmF0ZVxyXG5cdFx0ICpcclxuXHRcdCAqIEBwYXJhbSB7YXJyYXl9IFNjZW5lc0FycmF5IC0gYW4gYXJyYXkgb2YgU2Nyb2xsTWFnaWMgU2NlbmVzIHRoYXQgc2hvdWxkIGJlIHNvcnRlZFxyXG5cdFx0ICogQHJldHVybiB7YXJyYXl9IFRoZSBzb3J0ZWQgYXJyYXkgb2YgU2NlbmVzLlxyXG5cdFx0ICovXHJcblx0XHR2YXIgc29ydFNjZW5lcyA9IGZ1bmN0aW9uIChTY2VuZXNBcnJheSkge1xyXG5cdFx0XHRpZiAoU2NlbmVzQXJyYXkubGVuZ3RoIDw9IDEpIHtcclxuXHRcdFx0XHRyZXR1cm4gU2NlbmVzQXJyYXk7XHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0dmFyIHNjZW5lcyA9IFNjZW5lc0FycmF5LnNsaWNlKDApO1xyXG5cdFx0XHRcdHNjZW5lcy5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7XHJcblx0XHRcdFx0XHRyZXR1cm4gYS5zY3JvbGxPZmZzZXQoKSA+IGIuc2Nyb2xsT2Zmc2V0KCkgPyAxIDogLTE7XHJcblx0XHRcdFx0fSk7XHJcblx0XHRcdFx0cmV0dXJuIHNjZW5lcztcclxuXHRcdFx0fVxyXG5cdFx0fTtcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdCAqIHB1YmxpYyBmdW5jdGlvbnNcclxuXHRcdCAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdCAqL1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogQWRkIG9uZSBvcmUgbW9yZSBzY2VuZShzKSB0byB0aGUgY29udHJvbGxlci4gIFxyXG5cdFx0ICogVGhpcyBpcyB0aGUgZXF1aXZhbGVudCB0byBgU2NlbmUuYWRkVG8oY29udHJvbGxlcilgLlxyXG5cdFx0ICogQHB1YmxpY1xyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIC8vIHdpdGggYSBwcmV2aW91c2x5IGRlZmluZWQgc2NlbmVcclxuXHRcdCAqIGNvbnRyb2xsZXIuYWRkU2NlbmUoc2NlbmUpO1xyXG5cdFx0ICpcclxuXHRcdCAqIC8vIHdpdGggYSBuZXdseSBjcmVhdGVkIHNjZW5lLlxyXG5cdFx0ICogY29udHJvbGxlci5hZGRTY2VuZShuZXcgU2Nyb2xsTWFnaWMuU2NlbmUoe2R1cmF0aW9uIDogMH0pKTtcclxuXHRcdCAqXHJcblx0XHQgKiAvLyBhZGRpbmcgbXVsdGlwbGUgc2NlbmVzXHJcblx0XHQgKiBjb250cm9sbGVyLmFkZFNjZW5lKFtzY2VuZSwgc2NlbmUyLCBuZXcgU2Nyb2xsTWFnaWMuU2NlbmUoe2R1cmF0aW9uIDogMH0pXSk7XHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIHsoU2Nyb2xsTWFnaWMuU2NlbmV8YXJyYXkpfSBuZXdTY2VuZSAtIFNjcm9sbE1hZ2ljIFNjZW5lIG9yIEFycmF5IG9mIFNjZW5lcyB0byBiZSBhZGRlZCB0byB0aGUgY29udHJvbGxlci5cclxuXHRcdCAqIEByZXR1cm4ge0NvbnRyb2xsZXJ9IFBhcmVudCBvYmplY3QgZm9yIGNoYWluaW5nLlxyXG5cdFx0ICovXHJcblx0XHR0aGlzLmFkZFNjZW5lID0gZnVuY3Rpb24gKG5ld1NjZW5lKSB7XHJcblx0XHRcdGlmIChfdXRpbC50eXBlLkFycmF5KG5ld1NjZW5lKSkge1xyXG5cdFx0XHRcdG5ld1NjZW5lLmZvckVhY2goZnVuY3Rpb24gKHNjZW5lLCBpbmRleCkge1xyXG5cdFx0XHRcdFx0Q29udHJvbGxlci5hZGRTY2VuZShzY2VuZSk7XHJcblx0XHRcdFx0fSk7XHJcblx0XHRcdH0gZWxzZSBpZiAobmV3U2NlbmUgaW5zdGFuY2VvZiBTY3JvbGxNYWdpYy5TY2VuZSkge1xyXG5cdFx0XHRcdGlmIChuZXdTY2VuZS5jb250cm9sbGVyKCkgIT09IENvbnRyb2xsZXIpIHtcclxuXHRcdFx0XHRcdG5ld1NjZW5lLmFkZFRvKENvbnRyb2xsZXIpO1xyXG5cdFx0XHRcdH0gZWxzZSBpZiAoX3NjZW5lT2JqZWN0cy5pbmRleE9mKG5ld1NjZW5lKSA8IDApIHtcclxuXHRcdFx0XHRcdC8vIG5ldyBzY2VuZVxyXG5cdFx0XHRcdFx0X3NjZW5lT2JqZWN0cy5wdXNoKG5ld1NjZW5lKTsgLy8gYWRkIHRvIGFycmF5XHJcblx0XHRcdFx0XHRfc2NlbmVPYmplY3RzID0gc29ydFNjZW5lcyhfc2NlbmVPYmplY3RzKTsgLy8gc29ydFxyXG5cdFx0XHRcdFx0bmV3U2NlbmUub24oXCJzaGlmdC5jb250cm9sbGVyX3NvcnRcIiwgZnVuY3Rpb24gKCkgeyAvLyByZXNvcnQgd2hlbmV2ZXIgc2NlbmUgbW92ZXNcclxuXHRcdFx0XHRcdFx0X3NjZW5lT2JqZWN0cyA9IHNvcnRTY2VuZXMoX3NjZW5lT2JqZWN0cyk7XHJcblx0XHRcdFx0XHR9KTtcclxuXHRcdFx0XHRcdC8vIGluc2VydCBHbG9iYWwgZGVmYXVsdHMuXHJcblx0XHRcdFx0XHRmb3IgKHZhciBrZXkgaW4gX29wdGlvbnMuZ2xvYmFsU2NlbmVPcHRpb25zKSB7XHJcblx0XHRcdFx0XHRcdGlmIChuZXdTY2VuZVtrZXldKSB7XHJcblx0XHRcdFx0XHRcdFx0bmV3U2NlbmVba2V5XS5jYWxsKG5ld1NjZW5lLCBfb3B0aW9ucy5nbG9iYWxTY2VuZU9wdGlvbnNba2V5XSk7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdGxvZygzLCBcImFkZGluZyBTY2VuZSAobm93IFwiICsgX3NjZW5lT2JqZWN0cy5sZW5ndGggKyBcIiB0b3RhbClcIik7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdGxvZygxLCBcIkVSUk9SOiBpbnZhbGlkIGFyZ3VtZW50IHN1cHBsaWVkIGZvciAnLmFkZFNjZW5lKCknXCIpO1xyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiBDb250cm9sbGVyO1xyXG5cdFx0fTtcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIFJlbW92ZSBvbmUgb3JlIG1vcmUgc2NlbmUocykgZnJvbSB0aGUgY29udHJvbGxlci4gIFxyXG5cdFx0ICogVGhpcyBpcyB0aGUgZXF1aXZhbGVudCB0byBgU2NlbmUucmVtb3ZlKClgLlxyXG5cdFx0ICogQHB1YmxpY1xyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIC8vIHJlbW92ZSBhIHNjZW5lIGZyb20gdGhlIGNvbnRyb2xsZXJcclxuXHRcdCAqIGNvbnRyb2xsZXIucmVtb3ZlU2NlbmUoc2NlbmUpO1xyXG5cdFx0ICpcclxuXHRcdCAqIC8vIHJlbW92ZSBtdWx0aXBsZSBzY2VuZXMgZnJvbSB0aGUgY29udHJvbGxlclxyXG5cdFx0ICogY29udHJvbGxlci5yZW1vdmVTY2VuZShbc2NlbmUsIHNjZW5lMiwgc2NlbmUzXSk7XHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIHsoU2Nyb2xsTWFnaWMuU2NlbmV8YXJyYXkpfSBTY2VuZSAtIFNjcm9sbE1hZ2ljIFNjZW5lIG9yIEFycmF5IG9mIFNjZW5lcyB0byBiZSByZW1vdmVkIGZyb20gdGhlIGNvbnRyb2xsZXIuXHJcblx0XHQgKiBAcmV0dXJucyB7Q29udHJvbGxlcn0gUGFyZW50IG9iamVjdCBmb3IgY2hhaW5pbmcuXHJcblx0XHQgKi9cclxuXHRcdHRoaXMucmVtb3ZlU2NlbmUgPSBmdW5jdGlvbiAoU2NlbmUpIHtcclxuXHRcdFx0aWYgKF91dGlsLnR5cGUuQXJyYXkoU2NlbmUpKSB7XHJcblx0XHRcdFx0U2NlbmUuZm9yRWFjaChmdW5jdGlvbiAoc2NlbmUsIGluZGV4KSB7XHJcblx0XHRcdFx0XHRDb250cm9sbGVyLnJlbW92ZVNjZW5lKHNjZW5lKTtcclxuXHRcdFx0XHR9KTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHR2YXIgaW5kZXggPSBfc2NlbmVPYmplY3RzLmluZGV4T2YoU2NlbmUpO1xyXG5cdFx0XHRcdGlmIChpbmRleCA+IC0xKSB7XHJcblx0XHRcdFx0XHRTY2VuZS5vZmYoXCJzaGlmdC5jb250cm9sbGVyX3NvcnRcIik7XHJcblx0XHRcdFx0XHRfc2NlbmVPYmplY3RzLnNwbGljZShpbmRleCwgMSk7XHJcblx0XHRcdFx0XHRsb2coMywgXCJyZW1vdmluZyBTY2VuZSAobm93IFwiICsgX3NjZW5lT2JqZWN0cy5sZW5ndGggKyBcIiBsZWZ0KVwiKTtcclxuXHRcdFx0XHRcdFNjZW5lLnJlbW92ZSgpO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0XHRyZXR1cm4gQ29udHJvbGxlcjtcclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0ICogVXBkYXRlIG9uZSBvcmUgbW9yZSBzY2VuZShzKSBhY2NvcmRpbmcgdG8gdGhlIHNjcm9sbCBwb3NpdGlvbiBvZiB0aGUgY29udGFpbmVyLiAgXHJcblx0ICogVGhpcyBpcyB0aGUgZXF1aXZhbGVudCB0byBgU2NlbmUudXBkYXRlKClgLiAgXHJcblx0ICogVGhlIHVwZGF0ZSBtZXRob2QgY2FsY3VsYXRlcyB0aGUgc2NlbmUncyBzdGFydCBhbmQgZW5kIHBvc2l0aW9uIChiYXNlZCBvbiB0aGUgdHJpZ2dlciBlbGVtZW50LCB0cmlnZ2VyIGhvb2ssIGR1cmF0aW9uIGFuZCBvZmZzZXQpIGFuZCBjaGVja3MgaXQgYWdhaW5zdCB0aGUgY3VycmVudCBzY3JvbGwgcG9zaXRpb24gb2YgdGhlIGNvbnRhaW5lci4gIFxyXG5cdCAqIEl0IHRoZW4gdXBkYXRlcyB0aGUgY3VycmVudCBzY2VuZSBzdGF0ZSBhY2NvcmRpbmdseSAob3IgZG9lcyBub3RoaW5nLCBpZiB0aGUgc3RhdGUgaXMgYWxyZWFkeSBjb3JyZWN0KSDigJMgUGlucyB3aWxsIGJlIHNldCB0byB0aGVpciBjb3JyZWN0IHBvc2l0aW9uIGFuZCB0d2VlbnMgd2lsbCBiZSB1cGRhdGVkIHRvIHRoZWlyIGNvcnJlY3QgcHJvZ3Jlc3MuICBcclxuXHQgKiBfKipOb3RlOioqIFRoaXMgbWV0aG9kIGdldHMgY2FsbGVkIGNvbnN0YW50bHkgd2hlbmV2ZXIgQ29udHJvbGxlciBkZXRlY3RzIGEgY2hhbmdlLiBUaGUgb25seSBhcHBsaWNhdGlvbiBmb3IgeW91IGlzIGlmIHlvdSBjaGFuZ2Ugc29tZXRoaW5nIG91dHNpZGUgb2YgdGhlIHJlYWxtIG9mIFNjcm9sbE1hZ2ljLCBsaWtlIG1vdmluZyB0aGUgdHJpZ2dlciBvciBjaGFuZ2luZyB0d2VlbiBwYXJhbWV0ZXJzLl9cclxuXHQgKiBAcHVibGljXHJcblx0ICogQGV4YW1wbGVcclxuXHQgKiAvLyB1cGRhdGUgYSBzcGVjaWZpYyBzY2VuZSBvbiBuZXh0IGN5Y2xlXHJcbiBcdCAqIGNvbnRyb2xsZXIudXBkYXRlU2NlbmUoc2NlbmUpO1xyXG4gXHQgKlxyXG5cdCAqIC8vIHVwZGF0ZSBhIHNwZWNpZmljIHNjZW5lIGltbWVkaWF0ZWx5XHJcblx0ICogY29udHJvbGxlci51cGRhdGVTY2VuZShzY2VuZSwgdHJ1ZSk7XHJcbiBcdCAqXHJcblx0ICogLy8gdXBkYXRlIG11bHRpcGxlIHNjZW5lcyBzY2VuZSBvbiBuZXh0IGN5Y2xlXHJcblx0ICogY29udHJvbGxlci51cGRhdGVTY2VuZShbc2NlbmUxLCBzY2VuZTIsIHNjZW5lM10pO1xyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtTY3JvbGxNYWdpYy5TY2VuZX0gU2NlbmUgLSBTY3JvbGxNYWdpYyBTY2VuZSBvciBBcnJheSBvZiBTY2VuZXMgdGhhdCBpcy9hcmUgc3VwcG9zZWQgdG8gYmUgdXBkYXRlZC5cclxuXHQgKiBAcGFyYW0ge2Jvb2xlYW59IFtpbW1lZGlhdGVseT1mYWxzZV0gLSBJZiBgdHJ1ZWAgdGhlIHVwZGF0ZSB3aWxsIGJlIGluc3RhbnQsIGlmIGBmYWxzZWAgaXQgd2lsbCB3YWl0IHVudGlsIG5leHQgdXBkYXRlIGN5Y2xlLiAgXHJcblx0IFx0XHRcdFx0XHRcdFx0XHRcdFx0ICBUaGlzIGlzIHVzZWZ1bCB3aGVuIGNoYW5naW5nIG11bHRpcGxlIHByb3BlcnRpZXMgb2YgdGhlIHNjZW5lIC0gdGhpcyB3YXkgaXQgd2lsbCBvbmx5IGJlIHVwZGF0ZWQgb25jZSBhbGwgbmV3IHByb3BlcnRpZXMgYXJlIHNldCAodXBkYXRlU2NlbmVzKS5cclxuXHQgKiBAcmV0dXJuIHtDb250cm9sbGVyfSBQYXJlbnQgb2JqZWN0IGZvciBjaGFpbmluZy5cclxuXHQgKi9cclxuXHRcdHRoaXMudXBkYXRlU2NlbmUgPSBmdW5jdGlvbiAoU2NlbmUsIGltbWVkaWF0ZWx5KSB7XHJcblx0XHRcdGlmIChfdXRpbC50eXBlLkFycmF5KFNjZW5lKSkge1xyXG5cdFx0XHRcdFNjZW5lLmZvckVhY2goZnVuY3Rpb24gKHNjZW5lLCBpbmRleCkge1xyXG5cdFx0XHRcdFx0Q29udHJvbGxlci51cGRhdGVTY2VuZShzY2VuZSwgaW1tZWRpYXRlbHkpO1xyXG5cdFx0XHRcdH0pO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdGlmIChpbW1lZGlhdGVseSkge1xyXG5cdFx0XHRcdFx0U2NlbmUudXBkYXRlKHRydWUpO1xyXG5cdFx0XHRcdH0gZWxzZSBpZiAoX3VwZGF0ZVNjZW5lc09uTmV4dEN5Y2xlICE9PSB0cnVlICYmIFNjZW5lIGluc3RhbmNlb2YgU2Nyb2xsTWFnaWMuU2NlbmUpIHsgLy8gaWYgX3VwZGF0ZVNjZW5lc09uTmV4dEN5Y2xlIGlzIHRydWUsIGFsbCBjb25uZWN0ZWQgc2NlbmVzIGFyZSBhbHJlYWR5IHNjaGVkdWxlZCBmb3IgdXBkYXRlXHJcblx0XHRcdFx0XHQvLyBwcmVwIGFycmF5IGZvciBuZXh0IHVwZGF0ZSBjeWNsZVxyXG5cdFx0XHRcdFx0X3VwZGF0ZVNjZW5lc09uTmV4dEN5Y2xlID0gX3VwZGF0ZVNjZW5lc09uTmV4dEN5Y2xlIHx8IFtdO1xyXG5cdFx0XHRcdFx0aWYgKF91cGRhdGVTY2VuZXNPbk5leHRDeWNsZS5pbmRleE9mKFNjZW5lKSA9PSAtMSkge1xyXG5cdFx0XHRcdFx0XHRfdXBkYXRlU2NlbmVzT25OZXh0Q3ljbGUucHVzaChTY2VuZSk7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRfdXBkYXRlU2NlbmVzT25OZXh0Q3ljbGUgPSBzb3J0U2NlbmVzKF91cGRhdGVTY2VuZXNPbk5leHRDeWNsZSk7IC8vIHNvcnRcclxuXHRcdFx0XHRcdGRlYm91bmNlVXBkYXRlKCk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiBDb250cm9sbGVyO1xyXG5cdFx0fTtcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIFVwZGF0ZXMgdGhlIGNvbnRyb2xsZXIgcGFyYW1zIGFuZCBjYWxscyB1cGRhdGVTY2VuZSBvbiBldmVyeSBzY2VuZSwgdGhhdCBpcyBhdHRhY2hlZCB0byB0aGUgY29udHJvbGxlci4gIFxyXG5cdFx0ICogU2VlIGBDb250cm9sbGVyLnVwZGF0ZVNjZW5lKClgIGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IHdoYXQgdGhpcyBtZWFucy4gIFxyXG5cdFx0ICogSW4gbW9zdCBjYXNlcyB5b3Ugd2lsbCBub3QgbmVlZCB0aGlzIGZ1bmN0aW9uLCBhcyBpdCBpcyBjYWxsZWQgY29uc3RhbnRseSwgd2hlbmV2ZXIgU2Nyb2xsTWFnaWMgZGV0ZWN0cyBhIHN0YXRlIGNoYW5nZSBldmVudCwgbGlrZSByZXNpemUgb3Igc2Nyb2xsLiAgXHJcblx0XHQgKiBUaGUgb25seSBhcHBsaWNhdGlvbiBmb3IgdGhpcyBtZXRob2QgaXMgd2hlbiBTY3JvbGxNYWdpYyBmYWlscyB0byBkZXRlY3QgdGhlc2UgZXZlbnRzLiAgXHJcblx0XHQgKiBPbmUgYXBwbGljYXRpb24gaXMgd2l0aCBzb21lIGV4dGVybmFsIHNjcm9sbCBsaWJyYXJpZXMgKGxpa2UgaVNjcm9sbCkgdGhhdCBtb3ZlIGFuIGludGVybmFsIGNvbnRhaW5lciB0byBhIG5lZ2F0aXZlIG9mZnNldCBpbnN0ZWFkIG9mIGFjdHVhbGx5IHNjcm9sbGluZy4gSW4gdGhpcyBjYXNlIHRoZSB1cGRhdGUgb24gdGhlIGNvbnRyb2xsZXIgbmVlZHMgdG8gYmUgY2FsbGVkIHdoZW5ldmVyIHRoZSBjaGlsZCBjb250YWluZXIncyBwb3NpdGlvbiBjaGFuZ2VzLlxyXG5cdFx0ICogRm9yIHRoaXMgY2FzZSB0aGVyZSB3aWxsIGFsc28gYmUgdGhlIG5lZWQgdG8gcHJvdmlkZSBhIGN1c3RvbSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIGNvcnJlY3Qgc2Nyb2xsIHBvc2l0aW9uLiBTZWUgYENvbnRyb2xsZXIuc2Nyb2xsUG9zKClgIGZvciBkZXRhaWxzLlxyXG5cdFx0ICogQHB1YmxpY1xyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIC8vIHVwZGF0ZSB0aGUgY29udHJvbGxlciBvbiBuZXh0IGN5Y2xlIChzYXZlcyBwZXJmb3JtYW5jZSBkdWUgdG8gZWxpbWluYXRpb24gb2YgcmVkdW5kYW50IHVwZGF0ZXMpXHJcblx0XHQgKiBjb250cm9sbGVyLnVwZGF0ZSgpO1xyXG5cdFx0ICpcclxuXHRcdCAqIC8vIHVwZGF0ZSB0aGUgY29udHJvbGxlciBpbW1lZGlhdGVseVxyXG5cdFx0ICogY29udHJvbGxlci51cGRhdGUodHJ1ZSk7XHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIHtib29sZWFufSBbaW1tZWRpYXRlbHk9ZmFsc2VdIC0gSWYgYHRydWVgIHRoZSB1cGRhdGUgd2lsbCBiZSBpbnN0YW50LCBpZiBgZmFsc2VgIGl0IHdpbGwgd2FpdCB1bnRpbCBuZXh0IHVwZGF0ZSBjeWNsZSAoYmV0dGVyIHBlcmZvcm1hbmNlKVxyXG5cdFx0ICogQHJldHVybiB7Q29udHJvbGxlcn0gUGFyZW50IG9iamVjdCBmb3IgY2hhaW5pbmcuXHJcblx0XHQgKi9cclxuXHRcdHRoaXMudXBkYXRlID0gZnVuY3Rpb24gKGltbWVkaWF0ZWx5KSB7XHJcblx0XHRcdG9uQ2hhbmdlKHtcclxuXHRcdFx0XHR0eXBlOiBcInJlc2l6ZVwiXHJcblx0XHRcdH0pOyAvLyB3aWxsIHVwZGF0ZSBzaXplIGFuZCBzZXQgX3VwZGF0ZVNjZW5lc09uTmV4dEN5Y2xlIHRvIHRydWVcclxuXHRcdFx0aWYgKGltbWVkaWF0ZWx5KSB7XHJcblx0XHRcdFx0dXBkYXRlU2NlbmVzKCk7XHJcblx0XHRcdH1cclxuXHRcdFx0cmV0dXJuIENvbnRyb2xsZXI7XHJcblx0XHR9O1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogU2Nyb2xsIHRvIGEgbnVtZXJpYyBzY3JvbGwgb2Zmc2V0LCBhIERPTSBlbGVtZW50LCB0aGUgc3RhcnQgb2YgYSBzY2VuZSBvciBwcm92aWRlIGFuIGFsdGVybmF0ZSBtZXRob2QgZm9yIHNjcm9sbGluZy4gIFxyXG5cdFx0ICogRm9yIHZlcnRpY2FsIGNvbnRyb2xsZXJzIGl0IHdpbGwgY2hhbmdlIHRoZSB0b3Agc2Nyb2xsIG9mZnNldCBhbmQgZm9yIGhvcml6b250YWwgYXBwbGljYXRpb25zIGl0IHdpbGwgY2hhbmdlIHRoZSBsZWZ0IG9mZnNldC5cclxuXHRcdCAqIEBwdWJsaWNcclxuXHRcdCAqXHJcblx0XHQgKiBAc2luY2UgMS4xLjBcclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiAvLyBzY3JvbGwgdG8gYW4gb2Zmc2V0IG9mIDEwMFxyXG5cdFx0ICogY29udHJvbGxlci5zY3JvbGxUbygxMDApO1xyXG5cdFx0ICpcclxuXHRcdCAqIC8vIHNjcm9sbCB0byBhIERPTSBlbGVtZW50XHJcblx0XHQgKiBjb250cm9sbGVyLnNjcm9sbFRvKFwiI2FuY2hvclwiKTtcclxuXHRcdCAqXHJcblx0XHQgKiAvLyBzY3JvbGwgdG8gdGhlIGJlZ2lubmluZyBvZiBhIHNjZW5lXHJcblx0XHQgKiB2YXIgc2NlbmUgPSBuZXcgU2Nyb2xsTWFnaWMuU2NlbmUoe29mZnNldDogMjAwfSk7XHJcblx0XHQgKiBjb250cm9sbGVyLnNjcm9sbFRvKHNjZW5lKTtcclxuXHRcdCAqXHJcblx0XHQgKiAvLyBkZWZpbmUgYSBuZXcgc2Nyb2xsIHBvc2l0aW9uIG1vZGlmaWNhdGlvbiBmdW5jdGlvbiAoalF1ZXJ5IGFuaW1hdGUgaW5zdGVhZCBvZiBqdW1wKVxyXG5cdFx0ICogY29udHJvbGxlci5zY3JvbGxUbyhmdW5jdGlvbiAobmV3U2Nyb2xsUG9zKSB7XHJcblx0XHQgKlx0JChcImh0bWwsIGJvZHlcIikuYW5pbWF0ZSh7c2Nyb2xsVG9wOiBuZXdTY3JvbGxQb3N9KTtcclxuXHRcdCAqIH0pO1xyXG5cdFx0ICogY29udHJvbGxlci5zY3JvbGxUbygxMDApOyAvLyBjYWxsIGFzIHVzdWFsLCBidXQgdGhlIG5ldyBmdW5jdGlvbiB3aWxsIGJlIHVzZWQgaW5zdGVhZFxyXG5cdFx0ICpcclxuXHRcdCAqIC8vIGRlZmluZSBhIG5ldyBzY3JvbGwgZnVuY3Rpb24gd2l0aCBhbiBhZGRpdGlvbmFsIHBhcmFtZXRlclxyXG5cdFx0ICogY29udHJvbGxlci5zY3JvbGxUbyhmdW5jdGlvbiAobmV3U2Nyb2xsUG9zLCBtZXNzYWdlKSB7XHJcblx0XHQgKiAgY29uc29sZS5sb2cobWVzc2FnZSk7XHJcblx0XHQgKlx0JCh0aGlzKS5hbmltYXRlKHtzY3JvbGxUb3A6IG5ld1Njcm9sbFBvc30pO1xyXG5cdFx0ICogfSk7XHJcblx0XHQgKiAvLyBjYWxsIGFzIHVzdWFsLCBidXQgc3VwcGx5IGFuIGV4dHJhIHBhcmFtZXRlciB0byB0aGUgZGVmaW5lZCBjdXN0b20gZnVuY3Rpb25cclxuXHRcdCAqIGNvbnRyb2xsZXIuc2Nyb2xsVG8oMTAwLCBcIm15IG1lc3NhZ2VcIik7XHJcblx0XHQgKlxyXG5cdFx0ICogLy8gZGVmaW5lIGEgbmV3IHNjcm9sbCBmdW5jdGlvbiB3aXRoIGFuIGFkZGl0aW9uYWwgcGFyYW1ldGVyIGNvbnRhaW5pbmcgbXVsdGlwbGUgdmFyaWFibGVzXHJcblx0XHQgKiBjb250cm9sbGVyLnNjcm9sbFRvKGZ1bmN0aW9uIChuZXdTY3JvbGxQb3MsIG9wdGlvbnMpIHtcclxuXHRcdCAqICBzb21lR2xvYmFsVmFyID0gb3B0aW9ucy5hICsgb3B0aW9ucy5iO1xyXG5cdFx0ICpcdCQodGhpcykuYW5pbWF0ZSh7c2Nyb2xsVG9wOiBuZXdTY3JvbGxQb3N9KTtcclxuXHRcdCAqIH0pO1xyXG5cdFx0ICogLy8gY2FsbCBhcyB1c3VhbCwgYnV0IHN1cHBseSBhbiBleHRyYSBwYXJhbWV0ZXIgY29udGFpbmluZyBtdWx0aXBsZSBvcHRpb25zXHJcblx0XHQgKiBjb250cm9sbGVyLnNjcm9sbFRvKDEwMCwge2E6IDEsIGI6IDJ9KTtcclxuXHRcdCAqXHJcblx0XHQgKiAvLyBkZWZpbmUgYSBuZXcgc2Nyb2xsIGZ1bmN0aW9uIHdpdGggYSBjYWxsYmFjayBzdXBwbGllZCBhcyBhbiBhZGRpdGlvbmFsIHBhcmFtZXRlclxyXG5cdFx0ICogY29udHJvbGxlci5zY3JvbGxUbyhmdW5jdGlvbiAobmV3U2Nyb2xsUG9zLCBjYWxsYmFjaykge1xyXG5cdFx0ICpcdCQodGhpcykuYW5pbWF0ZSh7c2Nyb2xsVG9wOiBuZXdTY3JvbGxQb3N9LCA0MDAsIFwic3dpbmdcIiwgY2FsbGJhY2spO1xyXG5cdFx0ICogfSk7XHJcblx0XHQgKiAvLyBjYWxsIGFzIHVzdWFsLCBidXQgc3VwcGx5IGFuIGV4dHJhIHBhcmFtZXRlciwgd2hpY2ggaXMgdXNlZCBhcyBhIGNhbGxiYWNrIGluIHRoZSBwcmV2aW91c2x5IGRlZmluZWQgY3VzdG9tIHNjcm9sbCBmdW5jdGlvblxyXG5cdFx0ICogY29udHJvbGxlci5zY3JvbGxUbygxMDAsIGZ1bmN0aW9uKCkge1xyXG5cdFx0ICpcdGNvbnNvbGUubG9nKFwic2Nyb2xsIGhhcyBmaW5pc2hlZC5cIik7XHJcblx0XHQgKiB9KTtcclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0ge21peGVkfSBzY3JvbGxUYXJnZXQgLSBUaGUgc3VwcGxpZWQgYXJndW1lbnQgY2FuIGJlIG9uZSBvZiB0aGVzZSB0eXBlczpcclxuXHRcdCAqIDEuIGBudW1iZXJgIC0+IFRoZSBjb250YWluZXIgd2lsbCBzY3JvbGwgdG8gdGhpcyBuZXcgc2Nyb2xsIG9mZnNldC5cclxuXHRcdCAqIDIuIGBzdHJpbmdgIG9yIGBvYmplY3RgIC0+IENhbiBiZSBhIHNlbGVjdG9yIG9yIGEgRE9NIG9iamVjdC4gIFxyXG5cdFx0ICogIFRoZSBjb250YWluZXIgd2lsbCBzY3JvbGwgdG8gdGhlIHBvc2l0aW9uIG9mIHRoaXMgZWxlbWVudC5cclxuXHRcdCAqIDMuIGBTY3JvbGxNYWdpYyBTY2VuZWAgLT4gVGhlIGNvbnRhaW5lciB3aWxsIHNjcm9sbCB0byB0aGUgc3RhcnQgb2YgdGhpcyBzY2VuZS5cclxuXHRcdCAqIDQuIGBmdW5jdGlvbmAgLT4gVGhpcyBmdW5jdGlvbiB3aWxsIGJlIHVzZWQgZm9yIGZ1dHVyZSBzY3JvbGwgcG9zaXRpb24gbW9kaWZpY2F0aW9ucy4gIFxyXG5cdFx0ICogIFRoaXMgcHJvdmlkZXMgYSB3YXkgZm9yIHlvdSB0byBjaGFuZ2UgdGhlIGJlaGF2aW91ciBvZiBzY3JvbGxpbmcgYW5kIGFkZGluZyBuZXcgYmVoYXZpb3VyIGxpa2UgYW5pbWF0aW9uLiBUaGUgZnVuY3Rpb24gcmVjZWl2ZXMgdGhlIG5ldyBzY3JvbGwgcG9zaXRpb24gYXMgYSBwYXJhbWV0ZXIgYW5kIGEgcmVmZXJlbmNlIHRvIHRoZSBjb250YWluZXIgZWxlbWVudCB1c2luZyBgdGhpc2AuICBcclxuXHRcdCAqICBJdCBtYXkgYWxzbyBvcHRpb25hbGx5IHJlY2VpdmUgYW4gb3B0aW9uYWwgYWRkaXRpb25hbCBwYXJhbWV0ZXIgKHNlZSBiZWxvdykgIFxyXG5cdFx0ICogIF8qKk5PVEU6KiogIFxyXG5cdFx0ICogIEFsbCBvdGhlciBvcHRpb25zIHdpbGwgc3RpbGwgd29yayBhcyBleHBlY3RlZCwgdXNpbmcgdGhlIG5ldyBmdW5jdGlvbiB0byBzY3JvbGwuX1xyXG5cdFx0ICogQHBhcmFtIHttaXhlZH0gW2FkZGl0aW9uYWxQYXJhbWV0ZXJdIC0gSWYgYSBjdXN0b20gc2Nyb2xsIGZ1bmN0aW9uIHdhcyBkZWZpbmVkIChzZWUgYWJvdmUgNC4pLCB5b3UgbWF5IHdhbnQgdG8gc3VwcGx5IGFkZGl0aW9uYWwgcGFyYW1ldGVycyB0byBpdCwgd2hlbiBjYWxsaW5nIGl0LiBZb3UgY2FuIGRvIHRoaXMgdXNpbmcgdGhpcyBwYXJhbWV0ZXIg4oCTIHNlZSBleGFtcGxlcyBmb3IgZGV0YWlscy4gUGxlYXNlIG5vdGUsIHRoYXQgdGhpcyBwYXJhbWV0ZXIgd2lsbCBoYXZlIG5vIGVmZmVjdCwgaWYgeW91IHVzZSB0aGUgZGVmYXVsdCBzY3JvbGxpbmcgZnVuY3Rpb24uXHJcblx0XHQgKiBAcmV0dXJucyB7Q29udHJvbGxlcn0gUGFyZW50IG9iamVjdCBmb3IgY2hhaW5pbmcuXHJcblx0XHQgKi9cclxuXHRcdHRoaXMuc2Nyb2xsVG8gPSBmdW5jdGlvbiAoc2Nyb2xsVGFyZ2V0LCBhZGRpdGlvbmFsUGFyYW1ldGVyKSB7XHJcblx0XHRcdGlmIChfdXRpbC50eXBlLk51bWJlcihzY3JvbGxUYXJnZXQpKSB7IC8vIGV4Y2VjdXRlXHJcblx0XHRcdFx0c2V0U2Nyb2xsUG9zLmNhbGwoX29wdGlvbnMuY29udGFpbmVyLCBzY3JvbGxUYXJnZXQsIGFkZGl0aW9uYWxQYXJhbWV0ZXIpO1xyXG5cdFx0XHR9IGVsc2UgaWYgKHNjcm9sbFRhcmdldCBpbnN0YW5jZW9mIFNjcm9sbE1hZ2ljLlNjZW5lKSB7IC8vIHNjcm9sbCB0byBzY2VuZVxyXG5cdFx0XHRcdGlmIChzY3JvbGxUYXJnZXQuY29udHJvbGxlcigpID09PSBDb250cm9sbGVyKSB7IC8vIGNoZWNrIGlmIHRoZSBjb250cm9sbGVyIGlzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHNjZW5lXHJcblx0XHRcdFx0XHRDb250cm9sbGVyLnNjcm9sbFRvKHNjcm9sbFRhcmdldC5zY3JvbGxPZmZzZXQoKSwgYWRkaXRpb25hbFBhcmFtZXRlcik7XHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdGxvZygyLCBcInNjcm9sbFRvKCk6IFRoZSBzdXBwbGllZCBzY2VuZSBkb2VzIG5vdCBiZWxvbmcgdG8gdGhpcyBjb250cm9sbGVyLiBTY3JvbGwgY2FuY2VsbGVkLlwiLCBzY3JvbGxUYXJnZXQpO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fSBlbHNlIGlmIChfdXRpbC50eXBlLkZ1bmN0aW9uKHNjcm9sbFRhcmdldCkpIHsgLy8gYXNzaWduIG5ldyBzY3JvbGwgZnVuY3Rpb25cclxuXHRcdFx0XHRzZXRTY3JvbGxQb3MgPSBzY3JvbGxUYXJnZXQ7XHJcblx0XHRcdH0gZWxzZSB7IC8vIHNjcm9sbCB0byBlbGVtZW50XHJcblx0XHRcdFx0dmFyIGVsZW0gPSBfdXRpbC5nZXQuZWxlbWVudHMoc2Nyb2xsVGFyZ2V0KVswXTtcclxuXHRcdFx0XHRpZiAoZWxlbSkge1xyXG5cdFx0XHRcdFx0Ly8gaWYgcGFyZW50IGlzIHBpbiBzcGFjZXIsIHVzZSBzcGFjZXIgcG9zaXRpb24gaW5zdGVhZCBzbyBjb3JyZWN0IHN0YXJ0IHBvc2l0aW9uIGlzIHJldHVybmVkIGZvciBwaW5uZWQgZWxlbWVudHMuXHJcblx0XHRcdFx0XHR3aGlsZSAoZWxlbS5wYXJlbnROb2RlLmhhc0F0dHJpYnV0ZShQSU5fU1BBQ0VSX0FUVFJJQlVURSkpIHtcclxuXHRcdFx0XHRcdFx0ZWxlbSA9IGVsZW0ucGFyZW50Tm9kZTtcclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR2YXJcclxuXHRcdFx0XHRcdFx0cGFyYW0gPSBfb3B0aW9ucy52ZXJ0aWNhbCA/IFwidG9wXCIgOiBcImxlZnRcIiwgLy8gd2hpY2ggcGFyYW0gaXMgb2YgaW50ZXJlc3QgP1xyXG5cdFx0XHRcdFx0XHRjb250YWluZXJPZmZzZXQgPSBfdXRpbC5nZXQub2Zmc2V0KF9vcHRpb25zLmNvbnRhaW5lciksIC8vIGNvbnRhaW5lciBwb3NpdGlvbiBpcyBuZWVkZWQgYmVjYXVzZSBlbGVtZW50IG9mZnNldCBpcyByZXR1cm5lZCBpbiByZWxhdGlvbiB0byBkb2N1bWVudCwgbm90IGluIHJlbGF0aW9uIHRvIGNvbnRhaW5lci5cclxuXHRcdFx0XHRcdFx0ZWxlbWVudE9mZnNldCA9IF91dGlsLmdldC5vZmZzZXQoZWxlbSk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCFfaXNEb2N1bWVudCkgeyAvLyBjb250YWluZXIgaXMgbm90IHRoZSBkb2N1bWVudCByb290LCBzbyBzdWJzdHJhY3Qgc2Nyb2xsIFBvc2l0aW9uIHRvIGdldCBjb3JyZWN0IHRyaWdnZXIgZWxlbWVudCBwb3NpdGlvbiByZWxhdGl2ZSB0byBzY3JvbGxjb250ZW50XHJcblx0XHRcdFx0XHRcdGNvbnRhaW5lck9mZnNldFtwYXJhbV0gLT0gQ29udHJvbGxlci5zY3JvbGxQb3MoKTtcclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRDb250cm9sbGVyLnNjcm9sbFRvKGVsZW1lbnRPZmZzZXRbcGFyYW1dIC0gY29udGFpbmVyT2Zmc2V0W3BhcmFtXSwgYWRkaXRpb25hbFBhcmFtZXRlcik7XHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdGxvZygyLCBcInNjcm9sbFRvKCk6IFRoZSBzdXBwbGllZCBhcmd1bWVudCBpcyBpbnZhbGlkLiBTY3JvbGwgY2FuY2VsbGVkLlwiLCBzY3JvbGxUYXJnZXQpO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0XHRyZXR1cm4gQ29udHJvbGxlcjtcclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiAqKkdldCoqIHRoZSBjdXJyZW50IHNjcm9sbFBvc2l0aW9uIG9yICoqU2V0KiogYSBuZXcgbWV0aG9kIHRvIGNhbGN1bGF0ZSBpdC4gIFxyXG5cdFx0ICogLT4gKipHRVQqKjpcclxuXHRcdCAqIFdoZW4gdXNlZCBhcyBhIGdldHRlciB0aGlzIGZ1bmN0aW9uIHdpbGwgcmV0dXJuIHRoZSBjdXJyZW50IHNjcm9sbCBwb3NpdGlvbi4gIFxyXG5cdFx0ICogVG8gZ2V0IGEgY2FjaGVkIHZhbHVlIHVzZSBDb250cm9sbGVyLmluZm8oXCJzY3JvbGxQb3NcIiksIHdoaWNoIHdpbGwgYmUgdXBkYXRlZCBpbiB0aGUgdXBkYXRlIGN5Y2xlLiAgXHJcblx0XHQgKiBGb3IgdmVydGljYWwgY29udHJvbGxlcnMgaXQgd2lsbCByZXR1cm4gdGhlIHRvcCBzY3JvbGwgb2Zmc2V0IGFuZCBmb3IgaG9yaXpvbnRhbCBhcHBsaWNhdGlvbnMgaXQgd2lsbCByZXR1cm4gdGhlIGxlZnQgb2Zmc2V0LlxyXG5cdFx0ICpcclxuXHRcdCAqIC0+ICoqU0VUKio6XHJcblx0XHQgKiBXaGVuIHVzZWQgYXMgYSBzZXR0ZXIgdGhpcyBtZXRob2QgcHJvZGVzIGEgd2F5IHRvIHBlcm1hbmVudGx5IG92ZXJ3cml0ZSB0aGUgY29udHJvbGxlcidzIHNjcm9sbCBwb3NpdGlvbiBjYWxjdWxhdGlvbi4gIFxyXG5cdFx0ICogQSB0eXBpY2FsIHVzZWNhc2UgaXMgd2hlbiB0aGUgc2Nyb2xsIHBvc2l0aW9uIGlzIG5vdCByZWZsZWN0ZWQgYnkgdGhlIGNvbnRhaW5lcnMgc2Nyb2xsVG9wIG9yIHNjcm9sbExlZnQgdmFsdWVzLCBidXQgZm9yIGV4YW1wbGUgYnkgdGhlIGlubmVyIG9mZnNldCBvZiBhIGNoaWxkIGNvbnRhaW5lci4gIFxyXG5cdFx0ICogTW92aW5nIGEgY2hpbGQgY29udGFpbmVyIGluc2lkZSBhIHBhcmVudCBpcyBhIGNvbW1vbmx5IHVzZWQgbWV0aG9kIGZvciBzZXZlcmFsIHNjcm9sbGluZyBmcmFtZXdvcmtzLCBpbmNsdWRpbmcgaVNjcm9sbC4gIFxyXG5cdFx0ICogQnkgcHJvdmlkaW5nIGFuIGFsdGVybmF0ZSBjYWxjdWxhdGlvbiBmdW5jdGlvbiB5b3UgY2FuIG1ha2Ugc3VyZSBTY3JvbGxNYWdpYyByZWNlaXZlcyB0aGUgY29ycmVjdCBzY3JvbGwgcG9zaXRpb24uICBcclxuXHRcdCAqIFBsZWFzZSBhbHNvIGJlYXIgaW4gbWluZCB0aGF0IHlvdXIgZnVuY3Rpb24gc2hvdWxkIHJldHVybiB5IHZhbHVlcyBmb3IgdmVydGljYWwgc2Nyb2xscyBhbiB4IGZvciBob3Jpem9udGFscy5cclxuXHRcdCAqXHJcblx0XHQgKiBUbyBjaGFuZ2UgdGhlIGN1cnJlbnQgc2Nyb2xsIHBvc2l0aW9uIHBsZWFzZSB1c2UgYENvbnRyb2xsZXIuc2Nyb2xsVG8oKWAuXHJcblx0XHQgKiBAcHVibGljXHJcblx0XHQgKlxyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIC8vIGdldCB0aGUgY3VycmVudCBzY3JvbGwgUG9zaXRpb25cclxuXHRcdCAqIHZhciBzY3JvbGxQb3MgPSBjb250cm9sbGVyLnNjcm9sbFBvcygpO1xyXG5cdFx0ICpcclxuXHRcdCAqIC8vIHNldCBhIG5ldyBzY3JvbGwgcG9zaXRpb24gY2FsY3VsYXRpb24gbWV0aG9kXHJcblx0XHQgKiBjb250cm9sbGVyLnNjcm9sbFBvcyhmdW5jdGlvbiAoKSB7XHJcblx0XHQgKlx0cmV0dXJuIHRoaXMuaW5mbyhcInZlcnRpY2FsXCIpID8gLW15Y2hpbGRjb250YWluZXIueSA6IC1teWNoaWxkY29udGFpbmVyLnhcclxuXHRcdCAqIH0pO1xyXG5cdFx0ICpcclxuXHRcdCAqIEBwYXJhbSB7ZnVuY3Rpb259IFtzY3JvbGxQb3NNZXRob2RdIC0gVGhlIGZ1bmN0aW9uIHRvIGJlIHVzZWQgZm9yIHRoZSBzY3JvbGwgcG9zaXRpb24gY2FsY3VsYXRpb24gb2YgdGhlIGNvbnRhaW5lci5cclxuXHRcdCAqIEByZXR1cm5zIHsobnVtYmVyfENvbnRyb2xsZXIpfSBDdXJyZW50IHNjcm9sbCBwb3NpdGlvbiBvciBwYXJlbnQgb2JqZWN0IGZvciBjaGFpbmluZy5cclxuXHRcdCAqL1xyXG5cdFx0dGhpcy5zY3JvbGxQb3MgPSBmdW5jdGlvbiAoc2Nyb2xsUG9zTWV0aG9kKSB7XHJcblx0XHRcdGlmICghYXJndW1lbnRzLmxlbmd0aCkgeyAvLyBnZXRcclxuXHRcdFx0XHRyZXR1cm4gZ2V0U2Nyb2xsUG9zLmNhbGwoQ29udHJvbGxlcik7XHJcblx0XHRcdH0gZWxzZSB7IC8vIHNldFxyXG5cdFx0XHRcdGlmIChfdXRpbC50eXBlLkZ1bmN0aW9uKHNjcm9sbFBvc01ldGhvZCkpIHtcclxuXHRcdFx0XHRcdGdldFNjcm9sbFBvcyA9IHNjcm9sbFBvc01ldGhvZDtcclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0bG9nKDIsIFwiUHJvdmlkZWQgdmFsdWUgZm9yIG1ldGhvZCAnc2Nyb2xsUG9zJyBpcyBub3QgYSBmdW5jdGlvbi4gVG8gY2hhbmdlIHRoZSBjdXJyZW50IHNjcm9sbCBwb3NpdGlvbiB1c2UgJ3Njcm9sbFRvKCknLlwiKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdFx0cmV0dXJuIENvbnRyb2xsZXI7XHJcblx0XHR9O1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogKipHZXQqKiBhbGwgaW5mb3Mgb3Igb25lIGluIHBhcnRpY3VsYXIgYWJvdXQgdGhlIGNvbnRyb2xsZXIuXHJcblx0XHQgKiBAcHVibGljXHJcblx0XHQgKiBAZXhhbXBsZVxyXG5cdFx0ICogLy8gcmV0dXJucyB0aGUgY3VycmVudCBzY3JvbGwgcG9zaXRpb24gKG51bWJlcilcclxuXHRcdCAqIHZhciBzY3JvbGxQb3MgPSBjb250cm9sbGVyLmluZm8oXCJzY3JvbGxQb3NcIik7XHJcblx0XHQgKlxyXG5cdFx0ICogLy8gcmV0dXJucyBhbGwgaW5mb3MgYXMgYW4gb2JqZWN0XHJcblx0XHQgKiB2YXIgaW5mb3MgPSBjb250cm9sbGVyLmluZm8oKTtcclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0ge3N0cmluZ30gW2Fib3V0XSAtIElmIHBhc3NlZCBvbmx5IHRoaXMgaW5mbyB3aWxsIGJlIHJldHVybmVkIGluc3RlYWQgb2YgYW4gb2JqZWN0IGNvbnRhaW5pbmcgYWxsLiAgXHJcblx0XHQgXHRcdFx0XHRcdFx0XHQgVmFsaWQgb3B0aW9ucyBhcmU6XHJcblx0XHQgXHRcdFx0XHRcdFx0XHQgKiogYFwic2l6ZVwiYCA9PiB0aGUgY3VycmVudCB2aWV3cG9ydCBzaXplIG9mIHRoZSBjb250YWluZXJcclxuXHRcdCBcdFx0XHRcdFx0XHRcdCAqKiBgXCJ2ZXJ0aWNhbFwiYCA9PiB0cnVlIGlmIHZlcnRpY2FsIHNjcm9sbGluZywgb3RoZXJ3aXNlIGZhbHNlXHJcblx0XHQgXHRcdFx0XHRcdFx0XHQgKiogYFwic2Nyb2xsUG9zXCJgID0+IHRoZSBjdXJyZW50IHNjcm9sbCBwb3NpdGlvblxyXG5cdFx0IFx0XHRcdFx0XHRcdFx0ICoqIGBcInNjcm9sbERpcmVjdGlvblwiYCA9PiB0aGUgbGFzdCBrbm93biBkaXJlY3Rpb24gb2YgdGhlIHNjcm9sbFxyXG5cdFx0IFx0XHRcdFx0XHRcdFx0ICoqIGBcImNvbnRhaW5lclwiYCA9PiB0aGUgY29udGFpbmVyIGVsZW1lbnRcclxuXHRcdCBcdFx0XHRcdFx0XHRcdCAqKiBgXCJpc0RvY3VtZW50XCJgID0+IHRydWUgaWYgY29udGFpbmVyIGVsZW1lbnQgaXMgdGhlIGRvY3VtZW50LlxyXG5cdFx0ICogQHJldHVybnMgeyhtaXhlZHxvYmplY3QpfSBUaGUgcmVxdWVzdGVkIGluZm8ocykuXHJcblx0XHQgKi9cclxuXHRcdHRoaXMuaW5mbyA9IGZ1bmN0aW9uIChhYm91dCkge1xyXG5cdFx0XHR2YXIgdmFsdWVzID0ge1xyXG5cdFx0XHRcdHNpemU6IF92aWV3UG9ydFNpemUsIC8vIGNvbnRhaW5zIGhlaWdodCBvciB3aWR0aCAoaW4gcmVnYXJkIHRvIG9yaWVudGF0aW9uKTtcclxuXHRcdFx0XHR2ZXJ0aWNhbDogX29wdGlvbnMudmVydGljYWwsXHJcblx0XHRcdFx0c2Nyb2xsUG9zOiBfc2Nyb2xsUG9zLFxyXG5cdFx0XHRcdHNjcm9sbERpcmVjdGlvbjogX3Njcm9sbERpcmVjdGlvbixcclxuXHRcdFx0XHRjb250YWluZXI6IF9vcHRpb25zLmNvbnRhaW5lcixcclxuXHRcdFx0XHRpc0RvY3VtZW50OiBfaXNEb2N1bWVudFxyXG5cdFx0XHR9O1xyXG5cdFx0XHRpZiAoIWFyZ3VtZW50cy5sZW5ndGgpIHsgLy8gZ2V0IGFsbCBhcyBhbiBvYmplY3RcclxuXHRcdFx0XHRyZXR1cm4gdmFsdWVzO1xyXG5cdFx0XHR9IGVsc2UgaWYgKHZhbHVlc1thYm91dF0gIT09IHVuZGVmaW5lZCkge1xyXG5cdFx0XHRcdHJldHVybiB2YWx1ZXNbYWJvdXRdO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdGxvZygxLCBcIkVSUk9SOiBvcHRpb24gXFxcIlwiICsgYWJvdXQgKyBcIlxcXCIgaXMgbm90IGF2YWlsYWJsZVwiKTtcclxuXHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdH1cclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiAqKkdldCoqIG9yICoqU2V0KiogdGhlIGN1cnJlbnQgbG9nbGV2ZWwgb3B0aW9uIHZhbHVlLlxyXG5cdFx0ICogQHB1YmxpY1xyXG5cdFx0ICpcclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiAvLyBnZXQgdGhlIGN1cnJlbnQgdmFsdWVcclxuXHRcdCAqIHZhciBsb2dsZXZlbCA9IGNvbnRyb2xsZXIubG9nbGV2ZWwoKTtcclxuXHRcdCAqXHJcblx0XHQgKiAvLyBzZXQgYSBuZXcgdmFsdWVcclxuXHRcdCAqIGNvbnRyb2xsZXIubG9nbGV2ZWwoMyk7XHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIHtudW1iZXJ9IFtuZXdMb2dsZXZlbF0gLSBUaGUgbmV3IGxvZ2xldmVsIHNldHRpbmcgb2YgdGhlIENvbnRyb2xsZXIuIGBbMC0zXWBcclxuXHRcdCAqIEByZXR1cm5zIHsobnVtYmVyfENvbnRyb2xsZXIpfSBDdXJyZW50IGxvZ2xldmVsIG9yIHBhcmVudCBvYmplY3QgZm9yIGNoYWluaW5nLlxyXG5cdFx0ICovXHJcblx0XHR0aGlzLmxvZ2xldmVsID0gZnVuY3Rpb24gKG5ld0xvZ2xldmVsKSB7XHJcblx0XHRcdGlmICghYXJndW1lbnRzLmxlbmd0aCkgeyAvLyBnZXRcclxuXHRcdFx0XHRyZXR1cm4gX29wdGlvbnMubG9nbGV2ZWw7XHJcblx0XHRcdH0gZWxzZSBpZiAoX29wdGlvbnMubG9nbGV2ZWwgIT0gbmV3TG9nbGV2ZWwpIHsgLy8gc2V0XHJcblx0XHRcdFx0X29wdGlvbnMubG9nbGV2ZWwgPSBuZXdMb2dsZXZlbDtcclxuXHRcdFx0fVxyXG5cdFx0XHRyZXR1cm4gQ29udHJvbGxlcjtcclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiAqKkdldCoqIG9yICoqU2V0KiogdGhlIGN1cnJlbnQgZW5hYmxlZCBzdGF0ZSBvZiB0aGUgY29udHJvbGxlci4gIFxyXG5cdFx0ICogVGhpcyBjYW4gYmUgdXNlZCB0byBkaXNhYmxlIGFsbCBTY2VuZXMgY29ubmVjdGVkIHRvIHRoZSBjb250cm9sbGVyIHdpdGhvdXQgZGVzdHJveWluZyBvciByZW1vdmluZyB0aGVtLlxyXG5cdFx0ICogQHB1YmxpY1xyXG5cdFx0ICpcclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiAvLyBnZXQgdGhlIGN1cnJlbnQgdmFsdWVcclxuXHRcdCAqIHZhciBlbmFibGVkID0gY29udHJvbGxlci5lbmFibGVkKCk7XHJcblx0XHQgKlxyXG5cdFx0ICogLy8gZGlzYWJsZSB0aGUgY29udHJvbGxlclxyXG5cdFx0ICogY29udHJvbGxlci5lbmFibGVkKGZhbHNlKTtcclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0ge2Jvb2xlYW59IFtuZXdTdGF0ZV0gLSBUaGUgbmV3IGVuYWJsZWQgc3RhdGUgb2YgdGhlIGNvbnRyb2xsZXIgYHRydWVgIG9yIGBmYWxzZWAuXHJcblx0XHQgKiBAcmV0dXJucyB7KGJvb2xlYW58Q29udHJvbGxlcil9IEN1cnJlbnQgZW5hYmxlZCBzdGF0ZSBvciBwYXJlbnQgb2JqZWN0IGZvciBjaGFpbmluZy5cclxuXHRcdCAqL1xyXG5cdFx0dGhpcy5lbmFibGVkID0gZnVuY3Rpb24gKG5ld1N0YXRlKSB7XHJcblx0XHRcdGlmICghYXJndW1lbnRzLmxlbmd0aCkgeyAvLyBnZXRcclxuXHRcdFx0XHRyZXR1cm4gX2VuYWJsZWQ7XHJcblx0XHRcdH0gZWxzZSBpZiAoX2VuYWJsZWQgIT0gbmV3U3RhdGUpIHsgLy8gc2V0XHJcblx0XHRcdFx0X2VuYWJsZWQgPSAhIW5ld1N0YXRlO1xyXG5cdFx0XHRcdENvbnRyb2xsZXIudXBkYXRlU2NlbmUoX3NjZW5lT2JqZWN0cywgdHJ1ZSk7XHJcblx0XHRcdH1cclxuXHRcdFx0cmV0dXJuIENvbnRyb2xsZXI7XHJcblx0XHR9O1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogRGVzdHJveSB0aGUgQ29udHJvbGxlciwgYWxsIFNjZW5lcyBhbmQgZXZlcnl0aGluZy5cclxuXHRcdCAqIEBwdWJsaWNcclxuXHRcdCAqXHJcblx0XHQgKiBAZXhhbXBsZVxyXG5cdFx0ICogLy8gd2l0aG91dCByZXNldHRpbmcgdGhlIHNjZW5lc1xyXG5cdFx0ICogY29udHJvbGxlciA9IGNvbnRyb2xsZXIuZGVzdHJveSgpO1xyXG5cdFx0ICpcclxuXHRcdCAqIC8vIHdpdGggc2NlbmUgcmVzZXRcclxuXHRcdCAqIGNvbnRyb2xsZXIgPSBjb250cm9sbGVyLmRlc3Ryb3kodHJ1ZSk7XHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIHtib29sZWFufSBbcmVzZXRTY2VuZXM9ZmFsc2VdIC0gSWYgYHRydWVgIHRoZSBwaW5zIGFuZCB0d2VlbnMgKGlmIGV4aXN0ZW50KSBvZiBhbGwgc2NlbmVzIHdpbGwgYmUgcmVzZXQuXHJcblx0XHQgKiBAcmV0dXJucyB7bnVsbH0gTnVsbCB0byB1bnNldCBoYW5kbGVyIHZhcmlhYmxlcy5cclxuXHRcdCAqL1xyXG5cdFx0dGhpcy5kZXN0cm95ID0gZnVuY3Rpb24gKHJlc2V0U2NlbmVzKSB7XHJcblx0XHRcdHdpbmRvdy5jbGVhclRpbWVvdXQoX3JlZnJlc2hUaW1lb3V0KTtcclxuXHRcdFx0dmFyIGkgPSBfc2NlbmVPYmplY3RzLmxlbmd0aDtcclxuXHRcdFx0d2hpbGUgKGktLSkge1xyXG5cdFx0XHRcdF9zY2VuZU9iamVjdHNbaV0uZGVzdHJveShyZXNldFNjZW5lcyk7XHJcblx0XHRcdH1cclxuXHRcdFx0X29wdGlvbnMuY29udGFpbmVyLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJyZXNpemVcIiwgb25DaGFuZ2UpO1xyXG5cdFx0XHRfb3B0aW9ucy5jb250YWluZXIucmVtb3ZlRXZlbnRMaXN0ZW5lcihcInNjcm9sbFwiLCBvbkNoYW5nZSk7XHJcblx0XHRcdF91dGlsLmNBRihfdXBkYXRlVGltZW91dCk7XHJcblx0XHRcdGxvZygzLCBcImRlc3Ryb3llZCBcIiArIE5BTUVTUEFDRSArIFwiIChyZXNldDogXCIgKyAocmVzZXRTY2VuZXMgPyBcInRydWVcIiA6IFwiZmFsc2VcIikgKyBcIilcIik7XHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cdFx0fTtcclxuXHJcblx0XHQvLyBJTklUXHJcblx0XHRjb25zdHJ1Y3QoKTtcclxuXHRcdHJldHVybiBDb250cm9sbGVyO1xyXG5cdH07XHJcblxyXG5cdC8vIHN0b3JlIHBhZ2V3aWRlIGNvbnRyb2xsZXIgb3B0aW9uc1xyXG5cdHZhciBDT05UUk9MTEVSX09QVElPTlMgPSB7XHJcblx0XHRkZWZhdWx0czoge1xyXG5cdFx0XHRjb250YWluZXI6IHdpbmRvdyxcclxuXHRcdFx0dmVydGljYWw6IHRydWUsXHJcblx0XHRcdGdsb2JhbFNjZW5lT3B0aW9uczoge30sXHJcblx0XHRcdGxvZ2xldmVsOiAyLFxyXG5cdFx0XHRyZWZyZXNoSW50ZXJ2YWw6IDEwMFxyXG5cdFx0fVxyXG5cdH07XHJcblx0LypcclxuXHQgKiBtZXRob2QgdXNlZCB0byBhZGQgYW4gb3B0aW9uIHRvIFNjcm9sbE1hZ2ljIFNjZW5lcy5cclxuXHQgKi9cclxuXHRTY3JvbGxNYWdpYy5Db250cm9sbGVyLmFkZE9wdGlvbiA9IGZ1bmN0aW9uIChuYW1lLCBkZWZhdWx0VmFsdWUpIHtcclxuXHRcdENPTlRST0xMRVJfT1BUSU9OUy5kZWZhdWx0c1tuYW1lXSA9IGRlZmF1bHRWYWx1ZTtcclxuXHR9O1xyXG5cdC8vIGluc3RhbmNlIGV4dGVuc2lvbiBmdW5jdGlvbiBmb3IgcGx1Z2luc1xyXG5cdFNjcm9sbE1hZ2ljLkNvbnRyb2xsZXIuZXh0ZW5kID0gZnVuY3Rpb24gKGV4dGVuc2lvbikge1xyXG5cdFx0dmFyIG9sZENsYXNzID0gdGhpcztcclxuXHRcdFNjcm9sbE1hZ2ljLkNvbnRyb2xsZXIgPSBmdW5jdGlvbiAoKSB7XHJcblx0XHRcdG9sZENsYXNzLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XHJcblx0XHRcdHRoaXMuJHN1cGVyID0gX3V0aWwuZXh0ZW5kKHt9LCB0aGlzKTsgLy8gY29weSBwYXJlbnQgc3RhdGVcclxuXHRcdFx0cmV0dXJuIGV4dGVuc2lvbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpIHx8IHRoaXM7XHJcblx0XHR9O1xyXG5cdFx0X3V0aWwuZXh0ZW5kKFNjcm9sbE1hZ2ljLkNvbnRyb2xsZXIsIG9sZENsYXNzKTsgLy8gY29weSBwcm9wZXJ0aWVzXHJcblx0XHRTY3JvbGxNYWdpYy5Db250cm9sbGVyLnByb3RvdHlwZSA9IG9sZENsYXNzLnByb3RvdHlwZTsgLy8gY29weSBwcm90b3R5cGVcclxuXHRcdFNjcm9sbE1hZ2ljLkNvbnRyb2xsZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gU2Nyb2xsTWFnaWMuQ29udHJvbGxlcjsgLy8gcmVzdG9yZSBjb25zdHJ1Y3RvclxyXG5cdH07XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBBIFNjZW5lIGRlZmluZXMgd2hlcmUgdGhlIGNvbnRyb2xsZXIgc2hvdWxkIHJlYWN0IGFuZCBob3cuXHJcblx0ICpcclxuXHQgKiBAY2xhc3NcclxuXHQgKlxyXG5cdCAqIEBleGFtcGxlXHJcblx0ICogLy8gY3JlYXRlIGEgc3RhbmRhcmQgc2NlbmUgYW5kIGFkZCBpdCB0byBhIGNvbnRyb2xsZXJcclxuXHQgKiBuZXcgU2Nyb2xsTWFnaWMuU2NlbmUoKVxyXG5cdCAqXHRcdC5hZGRUbyhjb250cm9sbGVyKTtcclxuXHQgKlxyXG5cdCAqIC8vIGNyZWF0ZSBhIHNjZW5lIHdpdGggY3VzdG9tIG9wdGlvbnMgYW5kIGFzc2lnbiBhIGhhbmRsZXIgdG8gaXQuXHJcblx0ICogdmFyIHNjZW5lID0gbmV3IFNjcm9sbE1hZ2ljLlNjZW5lKHtcclxuXHQgKiBcdFx0ZHVyYXRpb246IDEwMCxcclxuXHQgKlx0XHRvZmZzZXQ6IDIwMCxcclxuXHQgKlx0XHR0cmlnZ2VySG9vazogXCJvbkVudGVyXCIsXHJcblx0ICpcdFx0cmV2ZXJzZTogZmFsc2VcclxuXHQgKiB9KTtcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7b2JqZWN0fSBbb3B0aW9uc10gLSBPcHRpb25zIGZvciB0aGUgU2NlbmUuIFRoZSBvcHRpb25zIGNhbiBiZSB1cGRhdGVkIGF0IGFueSB0aW1lLiAgXHJcblx0IFx0XHRcdFx0XHRcdFx0ICAgSW5zdGVhZCBvZiBzZXR0aW5nIHRoZSBvcHRpb25zIGZvciBlYWNoIHNjZW5lIGluZGl2aWR1YWxseSB5b3UgY2FuIGFsc28gc2V0IHRoZW0gZ2xvYmFsbHkgaW4gdGhlIGNvbnRyb2xsZXIgYXMgdGhlIGNvbnRyb2xsZXJzIGBnbG9iYWxTY2VuZU9wdGlvbnNgIG9wdGlvbi4gVGhlIG9iamVjdCBhY2NlcHRzIHRoZSBzYW1lIHByb3BlcnRpZXMgYXMgdGhlIG9uZXMgYmVsb3cuICBcclxuXHQgXHRcdFx0XHRcdFx0XHQgICBXaGVuIGEgc2NlbmUgaXMgYWRkZWQgdG8gdGhlIGNvbnRyb2xsZXIgdGhlIG9wdGlvbnMgZGVmaW5lZCB1c2luZyB0aGUgU2NlbmUgY29uc3RydWN0b3Igd2lsbCBiZSBvdmVyd3JpdHRlbiBieSB0aG9zZSBzZXQgaW4gYGdsb2JhbFNjZW5lT3B0aW9uc2AuXHJcblx0ICogQHBhcmFtIHsobnVtYmVyfHN0cmluZ3xmdW5jdGlvbil9IFtvcHRpb25zLmR1cmF0aW9uPTBdIC0gVGhlIGR1cmF0aW9uIG9mIHRoZSBzY2VuZS4gXHJcblx0IFx0XHRcdFx0XHRQbGVhc2Ugc2VlIGBTY2VuZS5kdXJhdGlvbigpYCBmb3IgZGV0YWlscy5cclxuXHQgKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMub2Zmc2V0PTBdIC0gT2Zmc2V0IFZhbHVlIGZvciB0aGUgVHJpZ2dlciBQb3NpdGlvbi4gSWYgbm8gdHJpZ2dlckVsZW1lbnQgaXMgZGVmaW5lZCB0aGlzIHdpbGwgYmUgdGhlIHNjcm9sbCBkaXN0YW5jZSBmcm9tIHRoZSBzdGFydCBvZiB0aGUgcGFnZSwgYWZ0ZXIgd2hpY2ggdGhlIHNjZW5lIHdpbGwgc3RhcnQuXHJcblx0ICogQHBhcmFtIHsoc3RyaW5nfG9iamVjdCl9IFtvcHRpb25zLnRyaWdnZXJFbGVtZW50PW51bGxdIC0gU2VsZWN0b3Igb3IgRE9NIG9iamVjdCB0aGF0IGRlZmluZXMgdGhlIHN0YXJ0IG9mIHRoZSBzY2VuZS4gSWYgdW5kZWZpbmVkIHRoZSBzY2VuZSB3aWxsIHN0YXJ0IHJpZ2h0IGF0IHRoZSBzdGFydCBvZiB0aGUgcGFnZSAodW5sZXNzIGFuIG9mZnNldCBpcyBzZXQpLlxyXG5cdCAqIEBwYXJhbSB7KG51bWJlcnxzdHJpbmcpfSBbb3B0aW9ucy50cmlnZ2VySG9vaz1cIm9uQ2VudGVyXCJdIC0gQ2FuIGJlIGEgbnVtYmVyIGJldHdlZW4gMCBhbmQgMSBkZWZpbmluZyB0aGUgcG9zaXRpb24gb2YgdGhlIHRyaWdnZXIgSG9vayBpbiByZWxhdGlvbiB0byB0aGUgdmlld3BvcnQuICBcclxuXHQgXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICBDYW4gYWxzbyBiZSBkZWZpbmVkIHVzaW5nIGEgc3RyaW5nOlxyXG5cdCBcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICoqIGBcIm9uRW50ZXJcImAgPT4gYDFgXHJcblx0IFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgKiogYFwib25DZW50ZXJcImAgPT4gYDAuNWBcclxuXHQgXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICAqKiBgXCJvbkxlYXZlXCJgID0+IGAwYFxyXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMucmV2ZXJzZT10cnVlXSAtIFNob3VsZCB0aGUgc2NlbmUgcmV2ZXJzZSwgd2hlbiBzY3JvbGxpbmcgdXA/XHJcblx0ICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLmxvZ2xldmVsPTJdIC0gTG9nbGV2ZWwgZm9yIGRlYnVnZ2luZy4gTm90ZSB0aGF0IGxvZ2dpbmcgaXMgZGlzYWJsZWQgaW4gdGhlIG1pbmlmaWVkIHZlcnNpb24gb2YgU2Nyb2xsTWFnaWMuXHJcblx0IFx0XHRcdFx0XHRcdFx0XHRcdFx0ICAqKiBgMGAgPT4gc2lsZW50XHJcblx0IFx0XHRcdFx0XHRcdFx0XHRcdFx0ICAqKiBgMWAgPT4gZXJyb3JzXHJcblx0IFx0XHRcdFx0XHRcdFx0XHRcdFx0ICAqKiBgMmAgPT4gZXJyb3JzLCB3YXJuaW5nc1xyXG5cdCBcdFx0XHRcdFx0XHRcdFx0XHRcdCAgKiogYDNgID0+IGVycm9ycywgd2FybmluZ3MsIGRlYnVnaW5mb1xyXG5cdCAqIFxyXG5cdCAqL1xyXG5cdFNjcm9sbE1hZ2ljLlNjZW5lID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcclxuXHJcblx0XHQvKlxyXG5cdFx0ICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0ICogc2V0dGluZ3NcclxuXHRcdCAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdCAqL1xyXG5cclxuXHRcdHZhclxyXG5cdFx0XHROQU1FU1BBQ0UgPSAnU2Nyb2xsTWFnaWMuU2NlbmUnLFxyXG5cdFx0XHRTQ0VORV9TVEFURV9CRUZPUkUgPSAnQkVGT1JFJyxcclxuXHRcdFx0U0NFTkVfU1RBVEVfRFVSSU5HID0gJ0RVUklORycsXHJcblx0XHRcdFNDRU5FX1NUQVRFX0FGVEVSID0gJ0FGVEVSJyxcclxuXHRcdFx0REVGQVVMVF9PUFRJT05TID0gU0NFTkVfT1BUSU9OUy5kZWZhdWx0cztcclxuXHJcblx0XHQvKlxyXG5cdFx0ICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0ICogcHJpdmF0ZSB2YXJzXHJcblx0XHQgKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHQgKi9cclxuXHJcblx0XHR2YXJcclxuXHRcdFx0U2NlbmUgPSB0aGlzLFxyXG5cdFx0XHRfb3B0aW9ucyA9IF91dGlsLmV4dGVuZCh7fSwgREVGQVVMVF9PUFRJT05TLCBvcHRpb25zKSxcclxuXHRcdFx0X3N0YXRlID0gU0NFTkVfU1RBVEVfQkVGT1JFLFxyXG5cdFx0XHRfcHJvZ3Jlc3MgPSAwLFxyXG5cdFx0XHRfc2Nyb2xsT2Zmc2V0ID0ge1xyXG5cdFx0XHRcdHN0YXJ0OiAwLFxyXG5cdFx0XHRcdGVuZDogMFxyXG5cdFx0XHR9LCAvLyByZWZsZWN0cyB0aGUgY29udHJvbGxlcnMncyBzY3JvbGwgcG9zaXRpb24gZm9yIHRoZSBzdGFydCBhbmQgZW5kIG9mIHRoZSBzY2VuZSByZXNwZWN0aXZlbHlcclxuXHRcdFx0X3RyaWdnZXJQb3MgPSAwLFxyXG5cdFx0XHRfZW5hYmxlZCA9IHRydWUsXHJcblx0XHRcdF9kdXJhdGlvblVwZGF0ZU1ldGhvZCxcclxuXHRcdFx0X2NvbnRyb2xsZXI7XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBJbnRlcm5hbCBjb25zdHJ1Y3RvciBmdW5jdGlvbiBvZiB0aGUgU2Nyb2xsTWFnaWMgU2NlbmVcclxuXHRcdCAqIEBwcml2YXRlXHJcblx0XHQgKi9cclxuXHRcdHZhciBjb25zdHJ1Y3QgPSBmdW5jdGlvbiAoKSB7XHJcblx0XHRcdGZvciAodmFyIGtleSBpbiBfb3B0aW9ucykgeyAvLyBjaGVjayBzdXBwbGllZCBvcHRpb25zXHJcblx0XHRcdFx0aWYgKCFERUZBVUxUX09QVElPTlMuaGFzT3duUHJvcGVydHkoa2V5KSkge1xyXG5cdFx0XHRcdFx0bG9nKDIsIFwiV0FSTklORzogVW5rbm93biBvcHRpb24gXFxcIlwiICsga2V5ICsgXCJcXFwiXCIpO1xyXG5cdFx0XHRcdFx0ZGVsZXRlIF9vcHRpb25zW2tleV07XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHRcdC8vIGFkZCBnZXR0ZXJzL3NldHRlcnMgZm9yIGFsbCBwb3NzaWJsZSBvcHRpb25zXHJcblx0XHRcdGZvciAodmFyIG9wdGlvbk5hbWUgaW4gREVGQVVMVF9PUFRJT05TKSB7XHJcblx0XHRcdFx0YWRkU2NlbmVPcHRpb24ob3B0aW9uTmFtZSk7XHJcblx0XHRcdH1cclxuXHRcdFx0Ly8gdmFsaWRhdGUgYWxsIG9wdGlvbnNcclxuXHRcdFx0dmFsaWRhdGVPcHRpb24oKTtcclxuXHRcdH07XHJcblxyXG5cdFx0LypcclxuXHRcdCAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdCAqIEV2ZW50IE1hbmFnZW1lbnRcclxuXHRcdCAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdCAqL1xyXG5cclxuXHRcdHZhciBfbGlzdGVuZXJzID0ge307XHJcblx0XHQvKipcclxuXHRcdCAqIFNjZW5lIHN0YXJ0IGV2ZW50LiAgXHJcblx0XHQgKiBGaXJlcyB3aGVuZXZlciB0aGUgc2Nyb2xsIHBvc2l0aW9uIGl0cyB0aGUgc3RhcnRpbmcgcG9pbnQgb2YgdGhlIHNjZW5lLiAgXHJcblx0XHQgKiBJdCB3aWxsIGFsc28gZmlyZSB3aGVuIHNjcm9sbGluZyBiYWNrIHVwIGdvaW5nIG92ZXIgdGhlIHN0YXJ0IHBvc2l0aW9uIG9mIHRoZSBzY2VuZS4gSWYgeW91IHdhbnQgc29tZXRoaW5nIHRvIGhhcHBlbiBvbmx5IHdoZW4gc2Nyb2xsaW5nIGRvd24vcmlnaHQsIHVzZSB0aGUgc2Nyb2xsRGlyZWN0aW9uIHBhcmFtZXRlciBwYXNzZWQgdG8gdGhlIGNhbGxiYWNrLlxyXG5cdFx0ICpcclxuXHRcdCAqIEZvciBkZXRhaWxzIG9uIHRoaXMgZXZlbnQgYW5kIHRoZSBvcmRlciBpbiB3aGljaCBpdCBpcyBmaXJlZCwgcGxlYXNlIHJldmlldyB0aGUge0BsaW5rIFNjZW5lLnByb2dyZXNzfSBtZXRob2QuXHJcblx0XHQgKlxyXG5cdFx0ICogQGV2ZW50IFNjcm9sbE1hZ2ljLlNjZW5lI3N0YXJ0XHJcblx0XHQgKlxyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIHNjZW5lLm9uKFwic3RhcnRcIiwgZnVuY3Rpb24gKGV2ZW50KSB7XHJcblx0XHQgKiBcdGNvbnNvbGUubG9nKFwiSGl0IHN0YXJ0IHBvaW50IG9mIHNjZW5lLlwiKTtcclxuXHRcdCAqIH0pO1xyXG5cdFx0ICpcclxuXHRcdCAqIEBwcm9wZXJ0eSB7b2JqZWN0fSBldmVudCAtIFRoZSBldmVudCBPYmplY3QgcGFzc2VkIHRvIGVhY2ggY2FsbGJhY2tcclxuXHRcdCAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBldmVudC50eXBlIC0gVGhlIG5hbWUgb2YgdGhlIGV2ZW50XHJcblx0XHQgKiBAcHJvcGVydHkge1NjZW5lfSBldmVudC50YXJnZXQgLSBUaGUgU2NlbmUgb2JqZWN0IHRoYXQgdHJpZ2dlcmVkIHRoaXMgZXZlbnRcclxuXHRcdCAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBldmVudC5wcm9ncmVzcyAtIFJlZmxlY3RzIHRoZSBjdXJyZW50IHByb2dyZXNzIG9mIHRoZSBzY2VuZVxyXG5cdFx0ICogQHByb3BlcnR5IHtzdHJpbmd9IGV2ZW50LnN0YXRlIC0gVGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHNjZW5lIGBcIkJFRk9SRVwiYCBvciBgXCJEVVJJTkdcImBcclxuXHRcdCAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBldmVudC5zY3JvbGxEaXJlY3Rpb24gLSBJbmRpY2F0ZXMgd2hpY2ggd2F5IHdlIGFyZSBzY3JvbGxpbmcgYFwiUEFVU0VEXCJgLCBgXCJGT1JXQVJEXCJgIG9yIGBcIlJFVkVSU0VcImBcclxuXHRcdCAqL1xyXG5cdFx0LyoqXHJcblx0XHQgKiBTY2VuZSBlbmQgZXZlbnQuICBcclxuXHRcdCAqIEZpcmVzIHdoZW5ldmVyIHRoZSBzY3JvbGwgcG9zaXRpb24gaXRzIHRoZSBlbmRpbmcgcG9pbnQgb2YgdGhlIHNjZW5lLiAgXHJcblx0XHQgKiBJdCB3aWxsIGFsc28gZmlyZSB3aGVuIHNjcm9sbGluZyBiYWNrIHVwIGZyb20gYWZ0ZXIgdGhlIHNjZW5lIGFuZCBnb2luZyBvdmVyIGl0cyBlbmQgcG9zaXRpb24uIElmIHlvdSB3YW50IHNvbWV0aGluZyB0byBoYXBwZW4gb25seSB3aGVuIHNjcm9sbGluZyBkb3duL3JpZ2h0LCB1c2UgdGhlIHNjcm9sbERpcmVjdGlvbiBwYXJhbWV0ZXIgcGFzc2VkIHRvIHRoZSBjYWxsYmFjay5cclxuXHRcdCAqXHJcblx0XHQgKiBGb3IgZGV0YWlscyBvbiB0aGlzIGV2ZW50IGFuZCB0aGUgb3JkZXIgaW4gd2hpY2ggaXQgaXMgZmlyZWQsIHBsZWFzZSByZXZpZXcgdGhlIHtAbGluayBTY2VuZS5wcm9ncmVzc30gbWV0aG9kLlxyXG5cdFx0ICpcclxuXHRcdCAqIEBldmVudCBTY3JvbGxNYWdpYy5TY2VuZSNlbmRcclxuXHRcdCAqXHJcblx0XHQgKiBAZXhhbXBsZVxyXG5cdFx0ICogc2NlbmUub24oXCJlbmRcIiwgZnVuY3Rpb24gKGV2ZW50KSB7XHJcblx0XHQgKiBcdGNvbnNvbGUubG9nKFwiSGl0IGVuZCBwb2ludCBvZiBzY2VuZS5cIik7XHJcblx0XHQgKiB9KTtcclxuXHRcdCAqXHJcblx0XHQgKiBAcHJvcGVydHkge29iamVjdH0gZXZlbnQgLSBUaGUgZXZlbnQgT2JqZWN0IHBhc3NlZCB0byBlYWNoIGNhbGxiYWNrXHJcblx0XHQgKiBAcHJvcGVydHkge3N0cmluZ30gZXZlbnQudHlwZSAtIFRoZSBuYW1lIG9mIHRoZSBldmVudFxyXG5cdFx0ICogQHByb3BlcnR5IHtTY2VuZX0gZXZlbnQudGFyZ2V0IC0gVGhlIFNjZW5lIG9iamVjdCB0aGF0IHRyaWdnZXJlZCB0aGlzIGV2ZW50XHJcblx0XHQgKiBAcHJvcGVydHkge251bWJlcn0gZXZlbnQucHJvZ3Jlc3MgLSBSZWZsZWN0cyB0aGUgY3VycmVudCBwcm9ncmVzcyBvZiB0aGUgc2NlbmVcclxuXHRcdCAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBldmVudC5zdGF0ZSAtIFRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBzY2VuZSBgXCJEVVJJTkdcImAgb3IgYFwiQUZURVJcImBcclxuXHRcdCAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBldmVudC5zY3JvbGxEaXJlY3Rpb24gLSBJbmRpY2F0ZXMgd2hpY2ggd2F5IHdlIGFyZSBzY3JvbGxpbmcgYFwiUEFVU0VEXCJgLCBgXCJGT1JXQVJEXCJgIG9yIGBcIlJFVkVSU0VcImBcclxuXHRcdCAqL1xyXG5cdFx0LyoqXHJcblx0XHQgKiBTY2VuZSBlbnRlciBldmVudC4gIFxyXG5cdFx0ICogRmlyZXMgd2hlbmV2ZXIgdGhlIHNjZW5lIGVudGVycyB0aGUgXCJEVVJJTkdcIiBzdGF0ZS4gIFxyXG5cdFx0ICogS2VlcCBpbiBtaW5kIHRoYXQgaXQgZG9lc24ndCBtYXR0ZXIgaWYgdGhlIHNjZW5lIHBsYXlzIGZvcndhcmQgb3IgYmFja3dhcmQ6IFRoaXMgZXZlbnQgYWx3YXlzIGZpcmVzIHdoZW4gdGhlIHNjZW5lIGVudGVycyBpdHMgYWN0aXZlIHNjcm9sbCB0aW1lZnJhbWUsIHJlZ2FyZGxlc3Mgb2YgdGhlIHNjcm9sbC1kaXJlY3Rpb24uXHJcblx0XHQgKlxyXG5cdFx0ICogRm9yIGRldGFpbHMgb24gdGhpcyBldmVudCBhbmQgdGhlIG9yZGVyIGluIHdoaWNoIGl0IGlzIGZpcmVkLCBwbGVhc2UgcmV2aWV3IHRoZSB7QGxpbmsgU2NlbmUucHJvZ3Jlc3N9IG1ldGhvZC5cclxuXHRcdCAqXHJcblx0XHQgKiBAZXZlbnQgU2Nyb2xsTWFnaWMuU2NlbmUjZW50ZXJcclxuXHRcdCAqXHJcblx0XHQgKiBAZXhhbXBsZVxyXG5cdFx0ICogc2NlbmUub24oXCJlbnRlclwiLCBmdW5jdGlvbiAoZXZlbnQpIHtcclxuXHRcdCAqIFx0Y29uc29sZS5sb2coXCJTY2VuZSBlbnRlcmVkLlwiKTtcclxuXHRcdCAqIH0pO1xyXG5cdFx0ICpcclxuXHRcdCAqIEBwcm9wZXJ0eSB7b2JqZWN0fSBldmVudCAtIFRoZSBldmVudCBPYmplY3QgcGFzc2VkIHRvIGVhY2ggY2FsbGJhY2tcclxuXHRcdCAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBldmVudC50eXBlIC0gVGhlIG5hbWUgb2YgdGhlIGV2ZW50XHJcblx0XHQgKiBAcHJvcGVydHkge1NjZW5lfSBldmVudC50YXJnZXQgLSBUaGUgU2NlbmUgb2JqZWN0IHRoYXQgdHJpZ2dlcmVkIHRoaXMgZXZlbnRcclxuXHRcdCAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBldmVudC5wcm9ncmVzcyAtIFJlZmxlY3RzIHRoZSBjdXJyZW50IHByb2dyZXNzIG9mIHRoZSBzY2VuZVxyXG5cdFx0ICogQHByb3BlcnR5IHtzdHJpbmd9IGV2ZW50LnN0YXRlIC0gVGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHNjZW5lIC0gYWx3YXlzIGBcIkRVUklOR1wiYFxyXG5cdFx0ICogQHByb3BlcnR5IHtzdHJpbmd9IGV2ZW50LnNjcm9sbERpcmVjdGlvbiAtIEluZGljYXRlcyB3aGljaCB3YXkgd2UgYXJlIHNjcm9sbGluZyBgXCJQQVVTRURcImAsIGBcIkZPUldBUkRcImAgb3IgYFwiUkVWRVJTRVwiYFxyXG5cdFx0ICovXHJcblx0XHQvKipcclxuXHRcdCAqIFNjZW5lIGxlYXZlIGV2ZW50LiAgXHJcblx0XHQgKiBGaXJlcyB3aGVuZXZlciB0aGUgc2NlbmUncyBzdGF0ZSBnb2VzIGZyb20gXCJEVVJJTkdcIiB0byBlaXRoZXIgXCJCRUZPUkVcIiBvciBcIkFGVEVSXCIuICBcclxuXHRcdCAqIEtlZXAgaW4gbWluZCB0aGF0IGl0IGRvZXNuJ3QgbWF0dGVyIGlmIHRoZSBzY2VuZSBwbGF5cyBmb3J3YXJkIG9yIGJhY2t3YXJkOiBUaGlzIGV2ZW50IGFsd2F5cyBmaXJlcyB3aGVuIHRoZSBzY2VuZSBsZWF2ZXMgaXRzIGFjdGl2ZSBzY3JvbGwgdGltZWZyYW1lLCByZWdhcmRsZXNzIG9mIHRoZSBzY3JvbGwtZGlyZWN0aW9uLlxyXG5cdFx0ICpcclxuXHRcdCAqIEZvciBkZXRhaWxzIG9uIHRoaXMgZXZlbnQgYW5kIHRoZSBvcmRlciBpbiB3aGljaCBpdCBpcyBmaXJlZCwgcGxlYXNlIHJldmlldyB0aGUge0BsaW5rIFNjZW5lLnByb2dyZXNzfSBtZXRob2QuXHJcblx0XHQgKlxyXG5cdFx0ICogQGV2ZW50IFNjcm9sbE1hZ2ljLlNjZW5lI2xlYXZlXHJcblx0XHQgKlxyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIHNjZW5lLm9uKFwibGVhdmVcIiwgZnVuY3Rpb24gKGV2ZW50KSB7XHJcblx0XHQgKiBcdGNvbnNvbGUubG9nKFwiU2NlbmUgbGVmdC5cIik7XHJcblx0XHQgKiB9KTtcclxuXHRcdCAqXHJcblx0XHQgKiBAcHJvcGVydHkge29iamVjdH0gZXZlbnQgLSBUaGUgZXZlbnQgT2JqZWN0IHBhc3NlZCB0byBlYWNoIGNhbGxiYWNrXHJcblx0XHQgKiBAcHJvcGVydHkge3N0cmluZ30gZXZlbnQudHlwZSAtIFRoZSBuYW1lIG9mIHRoZSBldmVudFxyXG5cdFx0ICogQHByb3BlcnR5IHtTY2VuZX0gZXZlbnQudGFyZ2V0IC0gVGhlIFNjZW5lIG9iamVjdCB0aGF0IHRyaWdnZXJlZCB0aGlzIGV2ZW50XHJcblx0XHQgKiBAcHJvcGVydHkge251bWJlcn0gZXZlbnQucHJvZ3Jlc3MgLSBSZWZsZWN0cyB0aGUgY3VycmVudCBwcm9ncmVzcyBvZiB0aGUgc2NlbmVcclxuXHRcdCAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBldmVudC5zdGF0ZSAtIFRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBzY2VuZSBgXCJCRUZPUkVcImAgb3IgYFwiQUZURVJcImBcclxuXHRcdCAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBldmVudC5zY3JvbGxEaXJlY3Rpb24gLSBJbmRpY2F0ZXMgd2hpY2ggd2F5IHdlIGFyZSBzY3JvbGxpbmcgYFwiUEFVU0VEXCJgLCBgXCJGT1JXQVJEXCJgIG9yIGBcIlJFVkVSU0VcImBcclxuXHRcdCAqL1xyXG5cdFx0LyoqXHJcblx0XHQgKiBTY2VuZSB1cGRhdGUgZXZlbnQuICBcclxuXHRcdCAqIEZpcmVzIHdoZW5ldmVyIHRoZSBzY2VuZSBpcyB1cGRhdGVkIChidXQgbm90IG5lY2Vzc2FyaWx5IGNoYW5nZXMgdGhlIHByb2dyZXNzKS5cclxuXHRcdCAqXHJcblx0XHQgKiBAZXZlbnQgU2Nyb2xsTWFnaWMuU2NlbmUjdXBkYXRlXHJcblx0XHQgKlxyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIHNjZW5lLm9uKFwidXBkYXRlXCIsIGZ1bmN0aW9uIChldmVudCkge1xyXG5cdFx0ICogXHRjb25zb2xlLmxvZyhcIlNjZW5lIHVwZGF0ZWQuXCIpO1xyXG5cdFx0ICogfSk7XHJcblx0XHQgKlxyXG5cdFx0ICogQHByb3BlcnR5IHtvYmplY3R9IGV2ZW50IC0gVGhlIGV2ZW50IE9iamVjdCBwYXNzZWQgdG8gZWFjaCBjYWxsYmFja1xyXG5cdFx0ICogQHByb3BlcnR5IHtzdHJpbmd9IGV2ZW50LnR5cGUgLSBUaGUgbmFtZSBvZiB0aGUgZXZlbnRcclxuXHRcdCAqIEBwcm9wZXJ0eSB7U2NlbmV9IGV2ZW50LnRhcmdldCAtIFRoZSBTY2VuZSBvYmplY3QgdGhhdCB0cmlnZ2VyZWQgdGhpcyBldmVudFxyXG5cdFx0ICogQHByb3BlcnR5IHtudW1iZXJ9IGV2ZW50LnN0YXJ0UG9zIC0gVGhlIHN0YXJ0aW5nIHBvc2l0aW9uIG9mIHRoZSBzY2VuZSAoaW4gcmVsYXRpb24gdG8gdGhlIGNvbmFpbmVyKVxyXG5cdFx0ICogQHByb3BlcnR5IHtudW1iZXJ9IGV2ZW50LmVuZFBvcyAtIFRoZSBlbmRpbmcgcG9zaXRpb24gb2YgdGhlIHNjZW5lIChpbiByZWxhdGlvbiB0byB0aGUgY29uYWluZXIpXHJcblx0XHQgKiBAcHJvcGVydHkge251bWJlcn0gZXZlbnQuc2Nyb2xsUG9zIC0gVGhlIGN1cnJlbnQgc2Nyb2xsIHBvc2l0aW9uIG9mIHRoZSBjb250YWluZXJcclxuXHRcdCAqL1xyXG5cdFx0LyoqXHJcblx0XHQgKiBTY2VuZSBwcm9ncmVzcyBldmVudC4gIFxyXG5cdFx0ICogRmlyZXMgd2hlbmV2ZXIgdGhlIHByb2dyZXNzIG9mIHRoZSBzY2VuZSBjaGFuZ2VzLlxyXG5cdFx0ICpcclxuXHRcdCAqIEZvciBkZXRhaWxzIG9uIHRoaXMgZXZlbnQgYW5kIHRoZSBvcmRlciBpbiB3aGljaCBpdCBpcyBmaXJlZCwgcGxlYXNlIHJldmlldyB0aGUge0BsaW5rIFNjZW5lLnByb2dyZXNzfSBtZXRob2QuXHJcblx0XHQgKlxyXG5cdFx0ICogQGV2ZW50IFNjcm9sbE1hZ2ljLlNjZW5lI3Byb2dyZXNzXHJcblx0XHQgKlxyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIHNjZW5lLm9uKFwicHJvZ3Jlc3NcIiwgZnVuY3Rpb24gKGV2ZW50KSB7XHJcblx0XHQgKiBcdGNvbnNvbGUubG9nKFwiU2NlbmUgcHJvZ3Jlc3MgY2hhbmdlZCB0byBcIiArIGV2ZW50LnByb2dyZXNzKTtcclxuXHRcdCAqIH0pO1xyXG5cdFx0ICpcclxuXHRcdCAqIEBwcm9wZXJ0eSB7b2JqZWN0fSBldmVudCAtIFRoZSBldmVudCBPYmplY3QgcGFzc2VkIHRvIGVhY2ggY2FsbGJhY2tcclxuXHRcdCAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBldmVudC50eXBlIC0gVGhlIG5hbWUgb2YgdGhlIGV2ZW50XHJcblx0XHQgKiBAcHJvcGVydHkge1NjZW5lfSBldmVudC50YXJnZXQgLSBUaGUgU2NlbmUgb2JqZWN0IHRoYXQgdHJpZ2dlcmVkIHRoaXMgZXZlbnRcclxuXHRcdCAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBldmVudC5wcm9ncmVzcyAtIFJlZmxlY3RzIHRoZSBjdXJyZW50IHByb2dyZXNzIG9mIHRoZSBzY2VuZVxyXG5cdFx0ICogQHByb3BlcnR5IHtzdHJpbmd9IGV2ZW50LnN0YXRlIC0gVGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHNjZW5lIGBcIkJFRk9SRVwiYCwgYFwiRFVSSU5HXCJgIG9yIGBcIkFGVEVSXCJgXHJcblx0XHQgKiBAcHJvcGVydHkge3N0cmluZ30gZXZlbnQuc2Nyb2xsRGlyZWN0aW9uIC0gSW5kaWNhdGVzIHdoaWNoIHdheSB3ZSBhcmUgc2Nyb2xsaW5nIGBcIlBBVVNFRFwiYCwgYFwiRk9SV0FSRFwiYCBvciBgXCJSRVZFUlNFXCJgXHJcblx0XHQgKi9cclxuXHRcdC8qKlxyXG5cdFx0ICogU2NlbmUgY2hhbmdlIGV2ZW50LiAgXHJcblx0XHQgKiBGaXJlcyB3aGVudmV2ZXIgYSBwcm9wZXJ0eSBvZiB0aGUgc2NlbmUgaXMgY2hhbmdlZC5cclxuXHRcdCAqXHJcblx0XHQgKiBAZXZlbnQgU2Nyb2xsTWFnaWMuU2NlbmUjY2hhbmdlXHJcblx0XHQgKlxyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIHNjZW5lLm9uKFwiY2hhbmdlXCIsIGZ1bmN0aW9uIChldmVudCkge1xyXG5cdFx0ICogXHRjb25zb2xlLmxvZyhcIlNjZW5lIFByb3BlcnR5IFxcXCJcIiArIGV2ZW50LndoYXQgKyBcIlxcXCIgY2hhbmdlZCB0byBcIiArIGV2ZW50Lm5ld3ZhbCk7XHJcblx0XHQgKiB9KTtcclxuXHRcdCAqXHJcblx0XHQgKiBAcHJvcGVydHkge29iamVjdH0gZXZlbnQgLSBUaGUgZXZlbnQgT2JqZWN0IHBhc3NlZCB0byBlYWNoIGNhbGxiYWNrXHJcblx0XHQgKiBAcHJvcGVydHkge3N0cmluZ30gZXZlbnQudHlwZSAtIFRoZSBuYW1lIG9mIHRoZSBldmVudFxyXG5cdFx0ICogQHByb3BlcnR5IHtTY2VuZX0gZXZlbnQudGFyZ2V0IC0gVGhlIFNjZW5lIG9iamVjdCB0aGF0IHRyaWdnZXJlZCB0aGlzIGV2ZW50XHJcblx0XHQgKiBAcHJvcGVydHkge3N0cmluZ30gZXZlbnQud2hhdCAtIEluZGljYXRlcyB3aGF0IHZhbHVlIGhhcyBiZWVuIGNoYW5nZWRcclxuXHRcdCAqIEBwcm9wZXJ0eSB7bWl4ZWR9IGV2ZW50Lm5ld3ZhbCAtIFRoZSBuZXcgdmFsdWUgb2YgdGhlIGNoYW5nZWQgcHJvcGVydHlcclxuXHRcdCAqL1xyXG5cdFx0LyoqXHJcblx0XHQgKiBTY2VuZSBzaGlmdCBldmVudC4gIFxyXG5cdFx0ICogRmlyZXMgd2hlbnZldmVyIHRoZSBzdGFydCBvciBlbmQgKipzY3JvbGwgb2Zmc2V0Kiogb2YgdGhlIHNjZW5lIGNoYW5nZS5cclxuXHRcdCAqIFRoaXMgaGFwcGVucyBleHBsaWNpdGVseSwgd2hlbiBvbmUgb2YgdGhlc2UgdmFsdWVzIGNoYW5nZTogYG9mZnNldGAsIGBkdXJhdGlvbmAgb3IgYHRyaWdnZXJIb29rYC5cclxuXHRcdCAqIEl0IHdpbGwgZmlyZSBpbXBsaWNpdGx5IHdoZW4gdGhlIGB0cmlnZ2VyRWxlbWVudGAgY2hhbmdlcywgaWYgdGhlIG5ldyBlbGVtZW50IGhhcyBhIGRpZmZlcmVudCBwb3NpdGlvbiAobW9zdCBjYXNlcykuXHJcblx0XHQgKiBJdCB3aWxsIGFsc28gZmlyZSBpbXBsaWNpdGx5IHdoZW4gdGhlIHNpemUgb2YgdGhlIGNvbnRhaW5lciBjaGFuZ2VzIGFuZCB0aGUgdHJpZ2dlckhvb2sgaXMgYW55dGhpbmcgb3RoZXIgdGhhbiBgb25MZWF2ZWAuXHJcblx0XHQgKlxyXG5cdFx0ICogQGV2ZW50IFNjcm9sbE1hZ2ljLlNjZW5lI3NoaWZ0XHJcblx0XHQgKiBAc2luY2UgMS4xLjBcclxuXHRcdCAqXHJcblx0XHQgKiBAZXhhbXBsZVxyXG5cdFx0ICogc2NlbmUub24oXCJzaGlmdFwiLCBmdW5jdGlvbiAoZXZlbnQpIHtcclxuXHRcdCAqIFx0Y29uc29sZS5sb2coXCJTY2VuZSBtb3ZlZCwgYmVjYXVzZSB0aGUgXCIgKyBldmVudC5yZWFzb24gKyBcIiBoYXMgY2hhbmdlZC4pXCIpO1xyXG5cdFx0ICogfSk7XHJcblx0XHQgKlxyXG5cdFx0ICogQHByb3BlcnR5IHtvYmplY3R9IGV2ZW50IC0gVGhlIGV2ZW50IE9iamVjdCBwYXNzZWQgdG8gZWFjaCBjYWxsYmFja1xyXG5cdFx0ICogQHByb3BlcnR5IHtzdHJpbmd9IGV2ZW50LnR5cGUgLSBUaGUgbmFtZSBvZiB0aGUgZXZlbnRcclxuXHRcdCAqIEBwcm9wZXJ0eSB7U2NlbmV9IGV2ZW50LnRhcmdldCAtIFRoZSBTY2VuZSBvYmplY3QgdGhhdCB0cmlnZ2VyZWQgdGhpcyBldmVudFxyXG5cdFx0ICogQHByb3BlcnR5IHtzdHJpbmd9IGV2ZW50LnJlYXNvbiAtIEluZGljYXRlcyB3aHkgdGhlIHNjZW5lIGhhcyBzaGlmdGVkXHJcblx0XHQgKi9cclxuXHRcdC8qKlxyXG5cdFx0ICogU2NlbmUgZGVzdHJveSBldmVudC4gIFxyXG5cdFx0ICogRmlyZXMgd2hlbnZldmVyIHRoZSBzY2VuZSBpcyBkZXN0cm95ZWQuXHJcblx0XHQgKiBUaGlzIGNhbiBiZSB1c2VkIHRvIHRpZHkgdXAgY3VzdG9tIGJlaGF2aW91ciB1c2VkIGluIGV2ZW50cy5cclxuXHRcdCAqXHJcblx0XHQgKiBAZXZlbnQgU2Nyb2xsTWFnaWMuU2NlbmUjZGVzdHJveVxyXG5cdFx0ICogQHNpbmNlIDEuMS4wXHJcblx0XHQgKlxyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIHNjZW5lLm9uKFwiZW50ZXJcIiwgZnVuY3Rpb24gKGV2ZW50KSB7XHJcblx0XHQgKiAgICAgICAgLy8gYWRkIGN1c3RvbSBhY3Rpb25cclxuXHRcdCAqICAgICAgICAkKFwiI215LWVsZW1cIikubGVmdChcIjIwMFwiKTtcclxuXHRcdCAqICAgICAgfSlcclxuXHRcdCAqICAgICAgLm9uKFwiZGVzdHJveVwiLCBmdW5jdGlvbiAoZXZlbnQpIHtcclxuXHRcdCAqICAgICAgICAvLyByZXNldCBteSBlbGVtZW50IHRvIHN0YXJ0IHBvc2l0aW9uXHJcblx0XHQgKiAgICAgICAgaWYgKGV2ZW50LnJlc2V0KSB7XHJcblx0XHQgKiAgICAgICAgICAkKFwiI215LWVsZW1cIikubGVmdChcIjBcIik7XHJcblx0XHQgKiAgICAgICAgfVxyXG5cdFx0ICogICAgICB9KTtcclxuXHRcdCAqXHJcblx0XHQgKiBAcHJvcGVydHkge29iamVjdH0gZXZlbnQgLSBUaGUgZXZlbnQgT2JqZWN0IHBhc3NlZCB0byBlYWNoIGNhbGxiYWNrXHJcblx0XHQgKiBAcHJvcGVydHkge3N0cmluZ30gZXZlbnQudHlwZSAtIFRoZSBuYW1lIG9mIHRoZSBldmVudFxyXG5cdFx0ICogQHByb3BlcnR5IHtTY2VuZX0gZXZlbnQudGFyZ2V0IC0gVGhlIFNjZW5lIG9iamVjdCB0aGF0IHRyaWdnZXJlZCB0aGlzIGV2ZW50XHJcblx0XHQgKiBAcHJvcGVydHkge2Jvb2xlYW59IGV2ZW50LnJlc2V0IC0gSW5kaWNhdGVzIGlmIHRoZSBkZXN0cm95IG1ldGhvZCB3YXMgY2FsbGVkIHdpdGggcmVzZXQgYHRydWVgIG9yIGBmYWxzZWAuXHJcblx0XHQgKi9cclxuXHRcdC8qKlxyXG5cdFx0ICogU2NlbmUgYWRkIGV2ZW50LiAgXHJcblx0XHQgKiBGaXJlcyB3aGVuIHRoZSBzY2VuZSBpcyBhZGRlZCB0byBhIGNvbnRyb2xsZXIuXHJcblx0XHQgKiBUaGlzIGlzIG1vc3RseSB1c2VkIGJ5IHBsdWdpbnMgdG8ga25vdyB0aGF0IGNoYW5nZSBtaWdodCBiZSBkdWUuXHJcblx0XHQgKlxyXG5cdFx0ICogQGV2ZW50IFNjcm9sbE1hZ2ljLlNjZW5lI2FkZFxyXG5cdFx0ICogQHNpbmNlIDIuMC4wXHJcblx0XHQgKlxyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIHNjZW5lLm9uKFwiYWRkXCIsIGZ1bmN0aW9uIChldmVudCkge1xyXG5cdFx0ICogXHRjb25zb2xlLmxvZygnU2NlbmUgd2FzIGFkZGVkIHRvIGEgbmV3IGNvbnRyb2xsZXIuJyk7XHJcblx0XHQgKiB9KTtcclxuXHRcdCAqXHJcblx0XHQgKiBAcHJvcGVydHkge29iamVjdH0gZXZlbnQgLSBUaGUgZXZlbnQgT2JqZWN0IHBhc3NlZCB0byBlYWNoIGNhbGxiYWNrXHJcblx0XHQgKiBAcHJvcGVydHkge3N0cmluZ30gZXZlbnQudHlwZSAtIFRoZSBuYW1lIG9mIHRoZSBldmVudFxyXG5cdFx0ICogQHByb3BlcnR5IHtTY2VuZX0gZXZlbnQudGFyZ2V0IC0gVGhlIFNjZW5lIG9iamVjdCB0aGF0IHRyaWdnZXJlZCB0aGlzIGV2ZW50XHJcblx0XHQgKiBAcHJvcGVydHkge2Jvb2xlYW59IGV2ZW50LmNvbnRyb2xsZXIgLSBUaGUgY29udHJvbGxlciBvYmplY3QgdGhlIHNjZW5lIHdhcyBhZGRlZCB0by5cclxuXHRcdCAqL1xyXG5cdFx0LyoqXHJcblx0XHQgKiBTY2VuZSByZW1vdmUgZXZlbnQuICBcclxuXHRcdCAqIEZpcmVzIHdoZW4gdGhlIHNjZW5lIGlzIHJlbW92ZWQgZnJvbSBhIGNvbnRyb2xsZXIuXHJcblx0XHQgKiBUaGlzIGlzIG1vc3RseSB1c2VkIGJ5IHBsdWdpbnMgdG8ga25vdyB0aGF0IGNoYW5nZSBtaWdodCBiZSBkdWUuXHJcblx0XHQgKlxyXG5cdFx0ICogQGV2ZW50IFNjcm9sbE1hZ2ljLlNjZW5lI3JlbW92ZVxyXG5cdFx0ICogQHNpbmNlIDIuMC4wXHJcblx0XHQgKlxyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIHNjZW5lLm9uKFwicmVtb3ZlXCIsIGZ1bmN0aW9uIChldmVudCkge1xyXG5cdFx0ICogXHRjb25zb2xlLmxvZygnU2NlbmUgd2FzIHJlbW92ZWQgZnJvbSBpdHMgY29udHJvbGxlci4nKTtcclxuXHRcdCAqIH0pO1xyXG5cdFx0ICpcclxuXHRcdCAqIEBwcm9wZXJ0eSB7b2JqZWN0fSBldmVudCAtIFRoZSBldmVudCBPYmplY3QgcGFzc2VkIHRvIGVhY2ggY2FsbGJhY2tcclxuXHRcdCAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBldmVudC50eXBlIC0gVGhlIG5hbWUgb2YgdGhlIGV2ZW50XHJcblx0XHQgKiBAcHJvcGVydHkge1NjZW5lfSBldmVudC50YXJnZXQgLSBUaGUgU2NlbmUgb2JqZWN0IHRoYXQgdHJpZ2dlcmVkIHRoaXMgZXZlbnRcclxuXHRcdCAqL1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogQWRkIG9uZSBvcmUgbW9yZSBldmVudCBsaXN0ZW5lci4gIFxyXG5cdFx0ICogVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHdpbGwgYmUgZmlyZWQgYXQgdGhlIHJlc3BlY3RpdmUgZXZlbnQsIGFuZCBhbiBvYmplY3QgY29udGFpbmluZyByZWxldmFudCBkYXRhIHdpbGwgYmUgcGFzc2VkIHRvIHRoZSBjYWxsYmFjay5cclxuXHRcdCAqIEBtZXRob2QgU2Nyb2xsTWFnaWMuU2NlbmUjb25cclxuXHRcdCAqXHJcblx0XHQgKiBAZXhhbXBsZVxyXG5cdFx0ICogZnVuY3Rpb24gY2FsbGJhY2sgKGV2ZW50KSB7XHJcblx0XHQgKiBcdFx0Y29uc29sZS5sb2coXCJFdmVudCBmaXJlZCEgKFwiICsgZXZlbnQudHlwZSArIFwiKVwiKTtcclxuXHRcdCAqIH1cclxuXHRcdCAqIC8vIGFkZCBsaXN0ZW5lcnNcclxuXHRcdCAqIHNjZW5lLm9uKFwiY2hhbmdlIHVwZGF0ZSBwcm9ncmVzcyBzdGFydCBlbmQgZW50ZXIgbGVhdmVcIiwgY2FsbGJhY2spO1xyXG5cdFx0ICpcclxuXHRcdCAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lcyAtIFRoZSBuYW1lIG9yIG5hbWVzIG9mIHRoZSBldmVudCB0aGUgY2FsbGJhY2sgc2hvdWxkIGJlIGF0dGFjaGVkIHRvLlxyXG5cdFx0ICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2sgLSBBIGZ1bmN0aW9uIHRoYXQgc2hvdWxkIGJlIGV4ZWN1dGVkLCB3aGVuIHRoZSBldmVudCBpcyBkaXNwYXRjaGVkLiBBbiBldmVudCBvYmplY3Qgd2lsbCBiZSBwYXNzZWQgdG8gdGhlIGNhbGxiYWNrLlxyXG5cdFx0ICogQHJldHVybnMge1NjZW5lfSBQYXJlbnQgb2JqZWN0IGZvciBjaGFpbmluZy5cclxuXHRcdCAqL1xyXG5cdFx0dGhpcy5vbiA9IGZ1bmN0aW9uIChuYW1lcywgY2FsbGJhY2spIHtcclxuXHRcdFx0aWYgKF91dGlsLnR5cGUuRnVuY3Rpb24oY2FsbGJhY2spKSB7XHJcblx0XHRcdFx0bmFtZXMgPSBuYW1lcy50cmltKCkuc3BsaXQoJyAnKTtcclxuXHRcdFx0XHRuYW1lcy5mb3JFYWNoKGZ1bmN0aW9uIChmdWxsbmFtZSkge1xyXG5cdFx0XHRcdFx0dmFyXHJcblx0XHRcdFx0XHRcdG5hbWVwYXJ0cyA9IGZ1bGxuYW1lLnNwbGl0KCcuJyksXHJcblx0XHRcdFx0XHRcdGV2ZW50bmFtZSA9IG5hbWVwYXJ0c1swXSxcclxuXHRcdFx0XHRcdFx0bmFtZXNwYWNlID0gbmFtZXBhcnRzWzFdO1xyXG5cdFx0XHRcdFx0aWYgKGV2ZW50bmFtZSAhPSBcIipcIikgeyAvLyBkaXNhbGxvdyB3aWxkY2FyZHNcclxuXHRcdFx0XHRcdFx0aWYgKCFfbGlzdGVuZXJzW2V2ZW50bmFtZV0pIHtcclxuXHRcdFx0XHRcdFx0XHRfbGlzdGVuZXJzW2V2ZW50bmFtZV0gPSBbXTtcclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRfbGlzdGVuZXJzW2V2ZW50bmFtZV0ucHVzaCh7XHJcblx0XHRcdFx0XHRcdFx0bmFtZXNwYWNlOiBuYW1lc3BhY2UgfHwgJycsXHJcblx0XHRcdFx0XHRcdFx0Y2FsbGJhY2s6IGNhbGxiYWNrXHJcblx0XHRcdFx0XHRcdH0pO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH0pO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdGxvZygxLCBcIkVSUk9SIHdoZW4gY2FsbGluZyAnLm9uKCknOiBTdXBwbGllZCBjYWxsYmFjayBmb3IgJ1wiICsgbmFtZXMgKyBcIicgaXMgbm90IGEgdmFsaWQgZnVuY3Rpb24hXCIpO1xyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiBTY2VuZTtcclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBSZW1vdmUgb25lIG9yIG1vcmUgZXZlbnQgbGlzdGVuZXIuXHJcblx0XHQgKiBAbWV0aG9kIFNjcm9sbE1hZ2ljLlNjZW5lI29mZlxyXG5cdFx0ICpcclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiBmdW5jdGlvbiBjYWxsYmFjayAoZXZlbnQpIHtcclxuXHRcdCAqIFx0XHRjb25zb2xlLmxvZyhcIkV2ZW50IGZpcmVkISAoXCIgKyBldmVudC50eXBlICsgXCIpXCIpO1xyXG5cdFx0ICogfVxyXG5cdFx0ICogLy8gYWRkIGxpc3RlbmVyc1xyXG5cdFx0ICogc2NlbmUub24oXCJjaGFuZ2UgdXBkYXRlXCIsIGNhbGxiYWNrKTtcclxuXHRcdCAqIC8vIHJlbW92ZSBsaXN0ZW5lcnNcclxuXHRcdCAqIHNjZW5lLm9mZihcImNoYW5nZSB1cGRhdGVcIiwgY2FsbGJhY2spO1xyXG5cdFx0ICpcclxuXHRcdCAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lcyAtIFRoZSBuYW1lIG9yIG5hbWVzIG9mIHRoZSBldmVudCB0aGF0IHNob3VsZCBiZSByZW1vdmVkLlxyXG5cdFx0ICogQHBhcmFtIHtmdW5jdGlvbn0gW2NhbGxiYWNrXSAtIEEgc3BlY2lmaWMgY2FsbGJhY2sgZnVuY3Rpb24gdGhhdCBzaG91bGQgYmUgcmVtb3ZlZC4gSWYgbm9uZSBpcyBwYXNzZWQgYWxsIGNhbGxiYWNrcyB0byB0aGUgZXZlbnQgbGlzdGVuZXIgd2lsbCBiZSByZW1vdmVkLlxyXG5cdFx0ICogQHJldHVybnMge1NjZW5lfSBQYXJlbnQgb2JqZWN0IGZvciBjaGFpbmluZy5cclxuXHRcdCAqL1xyXG5cdFx0dGhpcy5vZmYgPSBmdW5jdGlvbiAobmFtZXMsIGNhbGxiYWNrKSB7XHJcblx0XHRcdGlmICghbmFtZXMpIHtcclxuXHRcdFx0XHRsb2coMSwgXCJFUlJPUjogSW52YWxpZCBldmVudCBuYW1lIHN1cHBsaWVkLlwiKTtcclxuXHRcdFx0XHRyZXR1cm4gU2NlbmU7XHJcblx0XHRcdH1cclxuXHRcdFx0bmFtZXMgPSBuYW1lcy50cmltKCkuc3BsaXQoJyAnKTtcclxuXHRcdFx0bmFtZXMuZm9yRWFjaChmdW5jdGlvbiAoZnVsbG5hbWUsIGtleSkge1xyXG5cdFx0XHRcdHZhclxyXG5cdFx0XHRcdFx0bmFtZXBhcnRzID0gZnVsbG5hbWUuc3BsaXQoJy4nKSxcclxuXHRcdFx0XHRcdGV2ZW50bmFtZSA9IG5hbWVwYXJ0c1swXSxcclxuXHRcdFx0XHRcdG5hbWVzcGFjZSA9IG5hbWVwYXJ0c1sxXSB8fCAnJyxcclxuXHRcdFx0XHRcdHJlbW92ZUxpc3QgPSBldmVudG5hbWUgPT09ICcqJyA/IE9iamVjdC5rZXlzKF9saXN0ZW5lcnMpIDogW2V2ZW50bmFtZV07XHJcblx0XHRcdFx0cmVtb3ZlTGlzdC5mb3JFYWNoKGZ1bmN0aW9uIChyZW1vdmUpIHtcclxuXHRcdFx0XHRcdHZhclxyXG5cdFx0XHRcdFx0XHRsaXN0ID0gX2xpc3RlbmVyc1tyZW1vdmVdIHx8IFtdLFxyXG5cdFx0XHRcdFx0XHRpID0gbGlzdC5sZW5ndGg7XHJcblx0XHRcdFx0XHR3aGlsZSAoaS0tKSB7XHJcblx0XHRcdFx0XHRcdHZhciBsaXN0ZW5lciA9IGxpc3RbaV07XHJcblx0XHRcdFx0XHRcdGlmIChsaXN0ZW5lciAmJiAobmFtZXNwYWNlID09PSBsaXN0ZW5lci5uYW1lc3BhY2UgfHwgbmFtZXNwYWNlID09PSAnKicpICYmICghY2FsbGJhY2sgfHwgY2FsbGJhY2sgPT0gbGlzdGVuZXIuY2FsbGJhY2spKSB7XHJcblx0XHRcdFx0XHRcdFx0bGlzdC5zcGxpY2UoaSwgMSk7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdGlmICghbGlzdC5sZW5ndGgpIHtcclxuXHRcdFx0XHRcdFx0ZGVsZXRlIF9saXN0ZW5lcnNbcmVtb3ZlXTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9KTtcclxuXHRcdFx0fSk7XHJcblx0XHRcdHJldHVybiBTY2VuZTtcclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBUcmlnZ2VyIGFuIGV2ZW50LlxyXG5cdFx0ICogQG1ldGhvZCBTY3JvbGxNYWdpYy5TY2VuZSN0cmlnZ2VyXHJcblx0XHQgKlxyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIHRoaXMudHJpZ2dlcihcImNoYW5nZVwiKTtcclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBldmVudCB0aGF0IHNob3VsZCBiZSB0cmlnZ2VyZWQuXHJcblx0XHQgKiBAcGFyYW0ge29iamVjdH0gW3ZhcnNdIC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgaW5mbyB0aGF0IHNob3VsZCBiZSBwYXNzZWQgdG8gdGhlIGNhbGxiYWNrLlxyXG5cdFx0ICogQHJldHVybnMge1NjZW5lfSBQYXJlbnQgb2JqZWN0IGZvciBjaGFpbmluZy5cclxuXHRcdCAqL1xyXG5cdFx0dGhpcy50cmlnZ2VyID0gZnVuY3Rpb24gKG5hbWUsIHZhcnMpIHtcclxuXHRcdFx0aWYgKG5hbWUpIHtcclxuXHRcdFx0XHR2YXJcclxuXHRcdFx0XHRcdG5hbWVwYXJ0cyA9IG5hbWUudHJpbSgpLnNwbGl0KCcuJyksXHJcblx0XHRcdFx0XHRldmVudG5hbWUgPSBuYW1lcGFydHNbMF0sXHJcblx0XHRcdFx0XHRuYW1lc3BhY2UgPSBuYW1lcGFydHNbMV0sXHJcblx0XHRcdFx0XHRsaXN0ZW5lcnMgPSBfbGlzdGVuZXJzW2V2ZW50bmFtZV07XHJcblx0XHRcdFx0bG9nKDMsICdldmVudCBmaXJlZDonLCBldmVudG5hbWUsIHZhcnMgPyBcIi0+XCIgOiAnJywgdmFycyB8fCAnJyk7XHJcblx0XHRcdFx0aWYgKGxpc3RlbmVycykge1xyXG5cdFx0XHRcdFx0bGlzdGVuZXJzLmZvckVhY2goZnVuY3Rpb24gKGxpc3RlbmVyLCBrZXkpIHtcclxuXHRcdFx0XHRcdFx0aWYgKCFuYW1lc3BhY2UgfHwgbmFtZXNwYWNlID09PSBsaXN0ZW5lci5uYW1lc3BhY2UpIHtcclxuXHRcdFx0XHRcdFx0XHRsaXN0ZW5lci5jYWxsYmFjay5jYWxsKFNjZW5lLCBuZXcgU2Nyb2xsTWFnaWMuRXZlbnQoZXZlbnRuYW1lLCBsaXN0ZW5lci5uYW1lc3BhY2UsIFNjZW5lLCB2YXJzKSk7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdH0pO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRsb2coMSwgXCJFUlJPUjogSW52YWxpZCBldmVudCBuYW1lIHN1cHBsaWVkLlwiKTtcclxuXHRcdFx0fVxyXG5cdFx0XHRyZXR1cm4gU2NlbmU7XHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIHNldCBldmVudCBsaXN0ZW5lcnNcclxuXHRcdFNjZW5lXHJcblx0XHRcdC5vbihcImNoYW5nZS5pbnRlcm5hbFwiLCBmdW5jdGlvbiAoZSkge1xyXG5cdFx0XHRcdGlmIChlLndoYXQgIT09IFwibG9nbGV2ZWxcIiAmJiBlLndoYXQgIT09IFwidHdlZW5DaGFuZ2VzXCIpIHsgLy8gbm8gbmVlZCBmb3IgYSBzY2VuZSB1cGRhdGUgc2NlbmUgd2l0aCB0aGVzZSBvcHRpb25zLi4uXHJcblx0XHRcdFx0XHRpZiAoZS53aGF0ID09PSBcInRyaWdnZXJFbGVtZW50XCIpIHtcclxuXHRcdFx0XHRcdFx0dXBkYXRlVHJpZ2dlckVsZW1lbnRQb3NpdGlvbigpO1xyXG5cdFx0XHRcdFx0fSBlbHNlIGlmIChlLndoYXQgPT09IFwicmV2ZXJzZVwiKSB7IC8vIHRoZSBvbmx5IHByb3BlcnR5IGxlZnQgdGhhdCBtYXkgaGF2ZSBhbiBpbXBhY3Qgb24gdGhlIGN1cnJlbnQgc2NlbmUgc3RhdGUuIEV2ZXJ5dGhpbmcgZWxzZSBpcyBoYW5kbGVkIGJ5IHRoZSBzaGlmdCBldmVudC5cclxuXHRcdFx0XHRcdFx0U2NlbmUudXBkYXRlKCk7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9KVxyXG5cdFx0XHQub24oXCJzaGlmdC5pbnRlcm5hbFwiLCBmdW5jdGlvbiAoZSkge1xyXG5cdFx0XHRcdHVwZGF0ZVNjcm9sbE9mZnNldCgpO1xyXG5cdFx0XHRcdFNjZW5lLnVwZGF0ZSgpOyAvLyB1cGRhdGUgc2NlbmUgdG8gcmVmbGVjdCBuZXcgcG9zaXRpb25cclxuXHRcdFx0fSk7XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBTZW5kIGEgZGVidWcgbWVzc2FnZSB0byB0aGUgY29uc29sZS5cclxuXHRcdCAqIEBwcml2YXRlXHJcblx0XHQgKiBidXQgcHJvdmlkZWQgcHVibGljbHkgd2l0aCBfbG9nIGZvciBwbHVnaW5zXHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIHtudW1iZXJ9IGxvZ2xldmVsIC0gVGhlIGxvZ2xldmVsIHJlcXVpcmVkIHRvIGluaXRpYXRlIG91dHB1dCBmb3IgdGhlIG1lc3NhZ2UuXHJcblx0XHQgKiBAcGFyYW0gey4uLm1peGVkfSBvdXRwdXQgLSBPbmUgb3IgbW9yZSB2YXJpYWJsZXMgdGhhdCBzaG91bGQgYmUgcGFzc2VkIHRvIHRoZSBjb25zb2xlLlxyXG5cdFx0ICovXHJcblx0XHR2YXIgbG9nID0gdGhpcy5fbG9nID0gZnVuY3Rpb24gKGxvZ2xldmVsLCBvdXRwdXQpIHtcclxuXHRcdFx0aWYgKF9vcHRpb25zLmxvZ2xldmVsID49IGxvZ2xldmVsKSB7XHJcblx0XHRcdFx0QXJyYXkucHJvdG90eXBlLnNwbGljZS5jYWxsKGFyZ3VtZW50cywgMSwgMCwgXCIoXCIgKyBOQU1FU1BBQ0UgKyBcIikgLT5cIik7XHJcblx0XHRcdFx0X3V0aWwubG9nLmFwcGx5KHdpbmRvdywgYXJndW1lbnRzKTtcclxuXHRcdFx0fVxyXG5cdFx0fTtcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIEFkZCB0aGUgc2NlbmUgdG8gYSBjb250cm9sbGVyLiAgXHJcblx0XHQgKiBUaGlzIGlzIHRoZSBlcXVpdmFsZW50IHRvIGBDb250cm9sbGVyLmFkZFNjZW5lKHNjZW5lKWAuXHJcblx0XHQgKiBAbWV0aG9kIFNjcm9sbE1hZ2ljLlNjZW5lI2FkZFRvXHJcblx0XHQgKlxyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIC8vIGFkZCBhIHNjZW5lIHRvIGEgU2Nyb2xsTWFnaWMgQ29udHJvbGxlclxyXG5cdFx0ICogc2NlbmUuYWRkVG8oY29udHJvbGxlcik7XHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIHtTY3JvbGxNYWdpYy5Db250cm9sbGVyfSBjb250cm9sbGVyIC0gVGhlIGNvbnRyb2xsZXIgdG8gd2hpY2ggdGhlIHNjZW5lIHNob3VsZCBiZSBhZGRlZC5cclxuXHRcdCAqIEByZXR1cm5zIHtTY2VuZX0gUGFyZW50IG9iamVjdCBmb3IgY2hhaW5pbmcuXHJcblx0XHQgKi9cclxuXHRcdHRoaXMuYWRkVG8gPSBmdW5jdGlvbiAoY29udHJvbGxlcikge1xyXG5cdFx0XHRpZiAoIShjb250cm9sbGVyIGluc3RhbmNlb2YgU2Nyb2xsTWFnaWMuQ29udHJvbGxlcikpIHtcclxuXHRcdFx0XHRsb2coMSwgXCJFUlJPUjogc3VwcGxpZWQgYXJndW1lbnQgb2YgJ2FkZFRvKCknIGlzIG5vdCBhIHZhbGlkIFNjcm9sbE1hZ2ljIENvbnRyb2xsZXJcIik7XHJcblx0XHRcdH0gZWxzZSBpZiAoX2NvbnRyb2xsZXIgIT0gY29udHJvbGxlcikge1xyXG5cdFx0XHRcdC8vIG5ldyBjb250cm9sbGVyXHJcblx0XHRcdFx0aWYgKF9jb250cm9sbGVyKSB7IC8vIHdhcyBhc3NvY2lhdGVkIHRvIGEgZGlmZmVyZW50IGNvbnRyb2xsZXIgYmVmb3JlLCBzbyByZW1vdmUgaXQuLi5cclxuXHRcdFx0XHRcdF9jb250cm9sbGVyLnJlbW92ZVNjZW5lKFNjZW5lKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0X2NvbnRyb2xsZXIgPSBjb250cm9sbGVyO1xyXG5cdFx0XHRcdHZhbGlkYXRlT3B0aW9uKCk7XHJcblx0XHRcdFx0dXBkYXRlRHVyYXRpb24odHJ1ZSk7XHJcblx0XHRcdFx0dXBkYXRlVHJpZ2dlckVsZW1lbnRQb3NpdGlvbih0cnVlKTtcclxuXHRcdFx0XHR1cGRhdGVTY3JvbGxPZmZzZXQoKTtcclxuXHRcdFx0XHRfY29udHJvbGxlci5pbmZvKFwiY29udGFpbmVyXCIpLmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIG9uQ29udGFpbmVyUmVzaXplKTtcclxuXHRcdFx0XHRjb250cm9sbGVyLmFkZFNjZW5lKFNjZW5lKTtcclxuXHRcdFx0XHRTY2VuZS50cmlnZ2VyKFwiYWRkXCIsIHtcclxuXHRcdFx0XHRcdGNvbnRyb2xsZXI6IF9jb250cm9sbGVyXHJcblx0XHRcdFx0fSk7XHJcblx0XHRcdFx0bG9nKDMsIFwiYWRkZWQgXCIgKyBOQU1FU1BBQ0UgKyBcIiB0byBjb250cm9sbGVyXCIpO1xyXG5cdFx0XHRcdFNjZW5lLnVwZGF0ZSgpO1xyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiBTY2VuZTtcclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiAqKkdldCoqIG9yICoqU2V0KiogdGhlIGN1cnJlbnQgZW5hYmxlZCBzdGF0ZSBvZiB0aGUgc2NlbmUuICBcclxuXHRcdCAqIFRoaXMgY2FuIGJlIHVzZWQgdG8gZGlzYWJsZSB0aGlzIHNjZW5lIHdpdGhvdXQgcmVtb3Zpbmcgb3IgZGVzdHJveWluZyBpdC5cclxuXHRcdCAqIEBtZXRob2QgU2Nyb2xsTWFnaWMuU2NlbmUjZW5hYmxlZFxyXG5cdFx0ICpcclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiAvLyBnZXQgdGhlIGN1cnJlbnQgdmFsdWVcclxuXHRcdCAqIHZhciBlbmFibGVkID0gc2NlbmUuZW5hYmxlZCgpO1xyXG5cdFx0ICpcclxuXHRcdCAqIC8vIGRpc2FibGUgdGhlIHNjZW5lXHJcblx0XHQgKiBzY2VuZS5lbmFibGVkKGZhbHNlKTtcclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0ge2Jvb2xlYW59IFtuZXdTdGF0ZV0gLSBUaGUgbmV3IGVuYWJsZWQgc3RhdGUgb2YgdGhlIHNjZW5lIGB0cnVlYCBvciBgZmFsc2VgLlxyXG5cdFx0ICogQHJldHVybnMgeyhib29sZWFufFNjZW5lKX0gQ3VycmVudCBlbmFibGVkIHN0YXRlIG9yIHBhcmVudCBvYmplY3QgZm9yIGNoYWluaW5nLlxyXG5cdFx0ICovXHJcblx0XHR0aGlzLmVuYWJsZWQgPSBmdW5jdGlvbiAobmV3U3RhdGUpIHtcclxuXHRcdFx0aWYgKCFhcmd1bWVudHMubGVuZ3RoKSB7IC8vIGdldFxyXG5cdFx0XHRcdHJldHVybiBfZW5hYmxlZDtcclxuXHRcdFx0fSBlbHNlIGlmIChfZW5hYmxlZCAhPSBuZXdTdGF0ZSkgeyAvLyBzZXRcclxuXHRcdFx0XHRfZW5hYmxlZCA9ICEhbmV3U3RhdGU7XHJcblx0XHRcdFx0U2NlbmUudXBkYXRlKHRydWUpO1xyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiBTY2VuZTtcclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBSZW1vdmUgdGhlIHNjZW5lIGZyb20gdGhlIGNvbnRyb2xsZXIuICBcclxuXHRcdCAqIFRoaXMgaXMgdGhlIGVxdWl2YWxlbnQgdG8gYENvbnRyb2xsZXIucmVtb3ZlU2NlbmUoc2NlbmUpYC5cclxuXHRcdCAqIFRoZSBzY2VuZSB3aWxsIG5vdCBiZSB1cGRhdGVkIGFueW1vcmUgdW50aWwgeW91IHJlYWRkIGl0IHRvIGEgY29udHJvbGxlci5cclxuXHRcdCAqIFRvIHJlbW92ZSB0aGUgcGluIG9yIHRoZSB0d2VlbiB5b3UgbmVlZCB0byBjYWxsIHJlbW92ZVR3ZWVuKCkgb3IgcmVtb3ZlUGluKCkgcmVzcGVjdGl2ZWx5LlxyXG5cdFx0ICogQG1ldGhvZCBTY3JvbGxNYWdpYy5TY2VuZSNyZW1vdmVcclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiAvLyByZW1vdmUgdGhlIHNjZW5lIGZyb20gaXRzIGNvbnRyb2xsZXJcclxuXHRcdCAqIHNjZW5lLnJlbW92ZSgpO1xyXG5cdFx0ICpcclxuXHRcdCAqIEByZXR1cm5zIHtTY2VuZX0gUGFyZW50IG9iamVjdCBmb3IgY2hhaW5pbmcuXHJcblx0XHQgKi9cclxuXHRcdHRoaXMucmVtb3ZlID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRpZiAoX2NvbnRyb2xsZXIpIHtcclxuXHRcdFx0XHRfY29udHJvbGxlci5pbmZvKFwiY29udGFpbmVyXCIpLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIG9uQ29udGFpbmVyUmVzaXplKTtcclxuXHRcdFx0XHR2YXIgdG1wUGFyZW50ID0gX2NvbnRyb2xsZXI7XHJcblx0XHRcdFx0X2NvbnRyb2xsZXIgPSB1bmRlZmluZWQ7XHJcblx0XHRcdFx0dG1wUGFyZW50LnJlbW92ZVNjZW5lKFNjZW5lKTtcclxuXHRcdFx0XHRTY2VuZS50cmlnZ2VyKFwicmVtb3ZlXCIpO1xyXG5cdFx0XHRcdGxvZygzLCBcInJlbW92ZWQgXCIgKyBOQU1FU1BBQ0UgKyBcIiBmcm9tIGNvbnRyb2xsZXJcIik7XHJcblx0XHRcdH1cclxuXHRcdFx0cmV0dXJuIFNjZW5lO1xyXG5cdFx0fTtcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIERlc3Ryb3kgdGhlIHNjZW5lIGFuZCBldmVyeXRoaW5nLlxyXG5cdFx0ICogQG1ldGhvZCBTY3JvbGxNYWdpYy5TY2VuZSNkZXN0cm95XHJcblx0XHQgKiBAZXhhbXBsZVxyXG5cdFx0ICogLy8gZGVzdHJveSB0aGUgc2NlbmUgd2l0aG91dCByZXNldHRpbmcgdGhlIHBpbiBhbmQgdHdlZW4gdG8gdGhlaXIgaW5pdGlhbCBwb3NpdGlvbnNcclxuXHRcdCAqIHNjZW5lID0gc2NlbmUuZGVzdHJveSgpO1xyXG5cdFx0ICpcclxuXHRcdCAqIC8vIGRlc3Ryb3kgdGhlIHNjZW5lIGFuZCByZXNldCB0aGUgcGluIGFuZCB0d2VlblxyXG5cdFx0ICogc2NlbmUgPSBzY2VuZS5kZXN0cm95KHRydWUpO1xyXG5cdFx0ICpcclxuXHRcdCAqIEBwYXJhbSB7Ym9vbGVhbn0gW3Jlc2V0PWZhbHNlXSAtIElmIGB0cnVlYCB0aGUgcGluIGFuZCB0d2VlbiAoaWYgZXhpc3RlbnQpIHdpbGwgYmUgcmVzZXQuXHJcblx0XHQgKiBAcmV0dXJucyB7bnVsbH0gTnVsbCB0byB1bnNldCBoYW5kbGVyIHZhcmlhYmxlcy5cclxuXHRcdCAqL1xyXG5cdFx0dGhpcy5kZXN0cm95ID0gZnVuY3Rpb24gKHJlc2V0KSB7XHJcblx0XHRcdFNjZW5lLnRyaWdnZXIoXCJkZXN0cm95XCIsIHtcclxuXHRcdFx0XHRyZXNldDogcmVzZXRcclxuXHRcdFx0fSk7XHJcblx0XHRcdFNjZW5lLnJlbW92ZSgpO1xyXG5cdFx0XHRTY2VuZS5vZmYoXCIqLipcIik7XHJcblx0XHRcdGxvZygzLCBcImRlc3Ryb3llZCBcIiArIE5BTUVTUEFDRSArIFwiIChyZXNldDogXCIgKyAocmVzZXQgPyBcInRydWVcIiA6IFwiZmFsc2VcIikgKyBcIilcIik7XHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cdFx0fTtcclxuXHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBVcGRhdGVzIHRoZSBTY2VuZSB0byByZWZsZWN0IHRoZSBjdXJyZW50IHN0YXRlLiAgXHJcblx0XHQgKiBUaGlzIGlzIHRoZSBlcXVpdmFsZW50IHRvIGBDb250cm9sbGVyLnVwZGF0ZVNjZW5lKHNjZW5lLCBpbW1lZGlhdGVseSlgLiAgXHJcblx0XHQgKiBUaGUgdXBkYXRlIG1ldGhvZCBjYWxjdWxhdGVzIHRoZSBzY2VuZSdzIHN0YXJ0IGFuZCBlbmQgcG9zaXRpb24gKGJhc2VkIG9uIHRoZSB0cmlnZ2VyIGVsZW1lbnQsIHRyaWdnZXIgaG9vaywgZHVyYXRpb24gYW5kIG9mZnNldCkgYW5kIGNoZWNrcyBpdCBhZ2FpbnN0IHRoZSBjdXJyZW50IHNjcm9sbCBwb3NpdGlvbiBvZiB0aGUgY29udGFpbmVyLiAgXHJcblx0XHQgKiBJdCB0aGVuIHVwZGF0ZXMgdGhlIGN1cnJlbnQgc2NlbmUgc3RhdGUgYWNjb3JkaW5nbHkgKG9yIGRvZXMgbm90aGluZywgaWYgdGhlIHN0YXRlIGlzIGFscmVhZHkgY29ycmVjdCkg4oCTIFBpbnMgd2lsbCBiZSBzZXQgdG8gdGhlaXIgY29ycmVjdCBwb3NpdGlvbiBhbmQgdHdlZW5zIHdpbGwgYmUgdXBkYXRlZCB0byB0aGVpciBjb3JyZWN0IHByb2dyZXNzLlxyXG5cdFx0ICogVGhpcyBtZWFucyBhbiB1cGRhdGUgZG9lc24ndCBuZWNlc3NhcmlseSByZXN1bHQgaW4gYSBwcm9ncmVzcyBjaGFuZ2UuIFRoZSBgcHJvZ3Jlc3NgIGV2ZW50IHdpbGwgYmUgZmlyZWQgaWYgdGhlIHByb2dyZXNzIGhhcyBpbmRlZWQgY2hhbmdlZCBiZXR3ZWVuIHRoaXMgdXBkYXRlIGFuZCB0aGUgbGFzdC4gIFxyXG5cdFx0ICogXyoqTk9URToqKiBUaGlzIG1ldGhvZCBnZXRzIGNhbGxlZCBjb25zdGFudGx5IHdoZW5ldmVyIFNjcm9sbE1hZ2ljIGRldGVjdHMgYSBjaGFuZ2UuIFRoZSBvbmx5IGFwcGxpY2F0aW9uIGZvciB5b3UgaXMgaWYgeW91IGNoYW5nZSBzb21ldGhpbmcgb3V0c2lkZSBvZiB0aGUgcmVhbG0gb2YgU2Nyb2xsTWFnaWMsIGxpa2UgbW92aW5nIHRoZSB0cmlnZ2VyIG9yIGNoYW5naW5nIHR3ZWVuIHBhcmFtZXRlcnMuX1xyXG5cdFx0ICogQG1ldGhvZCBTY3JvbGxNYWdpYy5TY2VuZSN1cGRhdGVcclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiAvLyB1cGRhdGUgdGhlIHNjZW5lIG9uIG5leHQgdGlja1xyXG5cdFx0ICogc2NlbmUudXBkYXRlKCk7XHJcblx0XHQgKlxyXG5cdFx0ICogLy8gdXBkYXRlIHRoZSBzY2VuZSBpbW1lZGlhdGVseVxyXG5cdFx0ICogc2NlbmUudXBkYXRlKHRydWUpO1xyXG5cdFx0ICpcclxuXHRcdCAqIEBmaXJlcyBTY2VuZS51cGRhdGVcclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0ge2Jvb2xlYW59IFtpbW1lZGlhdGVseT1mYWxzZV0gLSBJZiBgdHJ1ZWAgdGhlIHVwZGF0ZSB3aWxsIGJlIGluc3RhbnQsIGlmIGBmYWxzZWAgaXQgd2lsbCB3YWl0IHVudGlsIG5leHQgdXBkYXRlIGN5Y2xlIChiZXR0ZXIgcGVyZm9ybWFuY2UpLlxyXG5cdFx0ICogQHJldHVybnMge1NjZW5lfSBQYXJlbnQgb2JqZWN0IGZvciBjaGFpbmluZy5cclxuXHRcdCAqL1xyXG5cdFx0dGhpcy51cGRhdGUgPSBmdW5jdGlvbiAoaW1tZWRpYXRlbHkpIHtcclxuXHRcdFx0aWYgKF9jb250cm9sbGVyKSB7XHJcblx0XHRcdFx0aWYgKGltbWVkaWF0ZWx5KSB7XHJcblx0XHRcdFx0XHRpZiAoX2NvbnRyb2xsZXIuZW5hYmxlZCgpICYmIF9lbmFibGVkKSB7XHJcblx0XHRcdFx0XHRcdHZhclxyXG5cdFx0XHRcdFx0XHRcdHNjcm9sbFBvcyA9IF9jb250cm9sbGVyLmluZm8oXCJzY3JvbGxQb3NcIiksXHJcblx0XHRcdFx0XHRcdFx0bmV3UHJvZ3Jlc3M7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoX29wdGlvbnMuZHVyYXRpb24gPiAwKSB7XHJcblx0XHRcdFx0XHRcdFx0bmV3UHJvZ3Jlc3MgPSAoc2Nyb2xsUG9zIC0gX3Njcm9sbE9mZnNldC5zdGFydCkgLyAoX3Njcm9sbE9mZnNldC5lbmQgLSBfc2Nyb2xsT2Zmc2V0LnN0YXJ0KTtcclxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdFx0XHRuZXdQcm9ncmVzcyA9IHNjcm9sbFBvcyA+PSBfc2Nyb2xsT2Zmc2V0LnN0YXJ0ID8gMSA6IDA7XHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdFNjZW5lLnRyaWdnZXIoXCJ1cGRhdGVcIiwge1xyXG5cdFx0XHRcdFx0XHRcdHN0YXJ0UG9zOiBfc2Nyb2xsT2Zmc2V0LnN0YXJ0LFxyXG5cdFx0XHRcdFx0XHRcdGVuZFBvczogX3Njcm9sbE9mZnNldC5lbmQsXHJcblx0XHRcdFx0XHRcdFx0c2Nyb2xsUG9zOiBzY3JvbGxQb3NcclxuXHRcdFx0XHRcdFx0fSk7XHJcblxyXG5cdFx0XHRcdFx0XHRTY2VuZS5wcm9ncmVzcyhuZXdQcm9ncmVzcyk7XHJcblx0XHRcdFx0XHR9IGVsc2UgaWYgKF9waW4gJiYgX3N0YXRlID09PSBTQ0VORV9TVEFURV9EVVJJTkcpIHtcclxuXHRcdFx0XHRcdFx0dXBkYXRlUGluU3RhdGUodHJ1ZSk7IC8vIHVucGluIGluIHBvc2l0aW9uXHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdF9jb250cm9sbGVyLnVwZGF0ZVNjZW5lKFNjZW5lLCBmYWxzZSk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiBTY2VuZTtcclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBVcGRhdGVzIGR5bmFtaWMgc2NlbmUgdmFyaWFibGVzIGxpa2UgdGhlIHRyaWdnZXIgZWxlbWVudCBwb3NpdGlvbiBvciB0aGUgZHVyYXRpb24uXHJcblx0XHQgKiBUaGlzIG1ldGhvZCBpcyBhdXRvbWF0aWNhbGx5IGNhbGxlZCBpbiByZWd1bGFyIGludGVydmFscyBmcm9tIHRoZSBjb250cm9sbGVyLiBTZWUge0BsaW5rIFNjcm9sbE1hZ2ljLkNvbnRyb2xsZXJ9IG9wdGlvbiBgcmVmcmVzaEludGVydmFsYC5cclxuXHRcdCAqIFxyXG5cdFx0ICogWW91IGNhbiBjYWxsIGl0IHRvIG1pbmltaXplIGxhZywgZm9yIGV4YW1wbGUgd2hlbiB5b3UgaW50ZW50aW9uYWxseSBjaGFuZ2UgdGhlIHBvc2l0aW9uIG9mIHRoZSB0cmlnZ2VyRWxlbWVudC5cclxuXHRcdCAqIElmIHlvdSBkb24ndCBpdCB3aWxsIHNpbXBseSBiZSB1cGRhdGVkIGluIHRoZSBuZXh0IHJlZnJlc2ggaW50ZXJ2YWwgb2YgdGhlIGNvbnRhaW5lciwgd2hpY2ggaXMgdXN1YWxseSBzdWZmaWNpZW50LlxyXG5cdFx0ICpcclxuXHRcdCAqIEBtZXRob2QgU2Nyb2xsTWFnaWMuU2NlbmUjcmVmcmVzaFxyXG5cdFx0ICogQHNpbmNlIDEuMS4wXHJcblx0XHQgKiBAZXhhbXBsZVxyXG5cdFx0ICogc2NlbmUgPSBuZXcgU2Nyb2xsTWFnaWMuU2NlbmUoe3RyaWdnZXJFbGVtZW50OiBcIiN0cmlnZ2VyXCJ9KTtcclxuXHRcdCAqIFxyXG5cdFx0ICogLy8gY2hhbmdlIHRoZSBwb3NpdGlvbiBvZiB0aGUgdHJpZ2dlclxyXG5cdFx0ICogJChcIiN0cmlnZ2VyXCIpLmNzcyhcInRvcFwiLCA1MDApO1xyXG5cdFx0ICogLy8gaW1tZWRpYXRlbHkgbGV0IHRoZSBzY2VuZSBrbm93IG9mIHRoaXMgY2hhbmdlXHJcblx0XHQgKiBzY2VuZS5yZWZyZXNoKCk7XHJcblx0XHQgKlxyXG5cdFx0ICogQGZpcmVzIHtAbGluayBTY2VuZS5zaGlmdH0sIGlmIHRoZSB0cmlnZ2VyIGVsZW1lbnQgcG9zaXRpb24gb3IgdGhlIGR1cmF0aW9uIGNoYW5nZWRcclxuXHRcdCAqIEBmaXJlcyB7QGxpbmsgU2NlbmUuY2hhbmdlfSwgaWYgdGhlIGR1cmF0aW9uIGNoYW5nZWRcclxuXHRcdCAqXHJcblx0XHQgKiBAcmV0dXJucyB7U2NlbmV9IFBhcmVudCBvYmplY3QgZm9yIGNoYWluaW5nLlxyXG5cdFx0ICovXHJcblx0XHR0aGlzLnJlZnJlc2ggPSBmdW5jdGlvbiAoKSB7XHJcblx0XHRcdHVwZGF0ZUR1cmF0aW9uKCk7XHJcblx0XHRcdHVwZGF0ZVRyaWdnZXJFbGVtZW50UG9zaXRpb24oKTtcclxuXHRcdFx0Ly8gdXBkYXRlIHRyaWdnZXIgZWxlbWVudCBwb3NpdGlvblxyXG5cdFx0XHRyZXR1cm4gU2NlbmU7XHJcblx0XHR9O1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogKipHZXQqKiBvciAqKlNldCoqIHRoZSBzY2VuZSdzIHByb2dyZXNzLiAgXHJcblx0XHQgKiBVc3VhbGx5IGl0IHNob3VsZG4ndCBiZSBuZWNlc3NhcnkgdG8gdXNlIHRoaXMgYXMgYSBzZXR0ZXIsIGFzIGl0IGlzIHNldCBhdXRvbWF0aWNhbGx5IGJ5IHNjZW5lLnVwZGF0ZSgpLiAgXHJcblx0XHQgKiBUaGUgb3JkZXIgaW4gd2hpY2ggdGhlIGV2ZW50cyBhcmUgZmlyZWQgZGVwZW5kcyBvbiB0aGUgZHVyYXRpb24gb2YgdGhlIHNjZW5lOlxyXG5cdFx0ICogIDEuIFNjZW5lcyB3aXRoIGBkdXJhdGlvbiA9PSAwYDogIFxyXG5cdFx0ICogIFNjZW5lcyB0aGF0IGhhdmUgbm8gZHVyYXRpb24gYnkgZGVmaW5pdGlvbiBoYXZlIG5vIGVuZGluZy4gVGh1cyB0aGUgYGVuZGAgZXZlbnQgd2lsbCBuZXZlciBiZSBmaXJlZC4gIFxyXG5cdFx0ICogIFdoZW4gdGhlIHRyaWdnZXIgcG9zaXRpb24gb2YgdGhlIHNjZW5lIGlzIHBhc3NlZCB0aGUgZXZlbnRzIGFyZSBhbHdheXMgZmlyZWQgaW4gdGhpcyBvcmRlcjogIFxyXG5cdFx0ICogIGBlbnRlcmAsIGBzdGFydGAsIGBwcm9ncmVzc2Agd2hlbiBzY3JvbGxpbmcgZm9yd2FyZCAgXHJcblx0XHQgKiAgYW5kICBcclxuXHRcdCAqICBgcHJvZ3Jlc3NgLCBgc3RhcnRgLCBgbGVhdmVgIHdoZW4gc2Nyb2xsaW5nIGluIHJldmVyc2VcclxuXHRcdCAqICAyLiBTY2VuZXMgd2l0aCBgZHVyYXRpb24gPiAwYDogIFxyXG5cdFx0ICogIFNjZW5lcyB3aXRoIGEgc2V0IGR1cmF0aW9uIGhhdmUgYSBkZWZpbmVkIHN0YXJ0IGFuZCBlbmQgcG9pbnQuICBcclxuXHRcdCAqICBXaGVuIHNjcm9sbGluZyBwYXN0IHRoZSBzdGFydCBwb3NpdGlvbiBvZiB0aGUgc2NlbmUgaXQgd2lsbCBmaXJlIHRoZXNlIGV2ZW50cyBpbiB0aGlzIG9yZGVyOiAgXHJcblx0XHQgKiAgYGVudGVyYCwgYHN0YXJ0YCwgYHByb2dyZXNzYCAgXHJcblx0XHQgKiAgV2hlbiBjb250aW51aW5nIHRvIHNjcm9sbCBhbmQgcGFzc2luZyB0aGUgZW5kIHBvaW50IGl0IHdpbGwgZmlyZSB0aGVzZSBldmVudHM6ICBcclxuXHRcdCAqICBgcHJvZ3Jlc3NgLCBgZW5kYCwgYGxlYXZlYCAgXHJcblx0XHQgKiAgV2hlbiByZXZlcnNpbmcgdGhyb3VnaCB0aGUgZW5kIHBvaW50IHRoZXNlIGV2ZW50cyBhcmUgZmlyZWQ6ICBcclxuXHRcdCAqICBgZW50ZXJgLCBgZW5kYCwgYHByb2dyZXNzYCAgXHJcblx0XHQgKiAgQW5kIHdoZW4gY29udGludWluZyB0byBzY3JvbGwgcGFzdCB0aGUgc3RhcnQgcG9zaXRpb24gaW4gcmV2ZXJzZSBpdCB3aWxsIGZpcmU6ICBcclxuXHRcdCAqICBgcHJvZ3Jlc3NgLCBgc3RhcnRgLCBgbGVhdmVgICBcclxuXHRcdCAqICBJbiBiZXR3ZWVuIHN0YXJ0IGFuZCBlbmQgdGhlIGBwcm9ncmVzc2AgZXZlbnQgd2lsbCBiZSBjYWxsZWQgY29uc3RhbnRseSwgd2hlbmV2ZXIgdGhlIHByb2dyZXNzIGNoYW5nZXMuXHJcblx0XHQgKiBcclxuXHRcdCAqIEluIHNob3J0OiAgXHJcblx0XHQgKiBgZW50ZXJgIGV2ZW50cyB3aWxsIGFsd2F5cyB0cmlnZ2VyICoqYmVmb3JlKiogdGhlIHByb2dyZXNzIHVwZGF0ZSBhbmQgYGxlYXZlYCBlbnZlbnRzIHdpbGwgdHJpZ2dlciAqKmFmdGVyKiogdGhlIHByb2dyZXNzIHVwZGF0ZS4gIFxyXG5cdFx0ICogYHN0YXJ0YCBhbmQgYGVuZGAgd2lsbCBhbHdheXMgdHJpZ2dlciBhdCB0aGVpciByZXNwZWN0aXZlIHBvc2l0aW9uLlxyXG5cdFx0ICogXHJcblx0XHQgKiBQbGVhc2UgcmV2aWV3IHRoZSBldmVudCBkZXNjcmlwdGlvbnMgZm9yIGRldGFpbHMgb24gdGhlIGV2ZW50cyBhbmQgdGhlIGV2ZW50IG9iamVjdCB0aGF0IGlzIHBhc3NlZCB0byB0aGUgY2FsbGJhY2suXHJcblx0XHQgKiBcclxuXHRcdCAqIEBtZXRob2QgU2Nyb2xsTWFnaWMuU2NlbmUjcHJvZ3Jlc3NcclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiAvLyBnZXQgdGhlIGN1cnJlbnQgc2NlbmUgcHJvZ3Jlc3NcclxuXHRcdCAqIHZhciBwcm9ncmVzcyA9IHNjZW5lLnByb2dyZXNzKCk7XHJcblx0XHQgKlxyXG5cdFx0ICogLy8gc2V0IG5ldyBzY2VuZSBwcm9ncmVzc1xyXG5cdFx0ICogc2NlbmUucHJvZ3Jlc3MoMC4zKTtcclxuXHRcdCAqXHJcblx0XHQgKiBAZmlyZXMge0BsaW5rIFNjZW5lLmVudGVyfSwgd2hlbiB1c2VkIGFzIHNldHRlclxyXG5cdFx0ICogQGZpcmVzIHtAbGluayBTY2VuZS5zdGFydH0sIHdoZW4gdXNlZCBhcyBzZXR0ZXJcclxuXHRcdCAqIEBmaXJlcyB7QGxpbmsgU2NlbmUucHJvZ3Jlc3N9LCB3aGVuIHVzZWQgYXMgc2V0dGVyXHJcblx0XHQgKiBAZmlyZXMge0BsaW5rIFNjZW5lLmVuZH0sIHdoZW4gdXNlZCBhcyBzZXR0ZXJcclxuXHRcdCAqIEBmaXJlcyB7QGxpbmsgU2NlbmUubGVhdmV9LCB3aGVuIHVzZWQgYXMgc2V0dGVyXHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIHtudW1iZXJ9IFtwcm9ncmVzc10gLSBUaGUgbmV3IHByb2dyZXNzIHZhbHVlIG9mIHRoZSBzY2VuZSBgWzAtMV1gLlxyXG5cdFx0ICogQHJldHVybnMge251bWJlcn0gYGdldGAgLSAgQ3VycmVudCBzY2VuZSBwcm9ncmVzcy5cclxuXHRcdCAqIEByZXR1cm5zIHtTY2VuZX0gYHNldGAgLSAgUGFyZW50IG9iamVjdCBmb3IgY2hhaW5pbmcuXHJcblx0XHQgKi9cclxuXHRcdHRoaXMucHJvZ3Jlc3MgPSBmdW5jdGlvbiAocHJvZ3Jlc3MpIHtcclxuXHRcdFx0aWYgKCFhcmd1bWVudHMubGVuZ3RoKSB7IC8vIGdldFxyXG5cdFx0XHRcdHJldHVybiBfcHJvZ3Jlc3M7XHJcblx0XHRcdH0gZWxzZSB7IC8vIHNldFxyXG5cdFx0XHRcdHZhclxyXG5cdFx0XHRcdFx0ZG9VcGRhdGUgPSBmYWxzZSxcclxuXHRcdFx0XHRcdG9sZFN0YXRlID0gX3N0YXRlLFxyXG5cdFx0XHRcdFx0c2Nyb2xsRGlyZWN0aW9uID0gX2NvbnRyb2xsZXIgPyBfY29udHJvbGxlci5pbmZvKFwic2Nyb2xsRGlyZWN0aW9uXCIpIDogJ1BBVVNFRCcsXHJcblx0XHRcdFx0XHRyZXZlcnNlT3JGb3J3YXJkID0gX29wdGlvbnMucmV2ZXJzZSB8fCBwcm9ncmVzcyA+PSBfcHJvZ3Jlc3M7XHJcblx0XHRcdFx0aWYgKF9vcHRpb25zLmR1cmF0aW9uID09PSAwKSB7XHJcblx0XHRcdFx0XHQvLyB6ZXJvIGR1cmF0aW9uIHNjZW5lc1xyXG5cdFx0XHRcdFx0ZG9VcGRhdGUgPSBfcHJvZ3Jlc3MgIT0gcHJvZ3Jlc3M7XHJcblx0XHRcdFx0XHRfcHJvZ3Jlc3MgPSBwcm9ncmVzcyA8IDEgJiYgcmV2ZXJzZU9yRm9yd2FyZCA/IDAgOiAxO1xyXG5cdFx0XHRcdFx0X3N0YXRlID0gX3Byb2dyZXNzID09PSAwID8gU0NFTkVfU1RBVEVfQkVGT1JFIDogU0NFTkVfU1RBVEVfRFVSSU5HO1xyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHQvLyBzY2VuZXMgd2l0aCBzdGFydCBhbmQgZW5kXHJcblx0XHRcdFx0XHRpZiAocHJvZ3Jlc3MgPCAwICYmIF9zdGF0ZSAhPT0gU0NFTkVfU1RBVEVfQkVGT1JFICYmIHJldmVyc2VPckZvcndhcmQpIHtcclxuXHRcdFx0XHRcdFx0Ly8gZ28gYmFjayB0byBpbml0aWFsIHN0YXRlXHJcblx0XHRcdFx0XHRcdF9wcm9ncmVzcyA9IDA7XHJcblx0XHRcdFx0XHRcdF9zdGF0ZSA9IFNDRU5FX1NUQVRFX0JFRk9SRTtcclxuXHRcdFx0XHRcdFx0ZG9VcGRhdGUgPSB0cnVlO1xyXG5cdFx0XHRcdFx0fSBlbHNlIGlmIChwcm9ncmVzcyA+PSAwICYmIHByb2dyZXNzIDwgMSAmJiByZXZlcnNlT3JGb3J3YXJkKSB7XHJcblx0XHRcdFx0XHRcdF9wcm9ncmVzcyA9IHByb2dyZXNzO1xyXG5cdFx0XHRcdFx0XHRfc3RhdGUgPSBTQ0VORV9TVEFURV9EVVJJTkc7XHJcblx0XHRcdFx0XHRcdGRvVXBkYXRlID0gdHJ1ZTtcclxuXHRcdFx0XHRcdH0gZWxzZSBpZiAocHJvZ3Jlc3MgPj0gMSAmJiBfc3RhdGUgIT09IFNDRU5FX1NUQVRFX0FGVEVSKSB7XHJcblx0XHRcdFx0XHRcdF9wcm9ncmVzcyA9IDE7XHJcblx0XHRcdFx0XHRcdF9zdGF0ZSA9IFNDRU5FX1NUQVRFX0FGVEVSO1xyXG5cdFx0XHRcdFx0XHRkb1VwZGF0ZSA9IHRydWU7XHJcblx0XHRcdFx0XHR9IGVsc2UgaWYgKF9zdGF0ZSA9PT0gU0NFTkVfU1RBVEVfRFVSSU5HICYmICFyZXZlcnNlT3JGb3J3YXJkKSB7XHJcblx0XHRcdFx0XHRcdHVwZGF0ZVBpblN0YXRlKCk7IC8vIGluIGNhc2Ugd2Ugc2Nyb2xsZWQgYmFja3dhcmRzIG1pZC1zY2VuZSBhbmQgcmV2ZXJzZSBpcyBkaXNhYmxlZCA9PiB1cGRhdGUgdGhlIHBpbiBwb3NpdGlvbiwgc28gaXQgZG9lc24ndCBtb3ZlIGJhY2sgYXMgd2VsbC5cclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0aWYgKGRvVXBkYXRlKSB7XHJcblx0XHRcdFx0XHQvLyBmaXJlIGV2ZW50c1xyXG5cdFx0XHRcdFx0dmFyXHJcblx0XHRcdFx0XHRcdGV2ZW50VmFycyA9IHtcclxuXHRcdFx0XHRcdFx0XHRwcm9ncmVzczogX3Byb2dyZXNzLFxyXG5cdFx0XHRcdFx0XHRcdHN0YXRlOiBfc3RhdGUsXHJcblx0XHRcdFx0XHRcdFx0c2Nyb2xsRGlyZWN0aW9uOiBzY3JvbGxEaXJlY3Rpb25cclxuXHRcdFx0XHRcdFx0fSxcclxuXHRcdFx0XHRcdFx0c3RhdGVDaGFuZ2VkID0gX3N0YXRlICE9IG9sZFN0YXRlO1xyXG5cclxuXHRcdFx0XHRcdHZhciB0cmlnZ2VyID0gZnVuY3Rpb24gKGV2ZW50TmFtZSkgeyAvLyB0bXAgaGVscGVyIHRvIHNpbXBsaWZ5IGNvZGVcclxuXHRcdFx0XHRcdFx0U2NlbmUudHJpZ2dlcihldmVudE5hbWUsIGV2ZW50VmFycyk7XHJcblx0XHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0XHRcdGlmIChzdGF0ZUNoYW5nZWQpIHsgLy8gZW50ZXIgZXZlbnRzXHJcblx0XHRcdFx0XHRcdGlmIChvbGRTdGF0ZSAhPT0gU0NFTkVfU1RBVEVfRFVSSU5HKSB7XHJcblx0XHRcdFx0XHRcdFx0dHJpZ2dlcihcImVudGVyXCIpO1xyXG5cdFx0XHRcdFx0XHRcdHRyaWdnZXIob2xkU3RhdGUgPT09IFNDRU5FX1NUQVRFX0JFRk9SRSA/IFwic3RhcnRcIiA6IFwiZW5kXCIpO1xyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR0cmlnZ2VyKFwicHJvZ3Jlc3NcIik7XHJcblx0XHRcdFx0XHRpZiAoc3RhdGVDaGFuZ2VkKSB7IC8vIGxlYXZlIGV2ZW50c1xyXG5cdFx0XHRcdFx0XHRpZiAoX3N0YXRlICE9PSBTQ0VORV9TVEFURV9EVVJJTkcpIHtcclxuXHRcdFx0XHRcdFx0XHR0cmlnZ2VyKF9zdGF0ZSA9PT0gU0NFTkVfU1RBVEVfQkVGT1JFID8gXCJzdGFydFwiIDogXCJlbmRcIik7XHJcblx0XHRcdFx0XHRcdFx0dHJpZ2dlcihcImxlYXZlXCIpO1xyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRyZXR1cm4gU2NlbmU7XHJcblx0XHRcdH1cclxuXHRcdH07XHJcblxyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogVXBkYXRlIHRoZSBzdGFydCBhbmQgZW5kIHNjcm9sbE9mZnNldCBvZiB0aGUgY29udGFpbmVyLlxyXG5cdFx0ICogVGhlIHBvc2l0aW9ucyByZWZsZWN0IHdoYXQgdGhlIGNvbnRyb2xsZXIncyBzY3JvbGwgcG9zaXRpb24gd2lsbCBiZSBhdCB0aGUgc3RhcnQgYW5kIGVuZCByZXNwZWN0aXZlbHkuXHJcblx0XHQgKiBJcyBjYWxsZWQsIHdoZW46XHJcblx0XHQgKiAgIC0gU2NlbmUgZXZlbnQgXCJjaGFuZ2VcIiBpcyBjYWxsZWQgd2l0aDogb2Zmc2V0LCB0cmlnZ2VySG9vaywgZHVyYXRpb24gXHJcblx0XHQgKiAgIC0gc2Nyb2xsIGNvbnRhaW5lciBldmVudCBcInJlc2l6ZVwiIGlzIGNhbGxlZFxyXG5cdFx0ICogICAtIHRoZSBwb3NpdGlvbiBvZiB0aGUgdHJpZ2dlckVsZW1lbnQgY2hhbmdlc1xyXG5cdFx0ICogICAtIHRoZSBjb250cm9sbGVyIGNoYW5nZXMgLT4gYWRkVG8oKVxyXG5cdFx0ICogQHByaXZhdGVcclxuXHRcdCAqL1xyXG5cdFx0dmFyIHVwZGF0ZVNjcm9sbE9mZnNldCA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0X3Njcm9sbE9mZnNldCA9IHtcclxuXHRcdFx0XHRzdGFydDogX3RyaWdnZXJQb3MgKyBfb3B0aW9ucy5vZmZzZXRcclxuXHRcdFx0fTtcclxuXHRcdFx0aWYgKF9jb250cm9sbGVyICYmIF9vcHRpb25zLnRyaWdnZXJFbGVtZW50KSB7XHJcblx0XHRcdFx0Ly8gdGFrZSBhd2F5IHRyaWdnZXJIb29rIHBvcnRpb24gdG8gZ2V0IHJlbGF0aXZlIHRvIHRvcFxyXG5cdFx0XHRcdF9zY3JvbGxPZmZzZXQuc3RhcnQgLT0gX2NvbnRyb2xsZXIuaW5mbyhcInNpemVcIikgKiBfb3B0aW9ucy50cmlnZ2VySG9vaztcclxuXHRcdFx0fVxyXG5cdFx0XHRfc2Nyb2xsT2Zmc2V0LmVuZCA9IF9zY3JvbGxPZmZzZXQuc3RhcnQgKyBfb3B0aW9ucy5kdXJhdGlvbjtcclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBVcGRhdGVzIHRoZSBkdXJhdGlvbiBpZiBzZXQgdG8gYSBkeW5hbWljIGZ1bmN0aW9uLlxyXG5cdFx0ICogVGhpcyBtZXRob2QgaXMgY2FsbGVkIHdoZW4gdGhlIHNjZW5lIGlzIGFkZGVkIHRvIGEgY29udHJvbGxlciBhbmQgaW4gcmVndWxhciBpbnRlcnZhbHMgZnJvbSB0aGUgY29udHJvbGxlciB0aHJvdWdoIHNjZW5lLnJlZnJlc2goKS5cclxuXHRcdCAqIFxyXG5cdFx0ICogQGZpcmVzIHtAbGluayBTY2VuZS5jaGFuZ2V9LCBpZiB0aGUgZHVyYXRpb24gY2hhbmdlZFxyXG5cdFx0ICogQGZpcmVzIHtAbGluayBTY2VuZS5zaGlmdH0sIGlmIHRoZSBkdXJhdGlvbiBjaGFuZ2VkXHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIHtib29sZWFufSBbc3VwcHJlc3NFdmVudHM9ZmFsc2VdIC0gSWYgdHJ1ZSB0aGUgc2hpZnQgZXZlbnQgd2lsbCBiZSBzdXBwcmVzc2VkLlxyXG5cdFx0ICogQHByaXZhdGVcclxuXHRcdCAqL1xyXG5cdFx0dmFyIHVwZGF0ZUR1cmF0aW9uID0gZnVuY3Rpb24gKHN1cHByZXNzRXZlbnRzKSB7XHJcblx0XHRcdC8vIHVwZGF0ZSBkdXJhdGlvblxyXG5cdFx0XHRpZiAoX2R1cmF0aW9uVXBkYXRlTWV0aG9kKSB7XHJcblx0XHRcdFx0dmFyIHZhcm5hbWUgPSBcImR1cmF0aW9uXCI7XHJcblx0XHRcdFx0aWYgKGNoYW5nZU9wdGlvbih2YXJuYW1lLCBfZHVyYXRpb25VcGRhdGVNZXRob2QuY2FsbChTY2VuZSkpICYmICFzdXBwcmVzc0V2ZW50cykgeyAvLyBzZXRcclxuXHRcdFx0XHRcdFNjZW5lLnRyaWdnZXIoXCJjaGFuZ2VcIiwge1xyXG5cdFx0XHRcdFx0XHR3aGF0OiB2YXJuYW1lLFxyXG5cdFx0XHRcdFx0XHRuZXd2YWw6IF9vcHRpb25zW3Zhcm5hbWVdXHJcblx0XHRcdFx0XHR9KTtcclxuXHRcdFx0XHRcdFNjZW5lLnRyaWdnZXIoXCJzaGlmdFwiLCB7XHJcblx0XHRcdFx0XHRcdHJlYXNvbjogdmFybmFtZVxyXG5cdFx0XHRcdFx0fSk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9O1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogVXBkYXRlcyB0aGUgcG9zaXRpb24gb2YgdGhlIHRyaWdnZXJFbGVtZW50LCBpZiBwcmVzZW50LlxyXG5cdFx0ICogVGhpcyBtZXRob2QgaXMgY2FsbGVkIC4uLlxyXG5cdFx0ICogIC0gLi4uIHdoZW4gdGhlIHRyaWdnZXJFbGVtZW50IGlzIGNoYW5nZWRcclxuXHRcdCAqICAtIC4uLiB3aGVuIHRoZSBzY2VuZSBpcyBhZGRlZCB0byBhIChuZXcpIGNvbnRyb2xsZXJcclxuXHRcdCAqICAtIC4uLiBpbiByZWd1bGFyIGludGVydmFscyBmcm9tIHRoZSBjb250cm9sbGVyIHRocm91Z2ggc2NlbmUucmVmcmVzaCgpLlxyXG5cdFx0ICogXHJcblx0XHQgKiBAZmlyZXMge0BsaW5rIFNjZW5lLnNoaWZ0fSwgaWYgdGhlIHBvc2l0aW9uIGNoYW5nZWRcclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0ge2Jvb2xlYW59IFtzdXBwcmVzc0V2ZW50cz1mYWxzZV0gLSBJZiB0cnVlIHRoZSBzaGlmdCBldmVudCB3aWxsIGJlIHN1cHByZXNzZWQuXHJcblx0XHQgKiBAcHJpdmF0ZVxyXG5cdFx0ICovXHJcblx0XHR2YXIgdXBkYXRlVHJpZ2dlckVsZW1lbnRQb3NpdGlvbiA9IGZ1bmN0aW9uIChzdXBwcmVzc0V2ZW50cykge1xyXG5cdFx0XHR2YXJcclxuXHRcdFx0XHRlbGVtZW50UG9zID0gMCxcclxuXHRcdFx0XHR0ZWxlbSA9IF9vcHRpb25zLnRyaWdnZXJFbGVtZW50O1xyXG5cdFx0XHRpZiAoX2NvbnRyb2xsZXIgJiYgKHRlbGVtIHx8IF90cmlnZ2VyUG9zID4gMCkpIHsgLy8gZWl0aGVyIGFuIGVsZW1lbnQgZXhpc3RzIG9yIHdhcyByZW1vdmVkIGFuZCB0aGUgdHJpZ2dlclBvcyBpcyBzdGlsbCA+IDBcclxuXHRcdFx0XHRpZiAodGVsZW0pIHsgLy8gdGhlcmUgY3VycmVudGx5IGEgdHJpZ2dlckVsZW1lbnQgc2V0XHJcblx0XHRcdFx0XHRpZiAodGVsZW0ucGFyZW50Tm9kZSkgeyAvLyBjaGVjayBpZiBlbGVtZW50IGlzIHN0aWxsIGF0dGFjaGVkIHRvIERPTVxyXG5cdFx0XHRcdFx0XHR2YXJcclxuXHRcdFx0XHRcdFx0XHRjb250cm9sbGVySW5mbyA9IF9jb250cm9sbGVyLmluZm8oKSxcclxuXHRcdFx0XHRcdFx0XHRjb250YWluZXJPZmZzZXQgPSBfdXRpbC5nZXQub2Zmc2V0KGNvbnRyb2xsZXJJbmZvLmNvbnRhaW5lciksIC8vIGNvbnRhaW5lciBwb3NpdGlvbiBpcyBuZWVkZWQgYmVjYXVzZSBlbGVtZW50IG9mZnNldCBpcyByZXR1cm5lZCBpbiByZWxhdGlvbiB0byBkb2N1bWVudCwgbm90IGluIHJlbGF0aW9uIHRvIGNvbnRhaW5lci5cclxuXHRcdFx0XHRcdFx0XHRwYXJhbSA9IGNvbnRyb2xsZXJJbmZvLnZlcnRpY2FsID8gXCJ0b3BcIiA6IFwibGVmdFwiOyAvLyB3aGljaCBwYXJhbSBpcyBvZiBpbnRlcmVzdCA/XHJcblxyXG5cdFx0XHRcdFx0XHQvLyBpZiBwYXJlbnQgaXMgc3BhY2VyLCB1c2Ugc3BhY2VyIHBvc2l0aW9uIGluc3RlYWQgc28gY29ycmVjdCBzdGFydCBwb3NpdGlvbiBpcyByZXR1cm5lZCBmb3IgcGlubmVkIGVsZW1lbnRzLlxyXG5cdFx0XHRcdFx0XHR3aGlsZSAodGVsZW0ucGFyZW50Tm9kZS5oYXNBdHRyaWJ1dGUoUElOX1NQQUNFUl9BVFRSSUJVVEUpKSB7XHJcblx0XHRcdFx0XHRcdFx0dGVsZW0gPSB0ZWxlbS5wYXJlbnROb2RlO1xyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHR2YXIgZWxlbWVudE9mZnNldCA9IF91dGlsLmdldC5vZmZzZXQodGVsZW0pO1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCFjb250cm9sbGVySW5mby5pc0RvY3VtZW50KSB7IC8vIGNvbnRhaW5lciBpcyBub3QgdGhlIGRvY3VtZW50IHJvb3QsIHNvIHN1YnN0cmFjdCBzY3JvbGwgUG9zaXRpb24gdG8gZ2V0IGNvcnJlY3QgdHJpZ2dlciBlbGVtZW50IHBvc2l0aW9uIHJlbGF0aXZlIHRvIHNjcm9sbGNvbnRlbnRcclxuXHRcdFx0XHRcdFx0XHRjb250YWluZXJPZmZzZXRbcGFyYW1dIC09IF9jb250cm9sbGVyLnNjcm9sbFBvcygpO1xyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRlbGVtZW50UG9zID0gZWxlbWVudE9mZnNldFtwYXJhbV0gLSBjb250YWluZXJPZmZzZXRbcGFyYW1dO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7IC8vIHRoZXJlIHdhcyBhbiBlbGVtZW50LCBidXQgaXQgd2FzIHJlbW92ZWQgZnJvbSBET01cclxuXHRcdFx0XHRcdFx0bG9nKDIsIFwiV0FSTklORzogdHJpZ2dlckVsZW1lbnQgd2FzIHJlbW92ZWQgZnJvbSBET00gYW5kIHdpbGwgYmUgcmVzZXQgdG9cIiwgdW5kZWZpbmVkKTtcclxuXHRcdFx0XHRcdFx0U2NlbmUudHJpZ2dlckVsZW1lbnQodW5kZWZpbmVkKTsgLy8gdW5zZXQsIHNvIGEgY2hhbmdlIGV2ZW50IGlzIHRyaWdnZXJlZFxyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0dmFyIGNoYW5nZWQgPSBlbGVtZW50UG9zICE9IF90cmlnZ2VyUG9zO1xyXG5cdFx0XHRcdF90cmlnZ2VyUG9zID0gZWxlbWVudFBvcztcclxuXHRcdFx0XHRpZiAoY2hhbmdlZCAmJiAhc3VwcHJlc3NFdmVudHMpIHtcclxuXHRcdFx0XHRcdFNjZW5lLnRyaWdnZXIoXCJzaGlmdFwiLCB7XHJcblx0XHRcdFx0XHRcdHJlYXNvbjogXCJ0cmlnZ2VyRWxlbWVudFBvc2l0aW9uXCJcclxuXHRcdFx0XHRcdH0pO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0fTtcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIFRyaWdnZXIgYSBzaGlmdCBldmVudCwgd2hlbiB0aGUgY29udGFpbmVyIGlzIHJlc2l6ZWQgYW5kIHRoZSB0cmlnZ2VySG9vayBpcyA+IDEuXHJcblx0XHQgKiBAcHJpdmF0ZVxyXG5cdFx0ICovXHJcblx0XHR2YXIgb25Db250YWluZXJSZXNpemUgPSBmdW5jdGlvbiAoZSkge1xyXG5cdFx0XHRpZiAoX29wdGlvbnMudHJpZ2dlckhvb2sgPiAwKSB7XHJcblx0XHRcdFx0U2NlbmUudHJpZ2dlcihcInNoaWZ0XCIsIHtcclxuXHRcdFx0XHRcdHJlYXNvbjogXCJjb250YWluZXJSZXNpemVcIlxyXG5cdFx0XHRcdH0pO1xyXG5cdFx0XHR9XHJcblx0XHR9O1xyXG5cclxuXHJcblx0XHR2YXIgX3ZhbGlkYXRlID0gX3V0aWwuZXh0ZW5kKFNDRU5FX09QVElPTlMudmFsaWRhdGUsIHtcclxuXHRcdFx0Ly8gdmFsaWRhdGlvbiBmb3IgZHVyYXRpb24gaGFuZGxlZCBpbnRlcm5hbGx5IGZvciByZWZlcmVuY2UgdG8gcHJpdmF0ZSB2YXIgX2R1cmF0aW9uTWV0aG9kXHJcblx0XHRcdGR1cmF0aW9uOiBmdW5jdGlvbiAodmFsKSB7XHJcblx0XHRcdFx0aWYgKF91dGlsLnR5cGUuU3RyaW5nKHZhbCkgJiYgdmFsLm1hdGNoKC9eKFxcLnxcXGQpKlxcZCslJC8pKSB7XHJcblx0XHRcdFx0XHQvLyBwZXJjZW50YWdlIHZhbHVlXHJcblx0XHRcdFx0XHR2YXIgcGVyYyA9IHBhcnNlRmxvYXQodmFsKSAvIDEwMDtcclxuXHRcdFx0XHRcdHZhbCA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0XHRcdFx0cmV0dXJuIF9jb250cm9sbGVyID8gX2NvbnRyb2xsZXIuaW5mbyhcInNpemVcIikgKiBwZXJjIDogMDtcclxuXHRcdFx0XHRcdH07XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGlmIChfdXRpbC50eXBlLkZ1bmN0aW9uKHZhbCkpIHtcclxuXHRcdFx0XHRcdC8vIGZ1bmN0aW9uXHJcblx0XHRcdFx0XHRfZHVyYXRpb25VcGRhdGVNZXRob2QgPSB2YWw7XHJcblx0XHRcdFx0XHR0cnkge1xyXG5cdFx0XHRcdFx0XHR2YWwgPSBwYXJzZUZsb2F0KF9kdXJhdGlvblVwZGF0ZU1ldGhvZC5jYWxsKFNjZW5lKSk7XHJcblx0XHRcdFx0XHR9IGNhdGNoIChlKSB7XHJcblx0XHRcdFx0XHRcdHZhbCA9IC0xOyAvLyB3aWxsIGNhdXNlIGVycm9yIGJlbG93XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdC8vIHZhbCBoYXMgdG8gYmUgZmxvYXRcclxuXHRcdFx0XHR2YWwgPSBwYXJzZUZsb2F0KHZhbCk7XHJcblx0XHRcdFx0aWYgKCFfdXRpbC50eXBlLk51bWJlcih2YWwpIHx8IHZhbCA8IDApIHtcclxuXHRcdFx0XHRcdGlmIChfZHVyYXRpb25VcGRhdGVNZXRob2QpIHtcclxuXHRcdFx0XHRcdFx0X2R1cmF0aW9uVXBkYXRlTWV0aG9kID0gdW5kZWZpbmVkO1xyXG5cdFx0XHRcdFx0XHR0aHJvdyBbXCJJbnZhbGlkIHJldHVybiB2YWx1ZSBvZiBzdXBwbGllZCBmdW5jdGlvbiBmb3Igb3B0aW9uIFxcXCJkdXJhdGlvblxcXCI6XCIsIHZhbF07XHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0XHR0aHJvdyBbXCJJbnZhbGlkIHZhbHVlIGZvciBvcHRpb24gXFxcImR1cmF0aW9uXFxcIjpcIiwgdmFsXTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0cmV0dXJuIHZhbDtcclxuXHRcdFx0fVxyXG5cdFx0fSk7XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBDaGVja3MgdGhlIHZhbGlkaXR5IG9mIGEgc3BlY2lmaWMgb3IgYWxsIG9wdGlvbnMgYW5kIHJlc2V0IHRvIGRlZmF1bHQgaWYgbmVjY2Vzc2FyeS5cclxuXHRcdCAqIEBwcml2YXRlXHJcblx0XHQgKi9cclxuXHRcdHZhciB2YWxpZGF0ZU9wdGlvbiA9IGZ1bmN0aW9uIChjaGVjaykge1xyXG5cdFx0XHRjaGVjayA9IGFyZ3VtZW50cy5sZW5ndGggPyBbY2hlY2tdIDogT2JqZWN0LmtleXMoX3ZhbGlkYXRlKTtcclxuXHRcdFx0Y2hlY2suZm9yRWFjaChmdW5jdGlvbiAob3B0aW9uTmFtZSwga2V5KSB7XHJcblx0XHRcdFx0dmFyIHZhbHVlO1xyXG5cdFx0XHRcdGlmIChfdmFsaWRhdGVbb3B0aW9uTmFtZV0pIHsgLy8gdGhlcmUgaXMgYSB2YWxpZGF0aW9uIG1ldGhvZCBmb3IgdGhpcyBvcHRpb25cclxuXHRcdFx0XHRcdHRyeSB7IC8vIHZhbGlkYXRlIHZhbHVlXHJcblx0XHRcdFx0XHRcdHZhbHVlID0gX3ZhbGlkYXRlW29wdGlvbk5hbWVdKF9vcHRpb25zW29wdGlvbk5hbWVdKTtcclxuXHRcdFx0XHRcdH0gY2F0Y2ggKGUpIHsgLy8gdmFsaWRhdGlvbiBmYWlsZWQgLT4gcmVzZXQgdG8gZGVmYXVsdFxyXG5cdFx0XHRcdFx0XHR2YWx1ZSA9IERFRkFVTFRfT1BUSU9OU1tvcHRpb25OYW1lXTtcclxuXHRcdFx0XHRcdFx0dmFyIGxvZ01TRyA9IF91dGlsLnR5cGUuU3RyaW5nKGUpID8gW2VdIDogZTtcclxuXHRcdFx0XHRcdFx0aWYgKF91dGlsLnR5cGUuQXJyYXkobG9nTVNHKSkge1xyXG5cdFx0XHRcdFx0XHRcdGxvZ01TR1swXSA9IFwiRVJST1I6IFwiICsgbG9nTVNHWzBdO1xyXG5cdFx0XHRcdFx0XHRcdGxvZ01TRy51bnNoaWZ0KDEpOyAvLyBsb2dsZXZlbCAxIGZvciBlcnJvciBtc2dcclxuXHRcdFx0XHRcdFx0XHRsb2cuYXBwbHkodGhpcywgbG9nTVNHKTtcclxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdFx0XHRsb2coMSwgXCJFUlJPUjogUHJvYmxlbSBleGVjdXRpbmcgdmFsaWRhdGlvbiBjYWxsYmFjayBmb3Igb3B0aW9uICdcIiArIG9wdGlvbk5hbWUgKyBcIic6XCIsIGUubWVzc2FnZSk7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdH0gZmluYWxseSB7XHJcblx0XHRcdFx0XHRcdF9vcHRpb25zW29wdGlvbk5hbWVdID0gdmFsdWU7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9KTtcclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBIZWxwZXIgdXNlZCBieSB0aGUgc2V0dGVyL2dldHRlcnMgZm9yIHNjZW5lIG9wdGlvbnNcclxuXHRcdCAqIEBwcml2YXRlXHJcblx0XHQgKi9cclxuXHRcdHZhciBjaGFuZ2VPcHRpb24gPSBmdW5jdGlvbiAodmFybmFtZSwgbmV3dmFsKSB7XHJcblx0XHRcdHZhclxyXG5cdFx0XHRcdGNoYW5nZWQgPSBmYWxzZSxcclxuXHRcdFx0XHRvbGR2YWwgPSBfb3B0aW9uc1t2YXJuYW1lXTtcclxuXHRcdFx0aWYgKF9vcHRpb25zW3Zhcm5hbWVdICE9IG5ld3ZhbCkge1xyXG5cdFx0XHRcdF9vcHRpb25zW3Zhcm5hbWVdID0gbmV3dmFsO1xyXG5cdFx0XHRcdHZhbGlkYXRlT3B0aW9uKHZhcm5hbWUpOyAvLyByZXNldHMgdG8gZGVmYXVsdCBpZiBuZWNlc3NhcnlcclxuXHRcdFx0XHRjaGFuZ2VkID0gb2xkdmFsICE9IF9vcHRpb25zW3Zhcm5hbWVdO1xyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiBjaGFuZ2VkO1xyXG5cdFx0fTtcclxuXHJcblx0XHQvLyBnZW5lcmF0ZSBnZXR0ZXJzL3NldHRlcnMgZm9yIGFsbCBvcHRpb25zXHJcblx0XHR2YXIgYWRkU2NlbmVPcHRpb24gPSBmdW5jdGlvbiAob3B0aW9uTmFtZSkge1xyXG5cdFx0XHRpZiAoIVNjZW5lW29wdGlvbk5hbWVdKSB7XHJcblx0XHRcdFx0U2NlbmVbb3B0aW9uTmFtZV0gPSBmdW5jdGlvbiAobmV3VmFsKSB7XHJcblx0XHRcdFx0XHRpZiAoIWFyZ3VtZW50cy5sZW5ndGgpIHsgLy8gZ2V0XHJcblx0XHRcdFx0XHRcdHJldHVybiBfb3B0aW9uc1tvcHRpb25OYW1lXTtcclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHRcdGlmIChvcHRpb25OYW1lID09PSBcImR1cmF0aW9uXCIpIHsgLy8gbmV3IGR1cmF0aW9uIGlzIHNldCwgc28gYW55IHByZXZpb3VzbHkgc2V0IGZ1bmN0aW9uIG11c3QgYmUgdW5zZXRcclxuXHRcdFx0XHRcdFx0XHRfZHVyYXRpb25VcGRhdGVNZXRob2QgPSB1bmRlZmluZWQ7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0aWYgKGNoYW5nZU9wdGlvbihvcHRpb25OYW1lLCBuZXdWYWwpKSB7IC8vIHNldFxyXG5cdFx0XHRcdFx0XHRcdFNjZW5lLnRyaWdnZXIoXCJjaGFuZ2VcIiwge1xyXG5cdFx0XHRcdFx0XHRcdFx0d2hhdDogb3B0aW9uTmFtZSxcclxuXHRcdFx0XHRcdFx0XHRcdG5ld3ZhbDogX29wdGlvbnNbb3B0aW9uTmFtZV1cclxuXHRcdFx0XHRcdFx0XHR9KTtcclxuXHRcdFx0XHRcdFx0XHRpZiAoU0NFTkVfT1BUSU9OUy5zaGlmdHMuaW5kZXhPZihvcHRpb25OYW1lKSA+IC0xKSB7XHJcblx0XHRcdFx0XHRcdFx0XHRTY2VuZS50cmlnZ2VyKFwic2hpZnRcIiwge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRyZWFzb246IG9wdGlvbk5hbWVcclxuXHRcdFx0XHRcdFx0XHRcdH0pO1xyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0cmV0dXJuIFNjZW5lO1xyXG5cdFx0XHRcdH07XHJcblx0XHRcdH1cclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiAqKkdldCoqIG9yICoqU2V0KiogdGhlIGR1cmF0aW9uIG9wdGlvbiB2YWx1ZS5cclxuXHRcdCAqXHJcblx0XHQgKiBBcyBhICoqc2V0dGVyKiogaXQgYWNjZXB0cyB0aHJlZSB0eXBlcyBvZiBwYXJhbWV0ZXJzOlxyXG5cdFx0ICogMS4gYG51bWJlcmA6IFNldHMgdGhlIGR1cmF0aW9uIG9mIHRoZSBzY2VuZSB0byBleGFjdGx5IHRoaXMgYW1vdW50IG9mIHBpeGVscy4gIFxyXG5cdFx0ICogICBUaGlzIG1lYW5zIHRoZSBzY2VuZSB3aWxsIGxhc3QgZm9yIGV4YWN0bHkgdGhpcyBhbW91bnQgb2YgcGl4ZWxzIHNjcm9sbGVkLiBTdWItUGl4ZWxzIGFyZSBhbHNvIHZhbGlkLlxyXG5cdFx0ICogICBBIHZhbHVlIG9mIGAwYCBtZWFucyB0aGF0IHRoZSBzY2VuZSBpcyAnb3BlbiBlbmQnIGFuZCBubyBlbmQgd2lsbCBiZSB0cmlnZ2VyZWQuIFBpbnMgd2lsbCBuZXZlciB1bnBpbiBhbmQgYW5pbWF0aW9ucyB3aWxsIHBsYXkgaW5kZXBlbmRlbnRseSBvZiBzY3JvbGwgcHJvZ3Jlc3MuXHJcblx0XHQgKiAyLiBgc3RyaW5nYDogQWx3YXlzIHVwZGF0ZXMgdGhlIGR1cmF0aW9uIHJlbGF0aXZlIHRvIHBhcmVudCBzY3JvbGwgY29udGFpbmVyLiAgXHJcblx0XHQgKiAgIEZvciBleGFtcGxlIGBcIjEwMCVcImAgd2lsbCBrZWVwIHRoZSBkdXJhdGlvbiBhbHdheXMgZXhhY3RseSBhdCB0aGUgaW5uZXIgaGVpZ2h0IG9mIHRoZSBzY3JvbGwgY29udGFpbmVyLlxyXG5cdFx0ICogICBXaGVuIHNjcm9sbGluZyB2ZXJ0aWNhbGx5IHRoZSB3aWR0aCBpcyB1c2VkIGZvciByZWZlcmVuY2UgcmVzcGVjdGl2ZWx5LlxyXG5cdFx0ICogMy4gYGZ1bmN0aW9uYDogVGhlIHN1cHBsaWVkIGZ1bmN0aW9uIHdpbGwgYmUgY2FsbGVkIHRvIHJldHVybiB0aGUgc2NlbmUgZHVyYXRpb24uXHJcblx0XHQgKiAgIFRoaXMgaXMgdXNlZnVsIGluIHNldHVwcyB3aGVyZSB0aGUgZHVyYXRpb24gZGVwZW5kcyBvbiBvdGhlciBlbGVtZW50cyB3aG8gbWlnaHQgY2hhbmdlIHNpemUuIEJ5IHN1cHBseWluZyBhIGZ1bmN0aW9uIHlvdSBjYW4gcmV0dXJuIGEgdmFsdWUgaW5zdGVhZCBvZiB1cGRhdGluZyBwb3RlbnRpYWxseSBtdWx0aXBsZSBzY2VuZSBkdXJhdGlvbnMuICBcclxuXHRcdCAqICAgVGhlIHNjZW5lIGNhbiBiZSByZWZlcmVuY2VkIGluc2lkZSB0aGUgY2FsbGJhY2sgdXNpbmcgYHRoaXNgLlxyXG5cdFx0ICogICBfKipXQVJOSU5HOioqIFRoaXMgaXMgYW4gZWFzeSB3YXkgdG8ga2lsbCBwZXJmb3JtYW5jZSwgYXMgdGhlIGNhbGxiYWNrIHdpbGwgYmUgZXhlY3V0ZWQgZXZlcnkgdGltZSBgU2NlbmUucmVmcmVzaCgpYCBpcyBjYWxsZWQsIHdoaWNoIGhhcHBlbnMgYSBsb3QuIFRoZSBpbnRlcnZhbCBpcyBkZWZpbmVkIGJ5IHRoZSBjb250cm9sbGVyIChzZWUgU2Nyb2xsTWFnaWMuQ29udHJvbGxlciBvcHRpb24gYHJlZnJlc2hJbnRlcnZhbGApLiAgXHJcblx0XHQgKiAgIEl0J3MgcmVjb21lbmRlZCB0byBhdm9pZCBjYWxjdWxhdGlvbnMgd2l0aGluIHRoZSBmdW5jdGlvbiBhbmQgdXNlIGNhY2hlZCB2YXJpYWJsZXMgYXMgcmV0dXJuIHZhbHVlcy4gIFxyXG5cdFx0ICogICBUaGlzIGNvdW50cyBkb3VibGUgaWYgeW91IHVzZSB0aGUgc2FtZSBmdW5jdGlvbiBmb3IgbXVsdGlwbGUgc2NlbmVzLl9cclxuXHRcdCAqXHJcblx0XHQgKiBAbWV0aG9kIFNjcm9sbE1hZ2ljLlNjZW5lI2R1cmF0aW9uXHJcblx0XHQgKiBAZXhhbXBsZVxyXG5cdFx0ICogLy8gZ2V0IHRoZSBjdXJyZW50IGR1cmF0aW9uIHZhbHVlXHJcblx0XHQgKiB2YXIgZHVyYXRpb24gPSBzY2VuZS5kdXJhdGlvbigpO1xyXG5cdFx0ICpcclxuXHRcdCAqIC8vIHNldCBhIG5ldyBkdXJhdGlvblxyXG5cdFx0ICogc2NlbmUuZHVyYXRpb24oMzAwKTtcclxuXHRcdCAqXHJcblx0XHQgKiAvLyBzZXQgZHVyYXRpb24gcmVzcG9uc2l2ZWx5IHRvIGNvbnRhaW5lciBzaXplXHJcblx0XHQgKiBzY2VuZS5kdXJhdGlvbihcIjEwMCVcIik7XHJcblx0XHQgKlxyXG5cdFx0ICogLy8gdXNlIGEgZnVuY3Rpb24gdG8gcmFuZG9taXplIHRoZSBkdXJhdGlvbiBmb3Igc29tZSByZWFzb24uXHJcblx0XHQgKiB2YXIgZHVyYXRpb25WYWx1ZUNhY2hlO1xyXG5cdFx0ICogZnVuY3Rpb24gZHVyYXRpb25DYWxsYmFjayAoKSB7XHJcblx0XHQgKiAgIHJldHVybiBkdXJhdGlvblZhbHVlQ2FjaGU7XHJcblx0XHQgKiB9XHJcblx0XHQgKiBmdW5jdGlvbiB1cGRhdGVEdXJhdGlvbiAoKSB7XHJcblx0XHQgKiAgIGR1cmF0aW9uVmFsdWVDYWNoZSA9IE1hdGgucmFuZG9tKCkgKiAxMDA7XHJcblx0XHQgKiB9XHJcblx0XHQgKiB1cGRhdGVEdXJhdGlvbigpOyAvLyBzZXQgdG8gaW5pdGlhbCB2YWx1ZVxyXG5cdFx0ICogc2NlbmUuZHVyYXRpb24oZHVyYXRpb25DYWxsYmFjayk7IC8vIHNldCBkdXJhdGlvbiBjYWxsYmFja1xyXG5cdFx0ICpcclxuXHRcdCAqIEBmaXJlcyB7QGxpbmsgU2NlbmUuY2hhbmdlfSwgd2hlbiB1c2VkIGFzIHNldHRlclxyXG5cdFx0ICogQGZpcmVzIHtAbGluayBTY2VuZS5zaGlmdH0sIHdoZW4gdXNlZCBhcyBzZXR0ZXJcclxuXHRcdCAqIEBwYXJhbSB7KG51bWJlcnxzdHJpbmd8ZnVuY3Rpb24pfSBbbmV3RHVyYXRpb25dIC0gVGhlIG5ldyBkdXJhdGlvbiBzZXR0aW5nIGZvciB0aGUgc2NlbmUuXHJcblx0XHQgKiBAcmV0dXJucyB7bnVtYmVyfSBgZ2V0YCAtICBDdXJyZW50IHNjZW5lIGR1cmF0aW9uLlxyXG5cdFx0ICogQHJldHVybnMge1NjZW5lfSBgc2V0YCAtICBQYXJlbnQgb2JqZWN0IGZvciBjaGFpbmluZy5cclxuXHRcdCAqL1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogKipHZXQqKiBvciAqKlNldCoqIHRoZSBvZmZzZXQgb3B0aW9uIHZhbHVlLlxyXG5cdFx0ICogQG1ldGhvZCBTY3JvbGxNYWdpYy5TY2VuZSNvZmZzZXRcclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiAvLyBnZXQgdGhlIGN1cnJlbnQgb2Zmc2V0XHJcblx0XHQgKiB2YXIgb2Zmc2V0ID0gc2NlbmUub2Zmc2V0KCk7XHJcblx0XHQgKlxyXG5cdFx0ICogLy8gc2V0IGEgbmV3IG9mZnNldFxyXG5cdFx0ICogc2NlbmUub2Zmc2V0KDEwMCk7XHJcblx0XHQgKlxyXG5cdFx0ICogQGZpcmVzIHtAbGluayBTY2VuZS5jaGFuZ2V9LCB3aGVuIHVzZWQgYXMgc2V0dGVyXHJcblx0XHQgKiBAZmlyZXMge0BsaW5rIFNjZW5lLnNoaWZ0fSwgd2hlbiB1c2VkIGFzIHNldHRlclxyXG5cdFx0ICogQHBhcmFtIHtudW1iZXJ9IFtuZXdPZmZzZXRdIC0gVGhlIG5ldyBvZmZzZXQgb2YgdGhlIHNjZW5lLlxyXG5cdFx0ICogQHJldHVybnMge251bWJlcn0gYGdldGAgLSAgQ3VycmVudCBzY2VuZSBvZmZzZXQuXHJcblx0XHQgKiBAcmV0dXJucyB7U2NlbmV9IGBzZXRgIC0gIFBhcmVudCBvYmplY3QgZm9yIGNoYWluaW5nLlxyXG5cdFx0ICovXHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiAqKkdldCoqIG9yICoqU2V0KiogdGhlIHRyaWdnZXJFbGVtZW50IG9wdGlvbiB2YWx1ZS5cclxuXHRcdCAqIERvZXMgKipub3QqKiBmaXJlIGBTY2VuZS5zaGlmdGAsIGJlY2F1c2UgY2hhbmdpbmcgdGhlIHRyaWdnZXIgRWxlbWVudCBkb2Vzbid0IG5lY2Vzc2FyaWx5IG1lYW4gdGhlIHN0YXJ0IHBvc2l0aW9uIGNoYW5nZXMuIFRoaXMgd2lsbCBiZSBkZXRlcm1pbmVkIGluIGBTY2VuZS5yZWZyZXNoKClgLCB3aGljaCBpcyBhdXRvbWF0aWNhbGx5IHRyaWdnZXJlZC5cclxuXHRcdCAqIEBtZXRob2QgU2Nyb2xsTWFnaWMuU2NlbmUjdHJpZ2dlckVsZW1lbnRcclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiAvLyBnZXQgdGhlIGN1cnJlbnQgdHJpZ2dlckVsZW1lbnRcclxuXHRcdCAqIHZhciB0cmlnZ2VyRWxlbWVudCA9IHNjZW5lLnRyaWdnZXJFbGVtZW50KCk7XHJcblx0XHQgKlxyXG5cdFx0ICogLy8gc2V0IGEgbmV3IHRyaWdnZXJFbGVtZW50IHVzaW5nIGEgc2VsZWN0b3JcclxuXHRcdCAqIHNjZW5lLnRyaWdnZXJFbGVtZW50KFwiI3RyaWdnZXJcIik7XHJcblx0XHQgKiAvLyBzZXQgYSBuZXcgdHJpZ2dlckVsZW1lbnQgdXNpbmcgYSBET00gb2JqZWN0XHJcblx0XHQgKiBzY2VuZS50cmlnZ2VyRWxlbWVudChkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInRyaWdnZXJcIikpO1xyXG5cdFx0ICpcclxuXHRcdCAqIEBmaXJlcyB7QGxpbmsgU2NlbmUuY2hhbmdlfSwgd2hlbiB1c2VkIGFzIHNldHRlclxyXG5cdFx0ICogQHBhcmFtIHsoc3RyaW5nfG9iamVjdCl9IFtuZXdUcmlnZ2VyRWxlbWVudF0gLSBUaGUgbmV3IHRyaWdnZXIgZWxlbWVudCBmb3IgdGhlIHNjZW5lLlxyXG5cdFx0ICogQHJldHVybnMgeyhzdHJpbmd8b2JqZWN0KX0gYGdldGAgLSAgQ3VycmVudCB0cmlnZ2VyRWxlbWVudC5cclxuXHRcdCAqIEByZXR1cm5zIHtTY2VuZX0gYHNldGAgLSAgUGFyZW50IG9iamVjdCBmb3IgY2hhaW5pbmcuXHJcblx0XHQgKi9cclxuXHJcblx0XHQvKipcclxuXHRcdCAqICoqR2V0Kiogb3IgKipTZXQqKiB0aGUgdHJpZ2dlckhvb2sgb3B0aW9uIHZhbHVlLlxyXG5cdFx0ICogQG1ldGhvZCBTY3JvbGxNYWdpYy5TY2VuZSN0cmlnZ2VySG9va1xyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIC8vIGdldCB0aGUgY3VycmVudCB0cmlnZ2VySG9vayB2YWx1ZVxyXG5cdFx0ICogdmFyIHRyaWdnZXJIb29rID0gc2NlbmUudHJpZ2dlckhvb2soKTtcclxuXHRcdCAqXHJcblx0XHQgKiAvLyBzZXQgYSBuZXcgdHJpZ2dlckhvb2sgdXNpbmcgYSBzdHJpbmdcclxuXHRcdCAqIHNjZW5lLnRyaWdnZXJIb29rKFwib25MZWF2ZVwiKTtcclxuXHRcdCAqIC8vIHNldCBhIG5ldyB0cmlnZ2VySG9vayB1c2luZyBhIG51bWJlclxyXG5cdFx0ICogc2NlbmUudHJpZ2dlckhvb2soMC43KTtcclxuXHRcdCAqXHJcblx0XHQgKiBAZmlyZXMge0BsaW5rIFNjZW5lLmNoYW5nZX0sIHdoZW4gdXNlZCBhcyBzZXR0ZXJcclxuXHRcdCAqIEBmaXJlcyB7QGxpbmsgU2NlbmUuc2hpZnR9LCB3aGVuIHVzZWQgYXMgc2V0dGVyXHJcblx0XHQgKiBAcGFyYW0geyhudW1iZXJ8c3RyaW5nKX0gW25ld1RyaWdnZXJIb29rXSAtIFRoZSBuZXcgdHJpZ2dlckhvb2sgb2YgdGhlIHNjZW5lLiBTZWUge0BsaW5rIFNjZW5lfSBwYXJhbWV0ZXIgZGVzY3JpcHRpb24gZm9yIHZhbHVlIG9wdGlvbnMuXHJcblx0XHQgKiBAcmV0dXJucyB7bnVtYmVyfSBgZ2V0YCAtICBDdXJyZW50IHRyaWdnZXJIb29rIChBTFdBWVMgbnVtZXJpY2FsKS5cclxuXHRcdCAqIEByZXR1cm5zIHtTY2VuZX0gYHNldGAgLSAgUGFyZW50IG9iamVjdCBmb3IgY2hhaW5pbmcuXHJcblx0XHQgKi9cclxuXHJcblx0XHQvKipcclxuXHRcdCAqICoqR2V0Kiogb3IgKipTZXQqKiB0aGUgcmV2ZXJzZSBvcHRpb24gdmFsdWUuXHJcblx0XHQgKiBAbWV0aG9kIFNjcm9sbE1hZ2ljLlNjZW5lI3JldmVyc2VcclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiAvLyBnZXQgdGhlIGN1cnJlbnQgcmV2ZXJzZSBvcHRpb25cclxuXHRcdCAqIHZhciByZXZlcnNlID0gc2NlbmUucmV2ZXJzZSgpO1xyXG5cdFx0ICpcclxuXHRcdCAqIC8vIHNldCBuZXcgcmV2ZXJzZSBvcHRpb25cclxuXHRcdCAqIHNjZW5lLnJldmVyc2UoZmFsc2UpO1xyXG5cdFx0ICpcclxuXHRcdCAqIEBmaXJlcyB7QGxpbmsgU2NlbmUuY2hhbmdlfSwgd2hlbiB1c2VkIGFzIHNldHRlclxyXG5cdFx0ICogQHBhcmFtIHtib29sZWFufSBbbmV3UmV2ZXJzZV0gLSBUaGUgbmV3IHJldmVyc2Ugc2V0dGluZyBvZiB0aGUgc2NlbmUuXHJcblx0XHQgKiBAcmV0dXJucyB7Ym9vbGVhbn0gYGdldGAgLSAgQ3VycmVudCByZXZlcnNlIG9wdGlvbiB2YWx1ZS5cclxuXHRcdCAqIEByZXR1cm5zIHtTY2VuZX0gYHNldGAgLSAgUGFyZW50IG9iamVjdCBmb3IgY2hhaW5pbmcuXHJcblx0XHQgKi9cclxuXHJcblx0XHQvKipcclxuXHRcdCAqICoqR2V0Kiogb3IgKipTZXQqKiB0aGUgbG9nbGV2ZWwgb3B0aW9uIHZhbHVlLlxyXG5cdFx0ICogQG1ldGhvZCBTY3JvbGxNYWdpYy5TY2VuZSNsb2dsZXZlbFxyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIC8vIGdldCB0aGUgY3VycmVudCBsb2dsZXZlbFxyXG5cdFx0ICogdmFyIGxvZ2xldmVsID0gc2NlbmUubG9nbGV2ZWwoKTtcclxuXHRcdCAqXHJcblx0XHQgKiAvLyBzZXQgbmV3IGxvZ2xldmVsXHJcblx0XHQgKiBzY2VuZS5sb2dsZXZlbCgzKTtcclxuXHRcdCAqXHJcblx0XHQgKiBAZmlyZXMge0BsaW5rIFNjZW5lLmNoYW5nZX0sIHdoZW4gdXNlZCBhcyBzZXR0ZXJcclxuXHRcdCAqIEBwYXJhbSB7bnVtYmVyfSBbbmV3TG9nbGV2ZWxdIC0gVGhlIG5ldyBsb2dsZXZlbCBzZXR0aW5nIG9mIHRoZSBzY2VuZS4gYFswLTNdYFxyXG5cdFx0ICogQHJldHVybnMge251bWJlcn0gYGdldGAgLSAgQ3VycmVudCBsb2dsZXZlbC5cclxuXHRcdCAqIEByZXR1cm5zIHtTY2VuZX0gYHNldGAgLSAgUGFyZW50IG9iamVjdCBmb3IgY2hhaW5pbmcuXHJcblx0XHQgKi9cclxuXHJcblx0XHQvKipcclxuXHRcdCAqICoqR2V0KiogdGhlIGFzc29jaWF0ZWQgY29udHJvbGxlci5cclxuXHRcdCAqIEBtZXRob2QgU2Nyb2xsTWFnaWMuU2NlbmUjY29udHJvbGxlclxyXG5cdFx0ICogQGV4YW1wbGVcclxuXHRcdCAqIC8vIGdldCB0aGUgY29udHJvbGxlciBvZiBhIHNjZW5lXHJcblx0XHQgKiB2YXIgY29udHJvbGxlciA9IHNjZW5lLmNvbnRyb2xsZXIoKTtcclxuXHRcdCAqXHJcblx0XHQgKiBAcmV0dXJucyB7U2Nyb2xsTWFnaWMuQ29udHJvbGxlcn0gUGFyZW50IGNvbnRyb2xsZXIgb3IgYHVuZGVmaW5lZGBcclxuXHRcdCAqL1xyXG5cdFx0dGhpcy5jb250cm9sbGVyID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRyZXR1cm4gX2NvbnRyb2xsZXI7XHJcblx0XHR9O1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogKipHZXQqKiB0aGUgY3VycmVudCBzdGF0ZS5cclxuXHRcdCAqIEBtZXRob2QgU2Nyb2xsTWFnaWMuU2NlbmUjc3RhdGVcclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiAvLyBnZXQgdGhlIGN1cnJlbnQgc3RhdGVcclxuXHRcdCAqIHZhciBzdGF0ZSA9IHNjZW5lLnN0YXRlKCk7XHJcblx0XHQgKlxyXG5cdFx0ICogQHJldHVybnMge3N0cmluZ30gYFwiQkVGT1JFXCJgLCBgXCJEVVJJTkdcImAgb3IgYFwiQUZURVJcImBcclxuXHRcdCAqL1xyXG5cdFx0dGhpcy5zdGF0ZSA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0cmV0dXJuIF9zdGF0ZTtcclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiAqKkdldCoqIHRoZSBjdXJyZW50IHNjcm9sbCBvZmZzZXQgZm9yIHRoZSBzdGFydCBvZiB0aGUgc2NlbmUuICBcclxuXHRcdCAqIE1pbmQsIHRoYXQgdGhlIHNjcm9sbE9mZnNldCBpcyByZWxhdGVkIHRvIHRoZSBzaXplIG9mIHRoZSBjb250YWluZXIsIGlmIGB0cmlnZ2VySG9va2AgaXMgYmlnZ2VyIHRoYW4gYDBgIChvciBgXCJvbkxlYXZlXCJgKS4gIFxyXG5cdFx0ICogVGhpcyBtZWFucywgdGhhdCByZXNpemluZyB0aGUgY29udGFpbmVyIG9yIGNoYW5naW5nIHRoZSBgdHJpZ2dlckhvb2tgIHdpbGwgaW5mbHVlbmNlIHRoZSBzY2VuZSdzIHN0YXJ0IG9mZnNldC5cclxuXHRcdCAqIEBtZXRob2QgU2Nyb2xsTWFnaWMuU2NlbmUjc2Nyb2xsT2Zmc2V0XHJcblx0XHQgKiBAZXhhbXBsZVxyXG5cdFx0ICogLy8gZ2V0IHRoZSBjdXJyZW50IHNjcm9sbCBvZmZzZXQgZm9yIHRoZSBzdGFydCBhbmQgZW5kIG9mIHRoZSBzY2VuZS5cclxuXHRcdCAqIHZhciBzdGFydCA9IHNjZW5lLnNjcm9sbE9mZnNldCgpO1xyXG5cdFx0ICogdmFyIGVuZCA9IHNjZW5lLnNjcm9sbE9mZnNldCgpICsgc2NlbmUuZHVyYXRpb24oKTtcclxuXHRcdCAqIGNvbnNvbGUubG9nKFwidGhlIHNjZW5lIHN0YXJ0cyBhdFwiLCBzdGFydCwgXCJhbmQgZW5kcyBhdFwiLCBlbmQpO1xyXG5cdFx0ICpcclxuXHRcdCAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBzY3JvbGwgb2Zmc2V0IChvZiB0aGUgY29udGFpbmVyKSBhdCB3aGljaCB0aGUgc2NlbmUgd2lsbCB0cmlnZ2VyLiBZIHZhbHVlIGZvciB2ZXJ0aWNhbCBhbmQgWCB2YWx1ZSBmb3IgaG9yaXpvbnRhbCBzY3JvbGxzLlxyXG5cdFx0ICovXHJcblx0XHR0aGlzLnNjcm9sbE9mZnNldCA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0cmV0dXJuIF9zY3JvbGxPZmZzZXQuc3RhcnQ7XHJcblx0XHR9O1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogKipHZXQqKiB0aGUgdHJpZ2dlciBwb3NpdGlvbiBvZiB0aGUgc2NlbmUgKGluY2x1ZGluZyB0aGUgdmFsdWUgb2YgdGhlIGBvZmZzZXRgIG9wdGlvbikuICBcclxuXHRcdCAqIEBtZXRob2QgU2Nyb2xsTWFnaWMuU2NlbmUjdHJpZ2dlclBvc2l0aW9uXHJcblx0XHQgKiBAZXhhbXBsZVxyXG5cdFx0ICogLy8gZ2V0IHRoZSBzY2VuZSdzIHRyaWdnZXIgcG9zaXRpb25cclxuXHRcdCAqIHZhciB0cmlnZ2VyUG9zaXRpb24gPSBzY2VuZS50cmlnZ2VyUG9zaXRpb24oKTtcclxuXHRcdCAqXHJcblx0XHQgKiBAcmV0dXJucyB7bnVtYmVyfSBTdGFydCBwb3NpdGlvbiBvZiB0aGUgc2NlbmUuIFRvcCBwb3NpdGlvbiB2YWx1ZSBmb3IgdmVydGljYWwgYW5kIGxlZnQgcG9zaXRpb24gdmFsdWUgZm9yIGhvcml6b250YWwgc2Nyb2xscy5cclxuXHRcdCAqL1xyXG5cdFx0dGhpcy50cmlnZ2VyUG9zaXRpb24gPSBmdW5jdGlvbiAoKSB7XHJcblx0XHRcdHZhciBwb3MgPSBfb3B0aW9ucy5vZmZzZXQ7IC8vIHRoZSBvZmZzZXQgaXMgdGhlIGJhc2lzXHJcblx0XHRcdGlmIChfY29udHJvbGxlcikge1xyXG5cdFx0XHRcdC8vIGdldCB0aGUgdHJpZ2dlciBwb3NpdGlvblxyXG5cdFx0XHRcdGlmIChfb3B0aW9ucy50cmlnZ2VyRWxlbWVudCkge1xyXG5cdFx0XHRcdFx0Ly8gRWxlbWVudCBhcyB0cmlnZ2VyXHJcblx0XHRcdFx0XHRwb3MgKz0gX3RyaWdnZXJQb3M7XHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdC8vIHJldHVybiB0aGUgaGVpZ2h0IG9mIHRoZSB0cmlnZ2VySG9vayB0byBzdGFydCBhdCB0aGUgYmVnaW5uaW5nXHJcblx0XHRcdFx0XHRwb3MgKz0gX2NvbnRyb2xsZXIuaW5mbyhcInNpemVcIikgKiBTY2VuZS50cmlnZ2VySG9vaygpO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0XHRyZXR1cm4gcG9zO1xyXG5cdFx0fTtcclxuXHJcblxyXG5cdFx0dmFyXHJcblx0XHRcdF9waW4sXHJcblx0XHRcdF9waW5PcHRpb25zO1xyXG5cclxuXHRcdFNjZW5lXHJcblx0XHRcdC5vbihcInNoaWZ0LmludGVybmFsXCIsIGZ1bmN0aW9uIChlKSB7XHJcblx0XHRcdFx0dmFyIGR1cmF0aW9uQ2hhbmdlZCA9IGUucmVhc29uID09PSBcImR1cmF0aW9uXCI7XHJcblx0XHRcdFx0aWYgKChfc3RhdGUgPT09IFNDRU5FX1NUQVRFX0FGVEVSICYmIGR1cmF0aW9uQ2hhbmdlZCkgfHwgKF9zdGF0ZSA9PT0gU0NFTkVfU1RBVEVfRFVSSU5HICYmIF9vcHRpb25zLmR1cmF0aW9uID09PSAwKSkge1xyXG5cdFx0XHRcdFx0Ly8gaWYgW2R1cmF0aW9uIGNoYW5nZWQgYWZ0ZXIgYSBzY2VuZSAoaW5zaWRlIHNjZW5lIHByb2dyZXNzIHVwZGF0ZXMgcGluIHBvc2l0aW9uKV0gb3IgW2R1cmF0aW9uIGlzIDAsIHdlIGFyZSBpbiBwaW4gcGhhc2UgYW5kIHNvbWUgb3RoZXIgdmFsdWUgY2hhbmdlZF0uXHJcblx0XHRcdFx0XHR1cGRhdGVQaW5TdGF0ZSgpO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRpZiAoZHVyYXRpb25DaGFuZ2VkKSB7XHJcblx0XHRcdFx0XHR1cGRhdGVQaW5EaW1lbnNpb25zKCk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9KVxyXG5cdFx0XHQub24oXCJwcm9ncmVzcy5pbnRlcm5hbFwiLCBmdW5jdGlvbiAoZSkge1xyXG5cdFx0XHRcdHVwZGF0ZVBpblN0YXRlKCk7XHJcblx0XHRcdH0pXHJcblx0XHRcdC5vbihcImFkZC5pbnRlcm5hbFwiLCBmdW5jdGlvbiAoZSkge1xyXG5cdFx0XHRcdHVwZGF0ZVBpbkRpbWVuc2lvbnMoKTtcclxuXHRcdFx0fSlcclxuXHRcdFx0Lm9uKFwiZGVzdHJveS5pbnRlcm5hbFwiLCBmdW5jdGlvbiAoZSkge1xyXG5cdFx0XHRcdFNjZW5lLnJlbW92ZVBpbihlLnJlc2V0KTtcclxuXHRcdFx0fSk7XHJcblx0XHQvKipcclxuXHRcdCAqIFVwZGF0ZSB0aGUgcGluIHN0YXRlLlxyXG5cdFx0ICogQHByaXZhdGVcclxuXHRcdCAqL1xyXG5cdFx0dmFyIHVwZGF0ZVBpblN0YXRlID0gZnVuY3Rpb24gKGZvcmNlVW5waW4pIHtcclxuXHRcdFx0aWYgKF9waW4gJiYgX2NvbnRyb2xsZXIpIHtcclxuXHRcdFx0XHR2YXJcclxuXHRcdFx0XHRcdGNvbnRhaW5lckluZm8gPSBfY29udHJvbGxlci5pbmZvKCksXHJcblx0XHRcdFx0XHRwaW5UYXJnZXQgPSBfcGluT3B0aW9ucy5zcGFjZXIuZmlyc3RDaGlsZDsgLy8gbWF5IGJlIHBpbiBlbGVtZW50IG9yIGFub3RoZXIgc3BhY2VyLCBpZiBjYXNjYWRpbmcgcGluc1xyXG5cclxuXHRcdFx0XHRpZiAoIWZvcmNlVW5waW4gJiYgX3N0YXRlID09PSBTQ0VORV9TVEFURV9EVVJJTkcpIHsgLy8gZHVyaW5nIHNjZW5lIG9yIGlmIGR1cmF0aW9uIGlzIDAgYW5kIHdlIGFyZSBwYXN0IHRoZSB0cmlnZ2VyXHJcblx0XHRcdFx0XHQvLyBwaW5uZWQgc3RhdGVcclxuXHRcdFx0XHRcdGlmIChfdXRpbC5jc3MocGluVGFyZ2V0LCBcInBvc2l0aW9uXCIpICE9IFwiZml4ZWRcIikge1xyXG5cdFx0XHRcdFx0XHQvLyBjaGFuZ2Ugc3RhdGUgYmVmb3JlIHVwZGF0aW5nIHBpbiBzcGFjZXIgKHBvc2l0aW9uIGNoYW5nZXMgZHVlIHRvIGZpeGVkIGNvbGxhcHNpbmcgbWlnaHQgb2NjdXIuKVxyXG5cdFx0XHRcdFx0XHRfdXRpbC5jc3MocGluVGFyZ2V0LCB7XHJcblx0XHRcdFx0XHRcdFx0XCJwb3NpdGlvblwiOiBcImZpeGVkXCJcclxuXHRcdFx0XHRcdFx0fSk7XHJcblx0XHRcdFx0XHRcdC8vIHVwZGF0ZSBwaW4gc3BhY2VyXHJcblx0XHRcdFx0XHRcdHVwZGF0ZVBpbkRpbWVuc2lvbnMoKTtcclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR2YXJcclxuXHRcdFx0XHRcdFx0Zml4ZWRQb3MgPSBfdXRpbC5nZXQub2Zmc2V0KF9waW5PcHRpb25zLnNwYWNlciwgdHJ1ZSksIC8vIGdldCB2aWV3cG9ydCBwb3NpdGlvbiBvZiBzcGFjZXJcclxuXHRcdFx0XHRcdFx0c2Nyb2xsRGlzdGFuY2UgPSBfb3B0aW9ucy5yZXZlcnNlIHx8IF9vcHRpb25zLmR1cmF0aW9uID09PSAwID9cclxuXHRcdFx0XHRcdFx0Y29udGFpbmVySW5mby5zY3JvbGxQb3MgLSBfc2Nyb2xsT2Zmc2V0LnN0YXJ0IC8vIHF1aWNrZXJcclxuXHRcdFx0XHRcdFx0OlxyXG5cdFx0XHRcdFx0XHRNYXRoLnJvdW5kKF9wcm9ncmVzcyAqIF9vcHRpb25zLmR1cmF0aW9uICogMTApIC8gMTA7IC8vIGlmIG5vIHJldmVyc2UgYW5kIGR1cmluZyBwaW4gdGhlIHBvc2l0aW9uIG5lZWRzIHRvIGJlIHJlY2FsY3VsYXRlZCB1c2luZyB0aGUgcHJvZ3Jlc3NcclxuXHJcblx0XHRcdFx0XHQvLyBhZGQgc2Nyb2xsRGlzdGFuY2VcclxuXHRcdFx0XHRcdGZpeGVkUG9zW2NvbnRhaW5lckluZm8udmVydGljYWwgPyBcInRvcFwiIDogXCJsZWZ0XCJdICs9IHNjcm9sbERpc3RhbmNlO1xyXG5cclxuXHRcdFx0XHRcdC8vIHNldCBuZXcgdmFsdWVzXHJcblx0XHRcdFx0XHRfdXRpbC5jc3MoX3Bpbk9wdGlvbnMuc3BhY2VyLmZpcnN0Q2hpbGQsIHtcclxuXHRcdFx0XHRcdFx0dG9wOiBmaXhlZFBvcy50b3AsXHJcblx0XHRcdFx0XHRcdGxlZnQ6IGZpeGVkUG9zLmxlZnRcclxuXHRcdFx0XHRcdH0pO1xyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHQvLyB1bnBpbm5lZCBzdGF0ZVxyXG5cdFx0XHRcdFx0dmFyXHJcblx0XHRcdFx0XHRcdG5ld0NTUyA9IHtcclxuXHRcdFx0XHRcdFx0XHRwb3NpdGlvbjogX3Bpbk9wdGlvbnMuaW5GbG93ID8gXCJyZWxhdGl2ZVwiIDogXCJhYnNvbHV0ZVwiLFxyXG5cdFx0XHRcdFx0XHRcdHRvcDogMCxcclxuXHRcdFx0XHRcdFx0XHRsZWZ0OiAwXHJcblx0XHRcdFx0XHRcdH0sXHJcblx0XHRcdFx0XHRcdGNoYW5nZSA9IF91dGlsLmNzcyhwaW5UYXJnZXQsIFwicG9zaXRpb25cIikgIT0gbmV3Q1NTLnBvc2l0aW9uO1xyXG5cclxuXHRcdFx0XHRcdGlmICghX3Bpbk9wdGlvbnMucHVzaEZvbGxvd2Vycykge1xyXG5cdFx0XHRcdFx0XHRuZXdDU1NbY29udGFpbmVySW5mby52ZXJ0aWNhbCA/IFwidG9wXCIgOiBcImxlZnRcIl0gPSBfb3B0aW9ucy5kdXJhdGlvbiAqIF9wcm9ncmVzcztcclxuXHRcdFx0XHRcdH0gZWxzZSBpZiAoX29wdGlvbnMuZHVyYXRpb24gPiAwKSB7IC8vIG9ubHkgY29uY2VybnMgc2NlbmVzIHdpdGggZHVyYXRpb25cclxuXHRcdFx0XHRcdFx0aWYgKF9zdGF0ZSA9PT0gU0NFTkVfU1RBVEVfQUZURVIgJiYgcGFyc2VGbG9hdChfdXRpbC5jc3MoX3Bpbk9wdGlvbnMuc3BhY2VyLCBcInBhZGRpbmctdG9wXCIpKSA9PT0gMCkge1xyXG5cdFx0XHRcdFx0XHRcdGNoYW5nZSA9IHRydWU7IC8vIGlmIGluIGFmdGVyIHN0YXRlIGJ1dCBoYXZlbnQgdXBkYXRlZCBzcGFjZXIgeWV0IChqdW1wZWQgcGFzdCBwaW4pXHJcblx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoX3N0YXRlID09PSBTQ0VORV9TVEFURV9CRUZPUkUgJiYgcGFyc2VGbG9hdChfdXRpbC5jc3MoX3Bpbk9wdGlvbnMuc3BhY2VyLCBcInBhZGRpbmctYm90dG9tXCIpKSA9PT0gMCkgeyAvLyBiZWZvcmVcclxuXHRcdFx0XHRcdFx0XHRjaGFuZ2UgPSB0cnVlOyAvLyBqdW1wZWQgcGFzdCBmaXhlZCBzdGF0ZSB1cHdhcmQgZGlyZWN0aW9uXHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdC8vIHNldCBuZXcgdmFsdWVzXHJcblx0XHRcdFx0XHRfdXRpbC5jc3MocGluVGFyZ2V0LCBuZXdDU1MpO1xyXG5cdFx0XHRcdFx0aWYgKGNoYW5nZSkge1xyXG5cdFx0XHRcdFx0XHQvLyB1cGRhdGUgcGluIHNwYWNlciBpZiBzdGF0ZSBjaGFuZ2VkXHJcblx0XHRcdFx0XHRcdHVwZGF0ZVBpbkRpbWVuc2lvbnMoKTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBVcGRhdGUgdGhlIHBpbiBzcGFjZXIgYW5kL29yIGVsZW1lbnQgc2l6ZS5cclxuXHRcdCAqIFRoZSBzaXplIG9mIHRoZSBzcGFjZXIgbmVlZHMgdG8gYmUgdXBkYXRlZCB3aGVuZXZlciB0aGUgZHVyYXRpb24gb2YgdGhlIHNjZW5lIGNoYW5nZXMsIGlmIGl0IGlzIHRvIHB1c2ggZG93biBmb2xsb3dpbmcgZWxlbWVudHMuXHJcblx0XHQgKiBAcHJpdmF0ZVxyXG5cdFx0ICovXHJcblx0XHR2YXIgdXBkYXRlUGluRGltZW5zaW9ucyA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0aWYgKF9waW4gJiYgX2NvbnRyb2xsZXIgJiYgX3Bpbk9wdGlvbnMuaW5GbG93KSB7IC8vIG5vIHNwYWNlcnJlc2l6ZSwgaWYgb3JpZ2luYWwgcG9zaXRpb24gaXMgYWJzb2x1dGVcclxuXHRcdFx0XHR2YXJcclxuXHRcdFx0XHRcdGFmdGVyID0gKF9zdGF0ZSA9PT0gU0NFTkVfU1RBVEVfQUZURVIpLFxyXG5cdFx0XHRcdFx0YmVmb3JlID0gKF9zdGF0ZSA9PT0gU0NFTkVfU1RBVEVfQkVGT1JFKSxcclxuXHRcdFx0XHRcdGR1cmluZyA9IChfc3RhdGUgPT09IFNDRU5FX1NUQVRFX0RVUklORyksXHJcblx0XHRcdFx0XHR2ZXJ0aWNhbCA9IF9jb250cm9sbGVyLmluZm8oXCJ2ZXJ0aWNhbFwiKSxcclxuXHRcdFx0XHRcdHBpblRhcmdldCA9IF9waW5PcHRpb25zLnNwYWNlci5maXJzdENoaWxkLCAvLyB1c3VhbGx5IHRoZSBwaW5lZCBlbGVtZW50IGJ1dCBjYW4gYWxzbyBiZSBhbm90aGVyIHNwYWNlciAoY2FzY2FkZWQgcGlucylcclxuXHRcdFx0XHRcdG1hcmdpbkNvbGxhcHNlID0gX3V0aWwuaXNNYXJnaW5Db2xsYXBzZVR5cGUoX3V0aWwuY3NzKF9waW5PcHRpb25zLnNwYWNlciwgXCJkaXNwbGF5XCIpKSxcclxuXHRcdFx0XHRcdGNzcyA9IHt9O1xyXG5cclxuXHRcdFx0XHQvLyBzZXQgbmV3IHNpemVcclxuXHRcdFx0XHQvLyBpZiByZWxzaXplOiBzcGFjZXIgLT4gcGluIHwgZWxzZTogcGluIC0+IHNwYWNlclxyXG5cdFx0XHRcdGlmIChfcGluT3B0aW9ucy5yZWxTaXplLndpZHRoIHx8IF9waW5PcHRpb25zLnJlbFNpemUuYXV0b0Z1bGxXaWR0aCkge1xyXG5cdFx0XHRcdFx0aWYgKGR1cmluZykge1xyXG5cdFx0XHRcdFx0XHRfdXRpbC5jc3MoX3Bpbiwge1xyXG5cdFx0XHRcdFx0XHRcdFwid2lkdGhcIjogX3V0aWwuZ2V0LndpZHRoKF9waW5PcHRpb25zLnNwYWNlcilcclxuXHRcdFx0XHRcdFx0fSk7XHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0XHRfdXRpbC5jc3MoX3Bpbiwge1xyXG5cdFx0XHRcdFx0XHRcdFwid2lkdGhcIjogXCIxMDAlXCJcclxuXHRcdFx0XHRcdFx0fSk7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdC8vIG1pbndpZHRoIGlzIG5lZWRlZCBmb3IgY2FzY2FkZWQgcGlucy5cclxuXHRcdFx0XHRcdGNzc1tcIm1pbi13aWR0aFwiXSA9IF91dGlsLmdldC53aWR0aCh2ZXJ0aWNhbCA/IF9waW4gOiBwaW5UYXJnZXQsIHRydWUsIHRydWUpO1xyXG5cdFx0XHRcdFx0Y3NzLndpZHRoID0gZHVyaW5nID8gY3NzW1wibWluLXdpZHRoXCJdIDogXCJhdXRvXCI7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGlmIChfcGluT3B0aW9ucy5yZWxTaXplLmhlaWdodCkge1xyXG5cdFx0XHRcdFx0aWYgKGR1cmluZykge1xyXG5cdFx0XHRcdFx0XHQvLyB0aGUgb25seSBwYWRkaW5nIHRoZSBzcGFjZXIgc2hvdWxkIGV2ZXIgaW5jbHVkZSBpcyB0aGUgZHVyYXRpb24gKGlmIHB1c2hGb2xsb3dlcnMgPSB0cnVlKSwgc28gd2UgbmVlZCB0byBzdWJzdHJhY3QgdGhhdC5cclxuXHRcdFx0XHRcdFx0X3V0aWwuY3NzKF9waW4sIHtcclxuXHRcdFx0XHRcdFx0XHRcImhlaWdodFwiOiBfdXRpbC5nZXQuaGVpZ2h0KF9waW5PcHRpb25zLnNwYWNlcikgLSAoX3Bpbk9wdGlvbnMucHVzaEZvbGxvd2VycyA/IF9vcHRpb25zLmR1cmF0aW9uIDogMClcclxuXHRcdFx0XHRcdFx0fSk7XHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0XHRfdXRpbC5jc3MoX3Bpbiwge1xyXG5cdFx0XHRcdFx0XHRcdFwiaGVpZ2h0XCI6IFwiMTAwJVwiXHJcblx0XHRcdFx0XHRcdH0pO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHQvLyBtYXJnaW4gaXMgb25seSBpbmNsdWRlZCBpZiBpdCdzIGEgY2FzY2FkZWQgcGluIHRvIHJlc29sdmUgYW4gSUU5IGJ1Z1xyXG5cdFx0XHRcdFx0Y3NzW1wibWluLWhlaWdodFwiXSA9IF91dGlsLmdldC5oZWlnaHQodmVydGljYWwgPyBwaW5UYXJnZXQgOiBfcGluLCB0cnVlLCAhbWFyZ2luQ29sbGFwc2UpOyAvLyBuZWVkZWQgZm9yIGNhc2NhZGluZyBwaW5zXHJcblx0XHRcdFx0XHRjc3MuaGVpZ2h0ID0gZHVyaW5nID8gY3NzW1wibWluLWhlaWdodFwiXSA6IFwiYXV0b1wiO1xyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Ly8gYWRkIHNwYWNlIGZvciBkdXJhdGlvbiBpZiBwdXNoRm9sbG93ZXJzIGlzIHRydWVcclxuXHRcdFx0XHRpZiAoX3Bpbk9wdGlvbnMucHVzaEZvbGxvd2Vycykge1xyXG5cdFx0XHRcdFx0Y3NzW1wicGFkZGluZ1wiICsgKHZlcnRpY2FsID8gXCJUb3BcIiA6IFwiTGVmdFwiKV0gPSBfb3B0aW9ucy5kdXJhdGlvbiAqIF9wcm9ncmVzcztcclxuXHRcdFx0XHRcdGNzc1tcInBhZGRpbmdcIiArICh2ZXJ0aWNhbCA/IFwiQm90dG9tXCIgOiBcIlJpZ2h0XCIpXSA9IF9vcHRpb25zLmR1cmF0aW9uICogKDEgLSBfcHJvZ3Jlc3MpO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRfdXRpbC5jc3MoX3Bpbk9wdGlvbnMuc3BhY2VyLCBjc3MpO1xyXG5cdFx0XHR9XHJcblx0XHR9O1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogVXBkYXRlcyB0aGUgUGluIHN0YXRlIChpbiBjZXJ0YWluIHNjZW5hcmlvcylcclxuXHRcdCAqIElmIHRoZSBjb250cm9sbGVyIGNvbnRhaW5lciBpcyBub3QgdGhlIGRvY3VtZW50IGFuZCB3ZSBhcmUgbWlkLXBpbi1waGFzZSBzY3JvbGxpbmcgb3IgcmVzaXppbmcgdGhlIG1haW4gZG9jdW1lbnQgY2FuIHJlc3VsdCB0byB3cm9uZyBwaW4gcG9zaXRpb25zLlxyXG5cdFx0ICogU28gdGhpcyBmdW5jdGlvbiBpcyBjYWxsZWQgb24gcmVzaXplIGFuZCBzY3JvbGwgb2YgdGhlIGRvY3VtZW50LlxyXG5cdFx0ICogQHByaXZhdGVcclxuXHRcdCAqL1xyXG5cdFx0dmFyIHVwZGF0ZVBpbkluQ29udGFpbmVyID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRpZiAoX2NvbnRyb2xsZXIgJiYgX3BpbiAmJiBfc3RhdGUgPT09IFNDRU5FX1NUQVRFX0RVUklORyAmJiAhX2NvbnRyb2xsZXIuaW5mbyhcImlzRG9jdW1lbnRcIikpIHtcclxuXHRcdFx0XHR1cGRhdGVQaW5TdGF0ZSgpO1xyXG5cdFx0XHR9XHJcblx0XHR9O1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogVXBkYXRlcyB0aGUgUGluIHNwYWNlciBzaXplIHN0YXRlIChpbiBjZXJ0YWluIHNjZW5hcmlvcylcclxuXHRcdCAqIElmIGNvbnRhaW5lciBpcyByZXNpemVkIGR1cmluZyBwaW4gYW5kIHJlbGF0aXZlbHkgc2l6ZWQgdGhlIHNpemUgb2YgdGhlIHBpbiBtaWdodCBuZWVkIHRvIGJlIHVwZGF0ZWQuLi5cclxuXHRcdCAqIFNvIHRoaXMgZnVuY3Rpb24gaXMgY2FsbGVkIG9uIHJlc2l6ZSBvZiB0aGUgY29udGFpbmVyLlxyXG5cdFx0ICogQHByaXZhdGVcclxuXHRcdCAqL1xyXG5cdFx0dmFyIHVwZGF0ZVJlbGF0aXZlUGluU3BhY2VyID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRpZiAoX2NvbnRyb2xsZXIgJiYgX3BpbiAmJiAvLyB3ZWxsLCBkdWhcclxuXHRcdFx0XHRfc3RhdGUgPT09IFNDRU5FX1NUQVRFX0RVUklORyAmJiAvLyBlbGVtZW50IGluIHBpbm5lZCBzdGF0ZT9cclxuXHRcdFx0XHQoIC8vIGlzIHdpZHRoIG9yIGhlaWdodCByZWxhdGl2ZWx5IHNpemVkLCBidXQgbm90IGluIHJlbGF0aW9uIHRvIGJvZHk/IHRoZW4gd2UgbmVlZCB0byByZWNhbGMuXHJcblx0XHRcdFx0XHQoKF9waW5PcHRpb25zLnJlbFNpemUud2lkdGggfHwgX3Bpbk9wdGlvbnMucmVsU2l6ZS5hdXRvRnVsbFdpZHRoKSAmJiBfdXRpbC5nZXQud2lkdGgod2luZG93KSAhPSBfdXRpbC5nZXQud2lkdGgoX3Bpbk9wdGlvbnMuc3BhY2VyLnBhcmVudE5vZGUpKSB8fFxyXG5cdFx0XHRcdFx0KF9waW5PcHRpb25zLnJlbFNpemUuaGVpZ2h0ICYmIF91dGlsLmdldC5oZWlnaHQod2luZG93KSAhPSBfdXRpbC5nZXQuaGVpZ2h0KF9waW5PcHRpb25zLnNwYWNlci5wYXJlbnROb2RlKSlcclxuXHRcdFx0XHQpXHJcblx0XHRcdCkge1xyXG5cdFx0XHRcdHVwZGF0ZVBpbkRpbWVuc2lvbnMoKTtcclxuXHRcdFx0fVxyXG5cdFx0fTtcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIElzIGNhbGxlZCwgd2hlbiB0aGUgbW91c2V3aGVsIGlzIHVzZWQgd2hpbGUgb3ZlciBhIHBpbm5lZCBlbGVtZW50IGluc2lkZSBhIGRpdiBjb250YWluZXIuXHJcblx0XHQgKiBJZiB0aGUgc2NlbmUgaXMgaW4gZml4ZWQgc3RhdGUgc2Nyb2xsIGV2ZW50cyB3b3VsZCBiZSBjb3VudGVkIHRvd2FyZHMgdGhlIGJvZHkuIFRoaXMgZm9yd2FyZHMgdGhlIGV2ZW50IHRvIHRoZSBzY3JvbGwgY29udGFpbmVyLlxyXG5cdFx0ICogQHByaXZhdGVcclxuXHRcdCAqL1xyXG5cdFx0dmFyIG9uTW91c2V3aGVlbE92ZXJQaW4gPSBmdW5jdGlvbiAoZSkge1xyXG5cdFx0XHRpZiAoX2NvbnRyb2xsZXIgJiYgX3BpbiAmJiBfc3RhdGUgPT09IFNDRU5FX1NUQVRFX0RVUklORyAmJiAhX2NvbnRyb2xsZXIuaW5mbyhcImlzRG9jdW1lbnRcIikpIHsgLy8gaW4gcGluIHN0YXRlXHJcblx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG5cdFx0XHRcdF9jb250cm9sbGVyLl9zZXRTY3JvbGxQb3MoX2NvbnRyb2xsZXIuaW5mbyhcInNjcm9sbFBvc1wiKSAtICgoZS53aGVlbERlbHRhIHx8IGVbX2NvbnRyb2xsZXIuaW5mbyhcInZlcnRpY2FsXCIpID8gXCJ3aGVlbERlbHRhWVwiIDogXCJ3aGVlbERlbHRhWFwiXSkgLyAzIHx8IC1lLmRldGFpbCAqIDMwKSk7XHJcblx0XHRcdH1cclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBQaW4gYW4gZWxlbWVudCBmb3IgdGhlIGR1cmF0aW9uIG9mIHRoZSBzY2VuZS5cclxuXHRcdCAqIElmIHRoZSBzY2VuZSBkdXJhdGlvbiBpcyAwIHRoZSBlbGVtZW50IHdpbGwgb25seSBiZSB1bnBpbm5lZCwgaWYgdGhlIHVzZXIgc2Nyb2xscyBiYWNrIHBhc3QgdGhlIHN0YXJ0IHBvc2l0aW9uLiAgXHJcblx0XHQgKiBNYWtlIHN1cmUgb25seSBvbmUgcGluIGlzIGFwcGxpZWQgdG8gYW4gZWxlbWVudCBhdCB0aGUgc2FtZSB0aW1lLlxyXG5cdFx0ICogQW4gZWxlbWVudCBjYW4gYmUgcGlubmVkIG11bHRpcGxlIHRpbWVzLCBidXQgb25seSBzdWNjZXNzaXZlbHkuXHJcblx0XHQgKiBfKipOT1RFOioqIFRoZSBvcHRpb24gYHB1c2hGb2xsb3dlcnNgIGhhcyBubyBlZmZlY3QsIHdoZW4gdGhlIHNjZW5lIGR1cmF0aW9uIGlzIDAuX1xyXG5cdFx0ICogQG1ldGhvZCBTY3JvbGxNYWdpYy5TY2VuZSNzZXRQaW5cclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiAvLyBwaW4gZWxlbWVudCBhbmQgcHVzaCBhbGwgZm9sbG93aW5nIGVsZW1lbnRzIGRvd24gYnkgdGhlIGFtb3VudCBvZiB0aGUgcGluIGR1cmF0aW9uLlxyXG5cdFx0ICogc2NlbmUuc2V0UGluKFwiI3BpblwiKTtcclxuXHRcdCAqXHJcblx0XHQgKiAvLyBwaW4gZWxlbWVudCBhbmQga2VlcGluZyBhbGwgZm9sbG93aW5nIGVsZW1lbnRzIGluIHRoZWlyIHBsYWNlLiBUaGUgcGlubmVkIGVsZW1lbnQgd2lsbCBtb3ZlIHBhc3QgdGhlbS5cclxuXHRcdCAqIHNjZW5lLnNldFBpbihcIiNwaW5cIiwge3B1c2hGb2xsb3dlcnM6IGZhbHNlfSk7XHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIHsoc3RyaW5nfG9iamVjdCl9IGVsZW1lbnQgLSBBIFNlbGVjdG9yIHRhcmdldGluZyBhbiBlbGVtZW50IG9yIGEgRE9NIG9iamVjdCB0aGF0IGlzIHN1cHBvc2VkIHRvIGJlIHBpbm5lZC5cclxuXHRcdCAqIEBwYXJhbSB7b2JqZWN0fSBbc2V0dGluZ3NdIC0gc2V0dGluZ3MgZm9yIHRoZSBwaW5cclxuXHRcdCAqIEBwYXJhbSB7Ym9vbGVhbn0gW3NldHRpbmdzLnB1c2hGb2xsb3dlcnM9dHJ1ZV0gLSBJZiBgdHJ1ZWAgZm9sbG93aW5nIGVsZW1lbnRzIHdpbGwgYmUgXCJwdXNoZWRcIiBkb3duIGZvciB0aGUgZHVyYXRpb24gb2YgdGhlIHBpbiwgaWYgYGZhbHNlYCB0aGUgcGlubmVkIGVsZW1lbnQgd2lsbCBqdXN0IHNjcm9sbCBwYXN0IHRoZW0uICBcclxuXHRcdCBcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICBJZ25vcmVkLCB3aGVuIGR1cmF0aW9uIGlzIGAwYC5cclxuXHRcdCAqIEBwYXJhbSB7c3RyaW5nfSBbc2V0dGluZ3Muc3BhY2VyQ2xhc3M9XCJzY3JvbGxtYWdpYy1waW4tc3BhY2VyXCJdIC0gQ2xhc3NuYW1lIG9mIHRoZSBwaW4gc3BhY2VyIGVsZW1lbnQsIHdoaWNoIGlzIHVzZWQgdG8gcmVwbGFjZSB0aGUgZWxlbWVudC5cclxuXHRcdCAqXHJcblx0XHQgKiBAcmV0dXJucyB7U2NlbmV9IFBhcmVudCBvYmplY3QgZm9yIGNoYWluaW5nLlxyXG5cdFx0ICovXHJcblx0XHR0aGlzLnNldFBpbiA9IGZ1bmN0aW9uIChlbGVtZW50LCBzZXR0aW5ncykge1xyXG5cdFx0XHR2YXJcclxuXHRcdFx0XHRkZWZhdWx0U2V0dGluZ3MgPSB7XHJcblx0XHRcdFx0XHRwdXNoRm9sbG93ZXJzOiB0cnVlLFxyXG5cdFx0XHRcdFx0c3BhY2VyQ2xhc3M6IFwic2Nyb2xsbWFnaWMtcGluLXNwYWNlclwiXHJcblx0XHRcdFx0fTtcclxuXHRcdFx0dmFyIHB1c2hGb2xsb3dlcnNBY3RpdmVseVNldCA9IHNldHRpbmdzICYmIHNldHRpbmdzLmhhc093blByb3BlcnR5KCdwdXNoRm9sbG93ZXJzJyk7XHJcblx0XHRcdHNldHRpbmdzID0gX3V0aWwuZXh0ZW5kKHt9LCBkZWZhdWx0U2V0dGluZ3MsIHNldHRpbmdzKTtcclxuXHJcblx0XHRcdC8vIHZhbGlkYXRlIEVsZW1lbnRcclxuXHRcdFx0ZWxlbWVudCA9IF91dGlsLmdldC5lbGVtZW50cyhlbGVtZW50KVswXTtcclxuXHRcdFx0aWYgKCFlbGVtZW50KSB7XHJcblx0XHRcdFx0bG9nKDEsIFwiRVJST1IgY2FsbGluZyBtZXRob2QgJ3NldFBpbigpJzogSW52YWxpZCBwaW4gZWxlbWVudCBzdXBwbGllZC5cIik7XHJcblx0XHRcdFx0cmV0dXJuIFNjZW5lOyAvLyBjYW5jZWxcclxuXHRcdFx0fSBlbHNlIGlmIChfdXRpbC5jc3MoZWxlbWVudCwgXCJwb3NpdGlvblwiKSA9PT0gXCJmaXhlZFwiKSB7XHJcblx0XHRcdFx0bG9nKDEsIFwiRVJST1IgY2FsbGluZyBtZXRob2QgJ3NldFBpbigpJzogUGluIGRvZXMgbm90IHdvcmsgd2l0aCBlbGVtZW50cyB0aGF0IGFyZSBwb3NpdGlvbmVkICdmaXhlZCcuXCIpO1xyXG5cdFx0XHRcdHJldHVybiBTY2VuZTsgLy8gY2FuY2VsXHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmIChfcGluKSB7IC8vIHByZWV4aXN0aW5nIHBpbj9cclxuXHRcdFx0XHRpZiAoX3BpbiA9PT0gZWxlbWVudCkge1xyXG5cdFx0XHRcdFx0Ly8gc2FtZSBwaW4gd2UgYWxyZWFkeSBoYXZlIC0+IGRvIG5vdGhpbmdcclxuXHRcdFx0XHRcdHJldHVybiBTY2VuZTsgLy8gY2FuY2VsXHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdC8vIGtpbGwgb2xkIHBpblxyXG5cdFx0XHRcdFx0U2NlbmUucmVtb3ZlUGluKCk7XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cdFx0XHRfcGluID0gZWxlbWVudDtcclxuXHJcblx0XHRcdHZhclxyXG5cdFx0XHRcdHBhcmVudERpc3BsYXkgPSBfcGluLnBhcmVudE5vZGUuc3R5bGUuZGlzcGxheSxcclxuXHRcdFx0XHRib3VuZHNQYXJhbXMgPSBbXCJ0b3BcIiwgXCJsZWZ0XCIsIFwiYm90dG9tXCIsIFwicmlnaHRcIiwgXCJtYXJnaW5cIiwgXCJtYXJnaW5MZWZ0XCIsIFwibWFyZ2luUmlnaHRcIiwgXCJtYXJnaW5Ub3BcIiwgXCJtYXJnaW5Cb3R0b21cIl07XHJcblxyXG5cdFx0XHRfcGluLnBhcmVudE5vZGUuc3R5bGUuZGlzcGxheSA9ICdub25lJzsgLy8gaGFjayBzdGFydCB0byBmb3JjZSBjc3MgdG8gcmV0dXJuIHN0eWxlc2hlZXQgdmFsdWVzIGluc3RlYWQgb2YgY2FsY3VsYXRlZCBweCB2YWx1ZXMuXHJcblx0XHRcdHZhclxyXG5cdFx0XHRcdGluRmxvdyA9IF91dGlsLmNzcyhfcGluLCBcInBvc2l0aW9uXCIpICE9IFwiYWJzb2x1dGVcIixcclxuXHRcdFx0XHRwaW5DU1MgPSBfdXRpbC5jc3MoX3BpbiwgYm91bmRzUGFyYW1zLmNvbmNhdChbXCJkaXNwbGF5XCJdKSksXHJcblx0XHRcdFx0c2l6ZUNTUyA9IF91dGlsLmNzcyhfcGluLCBbXCJ3aWR0aFwiLCBcImhlaWdodFwiXSk7XHJcblx0XHRcdF9waW4ucGFyZW50Tm9kZS5zdHlsZS5kaXNwbGF5ID0gcGFyZW50RGlzcGxheTsgLy8gaGFjayBlbmQuXHJcblxyXG5cdFx0XHRpZiAoIWluRmxvdyAmJiBzZXR0aW5ncy5wdXNoRm9sbG93ZXJzKSB7XHJcblx0XHRcdFx0bG9nKDIsIFwiV0FSTklORzogSWYgdGhlIHBpbm5lZCBlbGVtZW50IGlzIHBvc2l0aW9uZWQgYWJzb2x1dGVseSBwdXNoRm9sbG93ZXJzIHdpbGwgYmUgZGlzYWJsZWQuXCIpO1xyXG5cdFx0XHRcdHNldHRpbmdzLnB1c2hGb2xsb3dlcnMgPSBmYWxzZTtcclxuXHRcdFx0fVxyXG5cdFx0XHR3aW5kb3cuc2V0VGltZW91dChmdW5jdGlvbiAoKSB7IC8vIHdhaXQgdW50aWwgYWxsIGZpbmlzaGVkLCBiZWNhdXNlIHdpdGggcmVzcG9uc2l2ZSBkdXJhdGlvbiBpdCB3aWxsIG9ubHkgYmUgc2V0IGFmdGVyIHNjZW5lIGlzIGFkZGVkIHRvIGNvbnRyb2xsZXJcclxuXHRcdFx0XHRpZiAoX3BpbiAmJiBfb3B0aW9ucy5kdXJhdGlvbiA9PT0gMCAmJiBwdXNoRm9sbG93ZXJzQWN0aXZlbHlTZXQgJiYgc2V0dGluZ3MucHVzaEZvbGxvd2Vycykge1xyXG5cdFx0XHRcdFx0bG9nKDIsIFwiV0FSTklORzogcHVzaEZvbGxvd2VycyA9XCIsIHRydWUsIFwiaGFzIG5vIGVmZmVjdCwgd2hlbiBzY2VuZSBkdXJhdGlvbiBpcyAwLlwiKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH0sIDApO1xyXG5cclxuXHRcdFx0Ly8gY3JlYXRlIHNwYWNlciBhbmQgaW5zZXJ0XHJcblx0XHRcdHZhclxyXG5cdFx0XHRcdHNwYWNlciA9IF9waW4ucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUoZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2JyksIF9waW4pLFxyXG5cdFx0XHRcdHNwYWNlckNTUyA9IF91dGlsLmV4dGVuZChwaW5DU1MsIHtcclxuXHRcdFx0XHRcdHBvc2l0aW9uOiBpbkZsb3cgPyBcInJlbGF0aXZlXCIgOiBcImFic29sdXRlXCIsXHJcblx0XHRcdFx0XHRib3hTaXppbmc6IFwiY29udGVudC1ib3hcIixcclxuXHRcdFx0XHRcdG1vekJveFNpemluZzogXCJjb250ZW50LWJveFwiLFxyXG5cdFx0XHRcdFx0d2Via2l0Qm94U2l6aW5nOiBcImNvbnRlbnQtYm94XCJcclxuXHRcdFx0XHR9KTtcclxuXHJcblx0XHRcdGlmICghaW5GbG93KSB7IC8vIGNvcHkgc2l6ZSBpZiBwb3NpdGlvbmVkIGFic29sdXRlbHksIHRvIHdvcmsgZm9yIGJvdHRvbS9yaWdodCBwb3NpdGlvbmVkIGVsZW1lbnRzLlxyXG5cdFx0XHRcdF91dGlsLmV4dGVuZChzcGFjZXJDU1MsIF91dGlsLmNzcyhfcGluLCBbXCJ3aWR0aFwiLCBcImhlaWdodFwiXSkpO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRfdXRpbC5jc3Moc3BhY2VyLCBzcGFjZXJDU1MpO1xyXG5cdFx0XHRzcGFjZXIuc2V0QXR0cmlidXRlKFBJTl9TUEFDRVJfQVRUUklCVVRFLCBcIlwiKTtcclxuXHRcdFx0X3V0aWwuYWRkQ2xhc3Moc3BhY2VyLCBzZXR0aW5ncy5zcGFjZXJDbGFzcyk7XHJcblxyXG5cdFx0XHQvLyBzZXQgdGhlIHBpbiBPcHRpb25zXHJcblx0XHRcdF9waW5PcHRpb25zID0ge1xyXG5cdFx0XHRcdHNwYWNlcjogc3BhY2VyLFxyXG5cdFx0XHRcdHJlbFNpemU6IHsgLy8gc2F2ZSBpZiBzaXplIGlzIGRlZmluZWQgdXNpbmcgJSB2YWx1ZXMuIGlmIHNvLCBoYW5kbGUgc3BhY2VyIHJlc2l6ZSBkaWZmZXJlbnRseS4uLlxyXG5cdFx0XHRcdFx0d2lkdGg6IHNpemVDU1Mud2lkdGguc2xpY2UoLTEpID09PSBcIiVcIixcclxuXHRcdFx0XHRcdGhlaWdodDogc2l6ZUNTUy5oZWlnaHQuc2xpY2UoLTEpID09PSBcIiVcIixcclxuXHRcdFx0XHRcdGF1dG9GdWxsV2lkdGg6IHNpemVDU1Mud2lkdGggPT09IFwiYXV0b1wiICYmIGluRmxvdyAmJiBfdXRpbC5pc01hcmdpbkNvbGxhcHNlVHlwZShwaW5DU1MuZGlzcGxheSlcclxuXHRcdFx0XHR9LFxyXG5cdFx0XHRcdHB1c2hGb2xsb3dlcnM6IHNldHRpbmdzLnB1c2hGb2xsb3dlcnMsXHJcblx0XHRcdFx0aW5GbG93OiBpbkZsb3csIC8vIHN0b3JlcyBpZiB0aGUgZWxlbWVudCB0YWtlcyB1cCBzcGFjZSBpbiB0aGUgZG9jdW1lbnQgZmxvd1xyXG5cdFx0XHR9O1xyXG5cclxuXHRcdFx0aWYgKCFfcGluLl9fX29yaWdTdHlsZSkge1xyXG5cdFx0XHRcdF9waW4uX19fb3JpZ1N0eWxlID0ge307XHJcblx0XHRcdFx0dmFyXHJcblx0XHRcdFx0XHRwaW5JbmxpbmVDU1MgPSBfcGluLnN0eWxlLFxyXG5cdFx0XHRcdFx0Y29weVN0eWxlcyA9IGJvdW5kc1BhcmFtcy5jb25jYXQoW1wid2lkdGhcIiwgXCJoZWlnaHRcIiwgXCJwb3NpdGlvblwiLCBcImJveFNpemluZ1wiLCBcIm1vekJveFNpemluZ1wiLCBcIndlYmtpdEJveFNpemluZ1wiXSk7XHJcblx0XHRcdFx0Y29weVN0eWxlcy5mb3JFYWNoKGZ1bmN0aW9uICh2YWwpIHtcclxuXHRcdFx0XHRcdF9waW4uX19fb3JpZ1N0eWxlW3ZhbF0gPSBwaW5JbmxpbmVDU1NbdmFsXSB8fCBcIlwiO1xyXG5cdFx0XHRcdH0pO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBpZiByZWxhdGl2ZSBzaXplLCB0cmFuc2ZlciBpdCB0byBzcGFjZXIgYW5kIG1ha2UgcGluIGNhbGN1bGF0ZSBpdC4uLlxyXG5cdFx0XHRpZiAoX3Bpbk9wdGlvbnMucmVsU2l6ZS53aWR0aCkge1xyXG5cdFx0XHRcdF91dGlsLmNzcyhzcGFjZXIsIHtcclxuXHRcdFx0XHRcdHdpZHRoOiBzaXplQ1NTLndpZHRoXHJcblx0XHRcdFx0fSk7XHJcblx0XHRcdH1cclxuXHRcdFx0aWYgKF9waW5PcHRpb25zLnJlbFNpemUuaGVpZ2h0KSB7XHJcblx0XHRcdFx0X3V0aWwuY3NzKHNwYWNlciwge1xyXG5cdFx0XHRcdFx0aGVpZ2h0OiBzaXplQ1NTLmhlaWdodFxyXG5cdFx0XHRcdH0pO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBub3cgcGxhY2UgdGhlIHBpbiBlbGVtZW50IGluc2lkZSB0aGUgc3BhY2VyXHRcclxuXHRcdFx0c3BhY2VyLmFwcGVuZENoaWxkKF9waW4pO1xyXG5cdFx0XHQvLyBhbmQgc2V0IG5ldyBjc3NcclxuXHRcdFx0X3V0aWwuY3NzKF9waW4sIHtcclxuXHRcdFx0XHRwb3NpdGlvbjogaW5GbG93ID8gXCJyZWxhdGl2ZVwiIDogXCJhYnNvbHV0ZVwiLFxyXG5cdFx0XHRcdG1hcmdpbjogXCJhdXRvXCIsXHJcblx0XHRcdFx0dG9wOiBcImF1dG9cIixcclxuXHRcdFx0XHRsZWZ0OiBcImF1dG9cIixcclxuXHRcdFx0XHRib3R0b206IFwiYXV0b1wiLFxyXG5cdFx0XHRcdHJpZ2h0OiBcImF1dG9cIlxyXG5cdFx0XHR9KTtcclxuXHJcblx0XHRcdGlmIChfcGluT3B0aW9ucy5yZWxTaXplLndpZHRoIHx8IF9waW5PcHRpb25zLnJlbFNpemUuYXV0b0Z1bGxXaWR0aCkge1xyXG5cdFx0XHRcdF91dGlsLmNzcyhfcGluLCB7XHJcblx0XHRcdFx0XHRib3hTaXppbmc6IFwiYm9yZGVyLWJveFwiLFxyXG5cdFx0XHRcdFx0bW96Qm94U2l6aW5nOiBcImJvcmRlci1ib3hcIixcclxuXHRcdFx0XHRcdHdlYmtpdEJveFNpemluZzogXCJib3JkZXItYm94XCJcclxuXHRcdFx0XHR9KTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gYWRkIGxpc3RlbmVyIHRvIGRvY3VtZW50IHRvIHVwZGF0ZSBwaW4gcG9zaXRpb24gaW4gY2FzZSBjb250cm9sbGVyIGlzIG5vdCB0aGUgZG9jdW1lbnQuXHJcblx0XHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdzY3JvbGwnLCB1cGRhdGVQaW5JbkNvbnRhaW5lcik7XHJcblx0XHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdyZXNpemUnLCB1cGRhdGVQaW5JbkNvbnRhaW5lcik7XHJcblx0XHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdyZXNpemUnLCB1cGRhdGVSZWxhdGl2ZVBpblNwYWNlcik7XHJcblx0XHRcdC8vIGFkZCBtb3VzZXdoZWVsIGxpc3RlbmVyIHRvIGNhdGNoIHNjcm9sbHMgb3ZlciBmaXhlZCBlbGVtZW50c1xyXG5cdFx0XHRfcGluLmFkZEV2ZW50TGlzdGVuZXIoXCJtb3VzZXdoZWVsXCIsIG9uTW91c2V3aGVlbE92ZXJQaW4pO1xyXG5cdFx0XHRfcGluLmFkZEV2ZW50TGlzdGVuZXIoXCJET01Nb3VzZVNjcm9sbFwiLCBvbk1vdXNld2hlZWxPdmVyUGluKTtcclxuXHJcblx0XHRcdGxvZygzLCBcImFkZGVkIHBpblwiKTtcclxuXHJcblx0XHRcdC8vIGZpbmFsbHkgdXBkYXRlIHRoZSBwaW4gdG8gaW5pdFxyXG5cdFx0XHR1cGRhdGVQaW5TdGF0ZSgpO1xyXG5cclxuXHRcdFx0cmV0dXJuIFNjZW5lO1xyXG5cdFx0fTtcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIFJlbW92ZSB0aGUgcGluIGZyb20gdGhlIHNjZW5lLlxyXG5cdFx0ICogQG1ldGhvZCBTY3JvbGxNYWdpYy5TY2VuZSNyZW1vdmVQaW5cclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiAvLyByZW1vdmUgdGhlIHBpbiBmcm9tIHRoZSBzY2VuZSB3aXRob3V0IHJlc2V0dGluZyBpdCAodGhlIHNwYWNlciBpcyBub3QgcmVtb3ZlZClcclxuXHRcdCAqIHNjZW5lLnJlbW92ZVBpbigpO1xyXG5cdFx0ICpcclxuXHRcdCAqIC8vIHJlbW92ZSB0aGUgcGluIGZyb20gdGhlIHNjZW5lIGFuZCByZXNldCB0aGUgcGluIGVsZW1lbnQgdG8gaXRzIGluaXRpYWwgcG9zaXRpb24gKHNwYWNlciBpcyByZW1vdmVkKVxyXG5cdFx0ICogc2NlbmUucmVtb3ZlUGluKHRydWUpO1xyXG5cdFx0ICpcclxuXHRcdCAqIEBwYXJhbSB7Ym9vbGVhbn0gW3Jlc2V0PWZhbHNlXSAtIElmIGBmYWxzZWAgdGhlIHNwYWNlciB3aWxsIG5vdCBiZSByZW1vdmVkIGFuZCB0aGUgZWxlbWVudCdzIHBvc2l0aW9uIHdpbGwgbm90IGJlIHJlc2V0LlxyXG5cdFx0ICogQHJldHVybnMge1NjZW5lfSBQYXJlbnQgb2JqZWN0IGZvciBjaGFpbmluZy5cclxuXHRcdCAqL1xyXG5cdFx0dGhpcy5yZW1vdmVQaW4gPSBmdW5jdGlvbiAocmVzZXQpIHtcclxuXHRcdFx0aWYgKF9waW4pIHtcclxuXHRcdFx0XHRpZiAoX3N0YXRlID09PSBTQ0VORV9TVEFURV9EVVJJTkcpIHtcclxuXHRcdFx0XHRcdHVwZGF0ZVBpblN0YXRlKHRydWUpOyAvLyBmb3JjZSB1bnBpbiBhdCBwb3NpdGlvblxyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRpZiAocmVzZXQgfHwgIV9jb250cm9sbGVyKSB7IC8vIGlmIHRoZXJlJ3Mgbm8gY29udHJvbGxlciBubyBwcm9ncmVzcyB3YXMgbWFkZSBhbnl3YXkuLi5cclxuXHRcdFx0XHRcdHZhciBwaW5UYXJnZXQgPSBfcGluT3B0aW9ucy5zcGFjZXIuZmlyc3RDaGlsZDsgLy8gdXN1YWxseSB0aGUgcGluIGVsZW1lbnQsIGJ1dCBtYXkgYmUgYW5vdGhlciBzcGFjZXIgKGNhc2NhZGVkIHBpbnMpLi4uXHJcblx0XHRcdFx0XHRpZiAocGluVGFyZ2V0Lmhhc0F0dHJpYnV0ZShQSU5fU1BBQ0VSX0FUVFJJQlVURSkpIHsgLy8gY29weSBtYXJnaW5zIHRvIGNoaWxkIHNwYWNlclxyXG5cdFx0XHRcdFx0XHR2YXJcclxuXHRcdFx0XHRcdFx0XHRzdHlsZSA9IF9waW5PcHRpb25zLnNwYWNlci5zdHlsZSxcclxuXHRcdFx0XHRcdFx0XHR2YWx1ZXMgPSBbXCJtYXJnaW5cIiwgXCJtYXJnaW5MZWZ0XCIsIFwibWFyZ2luUmlnaHRcIiwgXCJtYXJnaW5Ub3BcIiwgXCJtYXJnaW5Cb3R0b21cIl0sXHJcblx0XHRcdFx0XHRcdFx0bWFyZ2lucyA9IHt9O1xyXG5cdFx0XHRcdFx0XHR2YWx1ZXMuZm9yRWFjaChmdW5jdGlvbiAodmFsKSB7XHJcblx0XHRcdFx0XHRcdFx0bWFyZ2luc1t2YWxdID0gc3R5bGVbdmFsXSB8fCBcIlwiO1xyXG5cdFx0XHRcdFx0XHR9KTtcclxuXHRcdFx0XHRcdFx0X3V0aWwuY3NzKHBpblRhcmdldCwgbWFyZ2lucyk7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRfcGluT3B0aW9ucy5zcGFjZXIucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUocGluVGFyZ2V0LCBfcGluT3B0aW9ucy5zcGFjZXIpO1xyXG5cdFx0XHRcdFx0X3Bpbk9wdGlvbnMuc3BhY2VyLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoX3Bpbk9wdGlvbnMuc3BhY2VyKTtcclxuXHRcdFx0XHRcdGlmICghX3Bpbi5wYXJlbnROb2RlLmhhc0F0dHJpYnV0ZShQSU5fU1BBQ0VSX0FUVFJJQlVURSkpIHsgLy8gaWYgaXQncyB0aGUgbGFzdCBwaW4gZm9yIHRoaXMgZWxlbWVudCAtPiByZXN0b3JlIGlubGluZSBzdHlsZXNcclxuXHRcdFx0XHRcdFx0Ly8gVE9ETzogb25seSBjb3JyZWN0bHkgc2V0IGZvciBmaXJzdCBwaW4gKHdoZW4gY2FzY2FkaW5nKSAtIGhvdyB0byBmaXg/XHJcblx0XHRcdFx0XHRcdF91dGlsLmNzcyhfcGluLCBfcGluLl9fX29yaWdTdHlsZSk7XHJcblx0XHRcdFx0XHRcdGRlbGV0ZSBfcGluLl9fX29yaWdTdHlsZTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0d2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3Njcm9sbCcsIHVwZGF0ZVBpbkluQ29udGFpbmVyKTtcclxuXHRcdFx0XHR3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcigncmVzaXplJywgdXBkYXRlUGluSW5Db250YWluZXIpO1xyXG5cdFx0XHRcdHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdyZXNpemUnLCB1cGRhdGVSZWxhdGl2ZVBpblNwYWNlcik7XHJcblx0XHRcdFx0X3Bpbi5yZW1vdmVFdmVudExpc3RlbmVyKFwibW91c2V3aGVlbFwiLCBvbk1vdXNld2hlZWxPdmVyUGluKTtcclxuXHRcdFx0XHRfcGluLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJET01Nb3VzZVNjcm9sbFwiLCBvbk1vdXNld2hlZWxPdmVyUGluKTtcclxuXHRcdFx0XHRfcGluID0gdW5kZWZpbmVkO1xyXG5cdFx0XHRcdGxvZygzLCBcInJlbW92ZWQgcGluIChyZXNldDogXCIgKyAocmVzZXQgPyBcInRydWVcIiA6IFwiZmFsc2VcIikgKyBcIilcIik7XHJcblx0XHRcdH1cclxuXHRcdFx0cmV0dXJuIFNjZW5lO1xyXG5cdFx0fTtcclxuXHJcblxyXG5cdFx0dmFyXHJcblx0XHRcdF9jc3NDbGFzc2VzLFxyXG5cdFx0XHRfY3NzQ2xhc3NFbGVtcyA9IFtdO1xyXG5cclxuXHRcdFNjZW5lXHJcblx0XHRcdC5vbihcImRlc3Ryb3kuaW50ZXJuYWxcIiwgZnVuY3Rpb24gKGUpIHtcclxuXHRcdFx0XHRTY2VuZS5yZW1vdmVDbGFzc1RvZ2dsZShlLnJlc2V0KTtcclxuXHRcdFx0fSk7XHJcblx0XHQvKipcclxuXHRcdCAqIERlZmluZSBhIGNzcyBjbGFzcyBtb2RpZmljYXRpb24gd2hpbGUgdGhlIHNjZW5lIGlzIGFjdGl2ZS4gIFxyXG5cdFx0ICogV2hlbiB0aGUgc2NlbmUgdHJpZ2dlcnMgdGhlIGNsYXNzZXMgd2lsbCBiZSBhZGRlZCB0byB0aGUgc3VwcGxpZWQgZWxlbWVudCBhbmQgcmVtb3ZlZCwgd2hlbiB0aGUgc2NlbmUgaXMgb3Zlci5cclxuXHRcdCAqIElmIHRoZSBzY2VuZSBkdXJhdGlvbiBpcyAwIHRoZSBjbGFzc2VzIHdpbGwgb25seSBiZSByZW1vdmVkIGlmIHRoZSB1c2VyIHNjcm9sbHMgYmFjayBwYXN0IHRoZSBzdGFydCBwb3NpdGlvbi5cclxuXHRcdCAqIEBtZXRob2QgU2Nyb2xsTWFnaWMuU2NlbmUjc2V0Q2xhc3NUb2dnbGVcclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiAvLyBhZGQgdGhlIGNsYXNzICdteWNsYXNzJyB0byB0aGUgZWxlbWVudCB3aXRoIHRoZSBpZCAnbXktZWxlbScgZm9yIHRoZSBkdXJhdGlvbiBvZiB0aGUgc2NlbmVcclxuXHRcdCAqIHNjZW5lLnNldENsYXNzVG9nZ2xlKFwiI215LWVsZW1cIiwgXCJteWNsYXNzXCIpO1xyXG5cdFx0ICpcclxuXHRcdCAqIC8vIGFkZCBtdWx0aXBsZSBjbGFzc2VzIHRvIG11bHRpcGxlIGVsZW1lbnRzIGRlZmluZWQgYnkgdGhlIHNlbGVjdG9yICcuY2xhc3NDaGFuZ2UnXHJcblx0XHQgKiBzY2VuZS5zZXRDbGFzc1RvZ2dsZShcIi5jbGFzc0NoYW5nZVwiLCBcImNsYXNzMSBjbGFzczIgY2xhc3MzXCIpO1xyXG5cdFx0ICpcclxuXHRcdCAqIEBwYXJhbSB7KHN0cmluZ3xvYmplY3QpfSBlbGVtZW50IC0gQSBTZWxlY3RvciB0YXJnZXRpbmcgb25lIG9yIG1vcmUgZWxlbWVudHMgb3IgYSBET00gb2JqZWN0IHRoYXQgaXMgc3VwcG9zZWQgdG8gYmUgbW9kaWZpZWQuXHJcblx0XHQgKiBAcGFyYW0ge3N0cmluZ30gY2xhc3NlcyAtIE9uZSBvciBtb3JlIENsYXNzbmFtZXMgKHNlcGFyYXRlZCBieSBzcGFjZSkgdGhhdCBzaG91bGQgYmUgYWRkZWQgdG8gdGhlIGVsZW1lbnQgZHVyaW5nIHRoZSBzY2VuZS5cclxuXHRcdCAqXHJcblx0XHQgKiBAcmV0dXJucyB7U2NlbmV9IFBhcmVudCBvYmplY3QgZm9yIGNoYWluaW5nLlxyXG5cdFx0ICovXHJcblx0XHR0aGlzLnNldENsYXNzVG9nZ2xlID0gZnVuY3Rpb24gKGVsZW1lbnQsIGNsYXNzZXMpIHtcclxuXHRcdFx0dmFyIGVsZW1zID0gX3V0aWwuZ2V0LmVsZW1lbnRzKGVsZW1lbnQpO1xyXG5cdFx0XHRpZiAoZWxlbXMubGVuZ3RoID09PSAwIHx8ICFfdXRpbC50eXBlLlN0cmluZyhjbGFzc2VzKSkge1xyXG5cdFx0XHRcdGxvZygxLCBcIkVSUk9SIGNhbGxpbmcgbWV0aG9kICdzZXRDbGFzc1RvZ2dsZSgpJzogSW52YWxpZCBcIiArIChlbGVtcy5sZW5ndGggPT09IDAgPyBcImVsZW1lbnRcIiA6IFwiY2xhc3Nlc1wiKSArIFwiIHN1cHBsaWVkLlwiKTtcclxuXHRcdFx0XHRyZXR1cm4gU2NlbmU7XHJcblx0XHRcdH1cclxuXHRcdFx0aWYgKF9jc3NDbGFzc0VsZW1zLmxlbmd0aCA+IDApIHtcclxuXHRcdFx0XHQvLyByZW1vdmUgb2xkIG9uZXNcclxuXHRcdFx0XHRTY2VuZS5yZW1vdmVDbGFzc1RvZ2dsZSgpO1xyXG5cdFx0XHR9XHJcblx0XHRcdF9jc3NDbGFzc2VzID0gY2xhc3NlcztcclxuXHRcdFx0X2Nzc0NsYXNzRWxlbXMgPSBlbGVtcztcclxuXHRcdFx0U2NlbmUub24oXCJlbnRlci5pbnRlcm5hbF9jbGFzcyBsZWF2ZS5pbnRlcm5hbF9jbGFzc1wiLCBmdW5jdGlvbiAoZSkge1xyXG5cdFx0XHRcdHZhciB0b2dnbGUgPSBlLnR5cGUgPT09IFwiZW50ZXJcIiA/IF91dGlsLmFkZENsYXNzIDogX3V0aWwucmVtb3ZlQ2xhc3M7XHJcblx0XHRcdFx0X2Nzc0NsYXNzRWxlbXMuZm9yRWFjaChmdW5jdGlvbiAoZWxlbSwga2V5KSB7XHJcblx0XHRcdFx0XHR0b2dnbGUoZWxlbSwgX2Nzc0NsYXNzZXMpO1xyXG5cdFx0XHRcdH0pO1xyXG5cdFx0XHR9KTtcclxuXHRcdFx0cmV0dXJuIFNjZW5lO1xyXG5cdFx0fTtcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIFJlbW92ZSB0aGUgY2xhc3MgYmluZGluZyBmcm9tIHRoZSBzY2VuZS5cclxuXHRcdCAqIEBtZXRob2QgU2Nyb2xsTWFnaWMuU2NlbmUjcmVtb3ZlQ2xhc3NUb2dnbGVcclxuXHRcdCAqIEBleGFtcGxlXHJcblx0XHQgKiAvLyByZW1vdmUgY2xhc3MgYmluZGluZyBmcm9tIHRoZSBzY2VuZSB3aXRob3V0IHJlc2V0XHJcblx0XHQgKiBzY2VuZS5yZW1vdmVDbGFzc1RvZ2dsZSgpO1xyXG5cdFx0ICpcclxuXHRcdCAqIC8vIHJlbW92ZSBjbGFzcyBiaW5kaW5nIGFuZCByZW1vdmUgdGhlIGNoYW5nZXMgaXQgY2F1c2VkXHJcblx0XHQgKiBzY2VuZS5yZW1vdmVDbGFzc1RvZ2dsZSh0cnVlKTtcclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0ge2Jvb2xlYW59IFtyZXNldD1mYWxzZV0gLSBJZiBgZmFsc2VgIGFuZCB0aGUgY2xhc3NlcyBhcmUgY3VycmVudGx5IGFjdGl2ZSwgdGhleSB3aWxsIHJlbWFpbiBvbiB0aGUgZWxlbWVudC4gSWYgYHRydWVgIHRoZXkgd2lsbCBiZSByZW1vdmVkLlxyXG5cdFx0ICogQHJldHVybnMge1NjZW5lfSBQYXJlbnQgb2JqZWN0IGZvciBjaGFpbmluZy5cclxuXHRcdCAqL1xyXG5cdFx0dGhpcy5yZW1vdmVDbGFzc1RvZ2dsZSA9IGZ1bmN0aW9uIChyZXNldCkge1xyXG5cdFx0XHRpZiAocmVzZXQpIHtcclxuXHRcdFx0XHRfY3NzQ2xhc3NFbGVtcy5mb3JFYWNoKGZ1bmN0aW9uIChlbGVtLCBrZXkpIHtcclxuXHRcdFx0XHRcdF91dGlsLnJlbW92ZUNsYXNzKGVsZW0sIF9jc3NDbGFzc2VzKTtcclxuXHRcdFx0XHR9KTtcclxuXHRcdFx0fVxyXG5cdFx0XHRTY2VuZS5vZmYoXCJzdGFydC5pbnRlcm5hbF9jbGFzcyBlbmQuaW50ZXJuYWxfY2xhc3NcIik7XHJcblx0XHRcdF9jc3NDbGFzc2VzID0gdW5kZWZpbmVkO1xyXG5cdFx0XHRfY3NzQ2xhc3NFbGVtcyA9IFtdO1xyXG5cdFx0XHRyZXR1cm4gU2NlbmU7XHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIElOSVRcclxuXHRcdGNvbnN0cnVjdCgpO1xyXG5cdFx0cmV0dXJuIFNjZW5lO1xyXG5cdH07XHJcblxyXG5cdC8vIHN0b3JlIHBhZ2V3aWRlIHNjZW5lIG9wdGlvbnNcclxuXHR2YXIgU0NFTkVfT1BUSU9OUyA9IHtcclxuXHRcdGRlZmF1bHRzOiB7XHJcblx0XHRcdGR1cmF0aW9uOiAwLFxyXG5cdFx0XHRvZmZzZXQ6IDAsXHJcblx0XHRcdHRyaWdnZXJFbGVtZW50OiB1bmRlZmluZWQsXHJcblx0XHRcdHRyaWdnZXJIb29rOiAwLjUsXHJcblx0XHRcdHJldmVyc2U6IHRydWUsXHJcblx0XHRcdGxvZ2xldmVsOiAyXHJcblx0XHR9LFxyXG5cdFx0dmFsaWRhdGU6IHtcclxuXHRcdFx0b2Zmc2V0OiBmdW5jdGlvbiAodmFsKSB7XHJcblx0XHRcdFx0dmFsID0gcGFyc2VGbG9hdCh2YWwpO1xyXG5cdFx0XHRcdGlmICghX3V0aWwudHlwZS5OdW1iZXIodmFsKSkge1xyXG5cdFx0XHRcdFx0dGhyb3cgW1wiSW52YWxpZCB2YWx1ZSBmb3Igb3B0aW9uIFxcXCJvZmZzZXRcXFwiOlwiLCB2YWxdO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRyZXR1cm4gdmFsO1xyXG5cdFx0XHR9LFxyXG5cdFx0XHR0cmlnZ2VyRWxlbWVudDogZnVuY3Rpb24gKHZhbCkge1xyXG5cdFx0XHRcdHZhbCA9IHZhbCB8fCB1bmRlZmluZWQ7XHJcblx0XHRcdFx0aWYgKHZhbCkge1xyXG5cdFx0XHRcdFx0dmFyIGVsZW0gPSBfdXRpbC5nZXQuZWxlbWVudHModmFsKVswXTtcclxuXHRcdFx0XHRcdGlmIChlbGVtICYmIGVsZW0ucGFyZW50Tm9kZSkge1xyXG5cdFx0XHRcdFx0XHR2YWwgPSBlbGVtO1xyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdFx0dGhyb3cgW1wiRWxlbWVudCBkZWZpbmVkIGluIG9wdGlvbiBcXFwidHJpZ2dlckVsZW1lbnRcXFwiIHdhcyBub3QgZm91bmQ6XCIsIHZhbF07XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdHJldHVybiB2YWw7XHJcblx0XHRcdH0sXHJcblx0XHRcdHRyaWdnZXJIb29rOiBmdW5jdGlvbiAodmFsKSB7XHJcblx0XHRcdFx0dmFyIHRyYW5zbGF0ZSA9IHtcclxuXHRcdFx0XHRcdFwib25DZW50ZXJcIjogMC41LFxyXG5cdFx0XHRcdFx0XCJvbkVudGVyXCI6IDEsXHJcblx0XHRcdFx0XHRcIm9uTGVhdmVcIjogMFxyXG5cdFx0XHRcdH07XHJcblx0XHRcdFx0aWYgKF91dGlsLnR5cGUuTnVtYmVyKHZhbCkpIHtcclxuXHRcdFx0XHRcdHZhbCA9IE1hdGgubWF4KDAsIE1hdGgubWluKHBhcnNlRmxvYXQodmFsKSwgMSkpOyAvLyAgbWFrZSBzdXJlIGl0cyBiZXR3ZWVlbiAwIGFuZCAxXHJcblx0XHRcdFx0fSBlbHNlIGlmICh2YWwgaW4gdHJhbnNsYXRlKSB7XHJcblx0XHRcdFx0XHR2YWwgPSB0cmFuc2xhdGVbdmFsXTtcclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0dGhyb3cgW1wiSW52YWxpZCB2YWx1ZSBmb3Igb3B0aW9uIFxcXCJ0cmlnZ2VySG9va1xcXCI6IFwiLCB2YWxdO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRyZXR1cm4gdmFsO1xyXG5cdFx0XHR9LFxyXG5cdFx0XHRyZXZlcnNlOiBmdW5jdGlvbiAodmFsKSB7XHJcblx0XHRcdFx0cmV0dXJuICEhdmFsOyAvLyBmb3JjZSBib29sZWFuXHJcblx0XHRcdH0sXHJcblx0XHRcdGxvZ2xldmVsOiBmdW5jdGlvbiAodmFsKSB7XHJcblx0XHRcdFx0dmFsID0gcGFyc2VJbnQodmFsKTtcclxuXHRcdFx0XHRpZiAoIV91dGlsLnR5cGUuTnVtYmVyKHZhbCkgfHwgdmFsIDwgMCB8fCB2YWwgPiAzKSB7XHJcblx0XHRcdFx0XHR0aHJvdyBbXCJJbnZhbGlkIHZhbHVlIGZvciBvcHRpb24gXFxcImxvZ2xldmVsXFxcIjpcIiwgdmFsXTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0cmV0dXJuIHZhbDtcclxuXHRcdFx0fVxyXG5cdFx0fSwgLy8gaG9sZGVyIGZvciAgdmFsaWRhdGlvbiBtZXRob2RzLiBkdXJhdGlvbiB2YWxpZGF0aW9uIGlzIGhhbmRsZWQgaW4gJ2dldHRlcnMtc2V0dGVycy5qcydcclxuXHRcdHNoaWZ0czogW1wiZHVyYXRpb25cIiwgXCJvZmZzZXRcIiwgXCJ0cmlnZ2VySG9va1wiXSwgLy8gbGlzdCBvZiBvcHRpb25zIHRoYXQgdHJpZ2dlciBhIGBzaGlmdGAgZXZlbnRcclxuXHR9O1xyXG5cdC8qXHJcblx0ICogbWV0aG9kIHVzZWQgdG8gYWRkIGFuIG9wdGlvbiB0byBTY3JvbGxNYWdpYyBTY2VuZXMuXHJcblx0ICogVE9ETzogRE9DIChwcml2YXRlIGZvciBkZXYpXHJcblx0ICovXHJcblx0U2Nyb2xsTWFnaWMuU2NlbmUuYWRkT3B0aW9uID0gZnVuY3Rpb24gKG5hbWUsIGRlZmF1bHRWYWx1ZSwgdmFsaWRhdGlvbkNhbGxiYWNrLCBzaGlmdHMpIHtcclxuXHRcdGlmICghKG5hbWUgaW4gU0NFTkVfT1BUSU9OUy5kZWZhdWx0cykpIHtcclxuXHRcdFx0U0NFTkVfT1BUSU9OUy5kZWZhdWx0c1tuYW1lXSA9IGRlZmF1bHRWYWx1ZTtcclxuXHRcdFx0U0NFTkVfT1BUSU9OUy52YWxpZGF0ZVtuYW1lXSA9IHZhbGlkYXRpb25DYWxsYmFjaztcclxuXHRcdFx0aWYgKHNoaWZ0cykge1xyXG5cdFx0XHRcdFNDRU5FX09QVElPTlMuc2hpZnRzLnB1c2gobmFtZSk7XHJcblx0XHRcdH1cclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdFNjcm9sbE1hZ2ljLl91dGlsLmxvZygxLCBcIltzdGF0aWNdIFNjcm9sbE1hZ2ljLlNjZW5lIC0+IENhbm5vdCBhZGQgU2NlbmUgb3B0aW9uICdcIiArIG5hbWUgKyBcIicsIGJlY2F1c2UgaXQgYWxyZWFkeSBleGlzdHMuXCIpO1xyXG5cdFx0fVxyXG5cdH07XHJcblx0Ly8gaW5zdGFuY2UgZXh0ZW5zaW9uIGZ1bmN0aW9uIGZvciBwbHVnaW5zXHJcblx0Ly8gVE9ETzogRE9DIChwcml2YXRlIGZvciBkZXYpXHJcblx0U2Nyb2xsTWFnaWMuU2NlbmUuZXh0ZW5kID0gZnVuY3Rpb24gKGV4dGVuc2lvbikge1xyXG5cdFx0dmFyIG9sZENsYXNzID0gdGhpcztcclxuXHRcdFNjcm9sbE1hZ2ljLlNjZW5lID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRvbGRDbGFzcy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xyXG5cdFx0XHR0aGlzLiRzdXBlciA9IF91dGlsLmV4dGVuZCh7fSwgdGhpcyk7IC8vIGNvcHkgcGFyZW50IHN0YXRlXHJcblx0XHRcdHJldHVybiBleHRlbnNpb24uYXBwbHkodGhpcywgYXJndW1lbnRzKSB8fCB0aGlzO1xyXG5cdFx0fTtcclxuXHRcdF91dGlsLmV4dGVuZChTY3JvbGxNYWdpYy5TY2VuZSwgb2xkQ2xhc3MpOyAvLyBjb3B5IHByb3BlcnRpZXNcclxuXHRcdFNjcm9sbE1hZ2ljLlNjZW5lLnByb3RvdHlwZSA9IG9sZENsYXNzLnByb3RvdHlwZTsgLy8gY29weSBwcm90b3R5cGVcclxuXHRcdFNjcm9sbE1hZ2ljLlNjZW5lLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFNjcm9sbE1hZ2ljLlNjZW5lOyAvLyByZXN0b3JlIGNvbnN0cnVjdG9yXHJcblx0fTtcclxuXHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBUT0RPOiBET0NTIChwcml2YXRlIGZvciBkZXYpXHJcblx0ICogQGNsYXNzXHJcblx0ICogQHByaXZhdGVcclxuXHQgKi9cclxuXHJcblx0U2Nyb2xsTWFnaWMuRXZlbnQgPSBmdW5jdGlvbiAodHlwZSwgbmFtZXNwYWNlLCB0YXJnZXQsIHZhcnMpIHtcclxuXHRcdHZhcnMgPSB2YXJzIHx8IHt9O1xyXG5cdFx0Zm9yICh2YXIga2V5IGluIHZhcnMpIHtcclxuXHRcdFx0dGhpc1trZXldID0gdmFyc1trZXldO1xyXG5cdFx0fVxyXG5cdFx0dGhpcy50eXBlID0gdHlwZTtcclxuXHRcdHRoaXMudGFyZ2V0ID0gdGhpcy5jdXJyZW50VGFyZ2V0ID0gdGFyZ2V0O1xyXG5cdFx0dGhpcy5uYW1lc3BhY2UgPSBuYW1lc3BhY2UgfHwgJyc7XHJcblx0XHR0aGlzLnRpbWVTdGFtcCA9IHRoaXMudGltZXN0YW1wID0gRGF0ZS5ub3coKTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH07XHJcblxyXG5cdC8qXHJcblx0ICogVE9ETzogRE9DUyAocHJpdmF0ZSBmb3IgZGV2KVxyXG5cdCAqL1xyXG5cclxuXHR2YXIgX3V0aWwgPSBTY3JvbGxNYWdpYy5fdXRpbCA9IChmdW5jdGlvbiAod2luZG93KSB7XHJcblx0XHR2YXIgVSA9IHt9LFxyXG5cdFx0XHRpO1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHQgKiBpbnRlcm5hbCBoZWxwZXJzXHJcblx0XHQgKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdCAqL1xyXG5cclxuXHRcdC8vIHBhcnNlIGZsb2F0IGFuZCBmYWxsIGJhY2sgdG8gMC5cclxuXHRcdHZhciBmbG9hdHZhbCA9IGZ1bmN0aW9uIChudW1iZXIpIHtcclxuXHRcdFx0cmV0dXJuIHBhcnNlRmxvYXQobnVtYmVyKSB8fCAwO1xyXG5cdFx0fTtcclxuXHRcdC8vIGdldCBjdXJyZW50IHN0eWxlIElFIHNhZmUgKG90aGVyd2lzZSBJRSB3b3VsZCByZXR1cm4gY2FsY3VsYXRlZCB2YWx1ZXMgZm9yICdhdXRvJylcclxuXHRcdHZhciBfZ2V0Q29tcHV0ZWRTdHlsZSA9IGZ1bmN0aW9uIChlbGVtKSB7XHJcblx0XHRcdHJldHVybiBlbGVtLmN1cnJlbnRTdHlsZSA/IGVsZW0uY3VycmVudFN0eWxlIDogd2luZG93LmdldENvbXB1dGVkU3R5bGUoZWxlbSk7XHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIGdldCBlbGVtZW50IGRpbWVuc2lvbiAod2lkdGggb3IgaGVpZ2h0KVxyXG5cdFx0dmFyIF9kaW1lbnNpb24gPSBmdW5jdGlvbiAod2hpY2gsIGVsZW0sIG91dGVyLCBpbmNsdWRlTWFyZ2luKSB7XHJcblx0XHRcdGVsZW0gPSAoZWxlbSA9PT0gZG9jdW1lbnQpID8gd2luZG93IDogZWxlbTtcclxuXHRcdFx0aWYgKGVsZW0gPT09IHdpbmRvdykge1xyXG5cdFx0XHRcdGluY2x1ZGVNYXJnaW4gPSBmYWxzZTtcclxuXHRcdFx0fSBlbHNlIGlmICghX3R5cGUuRG9tRWxlbWVudChlbGVtKSkge1xyXG5cdFx0XHRcdHJldHVybiAwO1xyXG5cdFx0XHR9XHJcblx0XHRcdHdoaWNoID0gd2hpY2guY2hhckF0KDApLnRvVXBwZXJDYXNlKCkgKyB3aGljaC5zdWJzdHIoMSkudG9Mb3dlckNhc2UoKTtcclxuXHRcdFx0dmFyIGRpbWVuc2lvbiA9IChvdXRlciA/IGVsZW1bJ29mZnNldCcgKyB3aGljaF0gfHwgZWxlbVsnb3V0ZXInICsgd2hpY2hdIDogZWxlbVsnY2xpZW50JyArIHdoaWNoXSB8fCBlbGVtWydpbm5lcicgKyB3aGljaF0pIHx8IDA7XHJcblx0XHRcdGlmIChvdXRlciAmJiBpbmNsdWRlTWFyZ2luKSB7XHJcblx0XHRcdFx0dmFyIHN0eWxlID0gX2dldENvbXB1dGVkU3R5bGUoZWxlbSk7XHJcblx0XHRcdFx0ZGltZW5zaW9uICs9IHdoaWNoID09PSAnSGVpZ2h0JyA/IGZsb2F0dmFsKHN0eWxlLm1hcmdpblRvcCkgKyBmbG9hdHZhbChzdHlsZS5tYXJnaW5Cb3R0b20pIDogZmxvYXR2YWwoc3R5bGUubWFyZ2luTGVmdCkgKyBmbG9hdHZhbChzdHlsZS5tYXJnaW5SaWdodCk7XHJcblx0XHRcdH1cclxuXHRcdFx0cmV0dXJuIGRpbWVuc2lvbjtcclxuXHRcdH07XHJcblx0XHQvLyBjb252ZXJ0cyAnbWFyZ2luLXRvcCcgaW50byAnbWFyZ2luVG9wJ1xyXG5cdFx0dmFyIF9jYW1lbENhc2UgPSBmdW5jdGlvbiAoc3RyKSB7XHJcblx0XHRcdHJldHVybiBzdHIucmVwbGFjZSgvXlteYS16XSsoW2Etel0pL2csICckMScpLnJlcGxhY2UoLy0oW2Etel0pL2csIGZ1bmN0aW9uIChnKSB7XHJcblx0XHRcdFx0cmV0dXJuIGdbMV0udG9VcHBlckNhc2UoKTtcclxuXHRcdFx0fSk7XHJcblx0XHR9O1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHQgKiBleHRlcm5hbCBoZWxwZXJzXHJcblx0XHQgKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdCAqL1xyXG5cclxuXHRcdC8vIGV4dGVuZCBvYmog4oCTIHNhbWUgYXMgalF1ZXJ5LmV4dGVuZCh7fSwgb2JqQSwgb2JqQilcclxuXHRcdFUuZXh0ZW5kID0gZnVuY3Rpb24gKG9iaikge1xyXG5cdFx0XHRvYmogPSBvYmogfHwge307XHJcblx0XHRcdGZvciAoaSA9IDE7IGkgPCBhcmd1bWVudHMubGVuZ3RoOyBpKyspIHtcclxuXHRcdFx0XHRpZiAoIWFyZ3VtZW50c1tpXSkge1xyXG5cdFx0XHRcdFx0Y29udGludWU7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGZvciAodmFyIGtleSBpbiBhcmd1bWVudHNbaV0pIHtcclxuXHRcdFx0XHRcdGlmIChhcmd1bWVudHNbaV0uaGFzT3duUHJvcGVydHkoa2V5KSkge1xyXG5cdFx0XHRcdFx0XHRvYmpba2V5XSA9IGFyZ3VtZW50c1tpXVtrZXldO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0XHRyZXR1cm4gb2JqO1xyXG5cdFx0fTtcclxuXHJcblx0XHQvLyBjaGVjayBpZiBhIGNzcyBkaXNwbGF5IHR5cGUgcmVzdWx0cyBpbiBtYXJnaW4tY29sbGFwc2Ugb3Igbm90XHJcblx0XHRVLmlzTWFyZ2luQ29sbGFwc2VUeXBlID0gZnVuY3Rpb24gKHN0cikge1xyXG5cdFx0XHRyZXR1cm4gW1wiYmxvY2tcIiwgXCJmbGV4XCIsIFwibGlzdC1pdGVtXCIsIFwidGFibGVcIiwgXCItd2Via2l0LWJveFwiXS5pbmRleE9mKHN0cikgPiAtMTtcclxuXHRcdH07XHJcblxyXG5cdFx0Ly8gaW1wbGVtZW50YXRpb24gb2YgcmVxdWVzdEFuaW1hdGlvbkZyYW1lXHJcblx0XHQvLyBiYXNlZCBvbiBodHRwczovL2dpc3QuZ2l0aHViLmNvbS9wYXVsaXJpc2gvMTU3OTY3MVxyXG5cdFx0dmFyXHJcblx0XHRcdGxhc3RUaW1lID0gMCxcclxuXHRcdFx0dmVuZG9ycyA9IFsnbXMnLCAnbW96JywgJ3dlYmtpdCcsICdvJ107XHJcblx0XHR2YXIgX3JlcXVlc3RBbmltYXRpb25GcmFtZSA9IHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWU7XHJcblx0XHR2YXIgX2NhbmNlbEFuaW1hdGlvbkZyYW1lID0gd2luZG93LmNhbmNlbEFuaW1hdGlvbkZyYW1lO1xyXG5cdFx0Ly8gdHJ5IHZlbmRvciBwcmVmaXhlcyBpZiB0aGUgYWJvdmUgZG9lc24ndCB3b3JrXHJcblx0XHRmb3IgKGkgPSAwOyAhX3JlcXVlc3RBbmltYXRpb25GcmFtZSAmJiBpIDwgdmVuZG9ycy5sZW5ndGg7ICsraSkge1xyXG5cdFx0XHRfcmVxdWVzdEFuaW1hdGlvbkZyYW1lID0gd2luZG93W3ZlbmRvcnNbaV0gKyAnUmVxdWVzdEFuaW1hdGlvbkZyYW1lJ107XHJcblx0XHRcdF9jYW5jZWxBbmltYXRpb25GcmFtZSA9IHdpbmRvd1t2ZW5kb3JzW2ldICsgJ0NhbmNlbEFuaW1hdGlvbkZyYW1lJ10gfHwgd2luZG93W3ZlbmRvcnNbaV0gKyAnQ2FuY2VsUmVxdWVzdEFuaW1hdGlvbkZyYW1lJ107XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gZmFsbGJhY2tzXHJcblx0XHRpZiAoIV9yZXF1ZXN0QW5pbWF0aW9uRnJhbWUpIHtcclxuXHRcdFx0X3JlcXVlc3RBbmltYXRpb25GcmFtZSA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xyXG5cdFx0XHRcdHZhclxyXG5cdFx0XHRcdFx0Y3VyclRpbWUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKSxcclxuXHRcdFx0XHRcdHRpbWVUb0NhbGwgPSBNYXRoLm1heCgwLCAxNiAtIChjdXJyVGltZSAtIGxhc3RUaW1lKSksXHJcblx0XHRcdFx0XHRpZCA9IHdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0XHRcdFx0Y2FsbGJhY2soY3VyclRpbWUgKyB0aW1lVG9DYWxsKTtcclxuXHRcdFx0XHRcdH0sIHRpbWVUb0NhbGwpO1xyXG5cdFx0XHRcdGxhc3RUaW1lID0gY3VyclRpbWUgKyB0aW1lVG9DYWxsO1xyXG5cdFx0XHRcdHJldHVybiBpZDtcclxuXHRcdFx0fTtcclxuXHRcdH1cclxuXHRcdGlmICghX2NhbmNlbEFuaW1hdGlvbkZyYW1lKSB7XHJcblx0XHRcdF9jYW5jZWxBbmltYXRpb25GcmFtZSA9IGZ1bmN0aW9uIChpZCkge1xyXG5cdFx0XHRcdHdpbmRvdy5jbGVhclRpbWVvdXQoaWQpO1xyXG5cdFx0XHR9O1xyXG5cdFx0fVxyXG5cdFx0VS5yQUYgPSBfcmVxdWVzdEFuaW1hdGlvbkZyYW1lLmJpbmQod2luZG93KTtcclxuXHRcdFUuY0FGID0gX2NhbmNlbEFuaW1hdGlvbkZyYW1lLmJpbmQod2luZG93KTtcclxuXHJcblx0XHR2YXJcclxuXHRcdFx0bG9nbGV2ZWxzID0gW1wiZXJyb3JcIiwgXCJ3YXJuXCIsIFwibG9nXCJdLFxyXG5cdFx0XHRjb25zb2xlID0gd2luZG93LmNvbnNvbGUgfHwge307XHJcblxyXG5cdFx0Y29uc29sZS5sb2cgPSBjb25zb2xlLmxvZyB8fCBmdW5jdGlvbiAoKSB7fTsgLy8gbm8gY29uc29sZSBsb2csIHdlbGwgLSBkbyBub3RoaW5nIHRoZW4uLi5cclxuXHRcdC8vIG1ha2Ugc3VyZSBtZXRob2RzIGZvciBhbGwgbGV2ZWxzIGV4aXN0LlxyXG5cdFx0Zm9yIChpID0gMDsgaSA8IGxvZ2xldmVscy5sZW5ndGg7IGkrKykge1xyXG5cdFx0XHR2YXIgbWV0aG9kID0gbG9nbGV2ZWxzW2ldO1xyXG5cdFx0XHRpZiAoIWNvbnNvbGVbbWV0aG9kXSkge1xyXG5cdFx0XHRcdGNvbnNvbGVbbWV0aG9kXSA9IGNvbnNvbGUubG9nOyAvLyBwcmVmZXIgLmxvZyBvdmVyIG5vdGhpbmdcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdFx0VS5sb2cgPSBmdW5jdGlvbiAobG9nbGV2ZWwpIHtcclxuXHRcdFx0aWYgKGxvZ2xldmVsID4gbG9nbGV2ZWxzLmxlbmd0aCB8fCBsb2dsZXZlbCA8PSAwKSBsb2dsZXZlbCA9IGxvZ2xldmVscy5sZW5ndGg7XHJcblx0XHRcdHZhciBub3cgPSBuZXcgRGF0ZSgpLFxyXG5cdFx0XHRcdHRpbWUgPSAoXCIwXCIgKyBub3cuZ2V0SG91cnMoKSkuc2xpY2UoLTIpICsgXCI6XCIgKyAoXCIwXCIgKyBub3cuZ2V0TWludXRlcygpKS5zbGljZSgtMikgKyBcIjpcIiArIChcIjBcIiArIG5vdy5nZXRTZWNvbmRzKCkpLnNsaWNlKC0yKSArIFwiOlwiICsgKFwiMDBcIiArIG5vdy5nZXRNaWxsaXNlY29uZHMoKSkuc2xpY2UoLTMpLFxyXG5cdFx0XHRcdG1ldGhvZCA9IGxvZ2xldmVsc1tsb2dsZXZlbCAtIDFdLFxyXG5cdFx0XHRcdGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc3BsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSxcclxuXHRcdFx0XHRmdW5jID0gRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQuY2FsbChjb25zb2xlW21ldGhvZF0sIGNvbnNvbGUpO1xyXG5cdFx0XHRhcmdzLnVuc2hpZnQodGltZSk7XHJcblx0XHRcdGZ1bmMuYXBwbHkoY29uc29sZSwgYXJncyk7XHJcblx0XHR9O1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHQgKiB0eXBlIHRlc3RpbmdcclxuXHRcdCAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0ICovXHJcblxyXG5cdFx0dmFyIF90eXBlID0gVS50eXBlID0gZnVuY3Rpb24gKHYpIHtcclxuXHRcdFx0cmV0dXJuIE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh2KS5yZXBsYWNlKC9eXFxbb2JqZWN0ICguKylcXF0kLywgXCIkMVwiKS50b0xvd2VyQ2FzZSgpO1xyXG5cdFx0fTtcclxuXHRcdF90eXBlLlN0cmluZyA9IGZ1bmN0aW9uICh2KSB7XHJcblx0XHRcdHJldHVybiBfdHlwZSh2KSA9PT0gJ3N0cmluZyc7XHJcblx0XHR9O1xyXG5cdFx0X3R5cGUuRnVuY3Rpb24gPSBmdW5jdGlvbiAodikge1xyXG5cdFx0XHRyZXR1cm4gX3R5cGUodikgPT09ICdmdW5jdGlvbic7XHJcblx0XHR9O1xyXG5cdFx0X3R5cGUuQXJyYXkgPSBmdW5jdGlvbiAodikge1xyXG5cdFx0XHRyZXR1cm4gQXJyYXkuaXNBcnJheSh2KTtcclxuXHRcdH07XHJcblx0XHRfdHlwZS5OdW1iZXIgPSBmdW5jdGlvbiAodikge1xyXG5cdFx0XHRyZXR1cm4gIV90eXBlLkFycmF5KHYpICYmICh2IC0gcGFyc2VGbG9hdCh2KSArIDEpID49IDA7XHJcblx0XHR9O1xyXG5cdFx0X3R5cGUuRG9tRWxlbWVudCA9IGZ1bmN0aW9uIChvKSB7XHJcblx0XHRcdHJldHVybiAoXHJcblx0XHRcdFx0dHlwZW9mIEhUTUxFbGVtZW50ID09PSBcIm9iamVjdFwiIHx8IHR5cGVvZiBIVE1MRWxlbWVudCA9PT0gXCJmdW5jdGlvblwiID8gbyBpbnN0YW5jZW9mIEhUTUxFbGVtZW50IHx8IG8gaW5zdGFuY2VvZiBTVkdFbGVtZW50IDogLy9ET00yXHJcblx0XHRcdFx0byAmJiB0eXBlb2YgbyA9PT0gXCJvYmplY3RcIiAmJiBvICE9PSBudWxsICYmIG8ubm9kZVR5cGUgPT09IDEgJiYgdHlwZW9mIG8ubm9kZU5hbWUgPT09IFwic3RyaW5nXCJcclxuXHRcdFx0KTtcclxuXHRcdH07XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdCAqIERPTSBFbGVtZW50IGluZm9cclxuXHRcdCAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0ICovXHJcblx0XHQvLyBhbHdheXMgcmV0dXJucyBhIGxpc3Qgb2YgbWF0Y2hpbmcgRE9NIGVsZW1lbnRzLCBmcm9tIGEgc2VsZWN0b3IsIGEgRE9NIGVsZW1lbnQgb3IgYW4gbGlzdCBvZiBlbGVtZW50cyBvciBldmVuIGFuIGFycmF5IG9mIHNlbGVjdG9yc1xyXG5cdFx0dmFyIF9nZXQgPSBVLmdldCA9IHt9O1xyXG5cdFx0X2dldC5lbGVtZW50cyA9IGZ1bmN0aW9uIChzZWxlY3Rvcikge1xyXG5cdFx0XHR2YXIgYXJyID0gW107XHJcblx0XHRcdGlmIChfdHlwZS5TdHJpbmcoc2VsZWN0b3IpKSB7XHJcblx0XHRcdFx0dHJ5IHtcclxuXHRcdFx0XHRcdHNlbGVjdG9yID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbChzZWxlY3Rvcik7XHJcblx0XHRcdFx0fSBjYXRjaCAoZSkgeyAvLyBpbnZhbGlkIHNlbGVjdG9yXHJcblx0XHRcdFx0XHRyZXR1cm4gYXJyO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0XHRpZiAoX3R5cGUoc2VsZWN0b3IpID09PSAnbm9kZWxpc3QnIHx8IF90eXBlLkFycmF5KHNlbGVjdG9yKSB8fCBzZWxlY3RvciBpbnN0YW5jZW9mIE5vZGVMaXN0KSB7XHJcblx0XHRcdFx0Zm9yICh2YXIgaSA9IDAsIHJlZiA9IGFyci5sZW5ndGggPSBzZWxlY3Rvci5sZW5ndGg7IGkgPCByZWY7IGkrKykgeyAvLyBsaXN0IG9mIGVsZW1lbnRzXHJcblx0XHRcdFx0XHR2YXIgZWxlbSA9IHNlbGVjdG9yW2ldO1xyXG5cdFx0XHRcdFx0YXJyW2ldID0gX3R5cGUuRG9tRWxlbWVudChlbGVtKSA/IGVsZW0gOiBfZ2V0LmVsZW1lbnRzKGVsZW0pOyAvLyBpZiBub3QgYW4gZWxlbWVudCwgdHJ5IHRvIHJlc29sdmUgcmVjdXJzaXZlbHlcclxuXHRcdFx0XHR9XHJcblx0XHRcdH0gZWxzZSBpZiAoX3R5cGUuRG9tRWxlbWVudChzZWxlY3RvcikgfHwgc2VsZWN0b3IgPT09IGRvY3VtZW50IHx8IHNlbGVjdG9yID09PSB3aW5kb3cpIHtcclxuXHRcdFx0XHRhcnIgPSBbc2VsZWN0b3JdOyAvLyBvbmx5IHRoZSBlbGVtZW50XHJcblx0XHRcdH1cclxuXHRcdFx0cmV0dXJuIGFycjtcclxuXHRcdH07XHJcblx0XHQvLyBnZXQgc2Nyb2xsIHRvcCB2YWx1ZVxyXG5cdFx0X2dldC5zY3JvbGxUb3AgPSBmdW5jdGlvbiAoZWxlbSkge1xyXG5cdFx0XHRyZXR1cm4gKGVsZW0gJiYgdHlwZW9mIGVsZW0uc2Nyb2xsVG9wID09PSAnbnVtYmVyJykgPyBlbGVtLnNjcm9sbFRvcCA6IHdpbmRvdy5wYWdlWU9mZnNldCB8fCAwO1xyXG5cdFx0fTtcclxuXHRcdC8vIGdldCBzY3JvbGwgbGVmdCB2YWx1ZVxyXG5cdFx0X2dldC5zY3JvbGxMZWZ0ID0gZnVuY3Rpb24gKGVsZW0pIHtcclxuXHRcdFx0cmV0dXJuIChlbGVtICYmIHR5cGVvZiBlbGVtLnNjcm9sbExlZnQgPT09ICdudW1iZXInKSA/IGVsZW0uc2Nyb2xsTGVmdCA6IHdpbmRvdy5wYWdlWE9mZnNldCB8fCAwO1xyXG5cdFx0fTtcclxuXHRcdC8vIGdldCBlbGVtZW50IGhlaWdodFxyXG5cdFx0X2dldC53aWR0aCA9IGZ1bmN0aW9uIChlbGVtLCBvdXRlciwgaW5jbHVkZU1hcmdpbikge1xyXG5cdFx0XHRyZXR1cm4gX2RpbWVuc2lvbignd2lkdGgnLCBlbGVtLCBvdXRlciwgaW5jbHVkZU1hcmdpbik7XHJcblx0XHR9O1xyXG5cdFx0Ly8gZ2V0IGVsZW1lbnQgd2lkdGhcclxuXHRcdF9nZXQuaGVpZ2h0ID0gZnVuY3Rpb24gKGVsZW0sIG91dGVyLCBpbmNsdWRlTWFyZ2luKSB7XHJcblx0XHRcdHJldHVybiBfZGltZW5zaW9uKCdoZWlnaHQnLCBlbGVtLCBvdXRlciwgaW5jbHVkZU1hcmdpbik7XHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIGdldCBlbGVtZW50IHBvc2l0aW9uIChvcHRpb25hbGx5IHJlbGF0aXZlIHRvIHZpZXdwb3J0KVxyXG5cdFx0X2dldC5vZmZzZXQgPSBmdW5jdGlvbiAoZWxlbSwgcmVsYXRpdmVUb1ZpZXdwb3J0KSB7XHJcblx0XHRcdHZhciBvZmZzZXQgPSB7XHJcblx0XHRcdFx0dG9wOiAwLFxyXG5cdFx0XHRcdGxlZnQ6IDBcclxuXHRcdFx0fTtcclxuXHRcdFx0aWYgKGVsZW0gJiYgZWxlbS5nZXRCb3VuZGluZ0NsaWVudFJlY3QpIHsgLy8gY2hlY2sgaWYgYXZhaWxhYmxlXHJcblx0XHRcdFx0dmFyIHJlY3QgPSBlbGVtLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG5cdFx0XHRcdG9mZnNldC50b3AgPSByZWN0LnRvcDtcclxuXHRcdFx0XHRvZmZzZXQubGVmdCA9IHJlY3QubGVmdDtcclxuXHRcdFx0XHRpZiAoIXJlbGF0aXZlVG9WaWV3cG9ydCkgeyAvLyBjbGllbnRSZWN0IGlzIGJ5IGRlZmF1bHQgcmVsYXRpdmUgdG8gdmlld3BvcnQuLi5cclxuXHRcdFx0XHRcdG9mZnNldC50b3AgKz0gX2dldC5zY3JvbGxUb3AoKTtcclxuXHRcdFx0XHRcdG9mZnNldC5sZWZ0ICs9IF9nZXQuc2Nyb2xsTGVmdCgpO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0XHRyZXR1cm4gb2Zmc2V0O1xyXG5cdFx0fTtcclxuXHJcblx0XHQvKipcclxuXHRcdCAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0ICogRE9NIEVsZW1lbnQgbWFuaXB1bGF0aW9uXHJcblx0XHQgKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdCAqL1xyXG5cclxuXHRcdFUuYWRkQ2xhc3MgPSBmdW5jdGlvbiAoZWxlbSwgY2xhc3NuYW1lKSB7XHJcblx0XHRcdGlmIChjbGFzc25hbWUpIHtcclxuXHRcdFx0XHRpZiAoZWxlbS5jbGFzc0xpc3QpXHJcblx0XHRcdFx0XHRlbGVtLmNsYXNzTGlzdC5hZGQoY2xhc3NuYW1lKTtcclxuXHRcdFx0XHRlbHNlXHJcblx0XHRcdFx0XHRlbGVtLmNsYXNzTmFtZSArPSAnICcgKyBjbGFzc25hbWU7XHJcblx0XHRcdH1cclxuXHRcdH07XHJcblx0XHRVLnJlbW92ZUNsYXNzID0gZnVuY3Rpb24gKGVsZW0sIGNsYXNzbmFtZSkge1xyXG5cdFx0XHRpZiAoY2xhc3NuYW1lKSB7XHJcblx0XHRcdFx0aWYgKGVsZW0uY2xhc3NMaXN0KVxyXG5cdFx0XHRcdFx0ZWxlbS5jbGFzc0xpc3QucmVtb3ZlKGNsYXNzbmFtZSk7XHJcblx0XHRcdFx0ZWxzZVxyXG5cdFx0XHRcdFx0ZWxlbS5jbGFzc05hbWUgPSBlbGVtLmNsYXNzTmFtZS5yZXBsYWNlKG5ldyBSZWdFeHAoJyhefFxcXFxiKScgKyBjbGFzc25hbWUuc3BsaXQoJyAnKS5qb2luKCd8JykgKyAnKFxcXFxifCQpJywgJ2dpJyksICcgJyk7XHJcblx0XHRcdH1cclxuXHRcdH07XHJcblx0XHQvLyBpZiBvcHRpb25zIGlzIHN0cmluZyAtPiByZXR1cm5zIGNzcyB2YWx1ZVxyXG5cdFx0Ly8gaWYgb3B0aW9ucyBpcyBhcnJheSAtPiByZXR1cm5zIG9iamVjdCB3aXRoIGNzcyB2YWx1ZSBwYWlyc1xyXG5cdFx0Ly8gaWYgb3B0aW9ucyBpcyBvYmplY3QgLT4gc2V0IG5ldyBjc3MgdmFsdWVzXHJcblx0XHRVLmNzcyA9IGZ1bmN0aW9uIChlbGVtLCBvcHRpb25zKSB7XHJcblx0XHRcdGlmIChfdHlwZS5TdHJpbmcob3B0aW9ucykpIHtcclxuXHRcdFx0XHRyZXR1cm4gX2dldENvbXB1dGVkU3R5bGUoZWxlbSlbX2NhbWVsQ2FzZShvcHRpb25zKV07XHJcblx0XHRcdH0gZWxzZSBpZiAoX3R5cGUuQXJyYXkob3B0aW9ucykpIHtcclxuXHRcdFx0XHR2YXJcclxuXHRcdFx0XHRcdG9iaiA9IHt9LFxyXG5cdFx0XHRcdFx0c3R5bGUgPSBfZ2V0Q29tcHV0ZWRTdHlsZShlbGVtKTtcclxuXHRcdFx0XHRvcHRpb25zLmZvckVhY2goZnVuY3Rpb24gKG9wdGlvbiwga2V5KSB7XHJcblx0XHRcdFx0XHRvYmpbb3B0aW9uXSA9IHN0eWxlW19jYW1lbENhc2Uob3B0aW9uKV07XHJcblx0XHRcdFx0fSk7XHJcblx0XHRcdFx0cmV0dXJuIG9iajtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRmb3IgKHZhciBvcHRpb24gaW4gb3B0aW9ucykge1xyXG5cdFx0XHRcdFx0dmFyIHZhbCA9IG9wdGlvbnNbb3B0aW9uXTtcclxuXHRcdFx0XHRcdGlmICh2YWwgPT0gcGFyc2VGbG9hdCh2YWwpKSB7IC8vIGFzc3VtZSBwaXhlbCBmb3Igc2VlbWluZ2x5IG51bWVyaWNhbCB2YWx1ZXNcclxuXHRcdFx0XHRcdFx0dmFsICs9ICdweCc7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRlbGVtLnN0eWxlW19jYW1lbENhc2Uob3B0aW9uKV0gPSB2YWw7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9O1xyXG5cclxuXHRcdHJldHVybiBVO1xyXG5cdH0od2luZG93IHx8IHt9KSk7XHJcblxyXG5cclxuXHRTY3JvbGxNYWdpYy5TY2VuZS5wcm90b3R5cGUuYWRkSW5kaWNhdG9ycyA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdFNjcm9sbE1hZ2ljLl91dGlsLmxvZygxLCAnKFNjcm9sbE1hZ2ljLlNjZW5lKSAtPiBFUlJPUiBjYWxsaW5nIGFkZEluZGljYXRvcnMoKSBkdWUgdG8gbWlzc2luZyBQbHVnaW4gXFwnZGVidWcuYWRkSW5kaWNhdG9yc1xcJy4gUGxlYXNlIG1ha2Ugc3VyZSB0byBpbmNsdWRlIHBsdWdpbnMvZGVidWcuYWRkSW5kaWNhdG9ycy5qcycpO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fVxyXG5cdFNjcm9sbE1hZ2ljLlNjZW5lLnByb3RvdHlwZS5yZW1vdmVJbmRpY2F0b3JzID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0U2Nyb2xsTWFnaWMuX3V0aWwubG9nKDEsICcoU2Nyb2xsTWFnaWMuU2NlbmUpIC0+IEVSUk9SIGNhbGxpbmcgcmVtb3ZlSW5kaWNhdG9ycygpIGR1ZSB0byBtaXNzaW5nIFBsdWdpbiBcXCdkZWJ1Zy5hZGRJbmRpY2F0b3JzXFwnLiBQbGVhc2UgbWFrZSBzdXJlIHRvIGluY2x1ZGUgcGx1Z2lucy9kZWJ1Zy5hZGRJbmRpY2F0b3JzLmpzJyk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9XHJcblx0U2Nyb2xsTWFnaWMuU2NlbmUucHJvdG90eXBlLnNldFR3ZWVuID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0U2Nyb2xsTWFnaWMuX3V0aWwubG9nKDEsICcoU2Nyb2xsTWFnaWMuU2NlbmUpIC0+IEVSUk9SIGNhbGxpbmcgc2V0VHdlZW4oKSBkdWUgdG8gbWlzc2luZyBQbHVnaW4gXFwnYW5pbWF0aW9uLmdzYXBcXCcuIFBsZWFzZSBtYWtlIHN1cmUgdG8gaW5jbHVkZSBwbHVnaW5zL2FuaW1hdGlvbi5nc2FwLmpzJyk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9XHJcblx0U2Nyb2xsTWFnaWMuU2NlbmUucHJvdG90eXBlLnJlbW92ZVR3ZWVuID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0U2Nyb2xsTWFnaWMuX3V0aWwubG9nKDEsICcoU2Nyb2xsTWFnaWMuU2NlbmUpIC0+IEVSUk9SIGNhbGxpbmcgcmVtb3ZlVHdlZW4oKSBkdWUgdG8gbWlzc2luZyBQbHVnaW4gXFwnYW5pbWF0aW9uLmdzYXBcXCcuIFBsZWFzZSBtYWtlIHN1cmUgdG8gaW5jbHVkZSBwbHVnaW5zL2FuaW1hdGlvbi5nc2FwLmpzJyk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9XHJcblx0U2Nyb2xsTWFnaWMuU2NlbmUucHJvdG90eXBlLnNldFZlbG9jaXR5ID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0U2Nyb2xsTWFnaWMuX3V0aWwubG9nKDEsICcoU2Nyb2xsTWFnaWMuU2NlbmUpIC0+IEVSUk9SIGNhbGxpbmcgc2V0VmVsb2NpdHkoKSBkdWUgdG8gbWlzc2luZyBQbHVnaW4gXFwnYW5pbWF0aW9uLnZlbG9jaXR5XFwnLiBQbGVhc2UgbWFrZSBzdXJlIHRvIGluY2x1ZGUgcGx1Z2lucy9hbmltYXRpb24udmVsb2NpdHkuanMnKTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH1cclxuXHRTY3JvbGxNYWdpYy5TY2VuZS5wcm90b3R5cGUucmVtb3ZlVmVsb2NpdHkgPSBmdW5jdGlvbiAoKSB7XHJcblx0XHRTY3JvbGxNYWdpYy5fdXRpbC5sb2coMSwgJyhTY3JvbGxNYWdpYy5TY2VuZSkgLT4gRVJST1IgY2FsbGluZyByZW1vdmVWZWxvY2l0eSgpIGR1ZSB0byBtaXNzaW5nIFBsdWdpbiBcXCdhbmltYXRpb24udmVsb2NpdHlcXCcuIFBsZWFzZSBtYWtlIHN1cmUgdG8gaW5jbHVkZSBwbHVnaW5zL2FuaW1hdGlvbi52ZWxvY2l0eS5qcycpO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fVxyXG5cclxuXHRyZXR1cm4gU2Nyb2xsTWFnaWM7XHJcbn0pKTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///131\n')},474:(module,__unused_webpack_exports,__webpack_require__)=>{eval("/*! yt-player. MIT License. Feross Aboukhadijeh */\nconst EventEmitter = (__webpack_require__(7).EventEmitter)\nconst loadScript = __webpack_require__(843)\n\nconst YOUTUBE_IFRAME_API_SRC = 'https://www.youtube.com/iframe_api'\n\nconst YOUTUBE_STATES = {\n '-1': 'unstarted',\n 0: 'ended',\n 1: 'playing',\n 2: 'paused',\n 3: 'buffering',\n 5: 'cued'\n}\n\nconst YOUTUBE_ERROR = {\n // The request contains an invalid parameter value. For example, this error\n // occurs if you specify a videoId that does not have 11 characters, or if the\n // videoId contains invalid characters, such as exclamation points or asterisks.\n INVALID_PARAM: 2,\n\n // The requested content cannot be played in an HTML5 player or another error\n // related to the HTML5 player has occurred.\n HTML5_ERROR: 5,\n\n // The video requested was not found. This error occurs when a video has been\n // removed (for any reason) or has been marked as private.\n NOT_FOUND: 100,\n\n // The owner of the requested video does not allow it to be played in embedded\n // players.\n UNPLAYABLE_1: 101,\n\n // This error is the same as 101. It's just a 101 error in disguise!\n UNPLAYABLE_2: 150\n}\n\nconst loadIframeAPICallbacks = []\n\n/**\n * YouTube Player. Exposes a better API, with nicer events.\n * @param {HTMLElement|selector} element\n */\nclass YouTubePlayer extends EventEmitter {\n constructor (element, opts) {\n super()\n\n const elem = typeof element === 'string'\n ? document.querySelector(element)\n : element\n\n if (elem.id) {\n this._id = elem.id // use existing element id\n } else {\n this._id = elem.id = 'ytplayer-' + Math.random().toString(16).slice(2, 8)\n }\n\n this._opts = Object.assign({\n width: 640,\n height: 360,\n autoplay: false,\n captions: undefined,\n controls: true,\n keyboard: true,\n fullscreen: true,\n annotations: true,\n modestBranding: false,\n related: true,\n timeupdateFrequency: 1000,\n playsInline: true,\n start: 0\n }, opts)\n\n this.videoId = null\n this.destroyed = false\n\n this._api = null\n this._autoplay = false // autoplay the first video?\n this._player = null\n this._ready = false // is player ready?\n this._queue = []\n\n this._interval = null\n\n // Setup listeners for 'timeupdate' events. The YouTube Player does not fire\n // 'timeupdate' events, so they are simulated using a setInterval().\n this._startInterval = this._startInterval.bind(this)\n this._stopInterval = this._stopInterval.bind(this)\n\n this.on('playing', this._startInterval)\n this.on('unstarted', this._stopInterval)\n this.on('ended', this._stopInterval)\n this.on('paused', this._stopInterval)\n this.on('buffering', this._stopInterval)\n\n this._loadIframeAPI((err, api) => {\n if (err) return this._destroy(new Error('YouTube Iframe API failed to load'))\n this._api = api\n\n // If load(videoId, [autoplay, [size]]) was called before Iframe API\n // loaded, ensure it gets called again now\n if (this.videoId) this.load(this.videoId, this._autoplay, this._start)\n })\n }\n\n load (videoId, autoplay = false, start = 0) {\n if (this.destroyed) return\n\n this.videoId = videoId\n this._autoplay = autoplay\n this._start = start\n\n // If the Iframe API is not ready yet, do nothing. Once the Iframe API is\n // ready, `load(this.videoId)` will be called.\n if (!this._api) return\n\n // If there is no player instance, create one.\n if (!this._player) {\n this._createPlayer(videoId)\n return\n }\n\n // If the player instance is not ready yet, do nothing. Once the player\n // instance is ready, `load(this.videoId)` will be called. This ensures that\n // the last call to `load()` is the one that takes effect.\n if (!this._ready) return\n\n // If the player instance is ready, load the given `videoId`.\n if (autoplay) {\n this._player.loadVideoById(videoId, start)\n } else {\n this._player.cueVideoById(videoId, start)\n }\n }\n\n play () {\n if (this._ready) this._player.playVideo()\n else this._queueCommand('play')\n }\n\n pause () {\n if (this._ready) this._player.pauseVideo()\n else this._queueCommand('pause')\n }\n\n stop () {\n if (this._ready) this._player.stopVideo()\n else this._queueCommand('stop')\n }\n\n seek (seconds) {\n if (this._ready) this._player.seekTo(seconds, true)\n else this._queueCommand('seek', seconds)\n }\n\n setVolume (volume) {\n if (this._ready) this._player.setVolume(volume)\n else this._queueCommand('setVolume', volume)\n }\n\n getVolume () {\n return (this._ready && this._player.getVolume()) || 0\n }\n\n mute () {\n if (this._ready) this._player.mute()\n else this._queueCommand('mute')\n }\n\n unMute () {\n if (this._ready) this._player.unMute()\n else this._queueCommand('unMute')\n }\n\n isMuted () {\n return (this._ready && this._player.isMuted()) || false\n }\n\n setSize (width, height) {\n if (this._ready) this._player.setSize(width, height)\n else this._queueCommand('setSize', width, height)\n }\n\n setPlaybackRate (rate) {\n if (this._ready) this._player.setPlaybackRate(rate)\n else this._queueCommand('setPlaybackRate', rate)\n }\n\n setPlaybackQuality (suggestedQuality) {\n if (this._ready) this._player.setPlaybackQuality(suggestedQuality)\n else this._queueCommand('setPlaybackQuality', suggestedQuality)\n }\n\n getPlaybackRate () {\n return (this._ready && this._player.getPlaybackRate()) || 1\n }\n\n getAvailablePlaybackRates () {\n return (this._ready && this._player.getAvailablePlaybackRates()) || [1]\n }\n\n getDuration () {\n return (this._ready && this._player.getDuration()) || 0\n }\n\n getProgress () {\n return (this._ready && this._player.getVideoLoadedFraction()) || 0\n }\n\n getState () {\n return (this._ready && YOUTUBE_STATES[this._player.getPlayerState()]) || 'unstarted'\n }\n\n getCurrentTime () {\n return (this._ready && this._player.getCurrentTime()) || 0\n }\n\n destroy () {\n this._destroy()\n }\n\n _destroy (err) {\n if (this.destroyed) return\n this.destroyed = true\n\n if (this._player) {\n this._player.stopVideo && this._player.stopVideo()\n this._player.destroy()\n }\n\n this.videoId = null\n\n this._id = null\n this._opts = null\n this._api = null\n this._player = null\n this._ready = false\n this._queue = null\n\n this._stopInterval()\n\n this.removeListener('playing', this._startInterval)\n this.removeListener('paused', this._stopInterval)\n this.removeListener('buffering', this._stopInterval)\n this.removeListener('unstarted', this._stopInterval)\n this.removeListener('ended', this._stopInterval)\n\n if (err) this.emit('error', err)\n }\n\n _queueCommand (command, ...args) {\n if (this.destroyed) return\n this._queue.push([command, args])\n }\n\n _flushQueue () {\n while (this._queue.length) {\n const command = this._queue.shift()\n this[command[0]].apply(this, command[1])\n }\n }\n\n _loadIframeAPI (cb) {\n // If API is loaded, there is nothing else to do\n if (window.YT && typeof window.YT.Player === 'function') {\n return cb(null, window.YT)\n }\n\n // Otherwise, queue callback until API is loaded\n loadIframeAPICallbacks.push(cb)\n\n const scripts = Array.from(document.getElementsByTagName('script'))\n const isLoading = scripts.some(script => script.src === YOUTUBE_IFRAME_API_SRC)\n\n // If API