260 lines
2.7 MiB
Plaintext
Vendored
260 lines
2.7 MiB
Plaintext
Vendored
/*
|
|
* ATTENTION: An "eval-source-map" devtool has been used.
|
|
* This devtool is neither made for production nor for readable output files.
|
|
* It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
|
|
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
|
|
* or disable the default devtool with "devtool: false".
|
|
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
|
|
*/
|
|
/******/ (() => { // webpackBootstrap
|
|
/******/ var __webpack_modules__ = ({
|
|
|
|
/***/ "./resources/js/app.js":
|
|
/*!*****************************!*\
|
|
!*** ./resources/js/app.js ***!
|
|
\*****************************/
|
|
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
|
|
|
|
eval("try {\n window.Popper = (__webpack_require__(/*! popper.js */ \"./node_modules/popper.js/dist/esm/popper.js\")[\"default\"]);\n window.$ = window.jQuery = __webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\");\n\n __webpack_require__(/*! bootstrap */ \"./node_modules/bootstrap/dist/js/bootstrap.js\");\n\n __webpack_require__(/*! datatables.net-bs4 */ \"./node_modules/datatables.net-bs4/js/dataTables.bootstrap4.js\");\n\n __webpack_require__(/*! jquery-confirm */ \"./node_modules/jquery-confirm/dist/jquery-confirm.min.js\");\n} catch (e) {}//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9yZXNvdXJjZXMvanMvYXBwLmpzLmpzIiwibWFwcGluZ3MiOiJBQUFBLElBQUk7QUFDQUEsRUFBQUEsTUFBTSxDQUFDQyxNQUFQLEdBQWdCQyxnR0FBaEI7QUFDQUYsRUFBQUEsTUFBTSxDQUFDRyxDQUFQLEdBQVdILE1BQU0sQ0FBQ0ksTUFBUCxHQUFnQkYsbUJBQU8sQ0FBQyxvREFBRCxDQUFsQzs7QUFFQUEsRUFBQUEsbUJBQU8sQ0FBQyxnRUFBRCxDQUFQOztBQUNBQSxFQUFBQSxtQkFBTyxDQUFDLHlGQUFELENBQVA7O0FBQ0FBLEVBQUFBLG1CQUFPLENBQUMsZ0ZBQUQsQ0FBUDtBQUNILENBUEQsQ0FPRSxPQUFPRyxDQUFQLEVBQVUsQ0FBRSIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL3Jlc291cmNlcy9qcy9hcHAuanM/Y2VkNiJdLCJzb3VyY2VzQ29udGVudCI6WyJ0cnkge1xyXG4gICAgd2luZG93LlBvcHBlciA9IHJlcXVpcmUoJ3BvcHBlci5qcycpLmRlZmF1bHQ7XHJcbiAgICB3aW5kb3cuJCA9IHdpbmRvdy5qUXVlcnkgPSByZXF1aXJlKCdqcXVlcnknKTtcclxuXHJcbiAgICByZXF1aXJlKCdib290c3RyYXAnKTtcclxuICAgIHJlcXVpcmUoJ2RhdGF0YWJsZXMubmV0LWJzNCcpO1xyXG4gICAgcmVxdWlyZSgnanF1ZXJ5LWNvbmZpcm0nKTtcclxufSBjYXRjaCAoZSkge30iXSwibmFtZXMiOlsid2luZG93IiwiUG9wcGVyIiwicmVxdWlyZSIsIiQiLCJqUXVlcnkiLCJlIl0sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./resources/js/app.js\n");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./node_modules/bootstrap/dist/js/bootstrap.js":
|
|
/*!*****************************************************!*\
|
|
!*** ./node_modules/bootstrap/dist/js/bootstrap.js ***!
|
|
\*****************************************************/
|
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
|
|
eval("/*!\n * Bootstrap v4.6.1 (https://getbootstrap.com/)\n * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n(function (global, factory) {\n true ? factory(exports, __webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\"), __webpack_require__(/*! popper.js */ \"./node_modules/popper.js/dist/esm/popper.js\")) :\n 0;\n})(this, (function (exports, $, Popper) { 'use strict';\n\n function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }\n\n var $__default = /*#__PURE__*/_interopDefaultLegacy($);\n var Popper__default = /*#__PURE__*/_interopDefaultLegacy(Popper);\n\n function _defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n }\n\n function _createClass(Constructor, protoProps, staticProps) {\n if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n if (staticProps) _defineProperties(Constructor, staticProps);\n return Constructor;\n }\n\n function _extends() {\n _extends = Object.assign || function (target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i];\n\n for (var key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n }\n }\n\n return target;\n };\n\n return _extends.apply(this, arguments);\n }\n\n function _inheritsLoose(subClass, superClass) {\n subClass.prototype = Object.create(superClass.prototype);\n subClass.prototype.constructor = subClass;\n\n _setPrototypeOf(subClass, superClass);\n }\n\n function _setPrototypeOf(o, p) {\n _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {\n o.__proto__ = p;\n return o;\n };\n\n return _setPrototypeOf(o, p);\n }\n\n /**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.6.1): util.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n /**\n * Private TransitionEnd Helpers\n */\n\n var TRANSITION_END = 'transitionend';\n var MAX_UID = 1000000;\n var MILLISECONDS_MULTIPLIER = 1000; // Shoutout AngusCroll (https://goo.gl/pxwQGp)\n\n function toType(obj) {\n if (obj === null || typeof obj === 'undefined') {\n return \"\" + obj;\n }\n\n return {}.toString.call(obj).match(/\\s([a-z]+)/i)[1].toLowerCase();\n }\n\n function getSpecialTransitionEndEvent() {\n return {\n bindType: TRANSITION_END,\n delegateType: TRANSITION_END,\n handle: function handle(event) {\n if ($__default[\"default\"](event.target).is(this)) {\n return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params\n }\n\n return undefined;\n }\n };\n }\n\n function transitionEndEmulator(duration) {\n var _this = this;\n\n var called = false;\n $__default[\"default\"](this).one(Util.TRANSITION_END, function () {\n called = true;\n });\n setTimeout(function () {\n if (!called) {\n Util.triggerTransitionEnd(_this);\n }\n }, duration);\n return this;\n }\n\n function setTransitionEndSupport() {\n $__default[\"default\"].fn.emulateTransitionEnd = transitionEndEmulator;\n $__default[\"default\"].event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent();\n }\n /**\n * Public Util API\n */\n\n\n var Util = {\n TRANSITION_END: 'bsTransitionEnd',\n getUID: function getUID(prefix) {\n do {\n // eslint-disable-next-line no-bitwise\n prefix += ~~(Math.random() * MAX_UID); // \"~~\" acts like a faster Math.floor() here\n } while (document.getElementById(prefix));\n\n return prefix;\n },\n getSelectorFromElement: function getSelectorFromElement(element) {\n var selector = element.getAttribute('data-target');\n\n if (!selector || selector === '#') {\n var hrefAttr = element.getAttribute('href');\n selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : '';\n }\n\n try {\n return document.querySelector(selector) ? selector : null;\n } catch (_) {\n return null;\n }\n },\n getTransitionDurationFromElement: function getTransitionDurationFromElement(element) {\n if (!element) {\n return 0;\n } // Get transition-duration of the element\n\n\n var transitionDuration = $__default[\"default\"](element).css('transition-duration');\n var transitionDelay = $__default[\"default\"](element).css('transition-delay');\n var floatTransitionDuration = parseFloat(transitionDuration);\n var floatTransitionDelay = parseFloat(transitionDelay); // Return 0 if element or transition duration is not found\n\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0;\n } // If multiple durations are defined, take the first\n\n\n transitionDuration = transitionDuration.split(',')[0];\n transitionDelay = transitionDelay.split(',')[0];\n return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;\n },\n reflow: function reflow(element) {\n return element.offsetHeight;\n },\n triggerTransitionEnd: function triggerTransitionEnd(element) {\n $__default[\"default\"](element).trigger(TRANSITION_END);\n },\n supportsTransitionEnd: function supportsTransitionEnd() {\n return Boolean(TRANSITION_END);\n },\n isElement: function isElement(obj) {\n return (obj[0] || obj).nodeType;\n },\n typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) {\n for (var property in configTypes) {\n if (Object.prototype.hasOwnProperty.call(configTypes, property)) {\n var expectedTypes = configTypes[property];\n var value = config[property];\n var valueType = value && Util.isElement(value) ? 'element' : toType(value);\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new Error(componentName.toUpperCase() + \": \" + (\"Option \\\"\" + property + \"\\\" provided type \\\"\" + valueType + \"\\\" \") + (\"but expected type \\\"\" + expectedTypes + \"\\\".\"));\n }\n }\n }\n },\n findShadowRoot: function findShadowRoot(element) {\n if (!document.documentElement.attachShadow) {\n return null;\n } // Can find the shadow root otherwise it'll return the document\n\n\n if (typeof element.getRootNode === 'function') {\n var root = element.getRootNode();\n return root instanceof ShadowRoot ? root : null;\n }\n\n if (element instanceof ShadowRoot) {\n return element;\n } // when we don't find a shadow root\n\n\n if (!element.parentNode) {\n return null;\n }\n\n return Util.findShadowRoot(element.parentNode);\n },\n jQueryDetection: function jQueryDetection() {\n if (typeof $__default[\"default\"] === 'undefined') {\n throw new TypeError('Bootstrap\\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\\'s JavaScript.');\n }\n\n var version = $__default[\"default\"].fn.jquery.split(' ')[0].split('.');\n var minMajor = 1;\n var ltMajor = 2;\n var minMinor = 9;\n var minPatch = 1;\n var maxMajor = 4;\n\n if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) {\n throw new Error('Bootstrap\\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0');\n }\n }\n };\n Util.jQueryDetection();\n setTransitionEndSupport();\n\n /**\n * Constants\n */\n\n var NAME$a = 'alert';\n var VERSION$a = '4.6.1';\n var DATA_KEY$a = 'bs.alert';\n var EVENT_KEY$a = \".\" + DATA_KEY$a;\n var DATA_API_KEY$7 = '.data-api';\n var JQUERY_NO_CONFLICT$a = $__default[\"default\"].fn[NAME$a];\n var CLASS_NAME_ALERT = 'alert';\n var CLASS_NAME_FADE$5 = 'fade';\n var CLASS_NAME_SHOW$7 = 'show';\n var EVENT_CLOSE = \"close\" + EVENT_KEY$a;\n var EVENT_CLOSED = \"closed\" + EVENT_KEY$a;\n var EVENT_CLICK_DATA_API$6 = \"click\" + EVENT_KEY$a + DATA_API_KEY$7;\n var SELECTOR_DISMISS = '[data-dismiss=\"alert\"]';\n /**\n * Class definition\n */\n\n var Alert = /*#__PURE__*/function () {\n function Alert(element) {\n this._element = element;\n } // Getters\n\n\n var _proto = Alert.prototype;\n\n // Public\n _proto.close = function close(element) {\n var rootElement = this._element;\n\n if (element) {\n rootElement = this._getRootElement(element);\n }\n\n var customEvent = this._triggerCloseEvent(rootElement);\n\n if (customEvent.isDefaultPrevented()) {\n return;\n }\n\n this._removeElement(rootElement);\n };\n\n _proto.dispose = function dispose() {\n $__default[\"default\"].removeData(this._element, DATA_KEY$a);\n this._element = null;\n } // Private\n ;\n\n _proto._getRootElement = function _getRootElement(element) {\n var selector = Util.getSelectorFromElement(element);\n var parent = false;\n\n if (selector) {\n parent = document.querySelector(selector);\n }\n\n if (!parent) {\n parent = $__default[\"default\"](element).closest(\".\" + CLASS_NAME_ALERT)[0];\n }\n\n return parent;\n };\n\n _proto._triggerCloseEvent = function _triggerCloseEvent(element) {\n var closeEvent = $__default[\"default\"].Event(EVENT_CLOSE);\n $__default[\"default\"](element).trigger(closeEvent);\n return closeEvent;\n };\n\n _proto._removeElement = function _removeElement(element) {\n var _this = this;\n\n $__default[\"default\"](element).removeClass(CLASS_NAME_SHOW$7);\n\n if (!$__default[\"default\"](element).hasClass(CLASS_NAME_FADE$5)) {\n this._destroyElement(element);\n\n return;\n }\n\n var transitionDuration = Util.getTransitionDurationFromElement(element);\n $__default[\"default\"](element).one(Util.TRANSITION_END, function (event) {\n return _this._destroyElement(element, event);\n }).emulateTransitionEnd(transitionDuration);\n };\n\n _proto._destroyElement = function _destroyElement(element) {\n $__default[\"default\"](element).detach().trigger(EVENT_CLOSED).remove();\n } // Static\n ;\n\n Alert._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var $element = $__default[\"default\"](this);\n var data = $element.data(DATA_KEY$a);\n\n if (!data) {\n data = new Alert(this);\n $element.data(DATA_KEY$a, data);\n }\n\n if (config === 'close') {\n data[config](this);\n }\n });\n };\n\n Alert._handleDismiss = function _handleDismiss(alertInstance) {\n return function (event) {\n if (event) {\n event.preventDefault();\n }\n\n alertInstance.close(this);\n };\n };\n\n _createClass(Alert, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION$a;\n }\n }]);\n\n return Alert;\n }();\n /**\n * Data API implementation\n */\n\n\n $__default[\"default\"](document).on(EVENT_CLICK_DATA_API$6, SELECTOR_DISMISS, Alert._handleDismiss(new Alert()));\n /**\n * jQuery\n */\n\n $__default[\"default\"].fn[NAME$a] = Alert._jQueryInterface;\n $__default[\"default\"].fn[NAME$a].Constructor = Alert;\n\n $__default[\"default\"].fn[NAME$a].noConflict = function () {\n $__default[\"default\"].fn[NAME$a] = JQUERY_NO_CONFLICT$a;\n return Alert._jQueryInterface;\n };\n\n /**\n * Constants\n */\n\n var NAME$9 = 'button';\n var VERSION$9 = '4.6.1';\n var DATA_KEY$9 = 'bs.button';\n var EVENT_KEY$9 = \".\" + DATA_KEY$9;\n var DATA_API_KEY$6 = '.data-api';\n var JQUERY_NO_CONFLICT$9 = $__default[\"default\"].fn[NAME$9];\n var CLASS_NAME_ACTIVE$3 = 'active';\n var CLASS_NAME_BUTTON = 'btn';\n var CLASS_NAME_FOCUS = 'focus';\n var EVENT_CLICK_DATA_API$5 = \"click\" + EVENT_KEY$9 + DATA_API_KEY$6;\n var EVENT_FOCUS_BLUR_DATA_API = \"focus\" + EVENT_KEY$9 + DATA_API_KEY$6 + \" \" + (\"blur\" + EVENT_KEY$9 + DATA_API_KEY$6);\n var EVENT_LOAD_DATA_API$2 = \"load\" + EVENT_KEY$9 + DATA_API_KEY$6;\n var SELECTOR_DATA_TOGGLE_CARROT = '[data-toggle^=\"button\"]';\n var SELECTOR_DATA_TOGGLES = '[data-toggle=\"buttons\"]';\n var SELECTOR_DATA_TOGGLE$4 = '[data-toggle=\"button\"]';\n var SELECTOR_DATA_TOGGLES_BUTTONS = '[data-toggle=\"buttons\"] .btn';\n var SELECTOR_INPUT = 'input:not([type=\"hidden\"])';\n var SELECTOR_ACTIVE$2 = '.active';\n var SELECTOR_BUTTON = '.btn';\n /**\n * Class definition\n */\n\n var Button = /*#__PURE__*/function () {\n function Button(element) {\n this._element = element;\n this.shouldAvoidTriggerChange = false;\n } // Getters\n\n\n var _proto = Button.prototype;\n\n // Public\n _proto.toggle = function toggle() {\n var triggerChangeEvent = true;\n var addAriaPressed = true;\n var rootElement = $__default[\"default\"](this._element).closest(SELECTOR_DATA_TOGGLES)[0];\n\n if (rootElement) {\n var input = this._element.querySelector(SELECTOR_INPUT);\n\n if (input) {\n if (input.type === 'radio') {\n if (input.checked && this._element.classList.contains(CLASS_NAME_ACTIVE$3)) {\n triggerChangeEvent = false;\n } else {\n var activeElement = rootElement.querySelector(SELECTOR_ACTIVE$2);\n\n if (activeElement) {\n $__default[\"default\"](activeElement).removeClass(CLASS_NAME_ACTIVE$3);\n }\n }\n }\n\n if (triggerChangeEvent) {\n // if it's not a radio button or checkbox don't add a pointless/invalid checked property to the input\n if (input.type === 'checkbox' || input.type === 'radio') {\n input.checked = !this._element.classList.contains(CLASS_NAME_ACTIVE$3);\n }\n\n if (!this.shouldAvoidTriggerChange) {\n $__default[\"default\"](input).trigger('change');\n }\n }\n\n input.focus();\n addAriaPressed = false;\n }\n }\n\n if (!(this._element.hasAttribute('disabled') || this._element.classList.contains('disabled'))) {\n if (addAriaPressed) {\n this._element.setAttribute('aria-pressed', !this._element.classList.contains(CLASS_NAME_ACTIVE$3));\n }\n\n if (triggerChangeEvent) {\n $__default[\"default\"](this._element).toggleClass(CLASS_NAME_ACTIVE$3);\n }\n }\n };\n\n _proto.dispose = function dispose() {\n $__default[\"default\"].removeData(this._element, DATA_KEY$9);\n this._element = null;\n } // Static\n ;\n\n Button._jQueryInterface = function _jQueryInterface(config, avoidTriggerChange) {\n return this.each(function () {\n var $element = $__default[\"default\"](this);\n var data = $element.data(DATA_KEY$9);\n\n if (!data) {\n data = new Button(this);\n $element.data(DATA_KEY$9, data);\n }\n\n data.shouldAvoidTriggerChange = avoidTriggerChange;\n\n if (config === 'toggle') {\n data[config]();\n }\n });\n };\n\n _createClass(Button, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION$9;\n }\n }]);\n\n return Button;\n }();\n /**\n * Data API implementation\n */\n\n\n $__default[\"default\"](document).on(EVENT_CLICK_DATA_API$5, SELECTOR_DATA_TOGGLE_CARROT, function (event) {\n var button = event.target;\n var initialButton = button;\n\n if (!$__default[\"default\"](button).hasClass(CLASS_NAME_BUTTON)) {\n button = $__default[\"default\"](button).closest(SELECTOR_BUTTON)[0];\n }\n\n if (!button || button.hasAttribute('disabled') || button.classList.contains('disabled')) {\n event.preventDefault(); // work around Firefox bug #1540995\n } else {\n var inputBtn = button.querySelector(SELECTOR_INPUT);\n\n if (inputBtn && (inputBtn.hasAttribute('disabled') || inputBtn.classList.contains('disabled'))) {\n event.preventDefault(); // work around Firefox bug #1540995\n\n return;\n }\n\n if (initialButton.tagName === 'INPUT' || button.tagName !== 'LABEL') {\n Button._jQueryInterface.call($__default[\"default\"](button), 'toggle', initialButton.tagName === 'INPUT');\n }\n }\n }).on(EVENT_FOCUS_BLUR_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, function (event) {\n var button = $__default[\"default\"](event.target).closest(SELECTOR_BUTTON)[0];\n $__default[\"default\"](button).toggleClass(CLASS_NAME_FOCUS, /^focus(in)?$/.test(event.type));\n });\n $__default[\"default\"](window).on(EVENT_LOAD_DATA_API$2, function () {\n // ensure correct active class is set to match the controls' actual values/states\n // find all checkboxes/readio buttons inside data-toggle groups\n var buttons = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLES_BUTTONS));\n\n for (var i = 0, len = buttons.length; i < len; i++) {\n var button = buttons[i];\n var input = button.querySelector(SELECTOR_INPUT);\n\n if (input.checked || input.hasAttribute('checked')) {\n button.classList.add(CLASS_NAME_ACTIVE$3);\n } else {\n button.classList.remove(CLASS_NAME_ACTIVE$3);\n }\n } // find all button toggles\n\n\n buttons = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE$4));\n\n for (var _i = 0, _len = buttons.length; _i < _len; _i++) {\n var _button = buttons[_i];\n\n if (_button.getAttribute('aria-pressed') === 'true') {\n _button.classList.add(CLASS_NAME_ACTIVE$3);\n } else {\n _button.classList.remove(CLASS_NAME_ACTIVE$3);\n }\n }\n });\n /**\n * jQuery\n */\n\n $__default[\"default\"].fn[NAME$9] = Button._jQueryInterface;\n $__default[\"default\"].fn[NAME$9].Constructor = Button;\n\n $__default[\"default\"].fn[NAME$9].noConflict = function () {\n $__default[\"default\"].fn[NAME$9] = JQUERY_NO_CONFLICT$9;\n return Button._jQueryInterface;\n };\n\n /**\n * Constants\n */\n\n var NAME$8 = 'carousel';\n var VERSION$8 = '4.6.1';\n var DATA_KEY$8 = 'bs.carousel';\n var EVENT_KEY$8 = \".\" + DATA_KEY$8;\n var DATA_API_KEY$5 = '.data-api';\n var JQUERY_NO_CONFLICT$8 = $__default[\"default\"].fn[NAME$8];\n var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key\n\n var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key\n\n var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch\n\n var SWIPE_THRESHOLD = 40;\n var CLASS_NAME_CAROUSEL = 'carousel';\n var CLASS_NAME_ACTIVE$2 = 'active';\n var CLASS_NAME_SLIDE = 'slide';\n var CLASS_NAME_RIGHT = 'carousel-item-right';\n var CLASS_NAME_LEFT = 'carousel-item-left';\n var CLASS_NAME_NEXT = 'carousel-item-next';\n var CLASS_NAME_PREV = 'carousel-item-prev';\n var CLASS_NAME_POINTER_EVENT = 'pointer-event';\n var DIRECTION_NEXT = 'next';\n var DIRECTION_PREV = 'prev';\n var DIRECTION_LEFT = 'left';\n var DIRECTION_RIGHT = 'right';\n var EVENT_SLIDE = \"slide\" + EVENT_KEY$8;\n var EVENT_SLID = \"slid\" + EVENT_KEY$8;\n var EVENT_KEYDOWN = \"keydown\" + EVENT_KEY$8;\n var EVENT_MOUSEENTER = \"mouseenter\" + EVENT_KEY$8;\n var EVENT_MOUSELEAVE = \"mouseleave\" + EVENT_KEY$8;\n var EVENT_TOUCHSTART = \"touchstart\" + EVENT_KEY$8;\n var EVENT_TOUCHMOVE = \"touchmove\" + EVENT_KEY$8;\n var EVENT_TOUCHEND = \"touchend\" + EVENT_KEY$8;\n var EVENT_POINTERDOWN = \"pointerdown\" + EVENT_KEY$8;\n var EVENT_POINTERUP = \"pointerup\" + EVENT_KEY$8;\n var EVENT_DRAG_START = \"dragstart\" + EVENT_KEY$8;\n var EVENT_LOAD_DATA_API$1 = \"load\" + EVENT_KEY$8 + DATA_API_KEY$5;\n var EVENT_CLICK_DATA_API$4 = \"click\" + EVENT_KEY$8 + DATA_API_KEY$5;\n var SELECTOR_ACTIVE$1 = '.active';\n var SELECTOR_ACTIVE_ITEM = '.active.carousel-item';\n var SELECTOR_ITEM = '.carousel-item';\n var SELECTOR_ITEM_IMG = '.carousel-item img';\n var SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev';\n var SELECTOR_INDICATORS = '.carousel-indicators';\n var SELECTOR_DATA_SLIDE = '[data-slide], [data-slide-to]';\n var SELECTOR_DATA_RIDE = '[data-ride=\"carousel\"]';\n var Default$7 = {\n interval: 5000,\n keyboard: true,\n slide: false,\n pause: 'hover',\n wrap: true,\n touch: true\n };\n var DefaultType$7 = {\n interval: '(number|boolean)',\n keyboard: 'boolean',\n slide: '(boolean|string)',\n pause: '(string|boolean)',\n wrap: 'boolean',\n touch: 'boolean'\n };\n var PointerType = {\n TOUCH: 'touch',\n PEN: 'pen'\n };\n /**\n * Class definition\n */\n\n var Carousel = /*#__PURE__*/function () {\n function Carousel(element, config) {\n this._items = null;\n this._interval = null;\n this._activeElement = null;\n this._isPaused = false;\n this._isSliding = false;\n this.touchTimeout = null;\n this.touchStartX = 0;\n this.touchDeltaX = 0;\n this._config = this._getConfig(config);\n this._element = element;\n this._indicatorsElement = this._element.querySelector(SELECTOR_INDICATORS);\n this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;\n this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent);\n\n this._addEventListeners();\n } // Getters\n\n\n var _proto = Carousel.prototype;\n\n // Public\n _proto.next = function next() {\n if (!this._isSliding) {\n this._slide(DIRECTION_NEXT);\n }\n };\n\n _proto.nextWhenVisible = function nextWhenVisible() {\n var $element = $__default[\"default\"](this._element); // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n\n if (!document.hidden && $element.is(':visible') && $element.css('visibility') !== 'hidden') {\n this.next();\n }\n };\n\n _proto.prev = function prev() {\n if (!this._isSliding) {\n this._slide(DIRECTION_PREV);\n }\n };\n\n _proto.pause = function pause(event) {\n if (!event) {\n this._isPaused = true;\n }\n\n if (this._element.querySelector(SELECTOR_NEXT_PREV)) {\n Util.triggerTransitionEnd(this._element);\n this.cycle(true);\n }\n\n clearInterval(this._interval);\n this._interval = null;\n };\n\n _proto.cycle = function cycle(event) {\n if (!event) {\n this._isPaused = false;\n }\n\n if (this._interval) {\n clearInterval(this._interval);\n this._interval = null;\n }\n\n if (this._config.interval && !this._isPaused) {\n this._updateInterval();\n\n this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval);\n }\n };\n\n _proto.to = function to(index) {\n var _this = this;\n\n this._activeElement = this._element.querySelector(SELECTOR_ACTIVE_ITEM);\n\n var activeIndex = this._getItemIndex(this._activeElement);\n\n if (index > this._items.length - 1 || index < 0) {\n return;\n }\n\n if (this._isSliding) {\n $__default[\"default\"](this._element).one(EVENT_SLID, function () {\n return _this.to(index);\n });\n return;\n }\n\n if (activeIndex === index) {\n this.pause();\n this.cycle();\n return;\n }\n\n var direction = index > activeIndex ? DIRECTION_NEXT : DIRECTION_PREV;\n\n this._slide(direction, this._items[index]);\n };\n\n _proto.dispose = function dispose() {\n $__default[\"default\"](this._element).off(EVENT_KEY$8);\n $__default[\"default\"].removeData(this._element, DATA_KEY$8);\n this._items = null;\n this._config = null;\n this._element = null;\n this._interval = null;\n this._isPaused = null;\n this._isSliding = null;\n this._activeElement = null;\n this._indicatorsElement = null;\n } // Private\n ;\n\n _proto._getConfig = function _getConfig(config) {\n config = _extends({}, Default$7, config);\n Util.typeCheckConfig(NAME$8, config, DefaultType$7);\n return config;\n };\n\n _proto._handleSwipe = function _handleSwipe() {\n var absDeltax = Math.abs(this.touchDeltaX);\n\n if (absDeltax <= SWIPE_THRESHOLD) {\n return;\n }\n\n var direction = absDeltax / this.touchDeltaX;\n this.touchDeltaX = 0; // swipe left\n\n if (direction > 0) {\n this.prev();\n } // swipe right\n\n\n if (direction < 0) {\n this.next();\n }\n };\n\n _proto._addEventListeners = function _addEventListeners() {\n var _this2 = this;\n\n if (this._config.keyboard) {\n $__default[\"default\"](this._element).on(EVENT_KEYDOWN, function (event) {\n return _this2._keydown(event);\n });\n }\n\n if (this._config.pause === 'hover') {\n $__default[\"default\"](this._element).on(EVENT_MOUSEENTER, function (event) {\n return _this2.pause(event);\n }).on(EVENT_MOUSELEAVE, function (event) {\n return _this2.cycle(event);\n });\n }\n\n if (this._config.touch) {\n this._addTouchEventListeners();\n }\n };\n\n _proto._addTouchEventListeners = function _addTouchEventListeners() {\n var _this3 = this;\n\n if (!this._touchSupported) {\n return;\n }\n\n var start = function start(event) {\n if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {\n _this3.touchStartX = event.originalEvent.clientX;\n } else if (!_this3._pointerEvent) {\n _this3.touchStartX = event.originalEvent.touches[0].clientX;\n }\n };\n\n var move = function move(event) {\n // ensure swiping with one touch and not pinching\n _this3.touchDeltaX = event.originalEvent.touches && event.originalEvent.touches.length > 1 ? 0 : event.originalEvent.touches[0].clientX - _this3.touchStartX;\n };\n\n var end = function end(event) {\n if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {\n _this3.touchDeltaX = event.originalEvent.clientX - _this3.touchStartX;\n }\n\n _this3._handleSwipe();\n\n if (_this3._config.pause === 'hover') {\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n _this3.pause();\n\n if (_this3.touchTimeout) {\n clearTimeout(_this3.touchTimeout);\n }\n\n _this3.touchTimeout = setTimeout(function (event) {\n return _this3.cycle(event);\n }, TOUCHEVENT_COMPAT_WAIT + _this3._config.interval);\n }\n };\n\n $__default[\"default\"](this._element.querySelectorAll(SELECTOR_ITEM_IMG)).on(EVENT_DRAG_START, function (e) {\n return e.preventDefault();\n });\n\n if (this._pointerEvent) {\n $__default[\"default\"](this._element).on(EVENT_POINTERDOWN, function (event) {\n return start(event);\n });\n $__default[\"default\"](this._element).on(EVENT_POINTERUP, function (event) {\n return end(event);\n });\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT);\n } else {\n $__default[\"default\"](this._element).on(EVENT_TOUCHSTART, function (event) {\n return start(event);\n });\n $__default[\"default\"](this._element).on(EVENT_TOUCHMOVE, function (event) {\n return move(event);\n });\n $__default[\"default\"](this._element).on(EVENT_TOUCHEND, function (event) {\n return end(event);\n });\n }\n };\n\n _proto._keydown = function _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return;\n }\n\n switch (event.which) {\n case ARROW_LEFT_KEYCODE:\n event.preventDefault();\n this.prev();\n break;\n\n case ARROW_RIGHT_KEYCODE:\n event.preventDefault();\n this.next();\n break;\n }\n };\n\n _proto._getItemIndex = function _getItemIndex(element) {\n this._items = element && element.parentNode ? [].slice.call(element.parentNode.querySelectorAll(SELECTOR_ITEM)) : [];\n return this._items.indexOf(element);\n };\n\n _proto._getItemByDirection = function _getItemByDirection(direction, activeElement) {\n var isNextDirection = direction === DIRECTION_NEXT;\n var isPrevDirection = direction === DIRECTION_PREV;\n\n var activeIndex = this._getItemIndex(activeElement);\n\n var lastItemIndex = this._items.length - 1;\n var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex;\n\n if (isGoingToWrap && !this._config.wrap) {\n return activeElement;\n }\n\n var delta = direction === DIRECTION_PREV ? -1 : 1;\n var itemIndex = (activeIndex + delta) % this._items.length;\n return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex];\n };\n\n _proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) {\n var targetIndex = this._getItemIndex(relatedTarget);\n\n var fromIndex = this._getItemIndex(this._element.querySelector(SELECTOR_ACTIVE_ITEM));\n\n var slideEvent = $__default[\"default\"].Event(EVENT_SLIDE, {\n relatedTarget: relatedTarget,\n direction: eventDirectionName,\n from: fromIndex,\n to: targetIndex\n });\n $__default[\"default\"](this._element).trigger(slideEvent);\n return slideEvent;\n };\n\n _proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) {\n if (this._indicatorsElement) {\n var indicators = [].slice.call(this._indicatorsElement.querySelectorAll(SELECTOR_ACTIVE$1));\n $__default[\"default\"](indicators).removeClass(CLASS_NAME_ACTIVE$2);\n\n var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)];\n\n if (nextIndicator) {\n $__default[\"default\"](nextIndicator).addClass(CLASS_NAME_ACTIVE$2);\n }\n }\n };\n\n _proto._updateInterval = function _updateInterval() {\n var element = this._activeElement || this._element.querySelector(SELECTOR_ACTIVE_ITEM);\n\n if (!element) {\n return;\n }\n\n var elementInterval = parseInt(element.getAttribute('data-interval'), 10);\n\n if (elementInterval) {\n this._config.defaultInterval = this._config.defaultInterval || this._config.interval;\n this._config.interval = elementInterval;\n } else {\n this._config.interval = this._config.defaultInterval || this._config.interval;\n }\n };\n\n _proto._slide = function _slide(direction, element) {\n var _this4 = this;\n\n var activeElement = this._element.querySelector(SELECTOR_ACTIVE_ITEM);\n\n var activeElementIndex = this._getItemIndex(activeElement);\n\n var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement);\n\n var nextElementIndex = this._getItemIndex(nextElement);\n\n var isCycling = Boolean(this._interval);\n var directionalClassName;\n var orderClassName;\n var eventDirectionName;\n\n if (direction === DIRECTION_NEXT) {\n directionalClassName = CLASS_NAME_LEFT;\n orderClassName = CLASS_NAME_NEXT;\n eventDirectionName = DIRECTION_LEFT;\n } else {\n directionalClassName = CLASS_NAME_RIGHT;\n orderClassName = CLASS_NAME_PREV;\n eventDirectionName = DIRECTION_RIGHT;\n }\n\n if (nextElement && $__default[\"default\"](nextElement).hasClass(CLASS_NAME_ACTIVE$2)) {\n this._isSliding = false;\n return;\n }\n\n var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName);\n\n if (slideEvent.isDefaultPrevented()) {\n return;\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n return;\n }\n\n this._isSliding = true;\n\n if (isCycling) {\n this.pause();\n }\n\n this._setActiveIndicatorElement(nextElement);\n\n this._activeElement = nextElement;\n var slidEvent = $__default[\"default\"].Event(EVENT_SLID, {\n relatedTarget: nextElement,\n direction: eventDirectionName,\n from: activeElementIndex,\n to: nextElementIndex\n });\n\n if ($__default[\"default\"](this._element).hasClass(CLASS_NAME_SLIDE)) {\n $__default[\"default\"](nextElement).addClass(orderClassName);\n Util.reflow(nextElement);\n $__default[\"default\"](activeElement).addClass(directionalClassName);\n $__default[\"default\"](nextElement).addClass(directionalClassName);\n var transitionDuration = Util.getTransitionDurationFromElement(activeElement);\n $__default[\"default\"](activeElement).one(Util.TRANSITION_END, function () {\n $__default[\"default\"](nextElement).removeClass(directionalClassName + \" \" + orderClassName).addClass(CLASS_NAME_ACTIVE$2);\n $__default[\"default\"](activeElement).removeClass(CLASS_NAME_ACTIVE$2 + \" \" + orderClassName + \" \" + directionalClassName);\n _this4._isSliding = false;\n setTimeout(function () {\n return $__default[\"default\"](_this4._element).trigger(slidEvent);\n }, 0);\n }).emulateTransitionEnd(transitionDuration);\n } else {\n $__default[\"default\"](activeElement).removeClass(CLASS_NAME_ACTIVE$2);\n $__default[\"default\"](nextElement).addClass(CLASS_NAME_ACTIVE$2);\n this._isSliding = false;\n $__default[\"default\"](this._element).trigger(slidEvent);\n }\n\n if (isCycling) {\n this.cycle();\n }\n } // Static\n ;\n\n Carousel._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var data = $__default[\"default\"](this).data(DATA_KEY$8);\n\n var _config = _extends({}, Default$7, $__default[\"default\"](this).data());\n\n if (typeof config === 'object') {\n _config = _extends({}, _config, config);\n }\n\n var action = typeof config === 'string' ? config : _config.slide;\n\n if (!data) {\n data = new Carousel(this, _config);\n $__default[\"default\"](this).data(DATA_KEY$8, data);\n }\n\n if (typeof config === 'number') {\n data.to(config);\n } else if (typeof action === 'string') {\n if (typeof data[action] === 'undefined') {\n throw new TypeError(\"No method named \\\"\" + action + \"\\\"\");\n }\n\n data[action]();\n } else if (_config.interval && _config.ride) {\n data.pause();\n data.cycle();\n }\n });\n };\n\n Carousel._dataApiClickHandler = function _dataApiClickHandler(event) {\n var selector = Util.getSelectorFromElement(this);\n\n if (!selector) {\n return;\n }\n\n var target = $__default[\"default\"](selector)[0];\n\n if (!target || !$__default[\"default\"](target).hasClass(CLASS_NAME_CAROUSEL)) {\n return;\n }\n\n var config = _extends({}, $__default[\"default\"](target).data(), $__default[\"default\"](this).data());\n\n var slideIndex = this.getAttribute('data-slide-to');\n\n if (slideIndex) {\n config.interval = false;\n }\n\n Carousel._jQueryInterface.call($__default[\"default\"](target), config);\n\n if (slideIndex) {\n $__default[\"default\"](target).data(DATA_KEY$8).to(slideIndex);\n }\n\n event.preventDefault();\n };\n\n _createClass(Carousel, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION$8;\n }\n }, {\n key: \"Default\",\n get: function get() {\n return Default$7;\n }\n }]);\n\n return Carousel;\n }();\n /**\n * Data API implementation\n */\n\n\n $__default[\"default\"](document).on(EVENT_CLICK_DATA_API$4, SELECTOR_DATA_SLIDE, Carousel._dataApiClickHandler);\n $__default[\"default\"](window).on(EVENT_LOAD_DATA_API$1, function () {\n var carousels = [].slice.call(document.querySelectorAll(SELECTOR_DATA_RIDE));\n\n for (var i = 0, len = carousels.length; i < len; i++) {\n var $carousel = $__default[\"default\"](carousels[i]);\n\n Carousel._jQueryInterface.call($carousel, $carousel.data());\n }\n });\n /**\n * jQuery\n */\n\n $__default[\"default\"].fn[NAME$8] = Carousel._jQueryInterface;\n $__default[\"default\"].fn[NAME$8].Constructor = Carousel;\n\n $__default[\"default\"].fn[NAME$8].noConflict = function () {\n $__default[\"default\"].fn[NAME$8] = JQUERY_NO_CONFLICT$8;\n return Carousel._jQueryInterface;\n };\n\n /**\n * Constants\n */\n\n var NAME$7 = 'collapse';\n var VERSION$7 = '4.6.1';\n var DATA_KEY$7 = 'bs.collapse';\n var EVENT_KEY$7 = \".\" + DATA_KEY$7;\n var DATA_API_KEY$4 = '.data-api';\n var JQUERY_NO_CONFLICT$7 = $__default[\"default\"].fn[NAME$7];\n var CLASS_NAME_SHOW$6 = 'show';\n var CLASS_NAME_COLLAPSE = 'collapse';\n var CLASS_NAME_COLLAPSING = 'collapsing';\n var CLASS_NAME_COLLAPSED = 'collapsed';\n var DIMENSION_WIDTH = 'width';\n var DIMENSION_HEIGHT = 'height';\n var EVENT_SHOW$4 = \"show\" + EVENT_KEY$7;\n var EVENT_SHOWN$4 = \"shown\" + EVENT_KEY$7;\n var EVENT_HIDE$4 = \"hide\" + EVENT_KEY$7;\n var EVENT_HIDDEN$4 = \"hidden\" + EVENT_KEY$7;\n var EVENT_CLICK_DATA_API$3 = \"click\" + EVENT_KEY$7 + DATA_API_KEY$4;\n var SELECTOR_ACTIVES = '.show, .collapsing';\n var SELECTOR_DATA_TOGGLE$3 = '[data-toggle=\"collapse\"]';\n var Default$6 = {\n toggle: true,\n parent: ''\n };\n var DefaultType$6 = {\n toggle: 'boolean',\n parent: '(string|element)'\n };\n /**\n * Class definition\n */\n\n var Collapse = /*#__PURE__*/function () {\n function Collapse(element, config) {\n this._isTransitioning = false;\n this._element = element;\n this._config = this._getConfig(config);\n this._triggerArray = [].slice.call(document.querySelectorAll(\"[data-toggle=\\\"collapse\\\"][href=\\\"#\" + element.id + \"\\\"],\" + (\"[data-toggle=\\\"collapse\\\"][data-target=\\\"#\" + element.id + \"\\\"]\")));\n var toggleList = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE$3));\n\n for (var i = 0, len = toggleList.length; i < len; i++) {\n var elem = toggleList[i];\n var selector = Util.getSelectorFromElement(elem);\n var filterElement = [].slice.call(document.querySelectorAll(selector)).filter(function (foundElem) {\n return foundElem === element;\n });\n\n if (selector !== null && filterElement.length > 0) {\n this._selector = selector;\n\n this._triggerArray.push(elem);\n }\n }\n\n this._parent = this._config.parent ? this._getParent() : null;\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._element, this._triggerArray);\n }\n\n if (this._config.toggle) {\n this.toggle();\n }\n } // Getters\n\n\n var _proto = Collapse.prototype;\n\n // Public\n _proto.toggle = function toggle() {\n if ($__default[\"default\"](this._element).hasClass(CLASS_NAME_SHOW$6)) {\n this.hide();\n } else {\n this.show();\n }\n };\n\n _proto.show = function show() {\n var _this = this;\n\n if (this._isTransitioning || $__default[\"default\"](this._element).hasClass(CLASS_NAME_SHOW$6)) {\n return;\n }\n\n var actives;\n var activesData;\n\n if (this._parent) {\n actives = [].slice.call(this._parent.querySelectorAll(SELECTOR_ACTIVES)).filter(function (elem) {\n if (typeof _this._config.parent === 'string') {\n return elem.getAttribute('data-parent') === _this._config.parent;\n }\n\n return elem.classList.contains(CLASS_NAME_COLLAPSE);\n });\n\n if (actives.length === 0) {\n actives = null;\n }\n }\n\n if (actives) {\n activesData = $__default[\"default\"](actives).not(this._selector).data(DATA_KEY$7);\n\n if (activesData && activesData._isTransitioning) {\n return;\n }\n }\n\n var startEvent = $__default[\"default\"].Event(EVENT_SHOW$4);\n $__default[\"default\"](this._element).trigger(startEvent);\n\n if (startEvent.isDefaultPrevented()) {\n return;\n }\n\n if (actives) {\n Collapse._jQueryInterface.call($__default[\"default\"](actives).not(this._selector), 'hide');\n\n if (!activesData) {\n $__default[\"default\"](actives).data(DATA_KEY$7, null);\n }\n }\n\n var dimension = this._getDimension();\n\n $__default[\"default\"](this._element).removeClass(CLASS_NAME_COLLAPSE).addClass(CLASS_NAME_COLLAPSING);\n this._element.style[dimension] = 0;\n\n if (this._triggerArray.length) {\n $__default[\"default\"](this._triggerArray).removeClass(CLASS_NAME_COLLAPSED).attr('aria-expanded', true);\n }\n\n this.setTransitioning(true);\n\n var complete = function complete() {\n $__default[\"default\"](_this._element).removeClass(CLASS_NAME_COLLAPSING).addClass(CLASS_NAME_COLLAPSE + \" \" + CLASS_NAME_SHOW$6);\n _this._element.style[dimension] = '';\n\n _this.setTransitioning(false);\n\n $__default[\"default\"](_this._element).trigger(EVENT_SHOWN$4);\n };\n\n var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);\n var scrollSize = \"scroll\" + capitalizedDimension;\n var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n $__default[\"default\"](this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n this._element.style[dimension] = this._element[scrollSize] + \"px\";\n };\n\n _proto.hide = function hide() {\n var _this2 = this;\n\n if (this._isTransitioning || !$__default[\"default\"](this._element).hasClass(CLASS_NAME_SHOW$6)) {\n return;\n }\n\n var startEvent = $__default[\"default\"].Event(EVENT_HIDE$4);\n $__default[\"default\"](this._element).trigger(startEvent);\n\n if (startEvent.isDefaultPrevented()) {\n return;\n }\n\n var dimension = this._getDimension();\n\n this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + \"px\";\n Util.reflow(this._element);\n $__default[\"default\"](this._element).addClass(CLASS_NAME_COLLAPSING).removeClass(CLASS_NAME_COLLAPSE + \" \" + CLASS_NAME_SHOW$6);\n var triggerArrayLength = this._triggerArray.length;\n\n if (triggerArrayLength > 0) {\n for (var i = 0; i < triggerArrayLength; i++) {\n var trigger = this._triggerArray[i];\n var selector = Util.getSelectorFromElement(trigger);\n\n if (selector !== null) {\n var $elem = $__default[\"default\"]([].slice.call(document.querySelectorAll(selector)));\n\n if (!$elem.hasClass(CLASS_NAME_SHOW$6)) {\n $__default[\"default\"](trigger).addClass(CLASS_NAME_COLLAPSED).attr('aria-expanded', false);\n }\n }\n }\n }\n\n this.setTransitioning(true);\n\n var complete = function complete() {\n _this2.setTransitioning(false);\n\n $__default[\"default\"](_this2._element).removeClass(CLASS_NAME_COLLAPSING).addClass(CLASS_NAME_COLLAPSE).trigger(EVENT_HIDDEN$4);\n };\n\n this._element.style[dimension] = '';\n var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n $__default[\"default\"](this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n };\n\n _proto.setTransitioning = function setTransitioning(isTransitioning) {\n this._isTransitioning = isTransitioning;\n };\n\n _proto.dispose = function dispose() {\n $__default[\"default\"].removeData(this._element, DATA_KEY$7);\n this._config = null;\n this._parent = null;\n this._element = null;\n this._triggerArray = null;\n this._isTransitioning = null;\n } // Private\n ;\n\n _proto._getConfig = function _getConfig(config) {\n config = _extends({}, Default$6, config);\n config.toggle = Boolean(config.toggle); // Coerce string values\n\n Util.typeCheckConfig(NAME$7, config, DefaultType$6);\n return config;\n };\n\n _proto._getDimension = function _getDimension() {\n var hasWidth = $__default[\"default\"](this._element).hasClass(DIMENSION_WIDTH);\n return hasWidth ? DIMENSION_WIDTH : DIMENSION_HEIGHT;\n };\n\n _proto._getParent = function _getParent() {\n var _this3 = this;\n\n var parent;\n\n if (Util.isElement(this._config.parent)) {\n parent = this._config.parent; // It's a jQuery object\n\n if (typeof this._config.parent.jquery !== 'undefined') {\n parent = this._config.parent[0];\n }\n } else {\n parent = document.querySelector(this._config.parent);\n }\n\n var selector = \"[data-toggle=\\\"collapse\\\"][data-parent=\\\"\" + this._config.parent + \"\\\"]\";\n var children = [].slice.call(parent.querySelectorAll(selector));\n $__default[\"default\"](children).each(function (i, element) {\n _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]);\n });\n return parent;\n };\n\n _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) {\n var isOpen = $__default[\"default\"](element).hasClass(CLASS_NAME_SHOW$6);\n\n if (triggerArray.length) {\n $__default[\"default\"](triggerArray).toggleClass(CLASS_NAME_COLLAPSED, !isOpen).attr('aria-expanded', isOpen);\n }\n } // Static\n ;\n\n Collapse._getTargetFromElement = function _getTargetFromElement(element) {\n var selector = Util.getSelectorFromElement(element);\n return selector ? document.querySelector(selector) : null;\n };\n\n Collapse._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var $element = $__default[\"default\"](this);\n var data = $element.data(DATA_KEY$7);\n\n var _config = _extends({}, Default$6, $element.data(), typeof config === 'object' && config ? config : {});\n\n if (!data && _config.toggle && typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false;\n }\n\n if (!data) {\n data = new Collapse(this, _config);\n $element.data(DATA_KEY$7, data);\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n }\n\n data[config]();\n }\n });\n };\n\n _createClass(Collapse, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION$7;\n }\n }, {\n key: \"Default\",\n get: function get() {\n return Default$6;\n }\n }]);\n\n return Collapse;\n }();\n /**\n * Data API implementation\n */\n\n\n $__default[\"default\"](document).on(EVENT_CLICK_DATA_API$3, SELECTOR_DATA_TOGGLE$3, function (event) {\n // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n if (event.currentTarget.tagName === 'A') {\n event.preventDefault();\n }\n\n var $trigger = $__default[\"default\"](this);\n var selector = Util.getSelectorFromElement(this);\n var selectors = [].slice.call(document.querySelectorAll(selector));\n $__default[\"default\"](selectors).each(function () {\n var $target = $__default[\"default\"](this);\n var data = $target.data(DATA_KEY$7);\n var config = data ? 'toggle' : $trigger.data();\n\n Collapse._jQueryInterface.call($target, config);\n });\n });\n /**\n * jQuery\n */\n\n $__default[\"default\"].fn[NAME$7] = Collapse._jQueryInterface;\n $__default[\"default\"].fn[NAME$7].Constructor = Collapse;\n\n $__default[\"default\"].fn[NAME$7].noConflict = function () {\n $__default[\"default\"].fn[NAME$7] = JQUERY_NO_CONFLICT$7;\n return Collapse._jQueryInterface;\n };\n\n /**\n * Constants\n */\n\n var NAME$6 = 'dropdown';\n var VERSION$6 = '4.6.1';\n var DATA_KEY$6 = 'bs.dropdown';\n var EVENT_KEY$6 = \".\" + DATA_KEY$6;\n var DATA_API_KEY$3 = '.data-api';\n var JQUERY_NO_CONFLICT$6 = $__default[\"default\"].fn[NAME$6];\n var ESCAPE_KEYCODE$1 = 27; // KeyboardEvent.which value for Escape (Esc) key\n\n var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key\n\n var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key\n\n var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key\n\n var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key\n\n var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse)\n\n var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + \"|\" + ARROW_DOWN_KEYCODE + \"|\" + ESCAPE_KEYCODE$1);\n var CLASS_NAME_DISABLED$1 = 'disabled';\n var CLASS_NAME_SHOW$5 = 'show';\n var CLASS_NAME_DROPUP = 'dropup';\n var CLASS_NAME_DROPRIGHT = 'dropright';\n var CLASS_NAME_DROPLEFT = 'dropleft';\n var CLASS_NAME_MENURIGHT = 'dropdown-menu-right';\n var CLASS_NAME_POSITION_STATIC = 'position-static';\n var EVENT_HIDE$3 = \"hide\" + EVENT_KEY$6;\n var EVENT_HIDDEN$3 = \"hidden\" + EVENT_KEY$6;\n var EVENT_SHOW$3 = \"show\" + EVENT_KEY$6;\n var EVENT_SHOWN$3 = \"shown\" + EVENT_KEY$6;\n var EVENT_CLICK = \"click\" + EVENT_KEY$6;\n var EVENT_CLICK_DATA_API$2 = \"click\" + EVENT_KEY$6 + DATA_API_KEY$3;\n var EVENT_KEYDOWN_DATA_API = \"keydown\" + EVENT_KEY$6 + DATA_API_KEY$3;\n var EVENT_KEYUP_DATA_API = \"keyup\" + EVENT_KEY$6 + DATA_API_KEY$3;\n var SELECTOR_DATA_TOGGLE$2 = '[data-toggle=\"dropdown\"]';\n var SELECTOR_FORM_CHILD = '.dropdown form';\n var SELECTOR_MENU = '.dropdown-menu';\n var SELECTOR_NAVBAR_NAV = '.navbar-nav';\n var SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)';\n var PLACEMENT_TOP = 'top-start';\n var PLACEMENT_TOPEND = 'top-end';\n var PLACEMENT_BOTTOM = 'bottom-start';\n var PLACEMENT_BOTTOMEND = 'bottom-end';\n var PLACEMENT_RIGHT = 'right-start';\n var PLACEMENT_LEFT = 'left-start';\n var Default$5 = {\n offset: 0,\n flip: true,\n boundary: 'scrollParent',\n reference: 'toggle',\n display: 'dynamic',\n popperConfig: null\n };\n var DefaultType$5 = {\n offset: '(number|string|function)',\n flip: 'boolean',\n boundary: '(string|element)',\n reference: '(string|element)',\n display: 'string',\n popperConfig: '(null|object)'\n };\n /**\n * Class definition\n */\n\n var Dropdown = /*#__PURE__*/function () {\n function Dropdown(element, config) {\n this._element = element;\n this._popper = null;\n this._config = this._getConfig(config);\n this._menu = this._getMenuElement();\n this._inNavbar = this._detectNavbar();\n\n this._addEventListeners();\n } // Getters\n\n\n var _proto = Dropdown.prototype;\n\n // Public\n _proto.toggle = function toggle() {\n if (this._element.disabled || $__default[\"default\"](this._element).hasClass(CLASS_NAME_DISABLED$1)) {\n return;\n }\n\n var isActive = $__default[\"default\"](this._menu).hasClass(CLASS_NAME_SHOW$5);\n\n Dropdown._clearMenus();\n\n if (isActive) {\n return;\n }\n\n this.show(true);\n };\n\n _proto.show = function show(usePopper) {\n if (usePopper === void 0) {\n usePopper = false;\n }\n\n if (this._element.disabled || $__default[\"default\"](this._element).hasClass(CLASS_NAME_DISABLED$1) || $__default[\"default\"](this._menu).hasClass(CLASS_NAME_SHOW$5)) {\n return;\n }\n\n var relatedTarget = {\n relatedTarget: this._element\n };\n var showEvent = $__default[\"default\"].Event(EVENT_SHOW$3, relatedTarget);\n\n var parent = Dropdown._getParentFromElement(this._element);\n\n $__default[\"default\"](parent).trigger(showEvent);\n\n if (showEvent.isDefaultPrevented()) {\n return;\n } // Totally disable Popper for Dropdowns in Navbar\n\n\n if (!this._inNavbar && usePopper) {\n // Check for Popper dependency\n if (typeof Popper__default[\"default\"] === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org)');\n }\n\n var referenceElement = this._element;\n\n if (this._config.reference === 'parent') {\n referenceElement = parent;\n } else if (Util.isElement(this._config.reference)) {\n referenceElement = this._config.reference; // Check if it's jQuery element\n\n if (typeof this._config.reference.jquery !== 'undefined') {\n referenceElement = this._config.reference[0];\n }\n } // If boundary is not `scrollParent`, then set position to `static`\n // to allow the menu to \"escape\" the scroll parent's boundaries\n // https://github.com/twbs/bootstrap/issues/24251\n\n\n if (this._config.boundary !== 'scrollParent') {\n $__default[\"default\"](parent).addClass(CLASS_NAME_POSITION_STATIC);\n }\n\n this._popper = new Popper__default[\"default\"](referenceElement, this._menu, this._getPopperConfig());\n } // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n\n\n if ('ontouchstart' in document.documentElement && $__default[\"default\"](parent).closest(SELECTOR_NAVBAR_NAV).length === 0) {\n $__default[\"default\"](document.body).children().on('mouseover', null, $__default[\"default\"].noop);\n }\n\n this._element.focus();\n\n this._element.setAttribute('aria-expanded', true);\n\n $__default[\"default\"](this._menu).toggleClass(CLASS_NAME_SHOW$5);\n $__default[\"default\"](parent).toggleClass(CLASS_NAME_SHOW$5).trigger($__default[\"default\"].Event(EVENT_SHOWN$3, relatedTarget));\n };\n\n _proto.hide = function hide() {\n if (this._element.disabled || $__default[\"default\"](this._element).hasClass(CLASS_NAME_DISABLED$1) || !$__default[\"default\"](this._menu).hasClass(CLASS_NAME_SHOW$5)) {\n return;\n }\n\n var relatedTarget = {\n relatedTarget: this._element\n };\n var hideEvent = $__default[\"default\"].Event(EVENT_HIDE$3, relatedTarget);\n\n var parent = Dropdown._getParentFromElement(this._element);\n\n $__default[\"default\"](parent).trigger(hideEvent);\n\n if (hideEvent.isDefaultPrevented()) {\n return;\n }\n\n if (this._popper) {\n this._popper.destroy();\n }\n\n $__default[\"default\"](this._menu).toggleClass(CLASS_NAME_SHOW$5);\n $__default[\"default\"](parent).toggleClass(CLASS_NAME_SHOW$5).trigger($__default[\"default\"].Event(EVENT_HIDDEN$3, relatedTarget));\n };\n\n _proto.dispose = function dispose() {\n $__default[\"default\"].removeData(this._element, DATA_KEY$6);\n $__default[\"default\"](this._element).off(EVENT_KEY$6);\n this._element = null;\n this._menu = null;\n\n if (this._popper !== null) {\n this._popper.destroy();\n\n this._popper = null;\n }\n };\n\n _proto.update = function update() {\n this._inNavbar = this._detectNavbar();\n\n if (this._popper !== null) {\n this._popper.scheduleUpdate();\n }\n } // Private\n ;\n\n _proto._addEventListeners = function _addEventListeners() {\n var _this = this;\n\n $__default[\"default\"](this._element).on(EVENT_CLICK, function (event) {\n event.preventDefault();\n event.stopPropagation();\n\n _this.toggle();\n });\n };\n\n _proto._getConfig = function _getConfig(config) {\n config = _extends({}, this.constructor.Default, $__default[\"default\"](this._element).data(), config);\n Util.typeCheckConfig(NAME$6, config, this.constructor.DefaultType);\n return config;\n };\n\n _proto._getMenuElement = function _getMenuElement() {\n if (!this._menu) {\n var parent = Dropdown._getParentFromElement(this._element);\n\n if (parent) {\n this._menu = parent.querySelector(SELECTOR_MENU);\n }\n }\n\n return this._menu;\n };\n\n _proto._getPlacement = function _getPlacement() {\n var $parentDropdown = $__default[\"default\"](this._element.parentNode);\n var placement = PLACEMENT_BOTTOM; // Handle dropup\n\n if ($parentDropdown.hasClass(CLASS_NAME_DROPUP)) {\n placement = $__default[\"default\"](this._menu).hasClass(CLASS_NAME_MENURIGHT) ? PLACEMENT_TOPEND : PLACEMENT_TOP;\n } else if ($parentDropdown.hasClass(CLASS_NAME_DROPRIGHT)) {\n placement = PLACEMENT_RIGHT;\n } else if ($parentDropdown.hasClass(CLASS_NAME_DROPLEFT)) {\n placement = PLACEMENT_LEFT;\n } else if ($__default[\"default\"](this._menu).hasClass(CLASS_NAME_MENURIGHT)) {\n placement = PLACEMENT_BOTTOMEND;\n }\n\n return placement;\n };\n\n _proto._detectNavbar = function _detectNavbar() {\n return $__default[\"default\"](this._element).closest('.navbar').length > 0;\n };\n\n _proto._getOffset = function _getOffset() {\n var _this2 = this;\n\n var offset = {};\n\n if (typeof this._config.offset === 'function') {\n offset.fn = function (data) {\n data.offsets = _extends({}, data.offsets, _this2._config.offset(data.offsets, _this2._element));\n return data;\n };\n } else {\n offset.offset = this._config.offset;\n }\n\n return offset;\n };\n\n _proto._getPopperConfig = function _getPopperConfig() {\n var popperConfig = {\n placement: this._getPlacement(),\n modifiers: {\n offset: this._getOffset(),\n flip: {\n enabled: this._config.flip\n },\n preventOverflow: {\n boundariesElement: this._config.boundary\n }\n }\n }; // Disable Popper if we have a static display\n\n if (this._config.display === 'static') {\n popperConfig.modifiers.applyStyle = {\n enabled: false\n };\n }\n\n return _extends({}, popperConfig, this._config.popperConfig);\n } // Static\n ;\n\n Dropdown._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var data = $__default[\"default\"](this).data(DATA_KEY$6);\n\n var _config = typeof config === 'object' ? config : null;\n\n if (!data) {\n data = new Dropdown(this, _config);\n $__default[\"default\"](this).data(DATA_KEY$6, data);\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n }\n\n data[config]();\n }\n });\n };\n\n Dropdown._clearMenus = function _clearMenus(event) {\n if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) {\n return;\n }\n\n var toggles = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE$2));\n\n for (var i = 0, len = toggles.length; i < len; i++) {\n var parent = Dropdown._getParentFromElement(toggles[i]);\n\n var context = $__default[\"default\"](toggles[i]).data(DATA_KEY$6);\n var relatedTarget = {\n relatedTarget: toggles[i]\n };\n\n if (event && event.type === 'click') {\n relatedTarget.clickEvent = event;\n }\n\n if (!context) {\n continue;\n }\n\n var dropdownMenu = context._menu;\n\n if (!$__default[\"default\"](parent).hasClass(CLASS_NAME_SHOW$5)) {\n continue;\n }\n\n if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $__default[\"default\"].contains(parent, event.target)) {\n continue;\n }\n\n var hideEvent = $__default[\"default\"].Event(EVENT_HIDE$3, relatedTarget);\n $__default[\"default\"](parent).trigger(hideEvent);\n\n if (hideEvent.isDefaultPrevented()) {\n continue;\n } // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n\n\n if ('ontouchstart' in document.documentElement) {\n $__default[\"default\"](document.body).children().off('mouseover', null, $__default[\"default\"].noop);\n }\n\n toggles[i].setAttribute('aria-expanded', 'false');\n\n if (context._popper) {\n context._popper.destroy();\n }\n\n $__default[\"default\"](dropdownMenu).removeClass(CLASS_NAME_SHOW$5);\n $__default[\"default\"](parent).removeClass(CLASS_NAME_SHOW$5).trigger($__default[\"default\"].Event(EVENT_HIDDEN$3, relatedTarget));\n }\n };\n\n Dropdown._getParentFromElement = function _getParentFromElement(element) {\n var parent;\n var selector = Util.getSelectorFromElement(element);\n\n if (selector) {\n parent = document.querySelector(selector);\n }\n\n return parent || element.parentNode;\n } // eslint-disable-next-line complexity\n ;\n\n Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) {\n // If not input/textarea:\n // - And not a key in REGEXP_KEYDOWN => not a dropdown command\n // If input/textarea:\n // - If space key => not a dropdown command\n // - If key is other than escape\n // - If key is not up or down => not a dropdown command\n // - If trigger inside the menu => not a dropdown command\n if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE$1 && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $__default[\"default\"](event.target).closest(SELECTOR_MENU).length) : !REGEXP_KEYDOWN.test(event.which)) {\n return;\n }\n\n if (this.disabled || $__default[\"default\"](this).hasClass(CLASS_NAME_DISABLED$1)) {\n return;\n }\n\n var parent = Dropdown._getParentFromElement(this);\n\n var isActive = $__default[\"default\"](parent).hasClass(CLASS_NAME_SHOW$5);\n\n if (!isActive && event.which === ESCAPE_KEYCODE$1) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n\n if (!isActive || event.which === ESCAPE_KEYCODE$1 || event.which === SPACE_KEYCODE) {\n if (event.which === ESCAPE_KEYCODE$1) {\n $__default[\"default\"](parent.querySelector(SELECTOR_DATA_TOGGLE$2)).trigger('focus');\n }\n\n $__default[\"default\"](this).trigger('click');\n return;\n }\n\n var items = [].slice.call(parent.querySelectorAll(SELECTOR_VISIBLE_ITEMS)).filter(function (item) {\n return $__default[\"default\"](item).is(':visible');\n });\n\n if (items.length === 0) {\n return;\n }\n\n var index = items.indexOf(event.target);\n\n if (event.which === ARROW_UP_KEYCODE && index > 0) {\n // Up\n index--;\n }\n\n if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) {\n // Down\n index++;\n }\n\n if (index < 0) {\n index = 0;\n }\n\n items[index].focus();\n };\n\n _createClass(Dropdown, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION$6;\n }\n }, {\n key: \"Default\",\n get: function get() {\n return Default$5;\n }\n }, {\n key: \"DefaultType\",\n get: function get() {\n return DefaultType$5;\n }\n }]);\n\n return Dropdown;\n }();\n /**\n * Data API implementation\n */\n\n\n $__default[\"default\"](document).on(EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE$2, Dropdown._dataApiKeydownHandler).on(EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown._dataApiKeydownHandler).on(EVENT_CLICK_DATA_API$2 + \" \" + EVENT_KEYUP_DATA_API, Dropdown._clearMenus).on(EVENT_CLICK_DATA_API$2, SELECTOR_DATA_TOGGLE$2, function (event) {\n event.preventDefault();\n event.stopPropagation();\n\n Dropdown._jQueryInterface.call($__default[\"default\"](this), 'toggle');\n }).on(EVENT_CLICK_DATA_API$2, SELECTOR_FORM_CHILD, function (e) {\n e.stopPropagation();\n });\n /**\n * jQuery\n */\n\n $__default[\"default\"].fn[NAME$6] = Dropdown._jQueryInterface;\n $__default[\"default\"].fn[NAME$6].Constructor = Dropdown;\n\n $__default[\"default\"].fn[NAME$6].noConflict = function () {\n $__default[\"default\"].fn[NAME$6] = JQUERY_NO_CONFLICT$6;\n return Dropdown._jQueryInterface;\n };\n\n /**\n * Constants\n */\n\n var NAME$5 = 'modal';\n var VERSION$5 = '4.6.1';\n var DATA_KEY$5 = 'bs.modal';\n var EVENT_KEY$5 = \".\" + DATA_KEY$5;\n var DATA_API_KEY$2 = '.data-api';\n var JQUERY_NO_CONFLICT$5 = $__default[\"default\"].fn[NAME$5];\n var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key\n\n var CLASS_NAME_SCROLLABLE = 'modal-dialog-scrollable';\n var CLASS_NAME_SCROLLBAR_MEASURER = 'modal-scrollbar-measure';\n var CLASS_NAME_BACKDROP = 'modal-backdrop';\n var CLASS_NAME_OPEN = 'modal-open';\n var CLASS_NAME_FADE$4 = 'fade';\n var CLASS_NAME_SHOW$4 = 'show';\n var CLASS_NAME_STATIC = 'modal-static';\n var EVENT_HIDE$2 = \"hide\" + EVENT_KEY$5;\n var EVENT_HIDE_PREVENTED = \"hidePrevented\" + EVENT_KEY$5;\n var EVENT_HIDDEN$2 = \"hidden\" + EVENT_KEY$5;\n var EVENT_SHOW$2 = \"show\" + EVENT_KEY$5;\n var EVENT_SHOWN$2 = \"shown\" + EVENT_KEY$5;\n var EVENT_FOCUSIN = \"focusin\" + EVENT_KEY$5;\n var EVENT_RESIZE = \"resize\" + EVENT_KEY$5;\n var EVENT_CLICK_DISMISS$1 = \"click.dismiss\" + EVENT_KEY$5;\n var EVENT_KEYDOWN_DISMISS = \"keydown.dismiss\" + EVENT_KEY$5;\n var EVENT_MOUSEUP_DISMISS = \"mouseup.dismiss\" + EVENT_KEY$5;\n var EVENT_MOUSEDOWN_DISMISS = \"mousedown.dismiss\" + EVENT_KEY$5;\n var EVENT_CLICK_DATA_API$1 = \"click\" + EVENT_KEY$5 + DATA_API_KEY$2;\n var SELECTOR_DIALOG = '.modal-dialog';\n var SELECTOR_MODAL_BODY = '.modal-body';\n var SELECTOR_DATA_TOGGLE$1 = '[data-toggle=\"modal\"]';\n var SELECTOR_DATA_DISMISS$1 = '[data-dismiss=\"modal\"]';\n var SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';\n var SELECTOR_STICKY_CONTENT = '.sticky-top';\n var Default$4 = {\n backdrop: true,\n keyboard: true,\n focus: true,\n show: true\n };\n var DefaultType$4 = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n focus: 'boolean',\n show: 'boolean'\n };\n /**\n * Class definition\n */\n\n var Modal = /*#__PURE__*/function () {\n function Modal(element, config) {\n this._config = this._getConfig(config);\n this._element = element;\n this._dialog = element.querySelector(SELECTOR_DIALOG);\n this._backdrop = null;\n this._isShown = false;\n this._isBodyOverflowing = false;\n this._ignoreBackdropClick = false;\n this._isTransitioning = false;\n this._scrollbarWidth = 0;\n } // Getters\n\n\n var _proto = Modal.prototype;\n\n // Public\n _proto.toggle = function toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget);\n };\n\n _proto.show = function show(relatedTarget) {\n var _this = this;\n\n if (this._isShown || this._isTransitioning) {\n return;\n }\n\n var showEvent = $__default[\"default\"].Event(EVENT_SHOW$2, {\n relatedTarget: relatedTarget\n });\n $__default[\"default\"](this._element).trigger(showEvent);\n\n if (showEvent.isDefaultPrevented()) {\n return;\n }\n\n this._isShown = true;\n\n if ($__default[\"default\"](this._element).hasClass(CLASS_NAME_FADE$4)) {\n this._isTransitioning = true;\n }\n\n this._checkScrollbar();\n\n this._setScrollbar();\n\n this._adjustDialog();\n\n this._setEscapeEvent();\n\n this._setResizeEvent();\n\n $__default[\"default\"](this._element).on(EVENT_CLICK_DISMISS$1, SELECTOR_DATA_DISMISS$1, function (event) {\n return _this.hide(event);\n });\n $__default[\"default\"](this._dialog).on(EVENT_MOUSEDOWN_DISMISS, function () {\n $__default[\"default\"](_this._element).one(EVENT_MOUSEUP_DISMISS, function (event) {\n if ($__default[\"default\"](event.target).is(_this._element)) {\n _this._ignoreBackdropClick = true;\n }\n });\n });\n\n this._showBackdrop(function () {\n return _this._showElement(relatedTarget);\n });\n };\n\n _proto.hide = function hide(event) {\n var _this2 = this;\n\n if (event) {\n event.preventDefault();\n }\n\n if (!this._isShown || this._isTransitioning) {\n return;\n }\n\n var hideEvent = $__default[\"default\"].Event(EVENT_HIDE$2);\n $__default[\"default\"](this._element).trigger(hideEvent);\n\n if (!this._isShown || hideEvent.isDefaultPrevented()) {\n return;\n }\n\n this._isShown = false;\n var transition = $__default[\"default\"](this._element).hasClass(CLASS_NAME_FADE$4);\n\n if (transition) {\n this._isTransitioning = true;\n }\n\n this._setEscapeEvent();\n\n this._setResizeEvent();\n\n $__default[\"default\"](document).off(EVENT_FOCUSIN);\n $__default[\"default\"](this._element).removeClass(CLASS_NAME_SHOW$4);\n $__default[\"default\"](this._element).off(EVENT_CLICK_DISMISS$1);\n $__default[\"default\"](this._dialog).off(EVENT_MOUSEDOWN_DISMISS);\n\n if (transition) {\n var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n $__default[\"default\"](this._element).one(Util.TRANSITION_END, function (event) {\n return _this2._hideModal(event);\n }).emulateTransitionEnd(transitionDuration);\n } else {\n this._hideModal();\n }\n };\n\n _proto.dispose = function dispose() {\n [window, this._element, this._dialog].forEach(function (htmlElement) {\n return $__default[\"default\"](htmlElement).off(EVENT_KEY$5);\n });\n /**\n * `document` has 2 events `EVENT_FOCUSIN` and `EVENT_CLICK_DATA_API`\n * Do not move `document` in `htmlElements` array\n * It will remove `EVENT_CLICK_DATA_API` event that should remain\n */\n\n $__default[\"default\"](document).off(EVENT_FOCUSIN);\n $__default[\"default\"].removeData(this._element, DATA_KEY$5);\n this._config = null;\n this._element = null;\n this._dialog = null;\n this._backdrop = null;\n this._isShown = null;\n this._isBodyOverflowing = null;\n this._ignoreBackdropClick = null;\n this._isTransitioning = null;\n this._scrollbarWidth = null;\n };\n\n _proto.handleUpdate = function handleUpdate() {\n this._adjustDialog();\n } // Private\n ;\n\n _proto._getConfig = function _getConfig(config) {\n config = _extends({}, Default$4, config);\n Util.typeCheckConfig(NAME$5, config, DefaultType$4);\n return config;\n };\n\n _proto._triggerBackdropTransition = function _triggerBackdropTransition() {\n var _this3 = this;\n\n var hideEventPrevented = $__default[\"default\"].Event(EVENT_HIDE_PREVENTED);\n $__default[\"default\"](this._element).trigger(hideEventPrevented);\n\n if (hideEventPrevented.isDefaultPrevented()) {\n return;\n }\n\n var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;\n\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden';\n }\n\n this._element.classList.add(CLASS_NAME_STATIC);\n\n var modalTransitionDuration = Util.getTransitionDurationFromElement(this._dialog);\n $__default[\"default\"](this._element).off(Util.TRANSITION_END);\n $__default[\"default\"](this._element).one(Util.TRANSITION_END, function () {\n _this3._element.classList.remove(CLASS_NAME_STATIC);\n\n if (!isModalOverflowing) {\n $__default[\"default\"](_this3._element).one(Util.TRANSITION_END, function () {\n _this3._element.style.overflowY = '';\n }).emulateTransitionEnd(_this3._element, modalTransitionDuration);\n }\n }).emulateTransitionEnd(modalTransitionDuration);\n\n this._element.focus();\n };\n\n _proto._showElement = function _showElement(relatedTarget) {\n var _this4 = this;\n\n var transition = $__default[\"default\"](this._element).hasClass(CLASS_NAME_FADE$4);\n var modalBody = this._dialog ? this._dialog.querySelector(SELECTOR_MODAL_BODY) : null;\n\n if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {\n // Don't move modal's DOM position\n document.body.appendChild(this._element);\n }\n\n this._element.style.display = 'block';\n\n this._element.removeAttribute('aria-hidden');\n\n this._element.setAttribute('aria-modal', true);\n\n this._element.setAttribute('role', 'dialog');\n\n if ($__default[\"default\"](this._dialog).hasClass(CLASS_NAME_SCROLLABLE) && modalBody) {\n modalBody.scrollTop = 0;\n } else {\n this._element.scrollTop = 0;\n }\n\n if (transition) {\n Util.reflow(this._element);\n }\n\n $__default[\"default\"](this._element).addClass(CLASS_NAME_SHOW$4);\n\n if (this._config.focus) {\n this._enforceFocus();\n }\n\n var shownEvent = $__default[\"default\"].Event(EVENT_SHOWN$2, {\n relatedTarget: relatedTarget\n });\n\n var transitionComplete = function transitionComplete() {\n if (_this4._config.focus) {\n _this4._element.focus();\n }\n\n _this4._isTransitioning = false;\n $__default[\"default\"](_this4._element).trigger(shownEvent);\n };\n\n if (transition) {\n var transitionDuration = Util.getTransitionDurationFromElement(this._dialog);\n $__default[\"default\"](this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(transitionDuration);\n } else {\n transitionComplete();\n }\n };\n\n _proto._enforceFocus = function _enforceFocus() {\n var _this5 = this;\n\n $__default[\"default\"](document).off(EVENT_FOCUSIN) // Guard against infinite focus loop\n .on(EVENT_FOCUSIN, function (event) {\n if (document !== event.target && _this5._element !== event.target && $__default[\"default\"](_this5._element).has(event.target).length === 0) {\n _this5._element.focus();\n }\n });\n };\n\n _proto._setEscapeEvent = function _setEscapeEvent() {\n var _this6 = this;\n\n if (this._isShown) {\n $__default[\"default\"](this._element).on(EVENT_KEYDOWN_DISMISS, function (event) {\n if (_this6._config.keyboard && event.which === ESCAPE_KEYCODE) {\n event.preventDefault();\n\n _this6.hide();\n } else if (!_this6._config.keyboard && event.which === ESCAPE_KEYCODE) {\n _this6._triggerBackdropTransition();\n }\n });\n } else if (!this._isShown) {\n $__default[\"default\"](this._element).off(EVENT_KEYDOWN_DISMISS);\n }\n };\n\n _proto._setResizeEvent = function _setResizeEvent() {\n var _this7 = this;\n\n if (this._isShown) {\n $__default[\"default\"](window).on(EVENT_RESIZE, function (event) {\n return _this7.handleUpdate(event);\n });\n } else {\n $__default[\"default\"](window).off(EVENT_RESIZE);\n }\n };\n\n _proto._hideModal = function _hideModal() {\n var _this8 = this;\n\n this._element.style.display = 'none';\n\n this._element.setAttribute('aria-hidden', true);\n\n this._element.removeAttribute('aria-modal');\n\n this._element.removeAttribute('role');\n\n this._isTransitioning = false;\n\n this._showBackdrop(function () {\n $__default[\"default\"](document.body).removeClass(CLASS_NAME_OPEN);\n\n _this8._resetAdjustments();\n\n _this8._resetScrollbar();\n\n $__default[\"default\"](_this8._element).trigger(EVENT_HIDDEN$2);\n });\n };\n\n _proto._removeBackdrop = function _removeBackdrop() {\n if (this._backdrop) {\n $__default[\"default\"](this._backdrop).remove();\n this._backdrop = null;\n }\n };\n\n _proto._showBackdrop = function _showBackdrop(callback) {\n var _this9 = this;\n\n var animate = $__default[\"default\"](this._element).hasClass(CLASS_NAME_FADE$4) ? CLASS_NAME_FADE$4 : '';\n\n if (this._isShown && this._config.backdrop) {\n this._backdrop = document.createElement('div');\n this._backdrop.className = CLASS_NAME_BACKDROP;\n\n if (animate) {\n this._backdrop.classList.add(animate);\n }\n\n $__default[\"default\"](this._backdrop).appendTo(document.body);\n $__default[\"default\"](this._element).on(EVENT_CLICK_DISMISS$1, function (event) {\n if (_this9._ignoreBackdropClick) {\n _this9._ignoreBackdropClick = false;\n return;\n }\n\n if (event.target !== event.currentTarget) {\n return;\n }\n\n if (_this9._config.backdrop === 'static') {\n _this9._triggerBackdropTransition();\n } else {\n _this9.hide();\n }\n });\n\n if (animate) {\n Util.reflow(this._backdrop);\n }\n\n $__default[\"default\"](this._backdrop).addClass(CLASS_NAME_SHOW$4);\n\n if (!callback) {\n return;\n }\n\n if (!animate) {\n callback();\n return;\n }\n\n var backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);\n $__default[\"default\"](this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(backdropTransitionDuration);\n } else if (!this._isShown && this._backdrop) {\n $__default[\"default\"](this._backdrop).removeClass(CLASS_NAME_SHOW$4);\n\n var callbackRemove = function callbackRemove() {\n _this9._removeBackdrop();\n\n if (callback) {\n callback();\n }\n };\n\n if ($__default[\"default\"](this._element).hasClass(CLASS_NAME_FADE$4)) {\n var _backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);\n\n $__default[\"default\"](this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(_backdropTransitionDuration);\n } else {\n callbackRemove();\n }\n } else if (callback) {\n callback();\n }\n } // ----------------------------------------------------------------------\n // the following methods are used to handle overflowing modals\n // todo (fat): these should probably be refactored out of modal.js\n // ----------------------------------------------------------------------\n ;\n\n _proto._adjustDialog = function _adjustDialog() {\n var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;\n\n if (!this._isBodyOverflowing && isModalOverflowing) {\n this._element.style.paddingLeft = this._scrollbarWidth + \"px\";\n }\n\n if (this._isBodyOverflowing && !isModalOverflowing) {\n this._element.style.paddingRight = this._scrollbarWidth + \"px\";\n }\n };\n\n _proto._resetAdjustments = function _resetAdjustments() {\n this._element.style.paddingLeft = '';\n this._element.style.paddingRight = '';\n };\n\n _proto._checkScrollbar = function _checkScrollbar() {\n var rect = document.body.getBoundingClientRect();\n this._isBodyOverflowing = Math.round(rect.left + rect.right) < window.innerWidth;\n this._scrollbarWidth = this._getScrollbarWidth();\n };\n\n _proto._setScrollbar = function _setScrollbar() {\n var _this10 = this;\n\n if (this._isBodyOverflowing) {\n // Note: DOMNode.style.paddingRight returns the actual value or '' if not set\n // while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set\n var fixedContent = [].slice.call(document.querySelectorAll(SELECTOR_FIXED_CONTENT));\n var stickyContent = [].slice.call(document.querySelectorAll(SELECTOR_STICKY_CONTENT)); // Adjust fixed content padding\n\n $__default[\"default\"](fixedContent).each(function (index, element) {\n var actualPadding = element.style.paddingRight;\n var calculatedPadding = $__default[\"default\"](element).css('padding-right');\n $__default[\"default\"](element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this10._scrollbarWidth + \"px\");\n }); // Adjust sticky content margin\n\n $__default[\"default\"](stickyContent).each(function (index, element) {\n var actualMargin = element.style.marginRight;\n var calculatedMargin = $__default[\"default\"](element).css('margin-right');\n $__default[\"default\"](element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this10._scrollbarWidth + \"px\");\n }); // Adjust body padding\n\n var actualPadding = document.body.style.paddingRight;\n var calculatedPadding = $__default[\"default\"](document.body).css('padding-right');\n $__default[\"default\"](document.body).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + \"px\");\n }\n\n $__default[\"default\"](document.body).addClass(CLASS_NAME_OPEN);\n };\n\n _proto._resetScrollbar = function _resetScrollbar() {\n // Restore fixed content padding\n var fixedContent = [].slice.call(document.querySelectorAll(SELECTOR_FIXED_CONTENT));\n $__default[\"default\"](fixedContent).each(function (index, element) {\n var padding = $__default[\"default\"](element).data('padding-right');\n $__default[\"default\"](element).removeData('padding-right');\n element.style.paddingRight = padding ? padding : '';\n }); // Restore sticky content\n\n var elements = [].slice.call(document.querySelectorAll(\"\" + SELECTOR_STICKY_CONTENT));\n $__default[\"default\"](elements).each(function (index, element) {\n var margin = $__default[\"default\"](element).data('margin-right');\n\n if (typeof margin !== 'undefined') {\n $__default[\"default\"](element).css('margin-right', margin).removeData('margin-right');\n }\n }); // Restore body padding\n\n var padding = $__default[\"default\"](document.body).data('padding-right');\n $__default[\"default\"](document.body).removeData('padding-right');\n document.body.style.paddingRight = padding ? padding : '';\n };\n\n _proto._getScrollbarWidth = function _getScrollbarWidth() {\n // thx d.walsh\n var scrollDiv = document.createElement('div');\n scrollDiv.className = CLASS_NAME_SCROLLBAR_MEASURER;\n document.body.appendChild(scrollDiv);\n var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;\n document.body.removeChild(scrollDiv);\n return scrollbarWidth;\n } // Static\n ;\n\n Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n var data = $__default[\"default\"](this).data(DATA_KEY$5);\n\n var _config = _extends({}, Default$4, $__default[\"default\"](this).data(), typeof config === 'object' && config ? config : {});\n\n if (!data) {\n data = new Modal(this, _config);\n $__default[\"default\"](this).data(DATA_KEY$5, data);\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n }\n\n data[config](relatedTarget);\n } else if (_config.show) {\n data.show(relatedTarget);\n }\n });\n };\n\n _createClass(Modal, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION$5;\n }\n }, {\n key: \"Default\",\n get: function get() {\n return Default$4;\n }\n }]);\n\n return Modal;\n }();\n /**\n * Data API implementation\n */\n\n\n $__default[\"default\"](document).on(EVENT_CLICK_DATA_API$1, SELECTOR_DATA_TOGGLE$1, function (event) {\n var _this11 = this;\n\n var target;\n var selector = Util.getSelectorFromElement(this);\n\n if (selector) {\n target = document.querySelector(selector);\n }\n\n var config = $__default[\"default\"](target).data(DATA_KEY$5) ? 'toggle' : _extends({}, $__default[\"default\"](target).data(), $__default[\"default\"](this).data());\n\n if (this.tagName === 'A' || this.tagName === 'AREA') {\n event.preventDefault();\n }\n\n var $target = $__default[\"default\"](target).one(EVENT_SHOW$2, function (showEvent) {\n if (showEvent.isDefaultPrevented()) {\n // Only register focus restorer if modal will actually get shown\n return;\n }\n\n $target.one(EVENT_HIDDEN$2, function () {\n if ($__default[\"default\"](_this11).is(':visible')) {\n _this11.focus();\n }\n });\n });\n\n Modal._jQueryInterface.call($__default[\"default\"](target), config, this);\n });\n /**\n * jQuery\n */\n\n $__default[\"default\"].fn[NAME$5] = Modal._jQueryInterface;\n $__default[\"default\"].fn[NAME$5].Constructor = Modal;\n\n $__default[\"default\"].fn[NAME$5].noConflict = function () {\n $__default[\"default\"].fn[NAME$5] = JQUERY_NO_CONFLICT$5;\n return Modal._jQueryInterface;\n };\n\n /**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.6.1): tools/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n var uriAttrs = ['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href'];\n var ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i;\n var DefaultWhitelist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n div: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n };\n /**\n * A pattern that recognizes a commonly useful subset of URLs that are safe.\n *\n * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts\n */\n\n var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i;\n /**\n * A pattern that matches safe data URLs. Only matches image, video and audio types.\n *\n * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts\n */\n\n var DATA_URL_PATTERN = /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[\\d+/a-z]+=*$/i;\n\n function allowedAttribute(attr, allowedAttributeList) {\n var attrName = attr.nodeName.toLowerCase();\n\n if (allowedAttributeList.indexOf(attrName) !== -1) {\n if (uriAttrs.indexOf(attrName) !== -1) {\n return Boolean(SAFE_URL_PATTERN.test(attr.nodeValue) || DATA_URL_PATTERN.test(attr.nodeValue));\n }\n\n return true;\n }\n\n var regExp = allowedAttributeList.filter(function (attrRegex) {\n return attrRegex instanceof RegExp;\n }); // Check if a regular expression validates the attribute.\n\n for (var i = 0, len = regExp.length; i < len; i++) {\n if (regExp[i].test(attrName)) {\n return true;\n }\n }\n\n return false;\n }\n\n function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {\n if (unsafeHtml.length === 0) {\n return unsafeHtml;\n }\n\n if (sanitizeFn && typeof sanitizeFn === 'function') {\n return sanitizeFn(unsafeHtml);\n }\n\n var domParser = new window.DOMParser();\n var createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');\n var whitelistKeys = Object.keys(whiteList);\n var elements = [].slice.call(createdDocument.body.querySelectorAll('*'));\n\n var _loop = function _loop(i, len) {\n var el = elements[i];\n var elName = el.nodeName.toLowerCase();\n\n if (whitelistKeys.indexOf(el.nodeName.toLowerCase()) === -1) {\n el.parentNode.removeChild(el);\n return \"continue\";\n }\n\n var attributeList = [].slice.call(el.attributes); // eslint-disable-next-line unicorn/prefer-spread\n\n var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []);\n attributeList.forEach(function (attr) {\n if (!allowedAttribute(attr, whitelistedAttributes)) {\n el.removeAttribute(attr.nodeName);\n }\n });\n };\n\n for (var i = 0, len = elements.length; i < len; i++) {\n var _ret = _loop(i);\n\n if (_ret === \"continue\") continue;\n }\n\n return createdDocument.body.innerHTML;\n }\n\n /**\n * Constants\n */\n\n var NAME$4 = 'tooltip';\n var VERSION$4 = '4.6.1';\n var DATA_KEY$4 = 'bs.tooltip';\n var EVENT_KEY$4 = \".\" + DATA_KEY$4;\n var JQUERY_NO_CONFLICT$4 = $__default[\"default\"].fn[NAME$4];\n var CLASS_PREFIX$1 = 'bs-tooltip';\n var BSCLS_PREFIX_REGEX$1 = new RegExp(\"(^|\\\\s)\" + CLASS_PREFIX$1 + \"\\\\S+\", 'g');\n var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'];\n var CLASS_NAME_FADE$3 = 'fade';\n var CLASS_NAME_SHOW$3 = 'show';\n var HOVER_STATE_SHOW = 'show';\n var HOVER_STATE_OUT = 'out';\n var SELECTOR_TOOLTIP_INNER = '.tooltip-inner';\n var SELECTOR_ARROW = '.arrow';\n var TRIGGER_HOVER = 'hover';\n var TRIGGER_FOCUS = 'focus';\n var TRIGGER_CLICK = 'click';\n var TRIGGER_MANUAL = 'manual';\n var AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: 'right',\n BOTTOM: 'bottom',\n LEFT: 'left'\n };\n var Default$3 = {\n animation: true,\n template: '<div class=\"tooltip\" role=\"tooltip\">' + '<div class=\"arrow\"></div>' + '<div class=\"tooltip-inner\"></div></div>',\n trigger: 'hover focus',\n title: '',\n delay: 0,\n html: false,\n selector: false,\n placement: 'top',\n offset: 0,\n container: false,\n fallbackPlacement: 'flip',\n boundary: 'scrollParent',\n customClass: '',\n sanitize: true,\n sanitizeFn: null,\n whiteList: DefaultWhitelist,\n popperConfig: null\n };\n var DefaultType$3 = {\n animation: 'boolean',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string',\n delay: '(number|object)',\n html: 'boolean',\n selector: '(string|boolean)',\n placement: '(string|function)',\n offset: '(number|string|function)',\n container: '(string|element|boolean)',\n fallbackPlacement: '(string|array)',\n boundary: '(string|element)',\n customClass: '(string|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n whiteList: 'object',\n popperConfig: '(null|object)'\n };\n var Event$1 = {\n HIDE: \"hide\" + EVENT_KEY$4,\n HIDDEN: \"hidden\" + EVENT_KEY$4,\n SHOW: \"show\" + EVENT_KEY$4,\n SHOWN: \"shown\" + EVENT_KEY$4,\n INSERTED: \"inserted\" + EVENT_KEY$4,\n CLICK: \"click\" + EVENT_KEY$4,\n FOCUSIN: \"focusin\" + EVENT_KEY$4,\n FOCUSOUT: \"focusout\" + EVENT_KEY$4,\n MOUSEENTER: \"mouseenter\" + EVENT_KEY$4,\n MOUSELEAVE: \"mouseleave\" + EVENT_KEY$4\n };\n /**\n * Class definition\n */\n\n var Tooltip = /*#__PURE__*/function () {\n function Tooltip(element, config) {\n if (typeof Popper__default[\"default\"] === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org)');\n } // Private\n\n\n this._isEnabled = true;\n this._timeout = 0;\n this._hoverState = '';\n this._activeTrigger = {};\n this._popper = null; // Protected\n\n this.element = element;\n this.config = this._getConfig(config);\n this.tip = null;\n\n this._setListeners();\n } // Getters\n\n\n var _proto = Tooltip.prototype;\n\n // Public\n _proto.enable = function enable() {\n this._isEnabled = true;\n };\n\n _proto.disable = function disable() {\n this._isEnabled = false;\n };\n\n _proto.toggleEnabled = function toggleEnabled() {\n this._isEnabled = !this._isEnabled;\n };\n\n _proto.toggle = function toggle(event) {\n if (!this._isEnabled) {\n return;\n }\n\n if (event) {\n var dataKey = this.constructor.DATA_KEY;\n var context = $__default[\"default\"](event.currentTarget).data(dataKey);\n\n if (!context) {\n context = new this.constructor(event.currentTarget, this._getDelegateConfig());\n $__default[\"default\"](event.currentTarget).data(dataKey, context);\n }\n\n context._activeTrigger.click = !context._activeTrigger.click;\n\n if (context._isWithActiveTrigger()) {\n context._enter(null, context);\n } else {\n context._leave(null, context);\n }\n } else {\n if ($__default[\"default\"](this.getTipElement()).hasClass(CLASS_NAME_SHOW$3)) {\n this._leave(null, this);\n\n return;\n }\n\n this._enter(null, this);\n }\n };\n\n _proto.dispose = function dispose() {\n clearTimeout(this._timeout);\n $__default[\"default\"].removeData(this.element, this.constructor.DATA_KEY);\n $__default[\"default\"](this.element).off(this.constructor.EVENT_KEY);\n $__default[\"default\"](this.element).closest('.modal').off('hide.bs.modal', this._hideModalHandler);\n\n if (this.tip) {\n $__default[\"default\"](this.tip).remove();\n }\n\n this._isEnabled = null;\n this._timeout = null;\n this._hoverState = null;\n this._activeTrigger = null;\n\n if (this._popper) {\n this._popper.destroy();\n }\n\n this._popper = null;\n this.element = null;\n this.config = null;\n this.tip = null;\n };\n\n _proto.show = function show() {\n var _this = this;\n\n if ($__default[\"default\"](this.element).css('display') === 'none') {\n throw new Error('Please use show on visible elements');\n }\n\n var showEvent = $__default[\"default\"].Event(this.constructor.Event.SHOW);\n\n if (this.isWithContent() && this._isEnabled) {\n $__default[\"default\"](this.element).trigger(showEvent);\n var shadowRoot = Util.findShadowRoot(this.element);\n var isInTheDom = $__default[\"default\"].contains(shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement, this.element);\n\n if (showEvent.isDefaultPrevented() || !isInTheDom) {\n return;\n }\n\n var tip = this.getTipElement();\n var tipId = Util.getUID(this.constructor.NAME);\n tip.setAttribute('id', tipId);\n this.element.setAttribute('aria-describedby', tipId);\n this.setContent();\n\n if (this.config.animation) {\n $__default[\"default\"](tip).addClass(CLASS_NAME_FADE$3);\n }\n\n var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement;\n\n var attachment = this._getAttachment(placement);\n\n this.addAttachmentClass(attachment);\n\n var container = this._getContainer();\n\n $__default[\"default\"](tip).data(this.constructor.DATA_KEY, this);\n\n if (!$__default[\"default\"].contains(this.element.ownerDocument.documentElement, this.tip)) {\n $__default[\"default\"](tip).appendTo(container);\n }\n\n $__default[\"default\"](this.element).trigger(this.constructor.Event.INSERTED);\n this._popper = new Popper__default[\"default\"](this.element, tip, this._getPopperConfig(attachment));\n $__default[\"default\"](tip).addClass(CLASS_NAME_SHOW$3);\n $__default[\"default\"](tip).addClass(this.config.customClass); // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n\n if ('ontouchstart' in document.documentElement) {\n $__default[\"default\"](document.body).children().on('mouseover', null, $__default[\"default\"].noop);\n }\n\n var complete = function complete() {\n if (_this.config.animation) {\n _this._fixTransition();\n }\n\n var prevHoverState = _this._hoverState;\n _this._hoverState = null;\n $__default[\"default\"](_this.element).trigger(_this.constructor.Event.SHOWN);\n\n if (prevHoverState === HOVER_STATE_OUT) {\n _this._leave(null, _this);\n }\n };\n\n if ($__default[\"default\"](this.tip).hasClass(CLASS_NAME_FADE$3)) {\n var transitionDuration = Util.getTransitionDurationFromElement(this.tip);\n $__default[\"default\"](this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n } else {\n complete();\n }\n }\n };\n\n _proto.hide = function hide(callback) {\n var _this2 = this;\n\n var tip = this.getTipElement();\n var hideEvent = $__default[\"default\"].Event(this.constructor.Event.HIDE);\n\n var complete = function complete() {\n if (_this2._hoverState !== HOVER_STATE_SHOW && tip.parentNode) {\n tip.parentNode.removeChild(tip);\n }\n\n _this2._cleanTipClass();\n\n _this2.element.removeAttribute('aria-describedby');\n\n $__default[\"default\"](_this2.element).trigger(_this2.constructor.Event.HIDDEN);\n\n if (_this2._popper !== null) {\n _this2._popper.destroy();\n }\n\n if (callback) {\n callback();\n }\n };\n\n $__default[\"default\"](this.element).trigger(hideEvent);\n\n if (hideEvent.isDefaultPrevented()) {\n return;\n }\n\n $__default[\"default\"](tip).removeClass(CLASS_NAME_SHOW$3); // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n\n if ('ontouchstart' in document.documentElement) {\n $__default[\"default\"](document.body).children().off('mouseover', null, $__default[\"default\"].noop);\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false;\n this._activeTrigger[TRIGGER_FOCUS] = false;\n this._activeTrigger[TRIGGER_HOVER] = false;\n\n if ($__default[\"default\"](this.tip).hasClass(CLASS_NAME_FADE$3)) {\n var transitionDuration = Util.getTransitionDurationFromElement(tip);\n $__default[\"default\"](tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n } else {\n complete();\n }\n\n this._hoverState = '';\n };\n\n _proto.update = function update() {\n if (this._popper !== null) {\n this._popper.scheduleUpdate();\n }\n } // Protected\n ;\n\n _proto.isWithContent = function isWithContent() {\n return Boolean(this.getTitle());\n };\n\n _proto.addAttachmentClass = function addAttachmentClass(attachment) {\n $__default[\"default\"](this.getTipElement()).addClass(CLASS_PREFIX$1 + \"-\" + attachment);\n };\n\n _proto.getTipElement = function getTipElement() {\n this.tip = this.tip || $__default[\"default\"](this.config.template)[0];\n return this.tip;\n };\n\n _proto.setContent = function setContent() {\n var tip = this.getTipElement();\n this.setElementContent($__default[\"default\"](tip.querySelectorAll(SELECTOR_TOOLTIP_INNER)), this.getTitle());\n $__default[\"default\"](tip).removeClass(CLASS_NAME_FADE$3 + \" \" + CLASS_NAME_SHOW$3);\n };\n\n _proto.setElementContent = function setElementContent($element, content) {\n if (typeof content === 'object' && (content.nodeType || content.jquery)) {\n // Content is a DOM node or a jQuery\n if (this.config.html) {\n if (!$__default[\"default\"](content).parent().is($element)) {\n $element.empty().append(content);\n }\n } else {\n $element.text($__default[\"default\"](content).text());\n }\n\n return;\n }\n\n if (this.config.html) {\n if (this.config.sanitize) {\n content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn);\n }\n\n $element.html(content);\n } else {\n $element.text(content);\n }\n };\n\n _proto.getTitle = function getTitle() {\n var title = this.element.getAttribute('data-original-title');\n\n if (!title) {\n title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title;\n }\n\n return title;\n } // Private\n ;\n\n _proto._getPopperConfig = function _getPopperConfig(attachment) {\n var _this3 = this;\n\n var defaultBsConfig = {\n placement: attachment,\n modifiers: {\n offset: this._getOffset(),\n flip: {\n behavior: this.config.fallbackPlacement\n },\n arrow: {\n element: SELECTOR_ARROW\n },\n preventOverflow: {\n boundariesElement: this.config.boundary\n }\n },\n onCreate: function onCreate(data) {\n if (data.originalPlacement !== data.placement) {\n _this3._handlePopperPlacementChange(data);\n }\n },\n onUpdate: function onUpdate(data) {\n return _this3._handlePopperPlacementChange(data);\n }\n };\n return _extends({}, defaultBsConfig, this.config.popperConfig);\n };\n\n _proto._getOffset = function _getOffset() {\n var _this4 = this;\n\n var offset = {};\n\n if (typeof this.config.offset === 'function') {\n offset.fn = function (data) {\n data.offsets = _extends({}, data.offsets, _this4.config.offset(data.offsets, _this4.element));\n return data;\n };\n } else {\n offset.offset = this.config.offset;\n }\n\n return offset;\n };\n\n _proto._getContainer = function _getContainer() {\n if (this.config.container === false) {\n return document.body;\n }\n\n if (Util.isElement(this.config.container)) {\n return $__default[\"default\"](this.config.container);\n }\n\n return $__default[\"default\"](document).find(this.config.container);\n };\n\n _proto._getAttachment = function _getAttachment(placement) {\n return AttachmentMap[placement.toUpperCase()];\n };\n\n _proto._setListeners = function _setListeners() {\n var _this5 = this;\n\n var triggers = this.config.trigger.split(' ');\n triggers.forEach(function (trigger) {\n if (trigger === 'click') {\n $__default[\"default\"](_this5.element).on(_this5.constructor.Event.CLICK, _this5.config.selector, function (event) {\n return _this5.toggle(event);\n });\n } else if (trigger !== TRIGGER_MANUAL) {\n var eventIn = trigger === TRIGGER_HOVER ? _this5.constructor.Event.MOUSEENTER : _this5.constructor.Event.FOCUSIN;\n var eventOut = trigger === TRIGGER_HOVER ? _this5.constructor.Event.MOUSELEAVE : _this5.constructor.Event.FOCUSOUT;\n $__default[\"default\"](_this5.element).on(eventIn, _this5.config.selector, function (event) {\n return _this5._enter(event);\n }).on(eventOut, _this5.config.selector, function (event) {\n return _this5._leave(event);\n });\n }\n });\n\n this._hideModalHandler = function () {\n if (_this5.element) {\n _this5.hide();\n }\n };\n\n $__default[\"default\"](this.element).closest('.modal').on('hide.bs.modal', this._hideModalHandler);\n\n if (this.config.selector) {\n this.config = _extends({}, this.config, {\n trigger: 'manual',\n selector: ''\n });\n } else {\n this._fixTitle();\n }\n };\n\n _proto._fixTitle = function _fixTitle() {\n var titleType = typeof this.element.getAttribute('data-original-title');\n\n if (this.element.getAttribute('title') || titleType !== 'string') {\n this.element.setAttribute('data-original-title', this.element.getAttribute('title') || '');\n this.element.setAttribute('title', '');\n }\n };\n\n _proto._enter = function _enter(event, context) {\n var dataKey = this.constructor.DATA_KEY;\n context = context || $__default[\"default\"](event.currentTarget).data(dataKey);\n\n if (!context) {\n context = new this.constructor(event.currentTarget, this._getDelegateConfig());\n $__default[\"default\"](event.currentTarget).data(dataKey, context);\n }\n\n if (event) {\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true;\n }\n\n if ($__default[\"default\"](context.getTipElement()).hasClass(CLASS_NAME_SHOW$3) || context._hoverState === HOVER_STATE_SHOW) {\n context._hoverState = HOVER_STATE_SHOW;\n return;\n }\n\n clearTimeout(context._timeout);\n context._hoverState = HOVER_STATE_SHOW;\n\n if (!context.config.delay || !context.config.delay.show) {\n context.show();\n return;\n }\n\n context._timeout = setTimeout(function () {\n if (context._hoverState === HOVER_STATE_SHOW) {\n context.show();\n }\n }, context.config.delay.show);\n };\n\n _proto._leave = function _leave(event, context) {\n var dataKey = this.constructor.DATA_KEY;\n context = context || $__default[\"default\"](event.currentTarget).data(dataKey);\n\n if (!context) {\n context = new this.constructor(event.currentTarget, this._getDelegateConfig());\n $__default[\"default\"](event.currentTarget).data(dataKey, context);\n }\n\n if (event) {\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = false;\n }\n\n if (context._isWithActiveTrigger()) {\n return;\n }\n\n clearTimeout(context._timeout);\n context._hoverState = HOVER_STATE_OUT;\n\n if (!context.config.delay || !context.config.delay.hide) {\n context.hide();\n return;\n }\n\n context._timeout = setTimeout(function () {\n if (context._hoverState === HOVER_STATE_OUT) {\n context.hide();\n }\n }, context.config.delay.hide);\n };\n\n _proto._isWithActiveTrigger = function _isWithActiveTrigger() {\n for (var trigger in this._activeTrigger) {\n if (this._activeTrigger[trigger]) {\n return true;\n }\n }\n\n return false;\n };\n\n _proto._getConfig = function _getConfig(config) {\n var dataAttributes = $__default[\"default\"](this.element).data();\n Object.keys(dataAttributes).forEach(function (dataAttr) {\n if (DISALLOWED_ATTRIBUTES.indexOf(dataAttr) !== -1) {\n delete dataAttributes[dataAttr];\n }\n });\n config = _extends({}, this.constructor.Default, dataAttributes, typeof config === 'object' && config ? config : {});\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n };\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString();\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString();\n }\n\n Util.typeCheckConfig(NAME$4, config, this.constructor.DefaultType);\n\n if (config.sanitize) {\n config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn);\n }\n\n return config;\n };\n\n _proto._getDelegateConfig = function _getDelegateConfig() {\n var config = {};\n\n if (this.config) {\n for (var key in this.config) {\n if (this.constructor.Default[key] !== this.config[key]) {\n config[key] = this.config[key];\n }\n }\n }\n\n return config;\n };\n\n _proto._cleanTipClass = function _cleanTipClass() {\n var $tip = $__default[\"default\"](this.getTipElement());\n var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX$1);\n\n if (tabClass !== null && tabClass.length) {\n $tip.removeClass(tabClass.join(''));\n }\n };\n\n _proto._handlePopperPlacementChange = function _handlePopperPlacementChange(popperData) {\n this.tip = popperData.instance.popper;\n\n this._cleanTipClass();\n\n this.addAttachmentClass(this._getAttachment(popperData.placement));\n };\n\n _proto._fixTransition = function _fixTransition() {\n var tip = this.getTipElement();\n var initConfigAnimation = this.config.animation;\n\n if (tip.getAttribute('x-placement') !== null) {\n return;\n }\n\n $__default[\"default\"](tip).removeClass(CLASS_NAME_FADE$3);\n this.config.animation = false;\n this.hide();\n this.show();\n this.config.animation = initConfigAnimation;\n } // Static\n ;\n\n Tooltip._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var $element = $__default[\"default\"](this);\n var data = $element.data(DATA_KEY$4);\n\n var _config = typeof config === 'object' && config;\n\n if (!data && /dispose|hide/.test(config)) {\n return;\n }\n\n if (!data) {\n data = new Tooltip(this, _config);\n $element.data(DATA_KEY$4, data);\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n }\n\n data[config]();\n }\n });\n };\n\n _createClass(Tooltip, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION$4;\n }\n }, {\n key: \"Default\",\n get: function get() {\n return Default$3;\n }\n }, {\n key: \"NAME\",\n get: function get() {\n return NAME$4;\n }\n }, {\n key: \"DATA_KEY\",\n get: function get() {\n return DATA_KEY$4;\n }\n }, {\n key: \"Event\",\n get: function get() {\n return Event$1;\n }\n }, {\n key: \"EVENT_KEY\",\n get: function get() {\n return EVENT_KEY$4;\n }\n }, {\n key: \"DefaultType\",\n get: function get() {\n return DefaultType$3;\n }\n }]);\n\n return Tooltip;\n }();\n /**\n * jQuery\n */\n\n\n $__default[\"default\"].fn[NAME$4] = Tooltip._jQueryInterface;\n $__default[\"default\"].fn[NAME$4].Constructor = Tooltip;\n\n $__default[\"default\"].fn[NAME$4].noConflict = function () {\n $__default[\"default\"].fn[NAME$4] = JQUERY_NO_CONFLICT$4;\n return Tooltip._jQueryInterface;\n };\n\n /**\n * Constants\n */\n\n var NAME$3 = 'popover';\n var VERSION$3 = '4.6.1';\n var DATA_KEY$3 = 'bs.popover';\n var EVENT_KEY$3 = \".\" + DATA_KEY$3;\n var JQUERY_NO_CONFLICT$3 = $__default[\"default\"].fn[NAME$3];\n var CLASS_PREFIX = 'bs-popover';\n var BSCLS_PREFIX_REGEX = new RegExp(\"(^|\\\\s)\" + CLASS_PREFIX + \"\\\\S+\", 'g');\n var CLASS_NAME_FADE$2 = 'fade';\n var CLASS_NAME_SHOW$2 = 'show';\n var SELECTOR_TITLE = '.popover-header';\n var SELECTOR_CONTENT = '.popover-body';\n\n var Default$2 = _extends({}, Tooltip.Default, {\n placement: 'right',\n trigger: 'click',\n content: '',\n template: '<div class=\"popover\" role=\"tooltip\">' + '<div class=\"arrow\"></div>' + '<h3 class=\"popover-header\"></h3>' + '<div class=\"popover-body\"></div></div>'\n });\n\n var DefaultType$2 = _extends({}, Tooltip.DefaultType, {\n content: '(string|element|function)'\n });\n\n var Event = {\n HIDE: \"hide\" + EVENT_KEY$3,\n HIDDEN: \"hidden\" + EVENT_KEY$3,\n SHOW: \"show\" + EVENT_KEY$3,\n SHOWN: \"shown\" + EVENT_KEY$3,\n INSERTED: \"inserted\" + EVENT_KEY$3,\n CLICK: \"click\" + EVENT_KEY$3,\n FOCUSIN: \"focusin\" + EVENT_KEY$3,\n FOCUSOUT: \"focusout\" + EVENT_KEY$3,\n MOUSEENTER: \"mouseenter\" + EVENT_KEY$3,\n MOUSELEAVE: \"mouseleave\" + EVENT_KEY$3\n };\n /**\n * Class definition\n */\n\n var Popover = /*#__PURE__*/function (_Tooltip) {\n _inheritsLoose(Popover, _Tooltip);\n\n function Popover() {\n return _Tooltip.apply(this, arguments) || this;\n }\n\n var _proto = Popover.prototype;\n\n // Overrides\n _proto.isWithContent = function isWithContent() {\n return this.getTitle() || this._getContent();\n };\n\n _proto.addAttachmentClass = function addAttachmentClass(attachment) {\n $__default[\"default\"](this.getTipElement()).addClass(CLASS_PREFIX + \"-\" + attachment);\n };\n\n _proto.getTipElement = function getTipElement() {\n this.tip = this.tip || $__default[\"default\"](this.config.template)[0];\n return this.tip;\n };\n\n _proto.setContent = function setContent() {\n var $tip = $__default[\"default\"](this.getTipElement()); // We use append for html objects to maintain js events\n\n this.setElementContent($tip.find(SELECTOR_TITLE), this.getTitle());\n\n var content = this._getContent();\n\n if (typeof content === 'function') {\n content = content.call(this.element);\n }\n\n this.setElementContent($tip.find(SELECTOR_CONTENT), content);\n $tip.removeClass(CLASS_NAME_FADE$2 + \" \" + CLASS_NAME_SHOW$2);\n } // Private\n ;\n\n _proto._getContent = function _getContent() {\n return this.element.getAttribute('data-content') || this.config.content;\n };\n\n _proto._cleanTipClass = function _cleanTipClass() {\n var $tip = $__default[\"default\"](this.getTipElement());\n var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);\n\n if (tabClass !== null && tabClass.length > 0) {\n $tip.removeClass(tabClass.join(''));\n }\n } // Static\n ;\n\n Popover._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var data = $__default[\"default\"](this).data(DATA_KEY$3);\n\n var _config = typeof config === 'object' ? config : null;\n\n if (!data && /dispose|hide/.test(config)) {\n return;\n }\n\n if (!data) {\n data = new Popover(this, _config);\n $__default[\"default\"](this).data(DATA_KEY$3, data);\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n }\n\n data[config]();\n }\n });\n };\n\n _createClass(Popover, null, [{\n key: \"VERSION\",\n get: // Getters\n function get() {\n return VERSION$3;\n }\n }, {\n key: \"Default\",\n get: function get() {\n return Default$2;\n }\n }, {\n key: \"NAME\",\n get: function get() {\n return NAME$3;\n }\n }, {\n key: \"DATA_KEY\",\n get: function get() {\n return DATA_KEY$3;\n }\n }, {\n key: \"Event\",\n get: function get() {\n return Event;\n }\n }, {\n key: \"EVENT_KEY\",\n get: function get() {\n return EVENT_KEY$3;\n }\n }, {\n key: \"DefaultType\",\n get: function get() {\n return DefaultType$2;\n }\n }]);\n\n return Popover;\n }(Tooltip);\n /**\n * jQuery\n */\n\n\n $__default[\"default\"].fn[NAME$3] = Popover._jQueryInterface;\n $__default[\"default\"].fn[NAME$3].Constructor = Popover;\n\n $__default[\"default\"].fn[NAME$3].noConflict = function () {\n $__default[\"default\"].fn[NAME$3] = JQUERY_NO_CONFLICT$3;\n return Popover._jQueryInterface;\n };\n\n /**\n * Constants\n */\n\n var NAME$2 = 'scrollspy';\n var VERSION$2 = '4.6.1';\n var DATA_KEY$2 = 'bs.scrollspy';\n var EVENT_KEY$2 = \".\" + DATA_KEY$2;\n var DATA_API_KEY$1 = '.data-api';\n var JQUERY_NO_CONFLICT$2 = $__default[\"default\"].fn[NAME$2];\n var CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item';\n var CLASS_NAME_ACTIVE$1 = 'active';\n var EVENT_ACTIVATE = \"activate\" + EVENT_KEY$2;\n var EVENT_SCROLL = \"scroll\" + EVENT_KEY$2;\n var EVENT_LOAD_DATA_API = \"load\" + EVENT_KEY$2 + DATA_API_KEY$1;\n var METHOD_OFFSET = 'offset';\n var METHOD_POSITION = 'position';\n var SELECTOR_DATA_SPY = '[data-spy=\"scroll\"]';\n var SELECTOR_NAV_LIST_GROUP$1 = '.nav, .list-group';\n var SELECTOR_NAV_LINKS = '.nav-link';\n var SELECTOR_NAV_ITEMS = '.nav-item';\n var SELECTOR_LIST_ITEMS = '.list-group-item';\n var SELECTOR_DROPDOWN$1 = '.dropdown';\n var SELECTOR_DROPDOWN_ITEMS = '.dropdown-item';\n var SELECTOR_DROPDOWN_TOGGLE$1 = '.dropdown-toggle';\n var Default$1 = {\n offset: 10,\n method: 'auto',\n target: ''\n };\n var DefaultType$1 = {\n offset: 'number',\n method: 'string',\n target: '(string|element)'\n };\n /**\n * Class definition\n */\n\n var ScrollSpy = /*#__PURE__*/function () {\n function ScrollSpy(element, config) {\n var _this = this;\n\n this._element = element;\n this._scrollElement = element.tagName === 'BODY' ? window : element;\n this._config = this._getConfig(config);\n this._selector = this._config.target + \" \" + SELECTOR_NAV_LINKS + \",\" + (this._config.target + \" \" + SELECTOR_LIST_ITEMS + \",\") + (this._config.target + \" \" + SELECTOR_DROPDOWN_ITEMS);\n this._offsets = [];\n this._targets = [];\n this._activeTarget = null;\n this._scrollHeight = 0;\n $__default[\"default\"](this._scrollElement).on(EVENT_SCROLL, function (event) {\n return _this._process(event);\n });\n this.refresh();\n\n this._process();\n } // Getters\n\n\n var _proto = ScrollSpy.prototype;\n\n // Public\n _proto.refresh = function refresh() {\n var _this2 = this;\n\n var autoMethod = this._scrollElement === this._scrollElement.window ? METHOD_OFFSET : METHOD_POSITION;\n var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;\n var offsetBase = offsetMethod === METHOD_POSITION ? this._getScrollTop() : 0;\n this._offsets = [];\n this._targets = [];\n this._scrollHeight = this._getScrollHeight();\n var targets = [].slice.call(document.querySelectorAll(this._selector));\n targets.map(function (element) {\n var target;\n var targetSelector = Util.getSelectorFromElement(element);\n\n if (targetSelector) {\n target = document.querySelector(targetSelector);\n }\n\n if (target) {\n var targetBCR = target.getBoundingClientRect();\n\n if (targetBCR.width || targetBCR.height) {\n // TODO (fat): remove sketch reliance on jQuery position/offset\n return [$__default[\"default\"](target)[offsetMethod]().top + offsetBase, targetSelector];\n }\n }\n\n return null;\n }).filter(function (item) {\n return item;\n }).sort(function (a, b) {\n return a[0] - b[0];\n }).forEach(function (item) {\n _this2._offsets.push(item[0]);\n\n _this2._targets.push(item[1]);\n });\n };\n\n _proto.dispose = function dispose() {\n $__default[\"default\"].removeData(this._element, DATA_KEY$2);\n $__default[\"default\"](this._scrollElement).off(EVENT_KEY$2);\n this._element = null;\n this._scrollElement = null;\n this._config = null;\n this._selector = null;\n this._offsets = null;\n this._targets = null;\n this._activeTarget = null;\n this._scrollHeight = null;\n } // Private\n ;\n\n _proto._getConfig = function _getConfig(config) {\n config = _extends({}, Default$1, typeof config === 'object' && config ? config : {});\n\n if (typeof config.target !== 'string' && Util.isElement(config.target)) {\n var id = $__default[\"default\"](config.target).attr('id');\n\n if (!id) {\n id = Util.getUID(NAME$2);\n $__default[\"default\"](config.target).attr('id', id);\n }\n\n config.target = \"#\" + id;\n }\n\n Util.typeCheckConfig(NAME$2, config, DefaultType$1);\n return config;\n };\n\n _proto._getScrollTop = function _getScrollTop() {\n return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop;\n };\n\n _proto._getScrollHeight = function _getScrollHeight() {\n return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);\n };\n\n _proto._getOffsetHeight = function _getOffsetHeight() {\n return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height;\n };\n\n _proto._process = function _process() {\n var scrollTop = this._getScrollTop() + this._config.offset;\n\n var scrollHeight = this._getScrollHeight();\n\n var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();\n\n if (this._scrollHeight !== scrollHeight) {\n this.refresh();\n }\n\n if (scrollTop >= maxScroll) {\n var target = this._targets[this._targets.length - 1];\n\n if (this._activeTarget !== target) {\n this._activate(target);\n }\n\n return;\n }\n\n if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {\n this._activeTarget = null;\n\n this._clear();\n\n return;\n }\n\n for (var i = this._offsets.length; i--;) {\n var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]);\n\n if (isActiveTarget) {\n this._activate(this._targets[i]);\n }\n }\n };\n\n _proto._activate = function _activate(target) {\n this._activeTarget = target;\n\n this._clear();\n\n var queries = this._selector.split(',').map(function (selector) {\n return selector + \"[data-target=\\\"\" + target + \"\\\"],\" + selector + \"[href=\\\"\" + target + \"\\\"]\";\n });\n\n var $link = $__default[\"default\"]([].slice.call(document.querySelectorAll(queries.join(','))));\n\n if ($link.hasClass(CLASS_NAME_DROPDOWN_ITEM)) {\n $link.closest(SELECTOR_DROPDOWN$1).find(SELECTOR_DROPDOWN_TOGGLE$1).addClass(CLASS_NAME_ACTIVE$1);\n $link.addClass(CLASS_NAME_ACTIVE$1);\n } else {\n // Set triggered link as active\n $link.addClass(CLASS_NAME_ACTIVE$1); // Set triggered links parents as active\n // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n\n $link.parents(SELECTOR_NAV_LIST_GROUP$1).prev(SELECTOR_NAV_LINKS + \", \" + SELECTOR_LIST_ITEMS).addClass(CLASS_NAME_ACTIVE$1); // Handle special case when .nav-link is inside .nav-item\n\n $link.parents(SELECTOR_NAV_LIST_GROUP$1).prev(SELECTOR_NAV_ITEMS).children(SELECTOR_NAV_LINKS).addClass(CLASS_NAME_ACTIVE$1);\n }\n\n $__default[\"default\"](this._scrollElement).trigger(EVENT_ACTIVATE, {\n relatedTarget: target\n });\n };\n\n _proto._clear = function _clear() {\n [].slice.call(document.querySelectorAll(this._selector)).filter(function (node) {\n return node.classList.contains(CLASS_NAME_ACTIVE$1);\n }).forEach(function (node) {\n return node.classList.remove(CLASS_NAME_ACTIVE$1);\n });\n } // Static\n ;\n\n ScrollSpy._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var data = $__default[\"default\"](this).data(DATA_KEY$2);\n\n var _config = typeof config === 'object' && config;\n\n if (!data) {\n data = new ScrollSpy(this, _config);\n $__default[\"default\"](this).data(DATA_KEY$2, data);\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n }\n\n data[config]();\n }\n });\n };\n\n _createClass(ScrollSpy, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION$2;\n }\n }, {\n key: \"Default\",\n get: function get() {\n return Default$1;\n }\n }]);\n\n return ScrollSpy;\n }();\n /**\n * Data API implementation\n */\n\n\n $__default[\"default\"](window).on(EVENT_LOAD_DATA_API, function () {\n var scrollSpys = [].slice.call(document.querySelectorAll(SELECTOR_DATA_SPY));\n var scrollSpysLength = scrollSpys.length;\n\n for (var i = scrollSpysLength; i--;) {\n var $spy = $__default[\"default\"](scrollSpys[i]);\n\n ScrollSpy._jQueryInterface.call($spy, $spy.data());\n }\n });\n /**\n * jQuery\n */\n\n $__default[\"default\"].fn[NAME$2] = ScrollSpy._jQueryInterface;\n $__default[\"default\"].fn[NAME$2].Constructor = ScrollSpy;\n\n $__default[\"default\"].fn[NAME$2].noConflict = function () {\n $__default[\"default\"].fn[NAME$2] = JQUERY_NO_CONFLICT$2;\n return ScrollSpy._jQueryInterface;\n };\n\n /**\n * Constants\n */\n\n var NAME$1 = 'tab';\n var VERSION$1 = '4.6.1';\n var DATA_KEY$1 = 'bs.tab';\n var EVENT_KEY$1 = \".\" + DATA_KEY$1;\n var DATA_API_KEY = '.data-api';\n var JQUERY_NO_CONFLICT$1 = $__default[\"default\"].fn[NAME$1];\n var CLASS_NAME_DROPDOWN_MENU = 'dropdown-menu';\n var CLASS_NAME_ACTIVE = 'active';\n var CLASS_NAME_DISABLED = 'disabled';\n var CLASS_NAME_FADE$1 = 'fade';\n var CLASS_NAME_SHOW$1 = 'show';\n var EVENT_HIDE$1 = \"hide\" + EVENT_KEY$1;\n var EVENT_HIDDEN$1 = \"hidden\" + EVENT_KEY$1;\n var EVENT_SHOW$1 = \"show\" + EVENT_KEY$1;\n var EVENT_SHOWN$1 = \"shown\" + EVENT_KEY$1;\n var EVENT_CLICK_DATA_API = \"click\" + EVENT_KEY$1 + DATA_API_KEY;\n var SELECTOR_DROPDOWN = '.dropdown';\n var SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';\n var SELECTOR_ACTIVE = '.active';\n var SELECTOR_ACTIVE_UL = '> li > .active';\n var SELECTOR_DATA_TOGGLE = '[data-toggle=\"tab\"], [data-toggle=\"pill\"], [data-toggle=\"list\"]';\n var SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';\n var SELECTOR_DROPDOWN_ACTIVE_CHILD = '> .dropdown-menu .active';\n /**\n * Class definition\n */\n\n var Tab = /*#__PURE__*/function () {\n function Tab(element) {\n this._element = element;\n } // Getters\n\n\n var _proto = Tab.prototype;\n\n // Public\n _proto.show = function show() {\n var _this = this;\n\n if (this._element.parentNode && this._element.parentNode.nodeType === Node.ELEMENT_NODE && $__default[\"default\"](this._element).hasClass(CLASS_NAME_ACTIVE) || $__default[\"default\"](this._element).hasClass(CLASS_NAME_DISABLED)) {\n return;\n }\n\n var target;\n var previous;\n var listElement = $__default[\"default\"](this._element).closest(SELECTOR_NAV_LIST_GROUP)[0];\n var selector = Util.getSelectorFromElement(this._element);\n\n if (listElement) {\n var itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? SELECTOR_ACTIVE_UL : SELECTOR_ACTIVE;\n previous = $__default[\"default\"].makeArray($__default[\"default\"](listElement).find(itemSelector));\n previous = previous[previous.length - 1];\n }\n\n var hideEvent = $__default[\"default\"].Event(EVENT_HIDE$1, {\n relatedTarget: this._element\n });\n var showEvent = $__default[\"default\"].Event(EVENT_SHOW$1, {\n relatedTarget: previous\n });\n\n if (previous) {\n $__default[\"default\"](previous).trigger(hideEvent);\n }\n\n $__default[\"default\"](this._element).trigger(showEvent);\n\n if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) {\n return;\n }\n\n if (selector) {\n target = document.querySelector(selector);\n }\n\n this._activate(this._element, listElement);\n\n var complete = function complete() {\n var hiddenEvent = $__default[\"default\"].Event(EVENT_HIDDEN$1, {\n relatedTarget: _this._element\n });\n var shownEvent = $__default[\"default\"].Event(EVENT_SHOWN$1, {\n relatedTarget: previous\n });\n $__default[\"default\"](previous).trigger(hiddenEvent);\n $__default[\"default\"](_this._element).trigger(shownEvent);\n };\n\n if (target) {\n this._activate(target, target.parentNode, complete);\n } else {\n complete();\n }\n };\n\n _proto.dispose = function dispose() {\n $__default[\"default\"].removeData(this._element, DATA_KEY$1);\n this._element = null;\n } // Private\n ;\n\n _proto._activate = function _activate(element, container, callback) {\n var _this2 = this;\n\n var activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ? $__default[\"default\"](container).find(SELECTOR_ACTIVE_UL) : $__default[\"default\"](container).children(SELECTOR_ACTIVE);\n var active = activeElements[0];\n var isTransitioning = callback && active && $__default[\"default\"](active).hasClass(CLASS_NAME_FADE$1);\n\n var complete = function complete() {\n return _this2._transitionComplete(element, active, callback);\n };\n\n if (active && isTransitioning) {\n var transitionDuration = Util.getTransitionDurationFromElement(active);\n $__default[\"default\"](active).removeClass(CLASS_NAME_SHOW$1).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n } else {\n complete();\n }\n };\n\n _proto._transitionComplete = function _transitionComplete(element, active, callback) {\n if (active) {\n $__default[\"default\"](active).removeClass(CLASS_NAME_ACTIVE);\n var dropdownChild = $__default[\"default\"](active.parentNode).find(SELECTOR_DROPDOWN_ACTIVE_CHILD)[0];\n\n if (dropdownChild) {\n $__default[\"default\"](dropdownChild).removeClass(CLASS_NAME_ACTIVE);\n }\n\n if (active.getAttribute('role') === 'tab') {\n active.setAttribute('aria-selected', false);\n }\n }\n\n $__default[\"default\"](element).addClass(CLASS_NAME_ACTIVE);\n\n if (element.getAttribute('role') === 'tab') {\n element.setAttribute('aria-selected', true);\n }\n\n Util.reflow(element);\n\n if (element.classList.contains(CLASS_NAME_FADE$1)) {\n element.classList.add(CLASS_NAME_SHOW$1);\n }\n\n var parent = element.parentNode;\n\n if (parent && parent.nodeName === 'LI') {\n parent = parent.parentNode;\n }\n\n if (parent && $__default[\"default\"](parent).hasClass(CLASS_NAME_DROPDOWN_MENU)) {\n var dropdownElement = $__default[\"default\"](element).closest(SELECTOR_DROPDOWN)[0];\n\n if (dropdownElement) {\n var dropdownToggleList = [].slice.call(dropdownElement.querySelectorAll(SELECTOR_DROPDOWN_TOGGLE));\n $__default[\"default\"](dropdownToggleList).addClass(CLASS_NAME_ACTIVE);\n }\n\n element.setAttribute('aria-expanded', true);\n }\n\n if (callback) {\n callback();\n }\n } // Static\n ;\n\n Tab._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var $this = $__default[\"default\"](this);\n var data = $this.data(DATA_KEY$1);\n\n if (!data) {\n data = new Tab(this);\n $this.data(DATA_KEY$1, data);\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n }\n\n data[config]();\n }\n });\n };\n\n _createClass(Tab, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION$1;\n }\n }]);\n\n return Tab;\n }();\n /**\n * Data API implementation\n */\n\n\n $__default[\"default\"](document).on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault();\n\n Tab._jQueryInterface.call($__default[\"default\"](this), 'show');\n });\n /**\n * jQuery\n */\n\n $__default[\"default\"].fn[NAME$1] = Tab._jQueryInterface;\n $__default[\"default\"].fn[NAME$1].Constructor = Tab;\n\n $__default[\"default\"].fn[NAME$1].noConflict = function () {\n $__default[\"default\"].fn[NAME$1] = JQUERY_NO_CONFLICT$1;\n return Tab._jQueryInterface;\n };\n\n /**\n * Constants\n */\n\n var NAME = 'toast';\n var VERSION = '4.6.1';\n var DATA_KEY = 'bs.toast';\n var EVENT_KEY = \".\" + DATA_KEY;\n var JQUERY_NO_CONFLICT = $__default[\"default\"].fn[NAME];\n var CLASS_NAME_FADE = 'fade';\n var CLASS_NAME_HIDE = 'hide';\n var CLASS_NAME_SHOW = 'show';\n var CLASS_NAME_SHOWING = 'showing';\n var EVENT_CLICK_DISMISS = \"click.dismiss\" + EVENT_KEY;\n var EVENT_HIDE = \"hide\" + EVENT_KEY;\n var EVENT_HIDDEN = \"hidden\" + EVENT_KEY;\n var EVENT_SHOW = \"show\" + EVENT_KEY;\n var EVENT_SHOWN = \"shown\" + EVENT_KEY;\n var SELECTOR_DATA_DISMISS = '[data-dismiss=\"toast\"]';\n var Default = {\n animation: true,\n autohide: true,\n delay: 500\n };\n var DefaultType = {\n animation: 'boolean',\n autohide: 'boolean',\n delay: 'number'\n };\n /**\n * Class definition\n */\n\n var Toast = /*#__PURE__*/function () {\n function Toast(element, config) {\n this._element = element;\n this._config = this._getConfig(config);\n this._timeout = null;\n\n this._setListeners();\n } // Getters\n\n\n var _proto = Toast.prototype;\n\n // Public\n _proto.show = function show() {\n var _this = this;\n\n var showEvent = $__default[\"default\"].Event(EVENT_SHOW);\n $__default[\"default\"](this._element).trigger(showEvent);\n\n if (showEvent.isDefaultPrevented()) {\n return;\n }\n\n this._clearTimeout();\n\n if (this._config.animation) {\n this._element.classList.add(CLASS_NAME_FADE);\n }\n\n var complete = function complete() {\n _this._element.classList.remove(CLASS_NAME_SHOWING);\n\n _this._element.classList.add(CLASS_NAME_SHOW);\n\n $__default[\"default\"](_this._element).trigger(EVENT_SHOWN);\n\n if (_this._config.autohide) {\n _this._timeout = setTimeout(function () {\n _this.hide();\n }, _this._config.delay);\n }\n };\n\n this._element.classList.remove(CLASS_NAME_HIDE);\n\n Util.reflow(this._element);\n\n this._element.classList.add(CLASS_NAME_SHOWING);\n\n if (this._config.animation) {\n var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n $__default[\"default\"](this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n } else {\n complete();\n }\n };\n\n _proto.hide = function hide() {\n if (!this._element.classList.contains(CLASS_NAME_SHOW)) {\n return;\n }\n\n var hideEvent = $__default[\"default\"].Event(EVENT_HIDE);\n $__default[\"default\"](this._element).trigger(hideEvent);\n\n if (hideEvent.isDefaultPrevented()) {\n return;\n }\n\n this._close();\n };\n\n _proto.dispose = function dispose() {\n this._clearTimeout();\n\n if (this._element.classList.contains(CLASS_NAME_SHOW)) {\n this._element.classList.remove(CLASS_NAME_SHOW);\n }\n\n $__default[\"default\"](this._element).off(EVENT_CLICK_DISMISS);\n $__default[\"default\"].removeData(this._element, DATA_KEY);\n this._element = null;\n this._config = null;\n } // Private\n ;\n\n _proto._getConfig = function _getConfig(config) {\n config = _extends({}, Default, $__default[\"default\"](this._element).data(), typeof config === 'object' && config ? config : {});\n Util.typeCheckConfig(NAME, config, this.constructor.DefaultType);\n return config;\n };\n\n _proto._setListeners = function _setListeners() {\n var _this2 = this;\n\n $__default[\"default\"](this._element).on(EVENT_CLICK_DISMISS, SELECTOR_DATA_DISMISS, function () {\n return _this2.hide();\n });\n };\n\n _proto._close = function _close() {\n var _this3 = this;\n\n var complete = function complete() {\n _this3._element.classList.add(CLASS_NAME_HIDE);\n\n $__default[\"default\"](_this3._element).trigger(EVENT_HIDDEN);\n };\n\n this._element.classList.remove(CLASS_NAME_SHOW);\n\n if (this._config.animation) {\n var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n $__default[\"default\"](this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n } else {\n complete();\n }\n };\n\n _proto._clearTimeout = function _clearTimeout() {\n clearTimeout(this._timeout);\n this._timeout = null;\n } // Static\n ;\n\n Toast._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var $element = $__default[\"default\"](this);\n var data = $element.data(DATA_KEY);\n\n var _config = typeof config === 'object' && config;\n\n if (!data) {\n data = new Toast(this, _config);\n $element.data(DATA_KEY, data);\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n }\n\n data[config](this);\n }\n });\n };\n\n _createClass(Toast, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION;\n }\n }, {\n key: \"DefaultType\",\n get: function get() {\n return DefaultType;\n }\n }, {\n key: \"Default\",\n get: function get() {\n return Default;\n }\n }]);\n\n return Toast;\n }();\n /**\n * jQuery\n */\n\n\n $__default[\"default\"].fn[NAME] = Toast._jQueryInterface;\n $__default[\"default\"].fn[NAME].Constructor = Toast;\n\n $__default[\"default\"].fn[NAME].noConflict = function () {\n $__default[\"default\"].fn[NAME] = JQUERY_NO_CONFLICT;\n return Toast._jQueryInterface;\n };\n\n exports.Alert = Alert;\n exports.Button = Button;\n exports.Carousel = Carousel;\n exports.Collapse = Collapse;\n exports.Dropdown = Dropdown;\n exports.Modal = Modal;\n exports.Popover = Popover;\n exports.Scrollspy = ScrollSpy;\n exports.Tab = Tab;\n exports.Toast = Toast;\n exports.Tooltip = Tooltip;\n exports.Util = Util;\n\n Object.defineProperty(exports, '__esModule', { value: true });\n\n}));\n//# sourceMappingURL=bootstrap.js.map\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvYm9vdHN0cmFwL2Rpc3QvanMvYm9vdHN0cmFwLmpzLmpzIiwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUUsS0FBNEQsb0JBQW9CLG1CQUFPLENBQUMsb0RBQVEsR0FBRyxtQkFBTyxDQUFDLDhEQUFXO0FBQ3hILEVBQUUsQ0FDd0k7QUFDMUksQ0FBQyx5Q0FBeUM7O0FBRTFDLHVDQUF1Qyw0REFBNEQ7O0FBRW5HO0FBQ0E7O0FBRUE7QUFDQSxvQkFBb0Isa0JBQWtCO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLHNCQUFzQixzQkFBc0I7QUFDNUM7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxzQ0FBc0M7O0FBRXRDO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGFBQWE7QUFDYjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpRUFBaUU7QUFDakU7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtDQUErQztBQUMvQyxRQUFROztBQUVSO0FBQ0EsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLFFBQVE7OztBQUdSO0FBQ0E7QUFDQTtBQUNBLDhEQUE4RDs7QUFFOUQ7QUFDQTtBQUNBLFFBQVE7OztBQUdSO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLFFBQVE7OztBQUdSO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxRQUFROzs7QUFHUjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxNQUFNOzs7QUFHTjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQSxNQUFNO0FBQ047O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNOzs7QUFHTjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSw4QkFBOEI7QUFDOUIsTUFBTTtBQUNOOztBQUVBO0FBQ0EsZ0NBQWdDOztBQUVoQztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsMENBQTBDLFNBQVM7QUFDbkQ7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQSxNQUFNOzs7QUFHTjs7QUFFQSw0Q0FBNEMsV0FBVztBQUN2RDs7QUFFQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0JBQStCOztBQUUvQixnQ0FBZ0M7O0FBRWhDLG9DQUFvQzs7QUFFcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLE1BQU07OztBQUdOOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDJEQUEyRDtBQUMzRDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjs7QUFFQTtBQUNBLDBCQUEwQjtBQUMxQjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSw0QkFBNEI7O0FBRTVCO0FBQ0E7QUFDQSxRQUFROzs7QUFHUjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxTQUFTO0FBQ1Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLFNBQVM7O0FBRVQ7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYLFNBQVM7QUFDVCxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047O0FBRUE7QUFDQTtBQUNBOztBQUVBLGlDQUFpQzs7QUFFakM7QUFDQSwrQkFBK0I7QUFDL0I7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSw4QkFBOEI7O0FBRTlCOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTs7QUFFQSw0Q0FBNEMsU0FBUztBQUNyRDs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsK0NBQStDLFNBQVM7QUFDeEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTOztBQUVUO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxNQUFNOzs7QUFHTjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsU0FBUzs7QUFFVDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0Esd0JBQXdCLHdCQUF3QjtBQUNoRDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047O0FBRUE7QUFDQSwwQkFBMEI7QUFDMUIsOENBQThDOztBQUU5QztBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLHNDQUFzQzs7QUFFdEM7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxpQ0FBaUMsZ0ZBQWdGOztBQUVqSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLO0FBQ0wsR0FBRztBQUNIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw2QkFBNkI7O0FBRTdCLDBCQUEwQjs7QUFFMUIsdUJBQXVCOztBQUV2Qiw2QkFBNkI7O0FBRTdCLCtCQUErQjs7QUFFL0Isb0NBQW9DOztBQUVwQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLE1BQU07OztBQUdOOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxRQUFROzs7QUFHUjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxVQUFVO0FBQ1YscURBQXFEOztBQUVyRDtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTs7O0FBR0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0EsMEJBQTBCO0FBQzFCO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0Esd0NBQXdDOztBQUV4QztBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0EsUUFBUTtBQUNSO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0Esb0NBQW9DO0FBQ3BDO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUzs7QUFFVDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHdCQUF3QjtBQUN4QixNQUFNO0FBQ047O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsNENBQTRDLFNBQVM7QUFDckQ7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFVBQVU7QUFDVjs7O0FBR0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsTUFBTTtBQUNOOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxHQUFHO0FBQ0g7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQjs7QUFFM0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07OztBQUdOOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsT0FBTzs7QUFFUDtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFRO0FBQ1I7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsTUFBTTtBQUNOOztBQUVBO0FBQ0EsMEJBQTBCO0FBQzFCO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsUUFBUTtBQUNSO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFRO0FBQ1I7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0EsU0FBUzs7QUFFVDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrRkFBK0Y7O0FBRS9GO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUyxHQUFHOztBQUVaO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUyxHQUFHOztBQUVaO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPLEdBQUc7O0FBRVY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU8sR0FBRzs7QUFFVjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxpQ0FBaUMsbUdBQW1HOztBQUVwSTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSx3RkFBd0Y7O0FBRXhGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQLEtBQUs7O0FBRUw7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHVJQUF1STs7QUFFdkk7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLLEdBQUc7O0FBRVIseUNBQXlDLFNBQVM7QUFDbEQ7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHdEQUF3RDs7QUFFeEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQSwyQ0FBMkMsU0FBUztBQUNwRDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7OztBQUdSO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMkJBQTJCOztBQUUzQjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxNQUFNOzs7QUFHTjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLHNFQUFzRTtBQUN0RTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsaUVBQWlFO0FBQ2pFOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLE1BQU07QUFDTjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3QjtBQUN4Qjs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxvQ0FBb0M7QUFDcEM7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWCxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQSxXQUFXO0FBQ1g7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxpQ0FBaUM7QUFDakM7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFRO0FBQ1I7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsMEJBQTBCLDhGQUE4Rjs7QUFFeEg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSw2QkFBNkI7QUFDN0I7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVILGlDQUFpQztBQUNqQztBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDhEQUE4RDs7QUFFOUQ7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxNQUFNO0FBQ047O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBOzs7QUFHQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQSxNQUFNOzs7QUFHTjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLE9BQU87QUFDUDtBQUNBLE9BQU87QUFDUDtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOOztBQUVBO0FBQ0EsMEJBQTBCLCtEQUErRDs7QUFFekY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSx5Q0FBeUMsSUFBSTtBQUM3Qzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLE9BQU87O0FBRVA7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0EsNkNBQTZDO0FBQzdDOztBQUVBLHNJQUFzSTs7QUFFdEk7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLE9BQU87QUFDUCxNQUFNO0FBQ047O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7O0FBRUEsbUNBQW1DLElBQUk7QUFDdkM7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxNQUFNOzs7QUFHTjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBOzs7QUFHQTtBQUNBOztBQUVBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsTUFBTTs7O0FBR047O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjs7QUFFQTtBQUNBLDBCQUEwQiwwR0FBMEc7QUFDcEk7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsaURBQWlELGFBQWE7O0FBRTlELENBQUM7QUFDRCIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9ib290c3RyYXAvZGlzdC9qcy9ib290c3RyYXAuanM/OTA5NSJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiFcbiAgKiBCb290c3RyYXAgdjQuNi4xIChodHRwczovL2dldGJvb3RzdHJhcC5jb20vKVxuICAqIENvcHlyaWdodCAyMDExLTIwMjEgVGhlIEJvb3RzdHJhcCBBdXRob3JzIChodHRwczovL2dpdGh1Yi5jb20vdHdicy9ib290c3RyYXAvZ3JhcGhzL2NvbnRyaWJ1dG9ycylcbiAgKiBMaWNlbnNlZCB1bmRlciBNSVQgKGh0dHBzOi8vZ2l0aHViLmNvbS90d2JzL2Jvb3RzdHJhcC9ibG9iL21haW4vTElDRU5TRSlcbiAgKi9cbihmdW5jdGlvbiAoZ2xvYmFsLCBmYWN0b3J5KSB7XG4gIHR5cGVvZiBleHBvcnRzID09PSAnb2JqZWN0JyAmJiB0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJyA/IGZhY3RvcnkoZXhwb3J0cywgcmVxdWlyZSgnanF1ZXJ5JyksIHJlcXVpcmUoJ3BvcHBlci5qcycpKSA6XG4gIHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCA/IGRlZmluZShbJ2V4cG9ydHMnLCAnanF1ZXJ5JywgJ3BvcHBlci5qcyddLCBmYWN0b3J5KSA6XG4gIChnbG9iYWwgPSB0eXBlb2YgZ2xvYmFsVGhpcyAhPT0gJ3VuZGVmaW5lZCcgPyBnbG9iYWxUaGlzIDogZ2xvYmFsIHx8IHNlbGYsIGZhY3RvcnkoZ2xvYmFsLmJvb3RzdHJhcCA9IHt9LCBnbG9iYWwualF1ZXJ5LCBnbG9iYWwuUG9wcGVyKSk7XG59KSh0aGlzLCAoZnVuY3Rpb24gKGV4cG9ydHMsICQsIFBvcHBlcikgeyAndXNlIHN0cmljdCc7XG5cbiAgZnVuY3Rpb24gX2ludGVyb3BEZWZhdWx0TGVnYWN5IChlKSB7IHJldHVybiBlICYmIHR5cGVvZiBlID09PSAnb2JqZWN0JyAmJiAnZGVmYXVsdCcgaW4gZSA/IGUgOiB7ICdkZWZhdWx0JzogZSB9OyB9XG5cbiAgdmFyICRfX2RlZmF1bHQgPSAvKiNfX1BVUkVfXyovX2ludGVyb3BEZWZhdWx0TGVnYWN5KCQpO1xuICB2YXIgUG9wcGVyX19kZWZhdWx0ID0gLyojX19QVVJFX18qL19pbnRlcm9wRGVmYXVsdExlZ2FjeShQb3BwZXIpO1xuXG4gIGZ1bmN0aW9uIF9kZWZpbmVQcm9wZXJ0aWVzKHRhcmdldCwgcHJvcHMpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHByb3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgZGVzY3JpcHRvciA9IHByb3BzW2ldO1xuICAgICAgZGVzY3JpcHRvci5lbnVtZXJhYmxlID0gZGVzY3JpcHRvci5lbnVtZXJhYmxlIHx8IGZhbHNlO1xuICAgICAgZGVzY3JpcHRvci5jb25maWd1cmFibGUgPSB0cnVlO1xuICAgICAgaWYgKFwidmFsdWVcIiBpbiBkZXNjcmlwdG9yKSBkZXNjcmlwdG9yLndyaXRhYmxlID0gdHJ1ZTtcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIGRlc2NyaXB0b3Iua2V5LCBkZXNjcmlwdG9yKTtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBfY3JlYXRlQ2xhc3MoQ29uc3RydWN0b3IsIHByb3RvUHJvcHMsIHN0YXRpY1Byb3BzKSB7XG4gICAgaWYgKHByb3RvUHJvcHMpIF9kZWZpbmVQcm9wZXJ0aWVzKENvbnN0cnVjdG9yLnByb3RvdHlwZSwgcHJvdG9Qcm9wcyk7XG4gICAgaWYgKHN0YXRpY1Byb3BzKSBfZGVmaW5lUHJvcGVydGllcyhDb25zdHJ1Y3Rvciwgc3RhdGljUHJvcHMpO1xuICAgIHJldHVybiBDb25zdHJ1Y3RvcjtcbiAgfVxuXG4gIGZ1bmN0aW9uIF9leHRlbmRzKCkge1xuICAgIF9leHRlbmRzID0gT2JqZWN0LmFzc2lnbiB8fCBmdW5jdGlvbiAodGFyZ2V0KSB7XG4gICAgICBmb3IgKHZhciBpID0gMTsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgc291cmNlID0gYXJndW1lbnRzW2ldO1xuXG4gICAgICAgIGZvciAodmFyIGtleSBpbiBzb3VyY2UpIHtcbiAgICAgICAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHNvdXJjZSwga2V5KSkge1xuICAgICAgICAgICAgdGFyZ2V0W2tleV0gPSBzb3VyY2Vba2V5XTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRhcmdldDtcbiAgICB9O1xuXG4gICAgcmV0dXJuIF9leHRlbmRzLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gIH1cblxuICBmdW5jdGlvbiBfaW5oZXJpdHNMb29zZShzdWJDbGFzcywgc3VwZXJDbGFzcykge1xuICAgIHN1YkNsYXNzLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoc3VwZXJDbGFzcy5wcm90b3R5cGUpO1xuICAgIHN1YkNsYXNzLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IHN1YkNsYXNzO1xuXG4gICAgX3NldFByb3RvdHlwZU9mKHN1YkNsYXNzLCBzdXBlckNsYXNzKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIF9zZXRQcm90b3R5cGVPZihvLCBwKSB7XG4gICAgX3NldFByb3RvdHlwZU9mID0gT2JqZWN0LnNldFByb3RvdHlwZU9mIHx8IGZ1bmN0aW9uIF9zZXRQcm90b3R5cGVPZihvLCBwKSB7XG4gICAgICBvLl9fcHJvdG9fXyA9IHA7XG4gICAgICByZXR1cm4gbztcbiAgICB9O1xuXG4gICAgcmV0dXJuIF9zZXRQcm90b3R5cGVPZihvLCBwKTtcbiAgfVxuXG4gIC8qKlxuICAgKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgKiBCb290c3RyYXAgKHY0LjYuMSk6IHV0aWwuanNcbiAgICogTGljZW5zZWQgdW5kZXIgTUlUIChodHRwczovL2dpdGh1Yi5jb20vdHdicy9ib290c3RyYXAvYmxvYi9tYWluL0xJQ0VOU0UpXG4gICAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAqL1xuICAvKipcbiAgICogUHJpdmF0ZSBUcmFuc2l0aW9uRW5kIEhlbHBlcnNcbiAgICovXG5cbiAgdmFyIFRSQU5TSVRJT05fRU5EID0gJ3RyYW5zaXRpb25lbmQnO1xuICB2YXIgTUFYX1VJRCA9IDEwMDAwMDA7XG4gIHZhciBNSUxMSVNFQ09ORFNfTVVMVElQTElFUiA9IDEwMDA7IC8vIFNob3V0b3V0IEFuZ3VzQ3JvbGwgKGh0dHBzOi8vZ29vLmdsL3B4d1FHcClcblxuICBmdW5jdGlvbiB0b1R5cGUob2JqKSB7XG4gICAgaWYgKG9iaiA9PT0gbnVsbCB8fCB0eXBlb2Ygb2JqID09PSAndW5kZWZpbmVkJykge1xuICAgICAgcmV0dXJuIFwiXCIgKyBvYmo7XG4gICAgfVxuXG4gICAgcmV0dXJuIHt9LnRvU3RyaW5nLmNhbGwob2JqKS5tYXRjaCgvXFxzKFthLXpdKykvaSlbMV0udG9Mb3dlckNhc2UoKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGdldFNwZWNpYWxUcmFuc2l0aW9uRW5kRXZlbnQoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGJpbmRUeXBlOiBUUkFOU0lUSU9OX0VORCxcbiAgICAgIGRlbGVnYXRlVHlwZTogVFJBTlNJVElPTl9FTkQsXG4gICAgICBoYW5kbGU6IGZ1bmN0aW9uIGhhbmRsZShldmVudCkge1xuICAgICAgICBpZiAoJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZXZlbnQudGFyZ2V0KS5pcyh0aGlzKSkge1xuICAgICAgICAgIHJldHVybiBldmVudC5oYW5kbGVPYmouaGFuZGxlci5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIHByZWZlci1yZXN0LXBhcmFtc1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgZnVuY3Rpb24gdHJhbnNpdGlvbkVuZEVtdWxhdG9yKGR1cmF0aW9uKSB7XG4gICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgIHZhciBjYWxsZWQgPSBmYWxzZTtcbiAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzKS5vbmUoVXRpbC5UUkFOU0lUSU9OX0VORCwgZnVuY3Rpb24gKCkge1xuICAgICAgY2FsbGVkID0gdHJ1ZTtcbiAgICB9KTtcbiAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgIGlmICghY2FsbGVkKSB7XG4gICAgICAgIFV0aWwudHJpZ2dlclRyYW5zaXRpb25FbmQoX3RoaXMpO1xuICAgICAgfVxuICAgIH0sIGR1cmF0aW9uKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGZ1bmN0aW9uIHNldFRyYW5zaXRpb25FbmRTdXBwb3J0KCkge1xuICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuLmVtdWxhdGVUcmFuc2l0aW9uRW5kID0gdHJhbnNpdGlvbkVuZEVtdWxhdG9yO1xuICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmV2ZW50LnNwZWNpYWxbVXRpbC5UUkFOU0lUSU9OX0VORF0gPSBnZXRTcGVjaWFsVHJhbnNpdGlvbkVuZEV2ZW50KCk7XG4gIH1cbiAgLyoqXG4gICAqIFB1YmxpYyBVdGlsIEFQSVxuICAgKi9cblxuXG4gIHZhciBVdGlsID0ge1xuICAgIFRSQU5TSVRJT05fRU5EOiAnYnNUcmFuc2l0aW9uRW5kJyxcbiAgICBnZXRVSUQ6IGZ1bmN0aW9uIGdldFVJRChwcmVmaXgpIHtcbiAgICAgIGRvIHtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWJpdHdpc2VcbiAgICAgICAgcHJlZml4ICs9IH5+KE1hdGgucmFuZG9tKCkgKiBNQVhfVUlEKTsgLy8gXCJ+flwiIGFjdHMgbGlrZSBhIGZhc3RlciBNYXRoLmZsb29yKCkgaGVyZVxuICAgICAgfSB3aGlsZSAoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQocHJlZml4KSk7XG5cbiAgICAgIHJldHVybiBwcmVmaXg7XG4gICAgfSxcbiAgICBnZXRTZWxlY3RvckZyb21FbGVtZW50OiBmdW5jdGlvbiBnZXRTZWxlY3RvckZyb21FbGVtZW50KGVsZW1lbnQpIHtcbiAgICAgIHZhciBzZWxlY3RvciA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXRhcmdldCcpO1xuXG4gICAgICBpZiAoIXNlbGVjdG9yIHx8IHNlbGVjdG9yID09PSAnIycpIHtcbiAgICAgICAgdmFyIGhyZWZBdHRyID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2hyZWYnKTtcbiAgICAgICAgc2VsZWN0b3IgPSBocmVmQXR0ciAmJiBocmVmQXR0ciAhPT0gJyMnID8gaHJlZkF0dHIudHJpbSgpIDogJyc7XG4gICAgICB9XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHNlbGVjdG9yKSA/IHNlbGVjdG9yIDogbnVsbDtcbiAgICAgIH0gY2F0Y2ggKF8pIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgfSxcbiAgICBnZXRUcmFuc2l0aW9uRHVyYXRpb25Gcm9tRWxlbWVudDogZnVuY3Rpb24gZ2V0VHJhbnNpdGlvbkR1cmF0aW9uRnJvbUVsZW1lbnQoZWxlbWVudCkge1xuICAgICAgaWYgKCFlbGVtZW50KSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgfSAvLyBHZXQgdHJhbnNpdGlvbi1kdXJhdGlvbiBvZiB0aGUgZWxlbWVudFxuXG5cbiAgICAgIHZhciB0cmFuc2l0aW9uRHVyYXRpb24gPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShlbGVtZW50KS5jc3MoJ3RyYW5zaXRpb24tZHVyYXRpb24nKTtcbiAgICAgIHZhciB0cmFuc2l0aW9uRGVsYXkgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShlbGVtZW50KS5jc3MoJ3RyYW5zaXRpb24tZGVsYXknKTtcbiAgICAgIHZhciBmbG9hdFRyYW5zaXRpb25EdXJhdGlvbiA9IHBhcnNlRmxvYXQodHJhbnNpdGlvbkR1cmF0aW9uKTtcbiAgICAgIHZhciBmbG9hdFRyYW5zaXRpb25EZWxheSA9IHBhcnNlRmxvYXQodHJhbnNpdGlvbkRlbGF5KTsgLy8gUmV0dXJuIDAgaWYgZWxlbWVudCBvciB0cmFuc2l0aW9uIGR1cmF0aW9uIGlzIG5vdCBmb3VuZFxuXG4gICAgICBpZiAoIWZsb2F0VHJhbnNpdGlvbkR1cmF0aW9uICYmICFmbG9hdFRyYW5zaXRpb25EZWxheSkge1xuICAgICAgICByZXR1cm4gMDtcbiAgICAgIH0gLy8gSWYgbXVsdGlwbGUgZHVyYXRpb25zIGFyZSBkZWZpbmVkLCB0YWtlIHRoZSBmaXJzdFxuXG5cbiAgICAgIHRyYW5zaXRpb25EdXJhdGlvbiA9IHRyYW5zaXRpb25EdXJhdGlvbi5zcGxpdCgnLCcpWzBdO1xuICAgICAgdHJhbnNpdGlvbkRlbGF5ID0gdHJhbnNpdGlvbkRlbGF5LnNwbGl0KCcsJylbMF07XG4gICAgICByZXR1cm4gKHBhcnNlRmxvYXQodHJhbnNpdGlvbkR1cmF0aW9uKSArIHBhcnNlRmxvYXQodHJhbnNpdGlvbkRlbGF5KSkgKiBNSUxMSVNFQ09ORFNfTVVMVElQTElFUjtcbiAgICB9LFxuICAgIHJlZmxvdzogZnVuY3Rpb24gcmVmbG93KGVsZW1lbnQpIHtcbiAgICAgIHJldHVybiBlbGVtZW50Lm9mZnNldEhlaWdodDtcbiAgICB9LFxuICAgIHRyaWdnZXJUcmFuc2l0aW9uRW5kOiBmdW5jdGlvbiB0cmlnZ2VyVHJhbnNpdGlvbkVuZChlbGVtZW50KSB7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShlbGVtZW50KS50cmlnZ2VyKFRSQU5TSVRJT05fRU5EKTtcbiAgICB9LFxuICAgIHN1cHBvcnRzVHJhbnNpdGlvbkVuZDogZnVuY3Rpb24gc3VwcG9ydHNUcmFuc2l0aW9uRW5kKCkge1xuICAgICAgcmV0dXJuIEJvb2xlYW4oVFJBTlNJVElPTl9FTkQpO1xuICAgIH0sXG4gICAgaXNFbGVtZW50OiBmdW5jdGlvbiBpc0VsZW1lbnQob2JqKSB7XG4gICAgICByZXR1cm4gKG9ialswXSB8fCBvYmopLm5vZGVUeXBlO1xuICAgIH0sXG4gICAgdHlwZUNoZWNrQ29uZmlnOiBmdW5jdGlvbiB0eXBlQ2hlY2tDb25maWcoY29tcG9uZW50TmFtZSwgY29uZmlnLCBjb25maWdUeXBlcykge1xuICAgICAgZm9yICh2YXIgcHJvcGVydHkgaW4gY29uZmlnVHlwZXMpIHtcbiAgICAgICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChjb25maWdUeXBlcywgcHJvcGVydHkpKSB7XG4gICAgICAgICAgdmFyIGV4cGVjdGVkVHlwZXMgPSBjb25maWdUeXBlc1twcm9wZXJ0eV07XG4gICAgICAgICAgdmFyIHZhbHVlID0gY29uZmlnW3Byb3BlcnR5XTtcbiAgICAgICAgICB2YXIgdmFsdWVUeXBlID0gdmFsdWUgJiYgVXRpbC5pc0VsZW1lbnQodmFsdWUpID8gJ2VsZW1lbnQnIDogdG9UeXBlKHZhbHVlKTtcblxuICAgICAgICAgIGlmICghbmV3IFJlZ0V4cChleHBlY3RlZFR5cGVzKS50ZXN0KHZhbHVlVHlwZSkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihjb21wb25lbnROYW1lLnRvVXBwZXJDYXNlKCkgKyBcIjogXCIgKyAoXCJPcHRpb24gXFxcIlwiICsgcHJvcGVydHkgKyBcIlxcXCIgcHJvdmlkZWQgdHlwZSBcXFwiXCIgKyB2YWx1ZVR5cGUgKyBcIlxcXCIgXCIpICsgKFwiYnV0IGV4cGVjdGVkIHR5cGUgXFxcIlwiICsgZXhwZWN0ZWRUeXBlcyArIFwiXFxcIi5cIikpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gICAgZmluZFNoYWRvd1Jvb3Q6IGZ1bmN0aW9uIGZpbmRTaGFkb3dSb290KGVsZW1lbnQpIHtcbiAgICAgIGlmICghZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmF0dGFjaFNoYWRvdykge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH0gLy8gQ2FuIGZpbmQgdGhlIHNoYWRvdyByb290IG90aGVyd2lzZSBpdCdsbCByZXR1cm4gdGhlIGRvY3VtZW50XG5cblxuICAgICAgaWYgKHR5cGVvZiBlbGVtZW50LmdldFJvb3ROb2RlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHZhciByb290ID0gZWxlbWVudC5nZXRSb290Tm9kZSgpO1xuICAgICAgICByZXR1cm4gcm9vdCBpbnN0YW5jZW9mIFNoYWRvd1Jvb3QgPyByb290IDogbnVsbDtcbiAgICAgIH1cblxuICAgICAgaWYgKGVsZW1lbnQgaW5zdGFuY2VvZiBTaGFkb3dSb290KSB7XG4gICAgICAgIHJldHVybiBlbGVtZW50O1xuICAgICAgfSAvLyB3aGVuIHdlIGRvbid0IGZpbmQgYSBzaGFkb3cgcm9vdFxuXG5cbiAgICAgIGlmICghZWxlbWVudC5wYXJlbnROb2RlKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gVXRpbC5maW5kU2hhZG93Um9vdChlbGVtZW50LnBhcmVudE5vZGUpO1xuICAgIH0sXG4gICAgalF1ZXJ5RGV0ZWN0aW9uOiBmdW5jdGlvbiBqUXVlcnlEZXRlY3Rpb24oKSB7XG4gICAgICBpZiAodHlwZW9mICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdCb290c3RyYXBcXCdzIEphdmFTY3JpcHQgcmVxdWlyZXMgalF1ZXJ5LiBqUXVlcnkgbXVzdCBiZSBpbmNsdWRlZCBiZWZvcmUgQm9vdHN0cmFwXFwncyBKYXZhU2NyaXB0LicpO1xuICAgICAgfVxuXG4gICAgICB2YXIgdmVyc2lvbiA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuLmpxdWVyeS5zcGxpdCgnICcpWzBdLnNwbGl0KCcuJyk7XG4gICAgICB2YXIgbWluTWFqb3IgPSAxO1xuICAgICAgdmFyIGx0TWFqb3IgPSAyO1xuICAgICAgdmFyIG1pbk1pbm9yID0gOTtcbiAgICAgIHZhciBtaW5QYXRjaCA9IDE7XG4gICAgICB2YXIgbWF4TWFqb3IgPSA0O1xuXG4gICAgICBpZiAodmVyc2lvblswXSA8IGx0TWFqb3IgJiYgdmVyc2lvblsxXSA8IG1pbk1pbm9yIHx8IHZlcnNpb25bMF0gPT09IG1pbk1ham9yICYmIHZlcnNpb25bMV0gPT09IG1pbk1pbm9yICYmIHZlcnNpb25bMl0gPCBtaW5QYXRjaCB8fCB2ZXJzaW9uWzBdID49IG1heE1ham9yKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQm9vdHN0cmFwXFwncyBKYXZhU2NyaXB0IHJlcXVpcmVzIGF0IGxlYXN0IGpRdWVyeSB2MS45LjEgYnV0IGxlc3MgdGhhbiB2NC4wLjAnKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG4gIFV0aWwualF1ZXJ5RGV0ZWN0aW9uKCk7XG4gIHNldFRyYW5zaXRpb25FbmRTdXBwb3J0KCk7XG5cbiAgLyoqXG4gICAqIENvbnN0YW50c1xuICAgKi9cblxuICB2YXIgTkFNRSRhID0gJ2FsZXJ0JztcbiAgdmFyIFZFUlNJT04kYSA9ICc0LjYuMSc7XG4gIHZhciBEQVRBX0tFWSRhID0gJ2JzLmFsZXJ0JztcbiAgdmFyIEVWRU5UX0tFWSRhID0gXCIuXCIgKyBEQVRBX0tFWSRhO1xuICB2YXIgREFUQV9BUElfS0VZJDcgPSAnLmRhdGEtYXBpJztcbiAgdmFyIEpRVUVSWV9OT19DT05GTElDVCRhID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSRhXTtcbiAgdmFyIENMQVNTX05BTUVfQUxFUlQgPSAnYWxlcnQnO1xuICB2YXIgQ0xBU1NfTkFNRV9GQURFJDUgPSAnZmFkZSc7XG4gIHZhciBDTEFTU19OQU1FX1NIT1ckNyA9ICdzaG93JztcbiAgdmFyIEVWRU5UX0NMT1NFID0gXCJjbG9zZVwiICsgRVZFTlRfS0VZJGE7XG4gIHZhciBFVkVOVF9DTE9TRUQgPSBcImNsb3NlZFwiICsgRVZFTlRfS0VZJGE7XG4gIHZhciBFVkVOVF9DTElDS19EQVRBX0FQSSQ2ID0gXCJjbGlja1wiICsgRVZFTlRfS0VZJGEgKyBEQVRBX0FQSV9LRVkkNztcbiAgdmFyIFNFTEVDVE9SX0RJU01JU1MgPSAnW2RhdGEtZGlzbWlzcz1cImFsZXJ0XCJdJztcbiAgLyoqXG4gICAqIENsYXNzIGRlZmluaXRpb25cbiAgICovXG5cbiAgdmFyIEFsZXJ0ID0gLyojX19QVVJFX18qL2Z1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBBbGVydChlbGVtZW50KSB7XG4gICAgICB0aGlzLl9lbGVtZW50ID0gZWxlbWVudDtcbiAgICB9IC8vIEdldHRlcnNcblxuXG4gICAgdmFyIF9wcm90byA9IEFsZXJ0LnByb3RvdHlwZTtcblxuICAgIC8vIFB1YmxpY1xuICAgIF9wcm90by5jbG9zZSA9IGZ1bmN0aW9uIGNsb3NlKGVsZW1lbnQpIHtcbiAgICAgIHZhciByb290RWxlbWVudCA9IHRoaXMuX2VsZW1lbnQ7XG5cbiAgICAgIGlmIChlbGVtZW50KSB7XG4gICAgICAgIHJvb3RFbGVtZW50ID0gdGhpcy5fZ2V0Um9vdEVsZW1lbnQoZWxlbWVudCk7XG4gICAgICB9XG5cbiAgICAgIHZhciBjdXN0b21FdmVudCA9IHRoaXMuX3RyaWdnZXJDbG9zZUV2ZW50KHJvb3RFbGVtZW50KTtcblxuICAgICAgaWYgKGN1c3RvbUV2ZW50LmlzRGVmYXVsdFByZXZlbnRlZCgpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5fcmVtb3ZlRWxlbWVudChyb290RWxlbWVudCk7XG4gICAgfTtcblxuICAgIF9wcm90by5kaXNwb3NlID0gZnVuY3Rpb24gZGlzcG9zZSgpIHtcbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLnJlbW92ZURhdGEodGhpcy5fZWxlbWVudCwgREFUQV9LRVkkYSk7XG4gICAgICB0aGlzLl9lbGVtZW50ID0gbnVsbDtcbiAgICB9IC8vIFByaXZhdGVcbiAgICA7XG5cbiAgICBfcHJvdG8uX2dldFJvb3RFbGVtZW50ID0gZnVuY3Rpb24gX2dldFJvb3RFbGVtZW50KGVsZW1lbnQpIHtcbiAgICAgIHZhciBzZWxlY3RvciA9IFV0aWwuZ2V0U2VsZWN0b3JGcm9tRWxlbWVudChlbGVtZW50KTtcbiAgICAgIHZhciBwYXJlbnQgPSBmYWxzZTtcblxuICAgICAgaWYgKHNlbGVjdG9yKSB7XG4gICAgICAgIHBhcmVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Ioc2VsZWN0b3IpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIXBhcmVudCkge1xuICAgICAgICBwYXJlbnQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShlbGVtZW50KS5jbG9zZXN0KFwiLlwiICsgQ0xBU1NfTkFNRV9BTEVSVClbMF07XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBwYXJlbnQ7XG4gICAgfTtcblxuICAgIF9wcm90by5fdHJpZ2dlckNsb3NlRXZlbnQgPSBmdW5jdGlvbiBfdHJpZ2dlckNsb3NlRXZlbnQoZWxlbWVudCkge1xuICAgICAgdmFyIGNsb3NlRXZlbnQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5FdmVudChFVkVOVF9DTE9TRSk7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShlbGVtZW50KS50cmlnZ2VyKGNsb3NlRXZlbnQpO1xuICAgICAgcmV0dXJuIGNsb3NlRXZlbnQ7XG4gICAgfTtcblxuICAgIF9wcm90by5fcmVtb3ZlRWxlbWVudCA9IGZ1bmN0aW9uIF9yZW1vdmVFbGVtZW50KGVsZW1lbnQpIHtcbiAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGVsZW1lbnQpLnJlbW92ZUNsYXNzKENMQVNTX05BTUVfU0hPVyQ3KTtcblxuICAgICAgaWYgKCEkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShlbGVtZW50KS5oYXNDbGFzcyhDTEFTU19OQU1FX0ZBREUkNSkpIHtcbiAgICAgICAgdGhpcy5fZGVzdHJveUVsZW1lbnQoZWxlbWVudCk7XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB2YXIgdHJhbnNpdGlvbkR1cmF0aW9uID0gVXRpbC5nZXRUcmFuc2l0aW9uRHVyYXRpb25Gcm9tRWxlbWVudChlbGVtZW50KTtcbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGVsZW1lbnQpLm9uZShVdGlsLlRSQU5TSVRJT05fRU5ELCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgcmV0dXJuIF90aGlzLl9kZXN0cm95RWxlbWVudChlbGVtZW50LCBldmVudCk7XG4gICAgICB9KS5lbXVsYXRlVHJhbnNpdGlvbkVuZCh0cmFuc2l0aW9uRHVyYXRpb24pO1xuICAgIH07XG5cbiAgICBfcHJvdG8uX2Rlc3Ryb3lFbGVtZW50ID0gZnVuY3Rpb24gX2Rlc3Ryb3lFbGVtZW50KGVsZW1lbnQpIHtcbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGVsZW1lbnQpLmRldGFjaCgpLnRyaWdnZXIoRVZFTlRfQ0xPU0VEKS5yZW1vdmUoKTtcbiAgICB9IC8vIFN0YXRpY1xuICAgIDtcblxuICAgIEFsZXJ0Ll9qUXVlcnlJbnRlcmZhY2UgPSBmdW5jdGlvbiBfalF1ZXJ5SW50ZXJmYWNlKGNvbmZpZykge1xuICAgICAgcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciAkZWxlbWVudCA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMpO1xuICAgICAgICB2YXIgZGF0YSA9ICRlbGVtZW50LmRhdGEoREFUQV9LRVkkYSk7XG5cbiAgICAgICAgaWYgKCFkYXRhKSB7XG4gICAgICAgICAgZGF0YSA9IG5ldyBBbGVydCh0aGlzKTtcbiAgICAgICAgICAkZWxlbWVudC5kYXRhKERBVEFfS0VZJGEsIGRhdGEpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNvbmZpZyA9PT0gJ2Nsb3NlJykge1xuICAgICAgICAgIGRhdGFbY29uZmlnXSh0aGlzKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIEFsZXJ0Ll9oYW5kbGVEaXNtaXNzID0gZnVuY3Rpb24gX2hhbmRsZURpc21pc3MoYWxlcnRJbnN0YW5jZSkge1xuICAgICAgcmV0dXJuIGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICBpZiAoZXZlbnQpIHtcbiAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgYWxlcnRJbnN0YW5jZS5jbG9zZSh0aGlzKTtcbiAgICAgIH07XG4gICAgfTtcblxuICAgIF9jcmVhdGVDbGFzcyhBbGVydCwgbnVsbCwgW3tcbiAgICAgIGtleTogXCJWRVJTSU9OXCIsXG4gICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgcmV0dXJuIFZFUlNJT04kYTtcbiAgICAgIH1cbiAgICB9XSk7XG5cbiAgICByZXR1cm4gQWxlcnQ7XG4gIH0oKTtcbiAgLyoqXG4gICAqIERhdGEgQVBJIGltcGxlbWVudGF0aW9uXG4gICAqL1xuXG5cbiAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZG9jdW1lbnQpLm9uKEVWRU5UX0NMSUNLX0RBVEFfQVBJJDYsIFNFTEVDVE9SX0RJU01JU1MsIEFsZXJ0Ll9oYW5kbGVEaXNtaXNzKG5ldyBBbGVydCgpKSk7XG4gIC8qKlxuICAgKiBqUXVlcnlcbiAgICovXG5cbiAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSRhXSA9IEFsZXJ0Ll9qUXVlcnlJbnRlcmZhY2U7XG4gICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuW05BTUUkYV0uQ29uc3RydWN0b3IgPSBBbGVydDtcblxuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJGFdLm5vQ29uZmxpY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSRhXSA9IEpRVUVSWV9OT19DT05GTElDVCRhO1xuICAgIHJldHVybiBBbGVydC5falF1ZXJ5SW50ZXJmYWNlO1xuICB9O1xuXG4gIC8qKlxuICAgKiBDb25zdGFudHNcbiAgICovXG5cbiAgdmFyIE5BTUUkOSA9ICdidXR0b24nO1xuICB2YXIgVkVSU0lPTiQ5ID0gJzQuNi4xJztcbiAgdmFyIERBVEFfS0VZJDkgPSAnYnMuYnV0dG9uJztcbiAgdmFyIEVWRU5UX0tFWSQ5ID0gXCIuXCIgKyBEQVRBX0tFWSQ5O1xuICB2YXIgREFUQV9BUElfS0VZJDYgPSAnLmRhdGEtYXBpJztcbiAgdmFyIEpRVUVSWV9OT19DT05GTElDVCQ5ID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQ5XTtcbiAgdmFyIENMQVNTX05BTUVfQUNUSVZFJDMgPSAnYWN0aXZlJztcbiAgdmFyIENMQVNTX05BTUVfQlVUVE9OID0gJ2J0bic7XG4gIHZhciBDTEFTU19OQU1FX0ZPQ1VTID0gJ2ZvY3VzJztcbiAgdmFyIEVWRU5UX0NMSUNLX0RBVEFfQVBJJDUgPSBcImNsaWNrXCIgKyBFVkVOVF9LRVkkOSArIERBVEFfQVBJX0tFWSQ2O1xuICB2YXIgRVZFTlRfRk9DVVNfQkxVUl9EQVRBX0FQSSA9IFwiZm9jdXNcIiArIEVWRU5UX0tFWSQ5ICsgREFUQV9BUElfS0VZJDYgKyBcIiBcIiArIChcImJsdXJcIiArIEVWRU5UX0tFWSQ5ICsgREFUQV9BUElfS0VZJDYpO1xuICB2YXIgRVZFTlRfTE9BRF9EQVRBX0FQSSQyID0gXCJsb2FkXCIgKyBFVkVOVF9LRVkkOSArIERBVEFfQVBJX0tFWSQ2O1xuICB2YXIgU0VMRUNUT1JfREFUQV9UT0dHTEVfQ0FSUk9UID0gJ1tkYXRhLXRvZ2dsZV49XCJidXR0b25cIl0nO1xuICB2YXIgU0VMRUNUT1JfREFUQV9UT0dHTEVTID0gJ1tkYXRhLXRvZ2dsZT1cImJ1dHRvbnNcIl0nO1xuICB2YXIgU0VMRUNUT1JfREFUQV9UT0dHTEUkNCA9ICdbZGF0YS10b2dnbGU9XCJidXR0b25cIl0nO1xuICB2YXIgU0VMRUNUT1JfREFUQV9UT0dHTEVTX0JVVFRPTlMgPSAnW2RhdGEtdG9nZ2xlPVwiYnV0dG9uc1wiXSAuYnRuJztcbiAgdmFyIFNFTEVDVE9SX0lOUFVUID0gJ2lucHV0Om5vdChbdHlwZT1cImhpZGRlblwiXSknO1xuICB2YXIgU0VMRUNUT1JfQUNUSVZFJDIgPSAnLmFjdGl2ZSc7XG4gIHZhciBTRUxFQ1RPUl9CVVRUT04gPSAnLmJ0bic7XG4gIC8qKlxuICAgKiBDbGFzcyBkZWZpbml0aW9uXG4gICAqL1xuXG4gIHZhciBCdXR0b24gPSAvKiNfX1BVUkVfXyovZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIEJ1dHRvbihlbGVtZW50KSB7XG4gICAgICB0aGlzLl9lbGVtZW50ID0gZWxlbWVudDtcbiAgICAgIHRoaXMuc2hvdWxkQXZvaWRUcmlnZ2VyQ2hhbmdlID0gZmFsc2U7XG4gICAgfSAvLyBHZXR0ZXJzXG5cblxuICAgIHZhciBfcHJvdG8gPSBCdXR0b24ucHJvdG90eXBlO1xuXG4gICAgLy8gUHVibGljXG4gICAgX3Byb3RvLnRvZ2dsZSA9IGZ1bmN0aW9uIHRvZ2dsZSgpIHtcbiAgICAgIHZhciB0cmlnZ2VyQ2hhbmdlRXZlbnQgPSB0cnVlO1xuICAgICAgdmFyIGFkZEFyaWFQcmVzc2VkID0gdHJ1ZTtcbiAgICAgIHZhciByb290RWxlbWVudCA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLmNsb3Nlc3QoU0VMRUNUT1JfREFUQV9UT0dHTEVTKVswXTtcblxuICAgICAgaWYgKHJvb3RFbGVtZW50KSB7XG4gICAgICAgIHZhciBpbnB1dCA9IHRoaXMuX2VsZW1lbnQucXVlcnlTZWxlY3RvcihTRUxFQ1RPUl9JTlBVVCk7XG5cbiAgICAgICAgaWYgKGlucHV0KSB7XG4gICAgICAgICAgaWYgKGlucHV0LnR5cGUgPT09ICdyYWRpbycpIHtcbiAgICAgICAgICAgIGlmIChpbnB1dC5jaGVja2VkICYmIHRoaXMuX2VsZW1lbnQuY2xhc3NMaXN0LmNvbnRhaW5zKENMQVNTX05BTUVfQUNUSVZFJDMpKSB7XG4gICAgICAgICAgICAgIHRyaWdnZXJDaGFuZ2VFdmVudCA9IGZhbHNlO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdmFyIGFjdGl2ZUVsZW1lbnQgPSByb290RWxlbWVudC5xdWVyeVNlbGVjdG9yKFNFTEVDVE9SX0FDVElWRSQyKTtcblxuICAgICAgICAgICAgICBpZiAoYWN0aXZlRWxlbWVudCkge1xuICAgICAgICAgICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGFjdGl2ZUVsZW1lbnQpLnJlbW92ZUNsYXNzKENMQVNTX05BTUVfQUNUSVZFJDMpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHRyaWdnZXJDaGFuZ2VFdmVudCkge1xuICAgICAgICAgICAgLy8gaWYgaXQncyBub3QgYSByYWRpbyBidXR0b24gb3IgY2hlY2tib3ggZG9uJ3QgYWRkIGEgcG9pbnRsZXNzL2ludmFsaWQgY2hlY2tlZCBwcm9wZXJ0eSB0byB0aGUgaW5wdXRcbiAgICAgICAgICAgIGlmIChpbnB1dC50eXBlID09PSAnY2hlY2tib3gnIHx8IGlucHV0LnR5cGUgPT09ICdyYWRpbycpIHtcbiAgICAgICAgICAgICAgaW5wdXQuY2hlY2tlZCA9ICF0aGlzLl9lbGVtZW50LmNsYXNzTGlzdC5jb250YWlucyhDTEFTU19OQU1FX0FDVElWRSQzKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCF0aGlzLnNob3VsZEF2b2lkVHJpZ2dlckNoYW5nZSkge1xuICAgICAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShpbnB1dCkudHJpZ2dlcignY2hhbmdlJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaW5wdXQuZm9jdXMoKTtcbiAgICAgICAgICBhZGRBcmlhUHJlc3NlZCA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICghKHRoaXMuX2VsZW1lbnQuaGFzQXR0cmlidXRlKCdkaXNhYmxlZCcpIHx8IHRoaXMuX2VsZW1lbnQuY2xhc3NMaXN0LmNvbnRhaW5zKCdkaXNhYmxlZCcpKSkge1xuICAgICAgICBpZiAoYWRkQXJpYVByZXNzZWQpIHtcbiAgICAgICAgICB0aGlzLl9lbGVtZW50LnNldEF0dHJpYnV0ZSgnYXJpYS1wcmVzc2VkJywgIXRoaXMuX2VsZW1lbnQuY2xhc3NMaXN0LmNvbnRhaW5zKENMQVNTX05BTUVfQUNUSVZFJDMpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0cmlnZ2VyQ2hhbmdlRXZlbnQpIHtcbiAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS50b2dnbGVDbGFzcyhDTEFTU19OQU1FX0FDVElWRSQzKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICBfcHJvdG8uZGlzcG9zZSA9IGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5yZW1vdmVEYXRhKHRoaXMuX2VsZW1lbnQsIERBVEFfS0VZJDkpO1xuICAgICAgdGhpcy5fZWxlbWVudCA9IG51bGw7XG4gICAgfSAvLyBTdGF0aWNcbiAgICA7XG5cbiAgICBCdXR0b24uX2pRdWVyeUludGVyZmFjZSA9IGZ1bmN0aW9uIF9qUXVlcnlJbnRlcmZhY2UoY29uZmlnLCBhdm9pZFRyaWdnZXJDaGFuZ2UpIHtcbiAgICAgIHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgJGVsZW1lbnQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzKTtcbiAgICAgICAgdmFyIGRhdGEgPSAkZWxlbWVudC5kYXRhKERBVEFfS0VZJDkpO1xuXG4gICAgICAgIGlmICghZGF0YSkge1xuICAgICAgICAgIGRhdGEgPSBuZXcgQnV0dG9uKHRoaXMpO1xuICAgICAgICAgICRlbGVtZW50LmRhdGEoREFUQV9LRVkkOSwgZGF0YSk7XG4gICAgICAgIH1cblxuICAgICAgICBkYXRhLnNob3VsZEF2b2lkVHJpZ2dlckNoYW5nZSA9IGF2b2lkVHJpZ2dlckNoYW5nZTtcblxuICAgICAgICBpZiAoY29uZmlnID09PSAndG9nZ2xlJykge1xuICAgICAgICAgIGRhdGFbY29uZmlnXSgpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgX2NyZWF0ZUNsYXNzKEJ1dHRvbiwgbnVsbCwgW3tcbiAgICAgIGtleTogXCJWRVJTSU9OXCIsXG4gICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgcmV0dXJuIFZFUlNJT04kOTtcbiAgICAgIH1cbiAgICB9XSk7XG5cbiAgICByZXR1cm4gQnV0dG9uO1xuICB9KCk7XG4gIC8qKlxuICAgKiBEYXRhIEFQSSBpbXBsZW1lbnRhdGlvblxuICAgKi9cblxuXG4gICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGRvY3VtZW50KS5vbihFVkVOVF9DTElDS19EQVRBX0FQSSQ1LCBTRUxFQ1RPUl9EQVRBX1RPR0dMRV9DQVJST1QsIGZ1bmN0aW9uIChldmVudCkge1xuICAgIHZhciBidXR0b24gPSBldmVudC50YXJnZXQ7XG4gICAgdmFyIGluaXRpYWxCdXR0b24gPSBidXR0b247XG5cbiAgICBpZiAoISRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGJ1dHRvbikuaGFzQ2xhc3MoQ0xBU1NfTkFNRV9CVVRUT04pKSB7XG4gICAgICBidXR0b24gPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShidXR0b24pLmNsb3Nlc3QoU0VMRUNUT1JfQlVUVE9OKVswXTtcbiAgICB9XG5cbiAgICBpZiAoIWJ1dHRvbiB8fCBidXR0b24uaGFzQXR0cmlidXRlKCdkaXNhYmxlZCcpIHx8IGJ1dHRvbi5jbGFzc0xpc3QuY29udGFpbnMoJ2Rpc2FibGVkJykpIHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7IC8vIHdvcmsgYXJvdW5kIEZpcmVmb3ggYnVnICMxNTQwOTk1XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBpbnB1dEJ0biA9IGJ1dHRvbi5xdWVyeVNlbGVjdG9yKFNFTEVDVE9SX0lOUFVUKTtcblxuICAgICAgaWYgKGlucHV0QnRuICYmIChpbnB1dEJ0bi5oYXNBdHRyaWJ1dGUoJ2Rpc2FibGVkJykgfHwgaW5wdXRCdG4uY2xhc3NMaXN0LmNvbnRhaW5zKCdkaXNhYmxlZCcpKSkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpOyAvLyB3b3JrIGFyb3VuZCBGaXJlZm94IGJ1ZyAjMTU0MDk5NVxuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKGluaXRpYWxCdXR0b24udGFnTmFtZSA9PT0gJ0lOUFVUJyB8fCBidXR0b24udGFnTmFtZSAhPT0gJ0xBQkVMJykge1xuICAgICAgICBCdXR0b24uX2pRdWVyeUludGVyZmFjZS5jYWxsKCRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGJ1dHRvbiksICd0b2dnbGUnLCBpbml0aWFsQnV0dG9uLnRhZ05hbWUgPT09ICdJTlBVVCcpO1xuICAgICAgfVxuICAgIH1cbiAgfSkub24oRVZFTlRfRk9DVVNfQkxVUl9EQVRBX0FQSSwgU0VMRUNUT1JfREFUQV9UT0dHTEVfQ0FSUk9ULCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICB2YXIgYnV0dG9uID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZXZlbnQudGFyZ2V0KS5jbG9zZXN0KFNFTEVDVE9SX0JVVFRPTilbMF07XG4gICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oYnV0dG9uKS50b2dnbGVDbGFzcyhDTEFTU19OQU1FX0ZPQ1VTLCAvXmZvY3VzKGluKT8kLy50ZXN0KGV2ZW50LnR5cGUpKTtcbiAgfSk7XG4gICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHdpbmRvdykub24oRVZFTlRfTE9BRF9EQVRBX0FQSSQyLCBmdW5jdGlvbiAoKSB7XG4gICAgLy8gZW5zdXJlIGNvcnJlY3QgYWN0aXZlIGNsYXNzIGlzIHNldCB0byBtYXRjaCB0aGUgY29udHJvbHMnIGFjdHVhbCB2YWx1ZXMvc3RhdGVzXG4gICAgLy8gZmluZCBhbGwgY2hlY2tib3hlcy9yZWFkaW8gYnV0dG9ucyBpbnNpZGUgZGF0YS10b2dnbGUgZ3JvdXBzXG4gICAgdmFyIGJ1dHRvbnMgPSBbXS5zbGljZS5jYWxsKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoU0VMRUNUT1JfREFUQV9UT0dHTEVTX0JVVFRPTlMpKTtcblxuICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSBidXR0b25zLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICB2YXIgYnV0dG9uID0gYnV0dG9uc1tpXTtcbiAgICAgIHZhciBpbnB1dCA9IGJ1dHRvbi5xdWVyeVNlbGVjdG9yKFNFTEVDVE9SX0lOUFVUKTtcblxuICAgICAgaWYgKGlucHV0LmNoZWNrZWQgfHwgaW5wdXQuaGFzQXR0cmlidXRlKCdjaGVja2VkJykpIHtcbiAgICAgICAgYnV0dG9uLmNsYXNzTGlzdC5hZGQoQ0xBU1NfTkFNRV9BQ1RJVkUkMyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBidXR0b24uY2xhc3NMaXN0LnJlbW92ZShDTEFTU19OQU1FX0FDVElWRSQzKTtcbiAgICAgIH1cbiAgICB9IC8vIGZpbmQgYWxsIGJ1dHRvbiB0b2dnbGVzXG5cblxuICAgIGJ1dHRvbnMgPSBbXS5zbGljZS5jYWxsKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoU0VMRUNUT1JfREFUQV9UT0dHTEUkNCkpO1xuXG4gICAgZm9yICh2YXIgX2kgPSAwLCBfbGVuID0gYnV0dG9ucy5sZW5ndGg7IF9pIDwgX2xlbjsgX2krKykge1xuICAgICAgdmFyIF9idXR0b24gPSBidXR0b25zW19pXTtcblxuICAgICAgaWYgKF9idXR0b24uZ2V0QXR0cmlidXRlKCdhcmlhLXByZXNzZWQnKSA9PT0gJ3RydWUnKSB7XG4gICAgICAgIF9idXR0b24uY2xhc3NMaXN0LmFkZChDTEFTU19OQU1FX0FDVElWRSQzKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIF9idXR0b24uY2xhc3NMaXN0LnJlbW92ZShDTEFTU19OQU1FX0FDVElWRSQzKTtcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xuICAvKipcbiAgICogalF1ZXJ5XG4gICAqL1xuXG4gICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuW05BTUUkOV0gPSBCdXR0b24uX2pRdWVyeUludGVyZmFjZTtcbiAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQ5XS5Db25zdHJ1Y3RvciA9IEJ1dHRvbjtcblxuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDldLm5vQ29uZmxpY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQ5XSA9IEpRVUVSWV9OT19DT05GTElDVCQ5O1xuICAgIHJldHVybiBCdXR0b24uX2pRdWVyeUludGVyZmFjZTtcbiAgfTtcblxuICAvKipcbiAgICogQ29uc3RhbnRzXG4gICAqL1xuXG4gIHZhciBOQU1FJDggPSAnY2Fyb3VzZWwnO1xuICB2YXIgVkVSU0lPTiQ4ID0gJzQuNi4xJztcbiAgdmFyIERBVEFfS0VZJDggPSAnYnMuY2Fyb3VzZWwnO1xuICB2YXIgRVZFTlRfS0VZJDggPSBcIi5cIiArIERBVEFfS0VZJDg7XG4gIHZhciBEQVRBX0FQSV9LRVkkNSA9ICcuZGF0YS1hcGknO1xuICB2YXIgSlFVRVJZX05PX0NPTkZMSUNUJDggPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDhdO1xuICB2YXIgQVJST1dfTEVGVF9LRVlDT0RFID0gMzc7IC8vIEtleWJvYXJkRXZlbnQud2hpY2ggdmFsdWUgZm9yIGxlZnQgYXJyb3cga2V5XG5cbiAgdmFyIEFSUk9XX1JJR0hUX0tFWUNPREUgPSAzOTsgLy8gS2V5Ym9hcmRFdmVudC53aGljaCB2YWx1ZSBmb3IgcmlnaHQgYXJyb3cga2V5XG5cbiAgdmFyIFRPVUNIRVZFTlRfQ09NUEFUX1dBSVQgPSA1MDA7IC8vIFRpbWUgZm9yIG1vdXNlIGNvbXBhdCBldmVudHMgdG8gZmlyZSBhZnRlciB0b3VjaFxuXG4gIHZhciBTV0lQRV9USFJFU0hPTEQgPSA0MDtcbiAgdmFyIENMQVNTX05BTUVfQ0FST1VTRUwgPSAnY2Fyb3VzZWwnO1xuICB2YXIgQ0xBU1NfTkFNRV9BQ1RJVkUkMiA9ICdhY3RpdmUnO1xuICB2YXIgQ0xBU1NfTkFNRV9TTElERSA9ICdzbGlkZSc7XG4gIHZhciBDTEFTU19OQU1FX1JJR0hUID0gJ2Nhcm91c2VsLWl0ZW0tcmlnaHQnO1xuICB2YXIgQ0xBU1NfTkFNRV9MRUZUID0gJ2Nhcm91c2VsLWl0ZW0tbGVmdCc7XG4gIHZhciBDTEFTU19OQU1FX05FWFQgPSAnY2Fyb3VzZWwtaXRlbS1uZXh0JztcbiAgdmFyIENMQVNTX05BTUVfUFJFViA9ICdjYXJvdXNlbC1pdGVtLXByZXYnO1xuICB2YXIgQ0xBU1NfTkFNRV9QT0lOVEVSX0VWRU5UID0gJ3BvaW50ZXItZXZlbnQnO1xuICB2YXIgRElSRUNUSU9OX05FWFQgPSAnbmV4dCc7XG4gIHZhciBESVJFQ1RJT05fUFJFViA9ICdwcmV2JztcbiAgdmFyIERJUkVDVElPTl9MRUZUID0gJ2xlZnQnO1xuICB2YXIgRElSRUNUSU9OX1JJR0hUID0gJ3JpZ2h0JztcbiAgdmFyIEVWRU5UX1NMSURFID0gXCJzbGlkZVwiICsgRVZFTlRfS0VZJDg7XG4gIHZhciBFVkVOVF9TTElEID0gXCJzbGlkXCIgKyBFVkVOVF9LRVkkODtcbiAgdmFyIEVWRU5UX0tFWURPV04gPSBcImtleWRvd25cIiArIEVWRU5UX0tFWSQ4O1xuICB2YXIgRVZFTlRfTU9VU0VFTlRFUiA9IFwibW91c2VlbnRlclwiICsgRVZFTlRfS0VZJDg7XG4gIHZhciBFVkVOVF9NT1VTRUxFQVZFID0gXCJtb3VzZWxlYXZlXCIgKyBFVkVOVF9LRVkkODtcbiAgdmFyIEVWRU5UX1RPVUNIU1RBUlQgPSBcInRvdWNoc3RhcnRcIiArIEVWRU5UX0tFWSQ4O1xuICB2YXIgRVZFTlRfVE9VQ0hNT1ZFID0gXCJ0b3VjaG1vdmVcIiArIEVWRU5UX0tFWSQ4O1xuICB2YXIgRVZFTlRfVE9VQ0hFTkQgPSBcInRvdWNoZW5kXCIgKyBFVkVOVF9LRVkkODtcbiAgdmFyIEVWRU5UX1BPSU5URVJET1dOID0gXCJwb2ludGVyZG93blwiICsgRVZFTlRfS0VZJDg7XG4gIHZhciBFVkVOVF9QT0lOVEVSVVAgPSBcInBvaW50ZXJ1cFwiICsgRVZFTlRfS0VZJDg7XG4gIHZhciBFVkVOVF9EUkFHX1NUQVJUID0gXCJkcmFnc3RhcnRcIiArIEVWRU5UX0tFWSQ4O1xuICB2YXIgRVZFTlRfTE9BRF9EQVRBX0FQSSQxID0gXCJsb2FkXCIgKyBFVkVOVF9LRVkkOCArIERBVEFfQVBJX0tFWSQ1O1xuICB2YXIgRVZFTlRfQ0xJQ0tfREFUQV9BUEkkNCA9IFwiY2xpY2tcIiArIEVWRU5UX0tFWSQ4ICsgREFUQV9BUElfS0VZJDU7XG4gIHZhciBTRUxFQ1RPUl9BQ1RJVkUkMSA9ICcuYWN0aXZlJztcbiAgdmFyIFNFTEVDVE9SX0FDVElWRV9JVEVNID0gJy5hY3RpdmUuY2Fyb3VzZWwtaXRlbSc7XG4gIHZhciBTRUxFQ1RPUl9JVEVNID0gJy5jYXJvdXNlbC1pdGVtJztcbiAgdmFyIFNFTEVDVE9SX0lURU1fSU1HID0gJy5jYXJvdXNlbC1pdGVtIGltZyc7XG4gIHZhciBTRUxFQ1RPUl9ORVhUX1BSRVYgPSAnLmNhcm91c2VsLWl0ZW0tbmV4dCwgLmNhcm91c2VsLWl0ZW0tcHJldic7XG4gIHZhciBTRUxFQ1RPUl9JTkRJQ0FUT1JTID0gJy5jYXJvdXNlbC1pbmRpY2F0b3JzJztcbiAgdmFyIFNFTEVDVE9SX0RBVEFfU0xJREUgPSAnW2RhdGEtc2xpZGVdLCBbZGF0YS1zbGlkZS10b10nO1xuICB2YXIgU0VMRUNUT1JfREFUQV9SSURFID0gJ1tkYXRhLXJpZGU9XCJjYXJvdXNlbFwiXSc7XG4gIHZhciBEZWZhdWx0JDcgPSB7XG4gICAgaW50ZXJ2YWw6IDUwMDAsXG4gICAga2V5Ym9hcmQ6IHRydWUsXG4gICAgc2xpZGU6IGZhbHNlLFxuICAgIHBhdXNlOiAnaG92ZXInLFxuICAgIHdyYXA6IHRydWUsXG4gICAgdG91Y2g6IHRydWVcbiAgfTtcbiAgdmFyIERlZmF1bHRUeXBlJDcgPSB7XG4gICAgaW50ZXJ2YWw6ICcobnVtYmVyfGJvb2xlYW4pJyxcbiAgICBrZXlib2FyZDogJ2Jvb2xlYW4nLFxuICAgIHNsaWRlOiAnKGJvb2xlYW58c3RyaW5nKScsXG4gICAgcGF1c2U6ICcoc3RyaW5nfGJvb2xlYW4pJyxcbiAgICB3cmFwOiAnYm9vbGVhbicsXG4gICAgdG91Y2g6ICdib29sZWFuJ1xuICB9O1xuICB2YXIgUG9pbnRlclR5cGUgPSB7XG4gICAgVE9VQ0g6ICd0b3VjaCcsXG4gICAgUEVOOiAncGVuJ1xuICB9O1xuICAvKipcbiAgICogQ2xhc3MgZGVmaW5pdGlvblxuICAgKi9cblxuICB2YXIgQ2Fyb3VzZWwgPSAvKiNfX1BVUkVfXyovZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIENhcm91c2VsKGVsZW1lbnQsIGNvbmZpZykge1xuICAgICAgdGhpcy5faXRlbXMgPSBudWxsO1xuICAgICAgdGhpcy5faW50ZXJ2YWwgPSBudWxsO1xuICAgICAgdGhpcy5fYWN0aXZlRWxlbWVudCA9IG51bGw7XG4gICAgICB0aGlzLl9pc1BhdXNlZCA9IGZhbHNlO1xuICAgICAgdGhpcy5faXNTbGlkaW5nID0gZmFsc2U7XG4gICAgICB0aGlzLnRvdWNoVGltZW91dCA9IG51bGw7XG4gICAgICB0aGlzLnRvdWNoU3RhcnRYID0gMDtcbiAgICAgIHRoaXMudG91Y2hEZWx0YVggPSAwO1xuICAgICAgdGhpcy5fY29uZmlnID0gdGhpcy5fZ2V0Q29uZmlnKGNvbmZpZyk7XG4gICAgICB0aGlzLl9lbGVtZW50ID0gZWxlbWVudDtcbiAgICAgIHRoaXMuX2luZGljYXRvcnNFbGVtZW50ID0gdGhpcy5fZWxlbWVudC5xdWVyeVNlbGVjdG9yKFNFTEVDVE9SX0lORElDQVRPUlMpO1xuICAgICAgdGhpcy5fdG91Y2hTdXBwb3J0ZWQgPSAnb250b3VjaHN0YXJ0JyBpbiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQgfHwgbmF2aWdhdG9yLm1heFRvdWNoUG9pbnRzID4gMDtcbiAgICAgIHRoaXMuX3BvaW50ZXJFdmVudCA9IEJvb2xlYW4od2luZG93LlBvaW50ZXJFdmVudCB8fCB3aW5kb3cuTVNQb2ludGVyRXZlbnQpO1xuXG4gICAgICB0aGlzLl9hZGRFdmVudExpc3RlbmVycygpO1xuICAgIH0gLy8gR2V0dGVyc1xuXG5cbiAgICB2YXIgX3Byb3RvID0gQ2Fyb3VzZWwucHJvdG90eXBlO1xuXG4gICAgLy8gUHVibGljXG4gICAgX3Byb3RvLm5leHQgPSBmdW5jdGlvbiBuZXh0KCkge1xuICAgICAgaWYgKCF0aGlzLl9pc1NsaWRpbmcpIHtcbiAgICAgICAgdGhpcy5fc2xpZGUoRElSRUNUSU9OX05FWFQpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBfcHJvdG8ubmV4dFdoZW5WaXNpYmxlID0gZnVuY3Rpb24gbmV4dFdoZW5WaXNpYmxlKCkge1xuICAgICAgdmFyICRlbGVtZW50ID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCk7IC8vIERvbid0IGNhbGwgbmV4dCB3aGVuIHRoZSBwYWdlIGlzbid0IHZpc2libGVcbiAgICAgIC8vIG9yIHRoZSBjYXJvdXNlbCBvciBpdHMgcGFyZW50IGlzbid0IHZpc2libGVcblxuICAgICAgaWYgKCFkb2N1bWVudC5oaWRkZW4gJiYgJGVsZW1lbnQuaXMoJzp2aXNpYmxlJykgJiYgJGVsZW1lbnQuY3NzKCd2aXNpYmlsaXR5JykgIT09ICdoaWRkZW4nKSB7XG4gICAgICAgIHRoaXMubmV4dCgpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBfcHJvdG8ucHJldiA9IGZ1bmN0aW9uIHByZXYoKSB7XG4gICAgICBpZiAoIXRoaXMuX2lzU2xpZGluZykge1xuICAgICAgICB0aGlzLl9zbGlkZShESVJFQ1RJT05fUFJFVik7XG4gICAgICB9XG4gICAgfTtcblxuICAgIF9wcm90by5wYXVzZSA9IGZ1bmN0aW9uIHBhdXNlKGV2ZW50KSB7XG4gICAgICBpZiAoIWV2ZW50KSB7XG4gICAgICAgIHRoaXMuX2lzUGF1c2VkID0gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuX2VsZW1lbnQucXVlcnlTZWxlY3RvcihTRUxFQ1RPUl9ORVhUX1BSRVYpKSB7XG4gICAgICAgIFV0aWwudHJpZ2dlclRyYW5zaXRpb25FbmQodGhpcy5fZWxlbWVudCk7XG4gICAgICAgIHRoaXMuY3ljbGUodHJ1ZSk7XG4gICAgICB9XG5cbiAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5faW50ZXJ2YWwpO1xuICAgICAgdGhpcy5faW50ZXJ2YWwgPSBudWxsO1xuICAgIH07XG5cbiAgICBfcHJvdG8uY3ljbGUgPSBmdW5jdGlvbiBjeWNsZShldmVudCkge1xuICAgICAgaWYgKCFldmVudCkge1xuICAgICAgICB0aGlzLl9pc1BhdXNlZCA9IGZhbHNlO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5faW50ZXJ2YWwpIHtcbiAgICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLl9pbnRlcnZhbCk7XG4gICAgICAgIHRoaXMuX2ludGVydmFsID0gbnVsbDtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuX2NvbmZpZy5pbnRlcnZhbCAmJiAhdGhpcy5faXNQYXVzZWQpIHtcbiAgICAgICAgdGhpcy5fdXBkYXRlSW50ZXJ2YWwoKTtcblxuICAgICAgICB0aGlzLl9pbnRlcnZhbCA9IHNldEludGVydmFsKChkb2N1bWVudC52aXNpYmlsaXR5U3RhdGUgPyB0aGlzLm5leHRXaGVuVmlzaWJsZSA6IHRoaXMubmV4dCkuYmluZCh0aGlzKSwgdGhpcy5fY29uZmlnLmludGVydmFsKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgX3Byb3RvLnRvID0gZnVuY3Rpb24gdG8oaW5kZXgpIHtcbiAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgIHRoaXMuX2FjdGl2ZUVsZW1lbnQgPSB0aGlzLl9lbGVtZW50LnF1ZXJ5U2VsZWN0b3IoU0VMRUNUT1JfQUNUSVZFX0lURU0pO1xuXG4gICAgICB2YXIgYWN0aXZlSW5kZXggPSB0aGlzLl9nZXRJdGVtSW5kZXgodGhpcy5fYWN0aXZlRWxlbWVudCk7XG5cbiAgICAgIGlmIChpbmRleCA+IHRoaXMuX2l0ZW1zLmxlbmd0aCAtIDEgfHwgaW5kZXggPCAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuX2lzU2xpZGluZykge1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5vbmUoRVZFTlRfU0xJRCwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIHJldHVybiBfdGhpcy50byhpbmRleCk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChhY3RpdmVJbmRleCA9PT0gaW5kZXgpIHtcbiAgICAgICAgdGhpcy5wYXVzZSgpO1xuICAgICAgICB0aGlzLmN5Y2xlKCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIGRpcmVjdGlvbiA9IGluZGV4ID4gYWN0aXZlSW5kZXggPyBESVJFQ1RJT05fTkVYVCA6IERJUkVDVElPTl9QUkVWO1xuXG4gICAgICB0aGlzLl9zbGlkZShkaXJlY3Rpb24sIHRoaXMuX2l0ZW1zW2luZGV4XSk7XG4gICAgfTtcblxuICAgIF9wcm90by5kaXNwb3NlID0gZnVuY3Rpb24gZGlzcG9zZSgpIHtcbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLm9mZihFVkVOVF9LRVkkOCk7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5yZW1vdmVEYXRhKHRoaXMuX2VsZW1lbnQsIERBVEFfS0VZJDgpO1xuICAgICAgdGhpcy5faXRlbXMgPSBudWxsO1xuICAgICAgdGhpcy5fY29uZmlnID0gbnVsbDtcbiAgICAgIHRoaXMuX2VsZW1lbnQgPSBudWxsO1xuICAgICAgdGhpcy5faW50ZXJ2YWwgPSBudWxsO1xuICAgICAgdGhpcy5faXNQYXVzZWQgPSBudWxsO1xuICAgICAgdGhpcy5faXNTbGlkaW5nID0gbnVsbDtcbiAgICAgIHRoaXMuX2FjdGl2ZUVsZW1lbnQgPSBudWxsO1xuICAgICAgdGhpcy5faW5kaWNhdG9yc0VsZW1lbnQgPSBudWxsO1xuICAgIH0gLy8gUHJpdmF0ZVxuICAgIDtcblxuICAgIF9wcm90by5fZ2V0Q29uZmlnID0gZnVuY3Rpb24gX2dldENvbmZpZyhjb25maWcpIHtcbiAgICAgIGNvbmZpZyA9IF9leHRlbmRzKHt9LCBEZWZhdWx0JDcsIGNvbmZpZyk7XG4gICAgICBVdGlsLnR5cGVDaGVja0NvbmZpZyhOQU1FJDgsIGNvbmZpZywgRGVmYXVsdFR5cGUkNyk7XG4gICAgICByZXR1cm4gY29uZmlnO1xuICAgIH07XG5cbiAgICBfcHJvdG8uX2hhbmRsZVN3aXBlID0gZnVuY3Rpb24gX2hhbmRsZVN3aXBlKCkge1xuICAgICAgdmFyIGFic0RlbHRheCA9IE1hdGguYWJzKHRoaXMudG91Y2hEZWx0YVgpO1xuXG4gICAgICBpZiAoYWJzRGVsdGF4IDw9IFNXSVBFX1RIUkVTSE9MRCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHZhciBkaXJlY3Rpb24gPSBhYnNEZWx0YXggLyB0aGlzLnRvdWNoRGVsdGFYO1xuICAgICAgdGhpcy50b3VjaERlbHRhWCA9IDA7IC8vIHN3aXBlIGxlZnRcblxuICAgICAgaWYgKGRpcmVjdGlvbiA+IDApIHtcbiAgICAgICAgdGhpcy5wcmV2KCk7XG4gICAgICB9IC8vIHN3aXBlIHJpZ2h0XG5cblxuICAgICAgaWYgKGRpcmVjdGlvbiA8IDApIHtcbiAgICAgICAgdGhpcy5uZXh0KCk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIF9wcm90by5fYWRkRXZlbnRMaXN0ZW5lcnMgPSBmdW5jdGlvbiBfYWRkRXZlbnRMaXN0ZW5lcnMoKSB7XG4gICAgICB2YXIgX3RoaXMyID0gdGhpcztcblxuICAgICAgaWYgKHRoaXMuX2NvbmZpZy5rZXlib2FyZCkge1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5vbihFVkVOVF9LRVlET1dOLCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICByZXR1cm4gX3RoaXMyLl9rZXlkb3duKGV2ZW50KTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLl9jb25maWcucGF1c2UgPT09ICdob3ZlcicpIHtcbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkub24oRVZFTlRfTU9VU0VFTlRFUiwgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgcmV0dXJuIF90aGlzMi5wYXVzZShldmVudCk7XG4gICAgICAgIH0pLm9uKEVWRU5UX01PVVNFTEVBVkUsIGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAgIHJldHVybiBfdGhpczIuY3ljbGUoZXZlbnQpO1xuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuX2NvbmZpZy50b3VjaCkge1xuICAgICAgICB0aGlzLl9hZGRUb3VjaEV2ZW50TGlzdGVuZXJzKCk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIF9wcm90by5fYWRkVG91Y2hFdmVudExpc3RlbmVycyA9IGZ1bmN0aW9uIF9hZGRUb3VjaEV2ZW50TGlzdGVuZXJzKCkge1xuICAgICAgdmFyIF90aGlzMyA9IHRoaXM7XG5cbiAgICAgIGlmICghdGhpcy5fdG91Y2hTdXBwb3J0ZWQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB2YXIgc3RhcnQgPSBmdW5jdGlvbiBzdGFydChldmVudCkge1xuICAgICAgICBpZiAoX3RoaXMzLl9wb2ludGVyRXZlbnQgJiYgUG9pbnRlclR5cGVbZXZlbnQub3JpZ2luYWxFdmVudC5wb2ludGVyVHlwZS50b1VwcGVyQ2FzZSgpXSkge1xuICAgICAgICAgIF90aGlzMy50b3VjaFN0YXJ0WCA9IGV2ZW50Lm9yaWdpbmFsRXZlbnQuY2xpZW50WDtcbiAgICAgICAgfSBlbHNlIGlmICghX3RoaXMzLl9wb2ludGVyRXZlbnQpIHtcbiAgICAgICAgICBfdGhpczMudG91Y2hTdGFydFggPSBldmVudC5vcmlnaW5hbEV2ZW50LnRvdWNoZXNbMF0uY2xpZW50WDtcbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgdmFyIG1vdmUgPSBmdW5jdGlvbiBtb3ZlKGV2ZW50KSB7XG4gICAgICAgIC8vIGVuc3VyZSBzd2lwaW5nIHdpdGggb25lIHRvdWNoIGFuZCBub3QgcGluY2hpbmdcbiAgICAgICAgX3RoaXMzLnRvdWNoRGVsdGFYID0gZXZlbnQub3JpZ2luYWxFdmVudC50b3VjaGVzICYmIGV2ZW50Lm9yaWdpbmFsRXZlbnQudG91Y2hlcy5sZW5ndGggPiAxID8gMCA6IGV2ZW50Lm9yaWdpbmFsRXZlbnQudG91Y2hlc1swXS5jbGllbnRYIC0gX3RoaXMzLnRvdWNoU3RhcnRYO1xuICAgICAgfTtcblxuICAgICAgdmFyIGVuZCA9IGZ1bmN0aW9uIGVuZChldmVudCkge1xuICAgICAgICBpZiAoX3RoaXMzLl9wb2ludGVyRXZlbnQgJiYgUG9pbnRlclR5cGVbZXZlbnQub3JpZ2luYWxFdmVudC5wb2ludGVyVHlwZS50b1VwcGVyQ2FzZSgpXSkge1xuICAgICAgICAgIF90aGlzMy50b3VjaERlbHRhWCA9IGV2ZW50Lm9yaWdpbmFsRXZlbnQuY2xpZW50WCAtIF90aGlzMy50b3VjaFN0YXJ0WDtcbiAgICAgICAgfVxuXG4gICAgICAgIF90aGlzMy5faGFuZGxlU3dpcGUoKTtcblxuICAgICAgICBpZiAoX3RoaXMzLl9jb25maWcucGF1c2UgPT09ICdob3ZlcicpIHtcbiAgICAgICAgICAvLyBJZiBpdCdzIGEgdG91Y2gtZW5hYmxlZCBkZXZpY2UsIG1vdXNlZW50ZXIvbGVhdmUgYXJlIGZpcmVkIGFzXG4gICAgICAgICAgLy8gcGFydCBvZiB0aGUgbW91c2UgY29tcGF0aWJpbGl0eSBldmVudHMgb24gZmlyc3QgdGFwIC0gdGhlIGNhcm91c2VsXG4gICAgICAgICAgLy8gd291bGQgc3RvcCBjeWNsaW5nIHVudGlsIHVzZXIgdGFwcGVkIG91dCBvZiBpdDtcbiAgICAgICAgICAvLyBoZXJlLCB3ZSBsaXN0ZW4gZm9yIHRvdWNoZW5kLCBleHBsaWNpdGx5IHBhdXNlIHRoZSBjYXJvdXNlbFxuICAgICAgICAgIC8vIChhcyBpZiBpdCdzIHRoZSBzZWNvbmQgdGltZSB3ZSB0YXAgb24gaXQsIG1vdXNlZW50ZXIgY29tcGF0IGV2ZW50XG4gICAgICAgICAgLy8gaXMgTk9UIGZpcmVkKSBhbmQgYWZ0ZXIgYSB0aW1lb3V0ICh0byBhbGxvdyBmb3IgbW91c2UgY29tcGF0aWJpbGl0eVxuICAgICAgICAgIC8vIGV2ZW50cyB0byBmaXJlKSB3ZSBleHBsaWNpdGx5IHJlc3RhcnQgY3ljbGluZ1xuICAgICAgICAgIF90aGlzMy5wYXVzZSgpO1xuXG4gICAgICAgICAgaWYgKF90aGlzMy50b3VjaFRpbWVvdXQpIHtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dChfdGhpczMudG91Y2hUaW1lb3V0KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBfdGhpczMudG91Y2hUaW1lb3V0ID0gc2V0VGltZW91dChmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIHJldHVybiBfdGhpczMuY3ljbGUoZXZlbnQpO1xuICAgICAgICAgIH0sIFRPVUNIRVZFTlRfQ09NUEFUX1dBSVQgKyBfdGhpczMuX2NvbmZpZy5pbnRlcnZhbCk7XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQucXVlcnlTZWxlY3RvckFsbChTRUxFQ1RPUl9JVEVNX0lNRykpLm9uKEVWRU5UX0RSQUdfU1RBUlQsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHJldHVybiBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKHRoaXMuX3BvaW50ZXJFdmVudCkge1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5vbihFVkVOVF9QT0lOVEVSRE9XTiwgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgcmV0dXJuIHN0YXJ0KGV2ZW50KTtcbiAgICAgICAgfSk7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLm9uKEVWRU5UX1BPSU5URVJVUCwgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgcmV0dXJuIGVuZChldmVudCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuX2VsZW1lbnQuY2xhc3NMaXN0LmFkZChDTEFTU19OQU1FX1BPSU5URVJfRVZFTlQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkub24oRVZFTlRfVE9VQ0hTVEFSVCwgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgcmV0dXJuIHN0YXJ0KGV2ZW50KTtcbiAgICAgICAgfSk7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLm9uKEVWRU5UX1RPVUNITU9WRSwgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgcmV0dXJuIG1vdmUoZXZlbnQpO1xuICAgICAgICB9KTtcbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkub24oRVZFTlRfVE9VQ0hFTkQsIGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAgIHJldHVybiBlbmQoZXZlbnQpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgX3Byb3RvLl9rZXlkb3duID0gZnVuY3Rpb24gX2tleWRvd24oZXZlbnQpIHtcbiAgICAgIGlmICgvaW5wdXR8dGV4dGFyZWEvaS50ZXN0KGV2ZW50LnRhcmdldC50YWdOYW1lKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHN3aXRjaCAoZXZlbnQud2hpY2gpIHtcbiAgICAgICAgY2FzZSBBUlJPV19MRUZUX0tFWUNPREU6XG4gICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICB0aGlzLnByZXYoKTtcbiAgICAgICAgICBicmVhaztcblxuICAgICAgICBjYXNlIEFSUk9XX1JJR0hUX0tFWUNPREU6XG4gICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICB0aGlzLm5leHQoKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgX3Byb3RvLl9nZXRJdGVtSW5kZXggPSBmdW5jdGlvbiBfZ2V0SXRlbUluZGV4KGVsZW1lbnQpIHtcbiAgICAgIHRoaXMuX2l0ZW1zID0gZWxlbWVudCAmJiBlbGVtZW50LnBhcmVudE5vZGUgPyBbXS5zbGljZS5jYWxsKGVsZW1lbnQucGFyZW50Tm9kZS5xdWVyeVNlbGVjdG9yQWxsKFNFTEVDVE9SX0lURU0pKSA6IFtdO1xuICAgICAgcmV0dXJuIHRoaXMuX2l0ZW1zLmluZGV4T2YoZWxlbWVudCk7XG4gICAgfTtcblxuICAgIF9wcm90by5fZ2V0SXRlbUJ5RGlyZWN0aW9uID0gZnVuY3Rpb24gX2dldEl0ZW1CeURpcmVjdGlvbihkaXJlY3Rpb24sIGFjdGl2ZUVsZW1lbnQpIHtcbiAgICAgIHZhciBpc05leHREaXJlY3Rpb24gPSBkaXJlY3Rpb24gPT09IERJUkVDVElPTl9ORVhUO1xuICAgICAgdmFyIGlzUHJldkRpcmVjdGlvbiA9IGRpcmVjdGlvbiA9PT0gRElSRUNUSU9OX1BSRVY7XG5cbiAgICAgIHZhciBhY3RpdmVJbmRleCA9IHRoaXMuX2dldEl0ZW1JbmRleChhY3RpdmVFbGVtZW50KTtcblxuICAgICAgdmFyIGxhc3RJdGVtSW5kZXggPSB0aGlzLl9pdGVtcy5sZW5ndGggLSAxO1xuICAgICAgdmFyIGlzR29pbmdUb1dyYXAgPSBpc1ByZXZEaXJlY3Rpb24gJiYgYWN0aXZlSW5kZXggPT09IDAgfHwgaXNOZXh0RGlyZWN0aW9uICYmIGFjdGl2ZUluZGV4ID09PSBsYXN0SXRlbUluZGV4O1xuXG4gICAgICBpZiAoaXNHb2luZ1RvV3JhcCAmJiAhdGhpcy5fY29uZmlnLndyYXApIHtcbiAgICAgICAgcmV0dXJuIGFjdGl2ZUVsZW1lbnQ7XG4gICAgICB9XG5cbiAgICAgIHZhciBkZWx0YSA9IGRpcmVjdGlvbiA9PT0gRElSRUNUSU9OX1BSRVYgPyAtMSA6IDE7XG4gICAgICB2YXIgaXRlbUluZGV4ID0gKGFjdGl2ZUluZGV4ICsgZGVsdGEpICUgdGhpcy5faXRlbXMubGVuZ3RoO1xuICAgICAgcmV0dXJuIGl0ZW1JbmRleCA9PT0gLTEgPyB0aGlzLl9pdGVtc1t0aGlzLl9pdGVtcy5sZW5ndGggLSAxXSA6IHRoaXMuX2l0ZW1zW2l0ZW1JbmRleF07XG4gICAgfTtcblxuICAgIF9wcm90by5fdHJpZ2dlclNsaWRlRXZlbnQgPSBmdW5jdGlvbiBfdHJpZ2dlclNsaWRlRXZlbnQocmVsYXRlZFRhcmdldCwgZXZlbnREaXJlY3Rpb25OYW1lKSB7XG4gICAgICB2YXIgdGFyZ2V0SW5kZXggPSB0aGlzLl9nZXRJdGVtSW5kZXgocmVsYXRlZFRhcmdldCk7XG5cbiAgICAgIHZhciBmcm9tSW5kZXggPSB0aGlzLl9nZXRJdGVtSW5kZXgodGhpcy5fZWxlbWVudC5xdWVyeVNlbGVjdG9yKFNFTEVDVE9SX0FDVElWRV9JVEVNKSk7XG5cbiAgICAgIHZhciBzbGlkZUV2ZW50ID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uRXZlbnQoRVZFTlRfU0xJREUsIHtcbiAgICAgICAgcmVsYXRlZFRhcmdldDogcmVsYXRlZFRhcmdldCxcbiAgICAgICAgZGlyZWN0aW9uOiBldmVudERpcmVjdGlvbk5hbWUsXG4gICAgICAgIGZyb206IGZyb21JbmRleCxcbiAgICAgICAgdG86IHRhcmdldEluZGV4XG4gICAgICB9KTtcbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLnRyaWdnZXIoc2xpZGVFdmVudCk7XG4gICAgICByZXR1cm4gc2xpZGVFdmVudDtcbiAgICB9O1xuXG4gICAgX3Byb3RvLl9zZXRBY3RpdmVJbmRpY2F0b3JFbGVtZW50ID0gZnVuY3Rpb24gX3NldEFjdGl2ZUluZGljYXRvckVsZW1lbnQoZWxlbWVudCkge1xuICAgICAgaWYgKHRoaXMuX2luZGljYXRvcnNFbGVtZW50KSB7XG4gICAgICAgIHZhciBpbmRpY2F0b3JzID0gW10uc2xpY2UuY2FsbCh0aGlzLl9pbmRpY2F0b3JzRWxlbWVudC5xdWVyeVNlbGVjdG9yQWxsKFNFTEVDVE9SX0FDVElWRSQxKSk7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGluZGljYXRvcnMpLnJlbW92ZUNsYXNzKENMQVNTX05BTUVfQUNUSVZFJDIpO1xuXG4gICAgICAgIHZhciBuZXh0SW5kaWNhdG9yID0gdGhpcy5faW5kaWNhdG9yc0VsZW1lbnQuY2hpbGRyZW5bdGhpcy5fZ2V0SXRlbUluZGV4KGVsZW1lbnQpXTtcblxuICAgICAgICBpZiAobmV4dEluZGljYXRvcikge1xuICAgICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKG5leHRJbmRpY2F0b3IpLmFkZENsYXNzKENMQVNTX05BTUVfQUNUSVZFJDIpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIF9wcm90by5fdXBkYXRlSW50ZXJ2YWwgPSBmdW5jdGlvbiBfdXBkYXRlSW50ZXJ2YWwoKSB7XG4gICAgICB2YXIgZWxlbWVudCA9IHRoaXMuX2FjdGl2ZUVsZW1lbnQgfHwgdGhpcy5fZWxlbWVudC5xdWVyeVNlbGVjdG9yKFNFTEVDVE9SX0FDVElWRV9JVEVNKTtcblxuICAgICAgaWYgKCFlbGVtZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIGVsZW1lbnRJbnRlcnZhbCA9IHBhcnNlSW50KGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLWludGVydmFsJyksIDEwKTtcblxuICAgICAgaWYgKGVsZW1lbnRJbnRlcnZhbCkge1xuICAgICAgICB0aGlzLl9jb25maWcuZGVmYXVsdEludGVydmFsID0gdGhpcy5fY29uZmlnLmRlZmF1bHRJbnRlcnZhbCB8fCB0aGlzLl9jb25maWcuaW50ZXJ2YWw7XG4gICAgICAgIHRoaXMuX2NvbmZpZy5pbnRlcnZhbCA9IGVsZW1lbnRJbnRlcnZhbDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuX2NvbmZpZy5pbnRlcnZhbCA9IHRoaXMuX2NvbmZpZy5kZWZhdWx0SW50ZXJ2YWwgfHwgdGhpcy5fY29uZmlnLmludGVydmFsO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBfcHJvdG8uX3NsaWRlID0gZnVuY3Rpb24gX3NsaWRlKGRpcmVjdGlvbiwgZWxlbWVudCkge1xuICAgICAgdmFyIF90aGlzNCA9IHRoaXM7XG5cbiAgICAgIHZhciBhY3RpdmVFbGVtZW50ID0gdGhpcy5fZWxlbWVudC5xdWVyeVNlbGVjdG9yKFNFTEVDVE9SX0FDVElWRV9JVEVNKTtcblxuICAgICAgdmFyIGFjdGl2ZUVsZW1lbnRJbmRleCA9IHRoaXMuX2dldEl0ZW1JbmRleChhY3RpdmVFbGVtZW50KTtcblxuICAgICAgdmFyIG5leHRFbGVtZW50ID0gZWxlbWVudCB8fCBhY3RpdmVFbGVtZW50ICYmIHRoaXMuX2dldEl0ZW1CeURpcmVjdGlvbihkaXJlY3Rpb24sIGFjdGl2ZUVsZW1lbnQpO1xuXG4gICAgICB2YXIgbmV4dEVsZW1lbnRJbmRleCA9IHRoaXMuX2dldEl0ZW1JbmRleChuZXh0RWxlbWVudCk7XG5cbiAgICAgIHZhciBpc0N5Y2xpbmcgPSBCb29sZWFuKHRoaXMuX2ludGVydmFsKTtcbiAgICAgIHZhciBkaXJlY3Rpb25hbENsYXNzTmFtZTtcbiAgICAgIHZhciBvcmRlckNsYXNzTmFtZTtcbiAgICAgIHZhciBldmVudERpcmVjdGlvbk5hbWU7XG5cbiAgICAgIGlmIChkaXJlY3Rpb24gPT09IERJUkVDVElPTl9ORVhUKSB7XG4gICAgICAgIGRpcmVjdGlvbmFsQ2xhc3NOYW1lID0gQ0xBU1NfTkFNRV9MRUZUO1xuICAgICAgICBvcmRlckNsYXNzTmFtZSA9IENMQVNTX05BTUVfTkVYVDtcbiAgICAgICAgZXZlbnREaXJlY3Rpb25OYW1lID0gRElSRUNUSU9OX0xFRlQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBkaXJlY3Rpb25hbENsYXNzTmFtZSA9IENMQVNTX05BTUVfUklHSFQ7XG4gICAgICAgIG9yZGVyQ2xhc3NOYW1lID0gQ0xBU1NfTkFNRV9QUkVWO1xuICAgICAgICBldmVudERpcmVjdGlvbk5hbWUgPSBESVJFQ1RJT05fUklHSFQ7XG4gICAgICB9XG5cbiAgICAgIGlmIChuZXh0RWxlbWVudCAmJiAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShuZXh0RWxlbWVudCkuaGFzQ2xhc3MoQ0xBU1NfTkFNRV9BQ1RJVkUkMikpIHtcbiAgICAgICAgdGhpcy5faXNTbGlkaW5nID0gZmFsc2U7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIHNsaWRlRXZlbnQgPSB0aGlzLl90cmlnZ2VyU2xpZGVFdmVudChuZXh0RWxlbWVudCwgZXZlbnREaXJlY3Rpb25OYW1lKTtcblxuICAgICAgaWYgKHNsaWRlRXZlbnQuaXNEZWZhdWx0UHJldmVudGVkKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWFjdGl2ZUVsZW1lbnQgfHwgIW5leHRFbGVtZW50KSB7XG4gICAgICAgIC8vIFNvbWUgd2VpcmRuZXNzIGlzIGhhcHBlbmluZywgc28gd2UgYmFpbFxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMuX2lzU2xpZGluZyA9IHRydWU7XG5cbiAgICAgIGlmIChpc0N5Y2xpbmcpIHtcbiAgICAgICAgdGhpcy5wYXVzZSgpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLl9zZXRBY3RpdmVJbmRpY2F0b3JFbGVtZW50KG5leHRFbGVtZW50KTtcblxuICAgICAgdGhpcy5fYWN0aXZlRWxlbWVudCA9IG5leHRFbGVtZW50O1xuICAgICAgdmFyIHNsaWRFdmVudCA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLkV2ZW50KEVWRU5UX1NMSUQsIHtcbiAgICAgICAgcmVsYXRlZFRhcmdldDogbmV4dEVsZW1lbnQsXG4gICAgICAgIGRpcmVjdGlvbjogZXZlbnREaXJlY3Rpb25OYW1lLFxuICAgICAgICBmcm9tOiBhY3RpdmVFbGVtZW50SW5kZXgsXG4gICAgICAgIHRvOiBuZXh0RWxlbWVudEluZGV4XG4gICAgICB9KTtcblxuICAgICAgaWYgKCRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLmhhc0NsYXNzKENMQVNTX05BTUVfU0xJREUpKSB7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKG5leHRFbGVtZW50KS5hZGRDbGFzcyhvcmRlckNsYXNzTmFtZSk7XG4gICAgICAgIFV0aWwucmVmbG93KG5leHRFbGVtZW50KTtcbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oYWN0aXZlRWxlbWVudCkuYWRkQ2xhc3MoZGlyZWN0aW9uYWxDbGFzc05hbWUpO1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShuZXh0RWxlbWVudCkuYWRkQ2xhc3MoZGlyZWN0aW9uYWxDbGFzc05hbWUpO1xuICAgICAgICB2YXIgdHJhbnNpdGlvbkR1cmF0aW9uID0gVXRpbC5nZXRUcmFuc2l0aW9uRHVyYXRpb25Gcm9tRWxlbWVudChhY3RpdmVFbGVtZW50KTtcbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oYWN0aXZlRWxlbWVudCkub25lKFV0aWwuVFJBTlNJVElPTl9FTkQsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShuZXh0RWxlbWVudCkucmVtb3ZlQ2xhc3MoZGlyZWN0aW9uYWxDbGFzc05hbWUgKyBcIiBcIiArIG9yZGVyQ2xhc3NOYW1lKS5hZGRDbGFzcyhDTEFTU19OQU1FX0FDVElWRSQyKTtcbiAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShhY3RpdmVFbGVtZW50KS5yZW1vdmVDbGFzcyhDTEFTU19OQU1FX0FDVElWRSQyICsgXCIgXCIgKyBvcmRlckNsYXNzTmFtZSArIFwiIFwiICsgZGlyZWN0aW9uYWxDbGFzc05hbWUpO1xuICAgICAgICAgIF90aGlzNC5faXNTbGlkaW5nID0gZmFsc2U7XG4gICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oX3RoaXM0Ll9lbGVtZW50KS50cmlnZ2VyKHNsaWRFdmVudCk7XG4gICAgICAgICAgfSwgMCk7XG4gICAgICAgIH0pLmVtdWxhdGVUcmFuc2l0aW9uRW5kKHRyYW5zaXRpb25EdXJhdGlvbik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShhY3RpdmVFbGVtZW50KS5yZW1vdmVDbGFzcyhDTEFTU19OQU1FX0FDVElWRSQyKTtcbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0obmV4dEVsZW1lbnQpLmFkZENsYXNzKENMQVNTX05BTUVfQUNUSVZFJDIpO1xuICAgICAgICB0aGlzLl9pc1NsaWRpbmcgPSBmYWxzZTtcbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkudHJpZ2dlcihzbGlkRXZlbnQpO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNDeWNsaW5nKSB7XG4gICAgICAgIHRoaXMuY3ljbGUoKTtcbiAgICAgIH1cbiAgICB9IC8vIFN0YXRpY1xuICAgIDtcblxuICAgIENhcm91c2VsLl9qUXVlcnlJbnRlcmZhY2UgPSBmdW5jdGlvbiBfalF1ZXJ5SW50ZXJmYWNlKGNvbmZpZykge1xuICAgICAgcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBkYXRhID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcykuZGF0YShEQVRBX0tFWSQ4KTtcblxuICAgICAgICB2YXIgX2NvbmZpZyA9IF9leHRlbmRzKHt9LCBEZWZhdWx0JDcsICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMpLmRhdGEoKSk7XG5cbiAgICAgICAgaWYgKHR5cGVvZiBjb25maWcgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgX2NvbmZpZyA9IF9leHRlbmRzKHt9LCBfY29uZmlnLCBjb25maWcpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGFjdGlvbiA9IHR5cGVvZiBjb25maWcgPT09ICdzdHJpbmcnID8gY29uZmlnIDogX2NvbmZpZy5zbGlkZTtcblxuICAgICAgICBpZiAoIWRhdGEpIHtcbiAgICAgICAgICBkYXRhID0gbmV3IENhcm91c2VsKHRoaXMsIF9jb25maWcpO1xuICAgICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMpLmRhdGEoREFUQV9LRVkkOCwgZGF0YSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIGNvbmZpZyA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgICBkYXRhLnRvKGNvbmZpZyk7XG4gICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGFjdGlvbiA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICBpZiAodHlwZW9mIGRhdGFbYWN0aW9uXSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJObyBtZXRob2QgbmFtZWQgXFxcIlwiICsgYWN0aW9uICsgXCJcXFwiXCIpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGRhdGFbYWN0aW9uXSgpO1xuICAgICAgICB9IGVsc2UgaWYgKF9jb25maWcuaW50ZXJ2YWwgJiYgX2NvbmZpZy5yaWRlKSB7XG4gICAgICAgICAgZGF0YS5wYXVzZSgpO1xuICAgICAgICAgIGRhdGEuY3ljbGUoKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIENhcm91c2VsLl9kYXRhQXBpQ2xpY2tIYW5kbGVyID0gZnVuY3Rpb24gX2RhdGFBcGlDbGlja0hhbmRsZXIoZXZlbnQpIHtcbiAgICAgIHZhciBzZWxlY3RvciA9IFV0aWwuZ2V0U2VsZWN0b3JGcm9tRWxlbWVudCh0aGlzKTtcblxuICAgICAgaWYgKCFzZWxlY3Rvcikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHZhciB0YXJnZXQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShzZWxlY3RvcilbMF07XG5cbiAgICAgIGlmICghdGFyZ2V0IHx8ICEkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0YXJnZXQpLmhhc0NsYXNzKENMQVNTX05BTUVfQ0FST1VTRUwpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIGNvbmZpZyA9IF9leHRlbmRzKHt9LCAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0YXJnZXQpLmRhdGEoKSwgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcykuZGF0YSgpKTtcblxuICAgICAgdmFyIHNsaWRlSW5kZXggPSB0aGlzLmdldEF0dHJpYnV0ZSgnZGF0YS1zbGlkZS10bycpO1xuXG4gICAgICBpZiAoc2xpZGVJbmRleCkge1xuICAgICAgICBjb25maWcuaW50ZXJ2YWwgPSBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgQ2Fyb3VzZWwuX2pRdWVyeUludGVyZmFjZS5jYWxsKCRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRhcmdldCksIGNvbmZpZyk7XG5cbiAgICAgIGlmIChzbGlkZUluZGV4KSB7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRhcmdldCkuZGF0YShEQVRBX0tFWSQ4KS50byhzbGlkZUluZGV4KTtcbiAgICAgIH1cblxuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9O1xuXG4gICAgX2NyZWF0ZUNsYXNzKENhcm91c2VsLCBudWxsLCBbe1xuICAgICAga2V5OiBcIlZFUlNJT05cIixcbiAgICAgIGdldDogZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgICByZXR1cm4gVkVSU0lPTiQ4O1xuICAgICAgfVxuICAgIH0sIHtcbiAgICAgIGtleTogXCJEZWZhdWx0XCIsXG4gICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgcmV0dXJuIERlZmF1bHQkNztcbiAgICAgIH1cbiAgICB9XSk7XG5cbiAgICByZXR1cm4gQ2Fyb3VzZWw7XG4gIH0oKTtcbiAgLyoqXG4gICAqIERhdGEgQVBJIGltcGxlbWVudGF0aW9uXG4gICAqL1xuXG5cbiAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZG9jdW1lbnQpLm9uKEVWRU5UX0NMSUNLX0RBVEFfQVBJJDQsIFNFTEVDVE9SX0RBVEFfU0xJREUsIENhcm91c2VsLl9kYXRhQXBpQ2xpY2tIYW5kbGVyKTtcbiAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0od2luZG93KS5vbihFVkVOVF9MT0FEX0RBVEFfQVBJJDEsIGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgY2Fyb3VzZWxzID0gW10uc2xpY2UuY2FsbChkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKFNFTEVDVE9SX0RBVEFfUklERSkpO1xuXG4gICAgZm9yICh2YXIgaSA9IDAsIGxlbiA9IGNhcm91c2Vscy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuICAgICAgdmFyICRjYXJvdXNlbCA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGNhcm91c2Vsc1tpXSk7XG5cbiAgICAgIENhcm91c2VsLl9qUXVlcnlJbnRlcmZhY2UuY2FsbCgkY2Fyb3VzZWwsICRjYXJvdXNlbC5kYXRhKCkpO1xuICAgIH1cbiAgfSk7XG4gIC8qKlxuICAgKiBqUXVlcnlcbiAgICovXG5cbiAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQ4XSA9IENhcm91c2VsLl9qUXVlcnlJbnRlcmZhY2U7XG4gICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuW05BTUUkOF0uQ29uc3RydWN0b3IgPSBDYXJvdXNlbDtcblxuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDhdLm5vQ29uZmxpY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQ4XSA9IEpRVUVSWV9OT19DT05GTElDVCQ4O1xuICAgIHJldHVybiBDYXJvdXNlbC5falF1ZXJ5SW50ZXJmYWNlO1xuICB9O1xuXG4gIC8qKlxuICAgKiBDb25zdGFudHNcbiAgICovXG5cbiAgdmFyIE5BTUUkNyA9ICdjb2xsYXBzZSc7XG4gIHZhciBWRVJTSU9OJDcgPSAnNC42LjEnO1xuICB2YXIgREFUQV9LRVkkNyA9ICdicy5jb2xsYXBzZSc7XG4gIHZhciBFVkVOVF9LRVkkNyA9IFwiLlwiICsgREFUQV9LRVkkNztcbiAgdmFyIERBVEFfQVBJX0tFWSQ0ID0gJy5kYXRhLWFwaSc7XG4gIHZhciBKUVVFUllfTk9fQ09ORkxJQ1QkNyA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuW05BTUUkN107XG4gIHZhciBDTEFTU19OQU1FX1NIT1ckNiA9ICdzaG93JztcbiAgdmFyIENMQVNTX05BTUVfQ09MTEFQU0UgPSAnY29sbGFwc2UnO1xuICB2YXIgQ0xBU1NfTkFNRV9DT0xMQVBTSU5HID0gJ2NvbGxhcHNpbmcnO1xuICB2YXIgQ0xBU1NfTkFNRV9DT0xMQVBTRUQgPSAnY29sbGFwc2VkJztcbiAgdmFyIERJTUVOU0lPTl9XSURUSCA9ICd3aWR0aCc7XG4gIHZhciBESU1FTlNJT05fSEVJR0hUID0gJ2hlaWdodCc7XG4gIHZhciBFVkVOVF9TSE9XJDQgPSBcInNob3dcIiArIEVWRU5UX0tFWSQ3O1xuICB2YXIgRVZFTlRfU0hPV04kNCA9IFwic2hvd25cIiArIEVWRU5UX0tFWSQ3O1xuICB2YXIgRVZFTlRfSElERSQ0ID0gXCJoaWRlXCIgKyBFVkVOVF9LRVkkNztcbiAgdmFyIEVWRU5UX0hJRERFTiQ0ID0gXCJoaWRkZW5cIiArIEVWRU5UX0tFWSQ3O1xuICB2YXIgRVZFTlRfQ0xJQ0tfREFUQV9BUEkkMyA9IFwiY2xpY2tcIiArIEVWRU5UX0tFWSQ3ICsgREFUQV9BUElfS0VZJDQ7XG4gIHZhciBTRUxFQ1RPUl9BQ1RJVkVTID0gJy5zaG93LCAuY29sbGFwc2luZyc7XG4gIHZhciBTRUxFQ1RPUl9EQVRBX1RPR0dMRSQzID0gJ1tkYXRhLXRvZ2dsZT1cImNvbGxhcHNlXCJdJztcbiAgdmFyIERlZmF1bHQkNiA9IHtcbiAgICB0b2dnbGU6IHRydWUsXG4gICAgcGFyZW50OiAnJ1xuICB9O1xuICB2YXIgRGVmYXVsdFR5cGUkNiA9IHtcbiAgICB0b2dnbGU6ICdib29sZWFuJyxcbiAgICBwYXJlbnQ6ICcoc3RyaW5nfGVsZW1lbnQpJ1xuICB9O1xuICAvKipcbiAgICogQ2xhc3MgZGVmaW5pdGlvblxuICAgKi9cblxuICB2YXIgQ29sbGFwc2UgPSAvKiNfX1BVUkVfXyovZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIENvbGxhcHNlKGVsZW1lbnQsIGNvbmZpZykge1xuICAgICAgdGhpcy5faXNUcmFuc2l0aW9uaW5nID0gZmFsc2U7XG4gICAgICB0aGlzLl9lbGVtZW50ID0gZWxlbWVudDtcbiAgICAgIHRoaXMuX2NvbmZpZyA9IHRoaXMuX2dldENvbmZpZyhjb25maWcpO1xuICAgICAgdGhpcy5fdHJpZ2dlckFycmF5ID0gW10uc2xpY2UuY2FsbChkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKFwiW2RhdGEtdG9nZ2xlPVxcXCJjb2xsYXBzZVxcXCJdW2hyZWY9XFxcIiNcIiArIGVsZW1lbnQuaWQgKyBcIlxcXCJdLFwiICsgKFwiW2RhdGEtdG9nZ2xlPVxcXCJjb2xsYXBzZVxcXCJdW2RhdGEtdGFyZ2V0PVxcXCIjXCIgKyBlbGVtZW50LmlkICsgXCJcXFwiXVwiKSkpO1xuICAgICAgdmFyIHRvZ2dsZUxpc3QgPSBbXS5zbGljZS5jYWxsKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoU0VMRUNUT1JfREFUQV9UT0dHTEUkMykpO1xuXG4gICAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gdG9nZ2xlTGlzdC5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuICAgICAgICB2YXIgZWxlbSA9IHRvZ2dsZUxpc3RbaV07XG4gICAgICAgIHZhciBzZWxlY3RvciA9IFV0aWwuZ2V0U2VsZWN0b3JGcm9tRWxlbWVudChlbGVtKTtcbiAgICAgICAgdmFyIGZpbHRlckVsZW1lbnQgPSBbXS5zbGljZS5jYWxsKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoc2VsZWN0b3IpKS5maWx0ZXIoZnVuY3Rpb24gKGZvdW5kRWxlbSkge1xuICAgICAgICAgIHJldHVybiBmb3VuZEVsZW0gPT09IGVsZW1lbnQ7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChzZWxlY3RvciAhPT0gbnVsbCAmJiBmaWx0ZXJFbGVtZW50Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICB0aGlzLl9zZWxlY3RvciA9IHNlbGVjdG9yO1xuXG4gICAgICAgICAgdGhpcy5fdHJpZ2dlckFycmF5LnB1c2goZWxlbSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdGhpcy5fcGFyZW50ID0gdGhpcy5fY29uZmlnLnBhcmVudCA/IHRoaXMuX2dldFBhcmVudCgpIDogbnVsbDtcblxuICAgICAgaWYgKCF0aGlzLl9jb25maWcucGFyZW50KSB7XG4gICAgICAgIHRoaXMuX2FkZEFyaWFBbmRDb2xsYXBzZWRDbGFzcyh0aGlzLl9lbGVtZW50LCB0aGlzLl90cmlnZ2VyQXJyYXkpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5fY29uZmlnLnRvZ2dsZSkge1xuICAgICAgICB0aGlzLnRvZ2dsZSgpO1xuICAgICAgfVxuICAgIH0gLy8gR2V0dGVyc1xuXG5cbiAgICB2YXIgX3Byb3RvID0gQ29sbGFwc2UucHJvdG90eXBlO1xuXG4gICAgLy8gUHVibGljXG4gICAgX3Byb3RvLnRvZ2dsZSA9IGZ1bmN0aW9uIHRvZ2dsZSgpIHtcbiAgICAgIGlmICgkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5oYXNDbGFzcyhDTEFTU19OQU1FX1NIT1ckNikpIHtcbiAgICAgICAgdGhpcy5oaWRlKCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnNob3coKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgX3Byb3RvLnNob3cgPSBmdW5jdGlvbiBzaG93KCkge1xuICAgICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgICAgaWYgKHRoaXMuX2lzVHJhbnNpdGlvbmluZyB8fCAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5oYXNDbGFzcyhDTEFTU19OQU1FX1NIT1ckNikpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB2YXIgYWN0aXZlcztcbiAgICAgIHZhciBhY3RpdmVzRGF0YTtcblxuICAgICAgaWYgKHRoaXMuX3BhcmVudCkge1xuICAgICAgICBhY3RpdmVzID0gW10uc2xpY2UuY2FsbCh0aGlzLl9wYXJlbnQucXVlcnlTZWxlY3RvckFsbChTRUxFQ1RPUl9BQ1RJVkVTKSkuZmlsdGVyKGZ1bmN0aW9uIChlbGVtKSB7XG4gICAgICAgICAgaWYgKHR5cGVvZiBfdGhpcy5fY29uZmlnLnBhcmVudCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIHJldHVybiBlbGVtLmdldEF0dHJpYnV0ZSgnZGF0YS1wYXJlbnQnKSA9PT0gX3RoaXMuX2NvbmZpZy5wYXJlbnQ7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIGVsZW0uY2xhc3NMaXN0LmNvbnRhaW5zKENMQVNTX05BTUVfQ09MTEFQU0UpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoYWN0aXZlcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICBhY3RpdmVzID0gbnVsbDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoYWN0aXZlcykge1xuICAgICAgICBhY3RpdmVzRGF0YSA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGFjdGl2ZXMpLm5vdCh0aGlzLl9zZWxlY3RvcikuZGF0YShEQVRBX0tFWSQ3KTtcblxuICAgICAgICBpZiAoYWN0aXZlc0RhdGEgJiYgYWN0aXZlc0RhdGEuX2lzVHJhbnNpdGlvbmluZykge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB2YXIgc3RhcnRFdmVudCA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLkV2ZW50KEVWRU5UX1NIT1ckNCk7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS50cmlnZ2VyKHN0YXJ0RXZlbnQpO1xuXG4gICAgICBpZiAoc3RhcnRFdmVudC5pc0RlZmF1bHRQcmV2ZW50ZWQoKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChhY3RpdmVzKSB7XG4gICAgICAgIENvbGxhcHNlLl9qUXVlcnlJbnRlcmZhY2UuY2FsbCgkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShhY3RpdmVzKS5ub3QodGhpcy5fc2VsZWN0b3IpLCAnaGlkZScpO1xuXG4gICAgICAgIGlmICghYWN0aXZlc0RhdGEpIHtcbiAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShhY3RpdmVzKS5kYXRhKERBVEFfS0VZJDcsIG51bGwpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHZhciBkaW1lbnNpb24gPSB0aGlzLl9nZXREaW1lbnNpb24oKTtcblxuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkucmVtb3ZlQ2xhc3MoQ0xBU1NfTkFNRV9DT0xMQVBTRSkuYWRkQ2xhc3MoQ0xBU1NfTkFNRV9DT0xMQVBTSU5HKTtcbiAgICAgIHRoaXMuX2VsZW1lbnQuc3R5bGVbZGltZW5zaW9uXSA9IDA7XG5cbiAgICAgIGlmICh0aGlzLl90cmlnZ2VyQXJyYXkubGVuZ3RoKSB7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX3RyaWdnZXJBcnJheSkucmVtb3ZlQ2xhc3MoQ0xBU1NfTkFNRV9DT0xMQVBTRUQpLmF0dHIoJ2FyaWEtZXhwYW5kZWQnLCB0cnVlKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRUcmFuc2l0aW9uaW5nKHRydWUpO1xuXG4gICAgICB2YXIgY29tcGxldGUgPSBmdW5jdGlvbiBjb21wbGV0ZSgpIHtcbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oX3RoaXMuX2VsZW1lbnQpLnJlbW92ZUNsYXNzKENMQVNTX05BTUVfQ09MTEFQU0lORykuYWRkQ2xhc3MoQ0xBU1NfTkFNRV9DT0xMQVBTRSArIFwiIFwiICsgQ0xBU1NfTkFNRV9TSE9XJDYpO1xuICAgICAgICBfdGhpcy5fZWxlbWVudC5zdHlsZVtkaW1lbnNpb25dID0gJyc7XG5cbiAgICAgICAgX3RoaXMuc2V0VHJhbnNpdGlvbmluZyhmYWxzZSk7XG5cbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oX3RoaXMuX2VsZW1lbnQpLnRyaWdnZXIoRVZFTlRfU0hPV04kNCk7XG4gICAgICB9O1xuXG4gICAgICB2YXIgY2FwaXRhbGl6ZWREaW1lbnNpb24gPSBkaW1lbnNpb25bMF0udG9VcHBlckNhc2UoKSArIGRpbWVuc2lvbi5zbGljZSgxKTtcbiAgICAgIHZhciBzY3JvbGxTaXplID0gXCJzY3JvbGxcIiArIGNhcGl0YWxpemVkRGltZW5zaW9uO1xuICAgICAgdmFyIHRyYW5zaXRpb25EdXJhdGlvbiA9IFV0aWwuZ2V0VHJhbnNpdGlvbkR1cmF0aW9uRnJvbUVsZW1lbnQodGhpcy5fZWxlbWVudCk7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5vbmUoVXRpbC5UUkFOU0lUSU9OX0VORCwgY29tcGxldGUpLmVtdWxhdGVUcmFuc2l0aW9uRW5kKHRyYW5zaXRpb25EdXJhdGlvbik7XG4gICAgICB0aGlzLl9lbGVtZW50LnN0eWxlW2RpbWVuc2lvbl0gPSB0aGlzLl9lbGVtZW50W3Njcm9sbFNpemVdICsgXCJweFwiO1xuICAgIH07XG5cbiAgICBfcHJvdG8uaGlkZSA9IGZ1bmN0aW9uIGhpZGUoKSB7XG4gICAgICB2YXIgX3RoaXMyID0gdGhpcztcblxuICAgICAgaWYgKHRoaXMuX2lzVHJhbnNpdGlvbmluZyB8fCAhJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkuaGFzQ2xhc3MoQ0xBU1NfTkFNRV9TSE9XJDYpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIHN0YXJ0RXZlbnQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5FdmVudChFVkVOVF9ISURFJDQpO1xuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkudHJpZ2dlcihzdGFydEV2ZW50KTtcblxuICAgICAgaWYgKHN0YXJ0RXZlbnQuaXNEZWZhdWx0UHJldmVudGVkKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB2YXIgZGltZW5zaW9uID0gdGhpcy5fZ2V0RGltZW5zaW9uKCk7XG5cbiAgICAgIHRoaXMuX2VsZW1lbnQuc3R5bGVbZGltZW5zaW9uXSA9IHRoaXMuX2VsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KClbZGltZW5zaW9uXSArIFwicHhcIjtcbiAgICAgIFV0aWwucmVmbG93KHRoaXMuX2VsZW1lbnQpO1xuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkuYWRkQ2xhc3MoQ0xBU1NfTkFNRV9DT0xMQVBTSU5HKS5yZW1vdmVDbGFzcyhDTEFTU19OQU1FX0NPTExBUFNFICsgXCIgXCIgKyBDTEFTU19OQU1FX1NIT1ckNik7XG4gICAgICB2YXIgdHJpZ2dlckFycmF5TGVuZ3RoID0gdGhpcy5fdHJpZ2dlckFycmF5Lmxlbmd0aDtcblxuICAgICAgaWYgKHRyaWdnZXJBcnJheUxlbmd0aCA+IDApIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0cmlnZ2VyQXJyYXlMZW5ndGg7IGkrKykge1xuICAgICAgICAgIHZhciB0cmlnZ2VyID0gdGhpcy5fdHJpZ2dlckFycmF5W2ldO1xuICAgICAgICAgIHZhciBzZWxlY3RvciA9IFV0aWwuZ2V0U2VsZWN0b3JGcm9tRWxlbWVudCh0cmlnZ2VyKTtcblxuICAgICAgICAgIGlmIChzZWxlY3RvciAhPT0gbnVsbCkge1xuICAgICAgICAgICAgdmFyICRlbGVtID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oW10uc2xpY2UuY2FsbChkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKHNlbGVjdG9yKSkpO1xuXG4gICAgICAgICAgICBpZiAoISRlbGVtLmhhc0NsYXNzKENMQVNTX05BTUVfU0hPVyQ2KSkge1xuICAgICAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0cmlnZ2VyKS5hZGRDbGFzcyhDTEFTU19OQU1FX0NPTExBUFNFRCkuYXR0cignYXJpYS1leHBhbmRlZCcsIGZhbHNlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdGhpcy5zZXRUcmFuc2l0aW9uaW5nKHRydWUpO1xuXG4gICAgICB2YXIgY29tcGxldGUgPSBmdW5jdGlvbiBjb21wbGV0ZSgpIHtcbiAgICAgICAgX3RoaXMyLnNldFRyYW5zaXRpb25pbmcoZmFsc2UpO1xuXG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKF90aGlzMi5fZWxlbWVudCkucmVtb3ZlQ2xhc3MoQ0xBU1NfTkFNRV9DT0xMQVBTSU5HKS5hZGRDbGFzcyhDTEFTU19OQU1FX0NPTExBUFNFKS50cmlnZ2VyKEVWRU5UX0hJRERFTiQ0KTtcbiAgICAgIH07XG5cbiAgICAgIHRoaXMuX2VsZW1lbnQuc3R5bGVbZGltZW5zaW9uXSA9ICcnO1xuICAgICAgdmFyIHRyYW5zaXRpb25EdXJhdGlvbiA9IFV0aWwuZ2V0VHJhbnNpdGlvbkR1cmF0aW9uRnJvbUVsZW1lbnQodGhpcy5fZWxlbWVudCk7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5vbmUoVXRpbC5UUkFOU0lUSU9OX0VORCwgY29tcGxldGUpLmVtdWxhdGVUcmFuc2l0aW9uRW5kKHRyYW5zaXRpb25EdXJhdGlvbik7XG4gICAgfTtcblxuICAgIF9wcm90by5zZXRUcmFuc2l0aW9uaW5nID0gZnVuY3Rpb24gc2V0VHJhbnNpdGlvbmluZyhpc1RyYW5zaXRpb25pbmcpIHtcbiAgICAgIHRoaXMuX2lzVHJhbnNpdGlvbmluZyA9IGlzVHJhbnNpdGlvbmluZztcbiAgICB9O1xuXG4gICAgX3Byb3RvLmRpc3Bvc2UgPSBmdW5jdGlvbiBkaXNwb3NlKCkge1xuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0ucmVtb3ZlRGF0YSh0aGlzLl9lbGVtZW50LCBEQVRBX0tFWSQ3KTtcbiAgICAgIHRoaXMuX2NvbmZpZyA9IG51bGw7XG4gICAgICB0aGlzLl9wYXJlbnQgPSBudWxsO1xuICAgICAgdGhpcy5fZWxlbWVudCA9IG51bGw7XG4gICAgICB0aGlzLl90cmlnZ2VyQXJyYXkgPSBudWxsO1xuICAgICAgdGhpcy5faXNUcmFuc2l0aW9uaW5nID0gbnVsbDtcbiAgICB9IC8vIFByaXZhdGVcbiAgICA7XG5cbiAgICBfcHJvdG8uX2dldENvbmZpZyA9IGZ1bmN0aW9uIF9nZXRDb25maWcoY29uZmlnKSB7XG4gICAgICBjb25maWcgPSBfZXh0ZW5kcyh7fSwgRGVmYXVsdCQ2LCBjb25maWcpO1xuICAgICAgY29uZmlnLnRvZ2dsZSA9IEJvb2xlYW4oY29uZmlnLnRvZ2dsZSk7IC8vIENvZXJjZSBzdHJpbmcgdmFsdWVzXG5cbiAgICAgIFV0aWwudHlwZUNoZWNrQ29uZmlnKE5BTUUkNywgY29uZmlnLCBEZWZhdWx0VHlwZSQ2KTtcbiAgICAgIHJldHVybiBjb25maWc7XG4gICAgfTtcblxuICAgIF9wcm90by5fZ2V0RGltZW5zaW9uID0gZnVuY3Rpb24gX2dldERpbWVuc2lvbigpIHtcbiAgICAgIHZhciBoYXNXaWR0aCA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLmhhc0NsYXNzKERJTUVOU0lPTl9XSURUSCk7XG4gICAgICByZXR1cm4gaGFzV2lkdGggPyBESU1FTlNJT05fV0lEVEggOiBESU1FTlNJT05fSEVJR0hUO1xuICAgIH07XG5cbiAgICBfcHJvdG8uX2dldFBhcmVudCA9IGZ1bmN0aW9uIF9nZXRQYXJlbnQoKSB7XG4gICAgICB2YXIgX3RoaXMzID0gdGhpcztcblxuICAgICAgdmFyIHBhcmVudDtcblxuICAgICAgaWYgKFV0aWwuaXNFbGVtZW50KHRoaXMuX2NvbmZpZy5wYXJlbnQpKSB7XG4gICAgICAgIHBhcmVudCA9IHRoaXMuX2NvbmZpZy5wYXJlbnQ7IC8vIEl0J3MgYSBqUXVlcnkgb2JqZWN0XG5cbiAgICAgICAgaWYgKHR5cGVvZiB0aGlzLl9jb25maWcucGFyZW50LmpxdWVyeSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICBwYXJlbnQgPSB0aGlzLl9jb25maWcucGFyZW50WzBdO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwYXJlbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuX2NvbmZpZy5wYXJlbnQpO1xuICAgICAgfVxuXG4gICAgICB2YXIgc2VsZWN0b3IgPSBcIltkYXRhLXRvZ2dsZT1cXFwiY29sbGFwc2VcXFwiXVtkYXRhLXBhcmVudD1cXFwiXCIgKyB0aGlzLl9jb25maWcucGFyZW50ICsgXCJcXFwiXVwiO1xuICAgICAgdmFyIGNoaWxkcmVuID0gW10uc2xpY2UuY2FsbChwYXJlbnQucXVlcnlTZWxlY3RvckFsbChzZWxlY3RvcikpO1xuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oY2hpbGRyZW4pLmVhY2goZnVuY3Rpb24gKGksIGVsZW1lbnQpIHtcbiAgICAgICAgX3RoaXMzLl9hZGRBcmlhQW5kQ29sbGFwc2VkQ2xhc3MoQ29sbGFwc2UuX2dldFRhcmdldEZyb21FbGVtZW50KGVsZW1lbnQpLCBbZWxlbWVudF0pO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gcGFyZW50O1xuICAgIH07XG5cbiAgICBfcHJvdG8uX2FkZEFyaWFBbmRDb2xsYXBzZWRDbGFzcyA9IGZ1bmN0aW9uIF9hZGRBcmlhQW5kQ29sbGFwc2VkQ2xhc3MoZWxlbWVudCwgdHJpZ2dlckFycmF5KSB7XG4gICAgICB2YXIgaXNPcGVuID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZWxlbWVudCkuaGFzQ2xhc3MoQ0xBU1NfTkFNRV9TSE9XJDYpO1xuXG4gICAgICBpZiAodHJpZ2dlckFycmF5Lmxlbmd0aCkge1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0cmlnZ2VyQXJyYXkpLnRvZ2dsZUNsYXNzKENMQVNTX05BTUVfQ09MTEFQU0VELCAhaXNPcGVuKS5hdHRyKCdhcmlhLWV4cGFuZGVkJywgaXNPcGVuKTtcbiAgICAgIH1cbiAgICB9IC8vIFN0YXRpY1xuICAgIDtcblxuICAgIENvbGxhcHNlLl9nZXRUYXJnZXRGcm9tRWxlbWVudCA9IGZ1bmN0aW9uIF9nZXRUYXJnZXRGcm9tRWxlbWVudChlbGVtZW50KSB7XG4gICAgICB2YXIgc2VsZWN0b3IgPSBVdGlsLmdldFNlbGVjdG9yRnJvbUVsZW1lbnQoZWxlbWVudCk7XG4gICAgICByZXR1cm4gc2VsZWN0b3IgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHNlbGVjdG9yKSA6IG51bGw7XG4gICAgfTtcblxuICAgIENvbGxhcHNlLl9qUXVlcnlJbnRlcmZhY2UgPSBmdW5jdGlvbiBfalF1ZXJ5SW50ZXJmYWNlKGNvbmZpZykge1xuICAgICAgcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciAkZWxlbWVudCA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMpO1xuICAgICAgICB2YXIgZGF0YSA9ICRlbGVtZW50LmRhdGEoREFUQV9LRVkkNyk7XG5cbiAgICAgICAgdmFyIF9jb25maWcgPSBfZXh0ZW5kcyh7fSwgRGVmYXVsdCQ2LCAkZWxlbWVudC5kYXRhKCksIHR5cGVvZiBjb25maWcgPT09ICdvYmplY3QnICYmIGNvbmZpZyA/IGNvbmZpZyA6IHt9KTtcblxuICAgICAgICBpZiAoIWRhdGEgJiYgX2NvbmZpZy50b2dnbGUgJiYgdHlwZW9mIGNvbmZpZyA9PT0gJ3N0cmluZycgJiYgL3Nob3d8aGlkZS8udGVzdChjb25maWcpKSB7XG4gICAgICAgICAgX2NvbmZpZy50b2dnbGUgPSBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghZGF0YSkge1xuICAgICAgICAgIGRhdGEgPSBuZXcgQ29sbGFwc2UodGhpcywgX2NvbmZpZyk7XG4gICAgICAgICAgJGVsZW1lbnQuZGF0YShEQVRBX0tFWSQ3LCBkYXRhKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgY29uZmlnID09PSAnc3RyaW5nJykge1xuICAgICAgICAgIGlmICh0eXBlb2YgZGF0YVtjb25maWddID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIk5vIG1ldGhvZCBuYW1lZCBcXFwiXCIgKyBjb25maWcgKyBcIlxcXCJcIik7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZGF0YVtjb25maWddKCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICBfY3JlYXRlQ2xhc3MoQ29sbGFwc2UsIG51bGwsIFt7XG4gICAgICBrZXk6IFwiVkVSU0lPTlwiLFxuICAgICAgZ2V0OiBmdW5jdGlvbiBnZXQoKSB7XG4gICAgICAgIHJldHVybiBWRVJTSU9OJDc7XG4gICAgICB9XG4gICAgfSwge1xuICAgICAga2V5OiBcIkRlZmF1bHRcIixcbiAgICAgIGdldDogZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgICByZXR1cm4gRGVmYXVsdCQ2O1xuICAgICAgfVxuICAgIH1dKTtcblxuICAgIHJldHVybiBDb2xsYXBzZTtcbiAgfSgpO1xuICAvKipcbiAgICogRGF0YSBBUEkgaW1wbGVtZW50YXRpb25cbiAgICovXG5cblxuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShkb2N1bWVudCkub24oRVZFTlRfQ0xJQ0tfREFUQV9BUEkkMywgU0VMRUNUT1JfREFUQV9UT0dHTEUkMywgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgLy8gcHJldmVudERlZmF1bHQgb25seSBmb3IgPGE+IGVsZW1lbnRzICh3aGljaCBjaGFuZ2UgdGhlIFVSTCkgbm90IGluc2lkZSB0aGUgY29sbGFwc2libGUgZWxlbWVudFxuICAgIGlmIChldmVudC5jdXJyZW50VGFyZ2V0LnRhZ05hbWUgPT09ICdBJykge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG5cbiAgICB2YXIgJHRyaWdnZXIgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzKTtcbiAgICB2YXIgc2VsZWN0b3IgPSBVdGlsLmdldFNlbGVjdG9yRnJvbUVsZW1lbnQodGhpcyk7XG4gICAgdmFyIHNlbGVjdG9ycyA9IFtdLnNsaWNlLmNhbGwoZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbChzZWxlY3RvcikpO1xuICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHNlbGVjdG9ycykuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICB2YXIgJHRhcmdldCA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMpO1xuICAgICAgdmFyIGRhdGEgPSAkdGFyZ2V0LmRhdGEoREFUQV9LRVkkNyk7XG4gICAgICB2YXIgY29uZmlnID0gZGF0YSA/ICd0b2dnbGUnIDogJHRyaWdnZXIuZGF0YSgpO1xuXG4gICAgICBDb2xsYXBzZS5falF1ZXJ5SW50ZXJmYWNlLmNhbGwoJHRhcmdldCwgY29uZmlnKTtcbiAgICB9KTtcbiAgfSk7XG4gIC8qKlxuICAgKiBqUXVlcnlcbiAgICovXG5cbiAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQ3XSA9IENvbGxhcHNlLl9qUXVlcnlJbnRlcmZhY2U7XG4gICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuW05BTUUkN10uQ29uc3RydWN0b3IgPSBDb2xsYXBzZTtcblxuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDddLm5vQ29uZmxpY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQ3XSA9IEpRVUVSWV9OT19DT05GTElDVCQ3O1xuICAgIHJldHVybiBDb2xsYXBzZS5falF1ZXJ5SW50ZXJmYWNlO1xuICB9O1xuXG4gIC8qKlxuICAgKiBDb25zdGFudHNcbiAgICovXG5cbiAgdmFyIE5BTUUkNiA9ICdkcm9wZG93bic7XG4gIHZhciBWRVJTSU9OJDYgPSAnNC42LjEnO1xuICB2YXIgREFUQV9LRVkkNiA9ICdicy5kcm9wZG93bic7XG4gIHZhciBFVkVOVF9LRVkkNiA9IFwiLlwiICsgREFUQV9LRVkkNjtcbiAgdmFyIERBVEFfQVBJX0tFWSQzID0gJy5kYXRhLWFwaSc7XG4gIHZhciBKUVVFUllfTk9fQ09ORkxJQ1QkNiA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuW05BTUUkNl07XG4gIHZhciBFU0NBUEVfS0VZQ09ERSQxID0gMjc7IC8vIEtleWJvYXJkRXZlbnQud2hpY2ggdmFsdWUgZm9yIEVzY2FwZSAoRXNjKSBrZXlcblxuICB2YXIgU1BBQ0VfS0VZQ09ERSA9IDMyOyAvLyBLZXlib2FyZEV2ZW50LndoaWNoIHZhbHVlIGZvciBzcGFjZSBrZXlcblxuICB2YXIgVEFCX0tFWUNPREUgPSA5OyAvLyBLZXlib2FyZEV2ZW50LndoaWNoIHZhbHVlIGZvciB0YWIga2V5XG5cbiAgdmFyIEFSUk9XX1VQX0tFWUNPREUgPSAzODsgLy8gS2V5Ym9hcmRFdmVudC53aGljaCB2YWx1ZSBmb3IgdXAgYXJyb3cga2V5XG5cbiAgdmFyIEFSUk9XX0RPV05fS0VZQ09ERSA9IDQwOyAvLyBLZXlib2FyZEV2ZW50LndoaWNoIHZhbHVlIGZvciBkb3duIGFycm93IGtleVxuXG4gIHZhciBSSUdIVF9NT1VTRV9CVVRUT05fV0hJQ0ggPSAzOyAvLyBNb3VzZUV2ZW50LndoaWNoIHZhbHVlIGZvciB0aGUgcmlnaHQgYnV0dG9uIChhc3N1bWluZyBhIHJpZ2h0LWhhbmRlZCBtb3VzZSlcblxuICB2YXIgUkVHRVhQX0tFWURPV04gPSBuZXcgUmVnRXhwKEFSUk9XX1VQX0tFWUNPREUgKyBcInxcIiArIEFSUk9XX0RPV05fS0VZQ09ERSArIFwifFwiICsgRVNDQVBFX0tFWUNPREUkMSk7XG4gIHZhciBDTEFTU19OQU1FX0RJU0FCTEVEJDEgPSAnZGlzYWJsZWQnO1xuICB2YXIgQ0xBU1NfTkFNRV9TSE9XJDUgPSAnc2hvdyc7XG4gIHZhciBDTEFTU19OQU1FX0RST1BVUCA9ICdkcm9wdXAnO1xuICB2YXIgQ0xBU1NfTkFNRV9EUk9QUklHSFQgPSAnZHJvcHJpZ2h0JztcbiAgdmFyIENMQVNTX05BTUVfRFJPUExFRlQgPSAnZHJvcGxlZnQnO1xuICB2YXIgQ0xBU1NfTkFNRV9NRU5VUklHSFQgPSAnZHJvcGRvd24tbWVudS1yaWdodCc7XG4gIHZhciBDTEFTU19OQU1FX1BPU0lUSU9OX1NUQVRJQyA9ICdwb3NpdGlvbi1zdGF0aWMnO1xuICB2YXIgRVZFTlRfSElERSQzID0gXCJoaWRlXCIgKyBFVkVOVF9LRVkkNjtcbiAgdmFyIEVWRU5UX0hJRERFTiQzID0gXCJoaWRkZW5cIiArIEVWRU5UX0tFWSQ2O1xuICB2YXIgRVZFTlRfU0hPVyQzID0gXCJzaG93XCIgKyBFVkVOVF9LRVkkNjtcbiAgdmFyIEVWRU5UX1NIT1dOJDMgPSBcInNob3duXCIgKyBFVkVOVF9LRVkkNjtcbiAgdmFyIEVWRU5UX0NMSUNLID0gXCJjbGlja1wiICsgRVZFTlRfS0VZJDY7XG4gIHZhciBFVkVOVF9DTElDS19EQVRBX0FQSSQyID0gXCJjbGlja1wiICsgRVZFTlRfS0VZJDYgKyBEQVRBX0FQSV9LRVkkMztcbiAgdmFyIEVWRU5UX0tFWURPV05fREFUQV9BUEkgPSBcImtleWRvd25cIiArIEVWRU5UX0tFWSQ2ICsgREFUQV9BUElfS0VZJDM7XG4gIHZhciBFVkVOVF9LRVlVUF9EQVRBX0FQSSA9IFwia2V5dXBcIiArIEVWRU5UX0tFWSQ2ICsgREFUQV9BUElfS0VZJDM7XG4gIHZhciBTRUxFQ1RPUl9EQVRBX1RPR0dMRSQyID0gJ1tkYXRhLXRvZ2dsZT1cImRyb3Bkb3duXCJdJztcbiAgdmFyIFNFTEVDVE9SX0ZPUk1fQ0hJTEQgPSAnLmRyb3Bkb3duIGZvcm0nO1xuICB2YXIgU0VMRUNUT1JfTUVOVSA9ICcuZHJvcGRvd24tbWVudSc7XG4gIHZhciBTRUxFQ1RPUl9OQVZCQVJfTkFWID0gJy5uYXZiYXItbmF2JztcbiAgdmFyIFNFTEVDVE9SX1ZJU0lCTEVfSVRFTVMgPSAnLmRyb3Bkb3duLW1lbnUgLmRyb3Bkb3duLWl0ZW06bm90KC5kaXNhYmxlZCk6bm90KDpkaXNhYmxlZCknO1xuICB2YXIgUExBQ0VNRU5UX1RPUCA9ICd0b3Atc3RhcnQnO1xuICB2YXIgUExBQ0VNRU5UX1RPUEVORCA9ICd0b3AtZW5kJztcbiAgdmFyIFBMQUNFTUVOVF9CT1RUT00gPSAnYm90dG9tLXN0YXJ0JztcbiAgdmFyIFBMQUNFTUVOVF9CT1RUT01FTkQgPSAnYm90dG9tLWVuZCc7XG4gIHZhciBQTEFDRU1FTlRfUklHSFQgPSAncmlnaHQtc3RhcnQnO1xuICB2YXIgUExBQ0VNRU5UX0xFRlQgPSAnbGVmdC1zdGFydCc7XG4gIHZhciBEZWZhdWx0JDUgPSB7XG4gICAgb2Zmc2V0OiAwLFxuICAgIGZsaXA6IHRydWUsXG4gICAgYm91bmRhcnk6ICdzY3JvbGxQYXJlbnQnLFxuICAgIHJlZmVyZW5jZTogJ3RvZ2dsZScsXG4gICAgZGlzcGxheTogJ2R5bmFtaWMnLFxuICAgIHBvcHBlckNvbmZpZzogbnVsbFxuICB9O1xuICB2YXIgRGVmYXVsdFR5cGUkNSA9IHtcbiAgICBvZmZzZXQ6ICcobnVtYmVyfHN0cmluZ3xmdW5jdGlvbiknLFxuICAgIGZsaXA6ICdib29sZWFuJyxcbiAgICBib3VuZGFyeTogJyhzdHJpbmd8ZWxlbWVudCknLFxuICAgIHJlZmVyZW5jZTogJyhzdHJpbmd8ZWxlbWVudCknLFxuICAgIGRpc3BsYXk6ICdzdHJpbmcnLFxuICAgIHBvcHBlckNvbmZpZzogJyhudWxsfG9iamVjdCknXG4gIH07XG4gIC8qKlxuICAgKiBDbGFzcyBkZWZpbml0aW9uXG4gICAqL1xuXG4gIHZhciBEcm9wZG93biA9IC8qI19fUFVSRV9fKi9mdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gRHJvcGRvd24oZWxlbWVudCwgY29uZmlnKSB7XG4gICAgICB0aGlzLl9lbGVtZW50ID0gZWxlbWVudDtcbiAgICAgIHRoaXMuX3BvcHBlciA9IG51bGw7XG4gICAgICB0aGlzLl9jb25maWcgPSB0aGlzLl9nZXRDb25maWcoY29uZmlnKTtcbiAgICAgIHRoaXMuX21lbnUgPSB0aGlzLl9nZXRNZW51RWxlbWVudCgpO1xuICAgICAgdGhpcy5faW5OYXZiYXIgPSB0aGlzLl9kZXRlY3ROYXZiYXIoKTtcblxuICAgICAgdGhpcy5fYWRkRXZlbnRMaXN0ZW5lcnMoKTtcbiAgICB9IC8vIEdldHRlcnNcblxuXG4gICAgdmFyIF9wcm90byA9IERyb3Bkb3duLnByb3RvdHlwZTtcblxuICAgIC8vIFB1YmxpY1xuICAgIF9wcm90by50b2dnbGUgPSBmdW5jdGlvbiB0b2dnbGUoKSB7XG4gICAgICBpZiAodGhpcy5fZWxlbWVudC5kaXNhYmxlZCB8fCAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5oYXNDbGFzcyhDTEFTU19OQU1FX0RJU0FCTEVEJDEpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIGlzQWN0aXZlID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fbWVudSkuaGFzQ2xhc3MoQ0xBU1NfTkFNRV9TSE9XJDUpO1xuXG4gICAgICBEcm9wZG93bi5fY2xlYXJNZW51cygpO1xuXG4gICAgICBpZiAoaXNBY3RpdmUpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnNob3codHJ1ZSk7XG4gICAgfTtcblxuICAgIF9wcm90by5zaG93ID0gZnVuY3Rpb24gc2hvdyh1c2VQb3BwZXIpIHtcbiAgICAgIGlmICh1c2VQb3BwZXIgPT09IHZvaWQgMCkge1xuICAgICAgICB1c2VQb3BwZXIgPSBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuX2VsZW1lbnQuZGlzYWJsZWQgfHwgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkuaGFzQ2xhc3MoQ0xBU1NfTkFNRV9ESVNBQkxFRCQxKSB8fCAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9tZW51KS5oYXNDbGFzcyhDTEFTU19OQU1FX1NIT1ckNSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB2YXIgcmVsYXRlZFRhcmdldCA9IHtcbiAgICAgICAgcmVsYXRlZFRhcmdldDogdGhpcy5fZWxlbWVudFxuICAgICAgfTtcbiAgICAgIHZhciBzaG93RXZlbnQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5FdmVudChFVkVOVF9TSE9XJDMsIHJlbGF0ZWRUYXJnZXQpO1xuXG4gICAgICB2YXIgcGFyZW50ID0gRHJvcGRvd24uX2dldFBhcmVudEZyb21FbGVtZW50KHRoaXMuX2VsZW1lbnQpO1xuXG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShwYXJlbnQpLnRyaWdnZXIoc2hvd0V2ZW50KTtcblxuICAgICAgaWYgKHNob3dFdmVudC5pc0RlZmF1bHRQcmV2ZW50ZWQoKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9IC8vIFRvdGFsbHkgZGlzYWJsZSBQb3BwZXIgZm9yIERyb3Bkb3ducyBpbiBOYXZiYXJcblxuXG4gICAgICBpZiAoIXRoaXMuX2luTmF2YmFyICYmIHVzZVBvcHBlcikge1xuICAgICAgICAvLyBDaGVjayBmb3IgUG9wcGVyIGRlcGVuZGVuY3lcbiAgICAgICAgaWYgKHR5cGVvZiBQb3BwZXJfX2RlZmF1bHRbXCJkZWZhdWx0XCJdID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0Jvb3RzdHJhcFxcJ3MgZHJvcGRvd25zIHJlcXVpcmUgUG9wcGVyIChodHRwczovL3BvcHBlci5qcy5vcmcpJyk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcmVmZXJlbmNlRWxlbWVudCA9IHRoaXMuX2VsZW1lbnQ7XG5cbiAgICAgICAgaWYgKHRoaXMuX2NvbmZpZy5yZWZlcmVuY2UgPT09ICdwYXJlbnQnKSB7XG4gICAgICAgICAgcmVmZXJlbmNlRWxlbWVudCA9IHBhcmVudDtcbiAgICAgICAgfSBlbHNlIGlmIChVdGlsLmlzRWxlbWVudCh0aGlzLl9jb25maWcucmVmZXJlbmNlKSkge1xuICAgICAgICAgIHJlZmVyZW5jZUVsZW1lbnQgPSB0aGlzLl9jb25maWcucmVmZXJlbmNlOyAvLyBDaGVjayBpZiBpdCdzIGpRdWVyeSBlbGVtZW50XG5cbiAgICAgICAgICBpZiAodHlwZW9mIHRoaXMuX2NvbmZpZy5yZWZlcmVuY2UuanF1ZXJ5ICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgcmVmZXJlbmNlRWxlbWVudCA9IHRoaXMuX2NvbmZpZy5yZWZlcmVuY2VbMF07XG4gICAgICAgICAgfVxuICAgICAgICB9IC8vIElmIGJvdW5kYXJ5IGlzIG5vdCBgc2Nyb2xsUGFyZW50YCwgdGhlbiBzZXQgcG9zaXRpb24gdG8gYHN0YXRpY2BcbiAgICAgICAgLy8gdG8gYWxsb3cgdGhlIG1lbnUgdG8gXCJlc2NhcGVcIiB0aGUgc2Nyb2xsIHBhcmVudCdzIGJvdW5kYXJpZXNcbiAgICAgICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL3R3YnMvYm9vdHN0cmFwL2lzc3Vlcy8yNDI1MVxuXG5cbiAgICAgICAgaWYgKHRoaXMuX2NvbmZpZy5ib3VuZGFyeSAhPT0gJ3Njcm9sbFBhcmVudCcpIHtcbiAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShwYXJlbnQpLmFkZENsYXNzKENMQVNTX05BTUVfUE9TSVRJT05fU1RBVElDKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuX3BvcHBlciA9IG5ldyBQb3BwZXJfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHJlZmVyZW5jZUVsZW1lbnQsIHRoaXMuX21lbnUsIHRoaXMuX2dldFBvcHBlckNvbmZpZygpKTtcbiAgICAgIH0gLy8gSWYgdGhpcyBpcyBhIHRvdWNoLWVuYWJsZWQgZGV2aWNlIHdlIGFkZCBleHRyYVxuICAgICAgLy8gZW1wdHkgbW91c2VvdmVyIGxpc3RlbmVycyB0byB0aGUgYm9keSdzIGltbWVkaWF0ZSBjaGlsZHJlbjtcbiAgICAgIC8vIG9ubHkgbmVlZGVkIGJlY2F1c2Ugb2YgYnJva2VuIGV2ZW50IGRlbGVnYXRpb24gb24gaU9TXG4gICAgICAvLyBodHRwczovL3d3dy5xdWlya3Ntb2RlLm9yZy9ibG9nL2FyY2hpdmVzLzIwMTQvMDIvbW91c2VfZXZlbnRfYnViLmh0bWxcblxuXG4gICAgICBpZiAoJ29udG91Y2hzdGFydCcgaW4gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50ICYmICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHBhcmVudCkuY2xvc2VzdChTRUxFQ1RPUl9OQVZCQVJfTkFWKS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZG9jdW1lbnQuYm9keSkuY2hpbGRyZW4oKS5vbignbW91c2VvdmVyJywgbnVsbCwgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0ubm9vcCk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuX2VsZW1lbnQuZm9jdXMoKTtcblxuICAgICAgdGhpcy5fZWxlbWVudC5zZXRBdHRyaWJ1dGUoJ2FyaWEtZXhwYW5kZWQnLCB0cnVlKTtcblxuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fbWVudSkudG9nZ2xlQ2xhc3MoQ0xBU1NfTkFNRV9TSE9XJDUpO1xuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0ocGFyZW50KS50b2dnbGVDbGFzcyhDTEFTU19OQU1FX1NIT1ckNSkudHJpZ2dlcigkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5FdmVudChFVkVOVF9TSE9XTiQzLCByZWxhdGVkVGFyZ2V0KSk7XG4gICAgfTtcblxuICAgIF9wcm90by5oaWRlID0gZnVuY3Rpb24gaGlkZSgpIHtcbiAgICAgIGlmICh0aGlzLl9lbGVtZW50LmRpc2FibGVkIHx8ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLmhhc0NsYXNzKENMQVNTX05BTUVfRElTQUJMRUQkMSkgfHwgISRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX21lbnUpLmhhc0NsYXNzKENMQVNTX05BTUVfU0hPVyQ1KSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHZhciByZWxhdGVkVGFyZ2V0ID0ge1xuICAgICAgICByZWxhdGVkVGFyZ2V0OiB0aGlzLl9lbGVtZW50XG4gICAgICB9O1xuICAgICAgdmFyIGhpZGVFdmVudCA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLkV2ZW50KEVWRU5UX0hJREUkMywgcmVsYXRlZFRhcmdldCk7XG5cbiAgICAgIHZhciBwYXJlbnQgPSBEcm9wZG93bi5fZ2V0UGFyZW50RnJvbUVsZW1lbnQodGhpcy5fZWxlbWVudCk7XG5cbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHBhcmVudCkudHJpZ2dlcihoaWRlRXZlbnQpO1xuXG4gICAgICBpZiAoaGlkZUV2ZW50LmlzRGVmYXVsdFByZXZlbnRlZCgpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuX3BvcHBlcikge1xuICAgICAgICB0aGlzLl9wb3BwZXIuZGVzdHJveSgpO1xuICAgICAgfVxuXG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9tZW51KS50b2dnbGVDbGFzcyhDTEFTU19OQU1FX1NIT1ckNSk7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShwYXJlbnQpLnRvZ2dsZUNsYXNzKENMQVNTX05BTUVfU0hPVyQ1KS50cmlnZ2VyKCRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLkV2ZW50KEVWRU5UX0hJRERFTiQzLCByZWxhdGVkVGFyZ2V0KSk7XG4gICAgfTtcblxuICAgIF9wcm90by5kaXNwb3NlID0gZnVuY3Rpb24gZGlzcG9zZSgpIHtcbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLnJlbW92ZURhdGEodGhpcy5fZWxlbWVudCwgREFUQV9LRVkkNik7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5vZmYoRVZFTlRfS0VZJDYpO1xuICAgICAgdGhpcy5fZWxlbWVudCA9IG51bGw7XG4gICAgICB0aGlzLl9tZW51ID0gbnVsbDtcblxuICAgICAgaWYgKHRoaXMuX3BvcHBlciAhPT0gbnVsbCkge1xuICAgICAgICB0aGlzLl9wb3BwZXIuZGVzdHJveSgpO1xuXG4gICAgICAgIHRoaXMuX3BvcHBlciA9IG51bGw7XG4gICAgICB9XG4gICAgfTtcblxuICAgIF9wcm90by51cGRhdGUgPSBmdW5jdGlvbiB1cGRhdGUoKSB7XG4gICAgICB0aGlzLl9pbk5hdmJhciA9IHRoaXMuX2RldGVjdE5hdmJhcigpO1xuXG4gICAgICBpZiAodGhpcy5fcG9wcGVyICE9PSBudWxsKSB7XG4gICAgICAgIHRoaXMuX3BvcHBlci5zY2hlZHVsZVVwZGF0ZSgpO1xuICAgICAgfVxuICAgIH0gLy8gUHJpdmF0ZVxuICAgIDtcblxuICAgIF9wcm90by5fYWRkRXZlbnRMaXN0ZW5lcnMgPSBmdW5jdGlvbiBfYWRkRXZlbnRMaXN0ZW5lcnMoKSB7XG4gICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5vbihFVkVOVF9DTElDSywgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuXG4gICAgICAgIF90aGlzLnRvZ2dsZSgpO1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIF9wcm90by5fZ2V0Q29uZmlnID0gZnVuY3Rpb24gX2dldENvbmZpZyhjb25maWcpIHtcbiAgICAgIGNvbmZpZyA9IF9leHRlbmRzKHt9LCB0aGlzLmNvbnN0cnVjdG9yLkRlZmF1bHQsICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLmRhdGEoKSwgY29uZmlnKTtcbiAgICAgIFV0aWwudHlwZUNoZWNrQ29uZmlnKE5BTUUkNiwgY29uZmlnLCB0aGlzLmNvbnN0cnVjdG9yLkRlZmF1bHRUeXBlKTtcbiAgICAgIHJldHVybiBjb25maWc7XG4gICAgfTtcblxuICAgIF9wcm90by5fZ2V0TWVudUVsZW1lbnQgPSBmdW5jdGlvbiBfZ2V0TWVudUVsZW1lbnQoKSB7XG4gICAgICBpZiAoIXRoaXMuX21lbnUpIHtcbiAgICAgICAgdmFyIHBhcmVudCA9IERyb3Bkb3duLl9nZXRQYXJlbnRGcm9tRWxlbWVudCh0aGlzLl9lbGVtZW50KTtcblxuICAgICAgICBpZiAocGFyZW50KSB7XG4gICAgICAgICAgdGhpcy5fbWVudSA9IHBhcmVudC5xdWVyeVNlbGVjdG9yKFNFTEVDVE9SX01FTlUpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzLl9tZW51O1xuICAgIH07XG5cbiAgICBfcHJvdG8uX2dldFBsYWNlbWVudCA9IGZ1bmN0aW9uIF9nZXRQbGFjZW1lbnQoKSB7XG4gICAgICB2YXIgJHBhcmVudERyb3Bkb3duID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudC5wYXJlbnROb2RlKTtcbiAgICAgIHZhciBwbGFjZW1lbnQgPSBQTEFDRU1FTlRfQk9UVE9NOyAvLyBIYW5kbGUgZHJvcHVwXG5cbiAgICAgIGlmICgkcGFyZW50RHJvcGRvd24uaGFzQ2xhc3MoQ0xBU1NfTkFNRV9EUk9QVVApKSB7XG4gICAgICAgIHBsYWNlbWVudCA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX21lbnUpLmhhc0NsYXNzKENMQVNTX05BTUVfTUVOVVJJR0hUKSA/IFBMQUNFTUVOVF9UT1BFTkQgOiBQTEFDRU1FTlRfVE9QO1xuICAgICAgfSBlbHNlIGlmICgkcGFyZW50RHJvcGRvd24uaGFzQ2xhc3MoQ0xBU1NfTkFNRV9EUk9QUklHSFQpKSB7XG4gICAgICAgIHBsYWNlbWVudCA9IFBMQUNFTUVOVF9SSUdIVDtcbiAgICAgIH0gZWxzZSBpZiAoJHBhcmVudERyb3Bkb3duLmhhc0NsYXNzKENMQVNTX05BTUVfRFJPUExFRlQpKSB7XG4gICAgICAgIHBsYWNlbWVudCA9IFBMQUNFTUVOVF9MRUZUO1xuICAgICAgfSBlbHNlIGlmICgkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9tZW51KS5oYXNDbGFzcyhDTEFTU19OQU1FX01FTlVSSUdIVCkpIHtcbiAgICAgICAgcGxhY2VtZW50ID0gUExBQ0VNRU5UX0JPVFRPTUVORDtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHBsYWNlbWVudDtcbiAgICB9O1xuXG4gICAgX3Byb3RvLl9kZXRlY3ROYXZiYXIgPSBmdW5jdGlvbiBfZGV0ZWN0TmF2YmFyKCkge1xuICAgICAgcmV0dXJuICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLmNsb3Nlc3QoJy5uYXZiYXInKS5sZW5ndGggPiAwO1xuICAgIH07XG5cbiAgICBfcHJvdG8uX2dldE9mZnNldCA9IGZ1bmN0aW9uIF9nZXRPZmZzZXQoKSB7XG4gICAgICB2YXIgX3RoaXMyID0gdGhpcztcblxuICAgICAgdmFyIG9mZnNldCA9IHt9O1xuXG4gICAgICBpZiAodHlwZW9mIHRoaXMuX2NvbmZpZy5vZmZzZXQgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgb2Zmc2V0LmZuID0gZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgICAgICBkYXRhLm9mZnNldHMgPSBfZXh0ZW5kcyh7fSwgZGF0YS5vZmZzZXRzLCBfdGhpczIuX2NvbmZpZy5vZmZzZXQoZGF0YS5vZmZzZXRzLCBfdGhpczIuX2VsZW1lbnQpKTtcbiAgICAgICAgICByZXR1cm4gZGF0YTtcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG9mZnNldC5vZmZzZXQgPSB0aGlzLl9jb25maWcub2Zmc2V0O1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gb2Zmc2V0O1xuICAgIH07XG5cbiAgICBfcHJvdG8uX2dldFBvcHBlckNvbmZpZyA9IGZ1bmN0aW9uIF9nZXRQb3BwZXJDb25maWcoKSB7XG4gICAgICB2YXIgcG9wcGVyQ29uZmlnID0ge1xuICAgICAgICBwbGFjZW1lbnQ6IHRoaXMuX2dldFBsYWNlbWVudCgpLFxuICAgICAgICBtb2RpZmllcnM6IHtcbiAgICAgICAgICBvZmZzZXQ6IHRoaXMuX2dldE9mZnNldCgpLFxuICAgICAgICAgIGZsaXA6IHtcbiAgICAgICAgICAgIGVuYWJsZWQ6IHRoaXMuX2NvbmZpZy5mbGlwXG4gICAgICAgICAgfSxcbiAgICAgICAgICBwcmV2ZW50T3ZlcmZsb3c6IHtcbiAgICAgICAgICAgIGJvdW5kYXJpZXNFbGVtZW50OiB0aGlzLl9jb25maWcuYm91bmRhcnlcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH07IC8vIERpc2FibGUgUG9wcGVyIGlmIHdlIGhhdmUgYSBzdGF0aWMgZGlzcGxheVxuXG4gICAgICBpZiAodGhpcy5fY29uZmlnLmRpc3BsYXkgPT09ICdzdGF0aWMnKSB7XG4gICAgICAgIHBvcHBlckNvbmZpZy5tb2RpZmllcnMuYXBwbHlTdHlsZSA9IHtcbiAgICAgICAgICBlbmFibGVkOiBmYWxzZVxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gX2V4dGVuZHMoe30sIHBvcHBlckNvbmZpZywgdGhpcy5fY29uZmlnLnBvcHBlckNvbmZpZyk7XG4gICAgfSAvLyBTdGF0aWNcbiAgICA7XG5cbiAgICBEcm9wZG93bi5falF1ZXJ5SW50ZXJmYWNlID0gZnVuY3Rpb24gX2pRdWVyeUludGVyZmFjZShjb25maWcpIHtcbiAgICAgIHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgZGF0YSA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMpLmRhdGEoREFUQV9LRVkkNik7XG5cbiAgICAgICAgdmFyIF9jb25maWcgPSB0eXBlb2YgY29uZmlnID09PSAnb2JqZWN0JyA/IGNvbmZpZyA6IG51bGw7XG5cbiAgICAgICAgaWYgKCFkYXRhKSB7XG4gICAgICAgICAgZGF0YSA9IG5ldyBEcm9wZG93bih0aGlzLCBfY29uZmlnKTtcbiAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzKS5kYXRhKERBVEFfS0VZJDYsIGRhdGEpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBjb25maWcgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgaWYgKHR5cGVvZiBkYXRhW2NvbmZpZ10gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiTm8gbWV0aG9kIG5hbWVkIFxcXCJcIiArIGNvbmZpZyArIFwiXFxcIlwiKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBkYXRhW2NvbmZpZ10oKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIERyb3Bkb3duLl9jbGVhck1lbnVzID0gZnVuY3Rpb24gX2NsZWFyTWVudXMoZXZlbnQpIHtcbiAgICAgIGlmIChldmVudCAmJiAoZXZlbnQud2hpY2ggPT09IFJJR0hUX01PVVNFX0JVVFRPTl9XSElDSCB8fCBldmVudC50eXBlID09PSAna2V5dXAnICYmIGV2ZW50LndoaWNoICE9PSBUQUJfS0VZQ09ERSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB2YXIgdG9nZ2xlcyA9IFtdLnNsaWNlLmNhbGwoZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbChTRUxFQ1RPUl9EQVRBX1RPR0dMRSQyKSk7XG5cbiAgICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSB0b2dnbGVzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgIHZhciBwYXJlbnQgPSBEcm9wZG93bi5fZ2V0UGFyZW50RnJvbUVsZW1lbnQodG9nZ2xlc1tpXSk7XG5cbiAgICAgICAgdmFyIGNvbnRleHQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0b2dnbGVzW2ldKS5kYXRhKERBVEFfS0VZJDYpO1xuICAgICAgICB2YXIgcmVsYXRlZFRhcmdldCA9IHtcbiAgICAgICAgICByZWxhdGVkVGFyZ2V0OiB0b2dnbGVzW2ldXG4gICAgICAgIH07XG5cbiAgICAgICAgaWYgKGV2ZW50ICYmIGV2ZW50LnR5cGUgPT09ICdjbGljaycpIHtcbiAgICAgICAgICByZWxhdGVkVGFyZ2V0LmNsaWNrRXZlbnQgPSBldmVudDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghY29udGV4dCkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRyb3Bkb3duTWVudSA9IGNvbnRleHQuX21lbnU7XG5cbiAgICAgICAgaWYgKCEkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShwYXJlbnQpLmhhc0NsYXNzKENMQVNTX05BTUVfU0hPVyQ1KSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGV2ZW50ICYmIChldmVudC50eXBlID09PSAnY2xpY2snICYmIC9pbnB1dHx0ZXh0YXJlYS9pLnRlc3QoZXZlbnQudGFyZ2V0LnRhZ05hbWUpIHx8IGV2ZW50LnR5cGUgPT09ICdrZXl1cCcgJiYgZXZlbnQud2hpY2ggPT09IFRBQl9LRVlDT0RFKSAmJiAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5jb250YWlucyhwYXJlbnQsIGV2ZW50LnRhcmdldCkpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBoaWRlRXZlbnQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5FdmVudChFVkVOVF9ISURFJDMsIHJlbGF0ZWRUYXJnZXQpO1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShwYXJlbnQpLnRyaWdnZXIoaGlkZUV2ZW50KTtcblxuICAgICAgICBpZiAoaGlkZUV2ZW50LmlzRGVmYXVsdFByZXZlbnRlZCgpKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH0gLy8gSWYgdGhpcyBpcyBhIHRvdWNoLWVuYWJsZWQgZGV2aWNlIHdlIHJlbW92ZSB0aGUgZXh0cmFcbiAgICAgICAgLy8gZW1wdHkgbW91c2VvdmVyIGxpc3RlbmVycyB3ZSBhZGRlZCBmb3IgaU9TIHN1cHBvcnRcblxuXG4gICAgICAgIGlmICgnb250b3VjaHN0YXJ0JyBpbiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQpIHtcbiAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShkb2N1bWVudC5ib2R5KS5jaGlsZHJlbigpLm9mZignbW91c2VvdmVyJywgbnVsbCwgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0ubm9vcCk7XG4gICAgICAgIH1cblxuICAgICAgICB0b2dnbGVzW2ldLnNldEF0dHJpYnV0ZSgnYXJpYS1leHBhbmRlZCcsICdmYWxzZScpO1xuXG4gICAgICAgIGlmIChjb250ZXh0Ll9wb3BwZXIpIHtcbiAgICAgICAgICBjb250ZXh0Ll9wb3BwZXIuZGVzdHJveSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZHJvcGRvd25NZW51KS5yZW1vdmVDbGFzcyhDTEFTU19OQU1FX1NIT1ckNSk7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHBhcmVudCkucmVtb3ZlQ2xhc3MoQ0xBU1NfTkFNRV9TSE9XJDUpLnRyaWdnZXIoJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uRXZlbnQoRVZFTlRfSElEREVOJDMsIHJlbGF0ZWRUYXJnZXQpKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgRHJvcGRvd24uX2dldFBhcmVudEZyb21FbGVtZW50ID0gZnVuY3Rpb24gX2dldFBhcmVudEZyb21FbGVtZW50KGVsZW1lbnQpIHtcbiAgICAgIHZhciBwYXJlbnQ7XG4gICAgICB2YXIgc2VsZWN0b3IgPSBVdGlsLmdldFNlbGVjdG9yRnJvbUVsZW1lbnQoZWxlbWVudCk7XG5cbiAgICAgIGlmIChzZWxlY3Rvcikge1xuICAgICAgICBwYXJlbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHNlbGVjdG9yKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHBhcmVudCB8fCBlbGVtZW50LnBhcmVudE5vZGU7XG4gICAgfSAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY29tcGxleGl0eVxuICAgIDtcblxuICAgIERyb3Bkb3duLl9kYXRhQXBpS2V5ZG93bkhhbmRsZXIgPSBmdW5jdGlvbiBfZGF0YUFwaUtleWRvd25IYW5kbGVyKGV2ZW50KSB7XG4gICAgICAvLyBJZiBub3QgaW5wdXQvdGV4dGFyZWE6XG4gICAgICAvLyAgLSBBbmQgbm90IGEga2V5IGluIFJFR0VYUF9LRVlET1dOID0+IG5vdCBhIGRyb3Bkb3duIGNvbW1hbmRcbiAgICAgIC8vIElmIGlucHV0L3RleHRhcmVhOlxuICAgICAgLy8gIC0gSWYgc3BhY2Uga2V5ID0+IG5vdCBhIGRyb3Bkb3duIGNvbW1hbmRcbiAgICAgIC8vICAtIElmIGtleSBpcyBvdGhlciB0aGFuIGVzY2FwZVxuICAgICAgLy8gICAgLSBJZiBrZXkgaXMgbm90IHVwIG9yIGRvd24gPT4gbm90IGEgZHJvcGRvd24gY29tbWFuZFxuICAgICAgLy8gICAgLSBJZiB0cmlnZ2VyIGluc2lkZSB0aGUgbWVudSA9PiBub3QgYSBkcm9wZG93biBjb21tYW5kXG4gICAgICBpZiAoL2lucHV0fHRleHRhcmVhL2kudGVzdChldmVudC50YXJnZXQudGFnTmFtZSkgPyBldmVudC53aGljaCA9PT0gU1BBQ0VfS0VZQ09ERSB8fCBldmVudC53aGljaCAhPT0gRVNDQVBFX0tFWUNPREUkMSAmJiAoZXZlbnQud2hpY2ggIT09IEFSUk9XX0RPV05fS0VZQ09ERSAmJiBldmVudC53aGljaCAhPT0gQVJST1dfVVBfS0VZQ09ERSB8fCAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShldmVudC50YXJnZXQpLmNsb3Nlc3QoU0VMRUNUT1JfTUVOVSkubGVuZ3RoKSA6ICFSRUdFWFBfS0VZRE9XTi50ZXN0KGV2ZW50LndoaWNoKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmRpc2FibGVkIHx8ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMpLmhhc0NsYXNzKENMQVNTX05BTUVfRElTQUJMRUQkMSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB2YXIgcGFyZW50ID0gRHJvcGRvd24uX2dldFBhcmVudEZyb21FbGVtZW50KHRoaXMpO1xuXG4gICAgICB2YXIgaXNBY3RpdmUgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShwYXJlbnQpLmhhc0NsYXNzKENMQVNTX05BTUVfU0hPVyQ1KTtcblxuICAgICAgaWYgKCFpc0FjdGl2ZSAmJiBldmVudC53aGljaCA9PT0gRVNDQVBFX0tFWUNPREUkMSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcblxuICAgICAgaWYgKCFpc0FjdGl2ZSB8fCBldmVudC53aGljaCA9PT0gRVNDQVBFX0tFWUNPREUkMSB8fCBldmVudC53aGljaCA9PT0gU1BBQ0VfS0VZQ09ERSkge1xuICAgICAgICBpZiAoZXZlbnQud2hpY2ggPT09IEVTQ0FQRV9LRVlDT0RFJDEpIHtcbiAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShwYXJlbnQucXVlcnlTZWxlY3RvcihTRUxFQ1RPUl9EQVRBX1RPR0dMRSQyKSkudHJpZ2dlcignZm9jdXMnKTtcbiAgICAgICAgfVxuXG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMpLnRyaWdnZXIoJ2NsaWNrJyk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIGl0ZW1zID0gW10uc2xpY2UuY2FsbChwYXJlbnQucXVlcnlTZWxlY3RvckFsbChTRUxFQ1RPUl9WSVNJQkxFX0lURU1TKSkuZmlsdGVyKGZ1bmN0aW9uIChpdGVtKSB7XG4gICAgICAgIHJldHVybiAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShpdGVtKS5pcygnOnZpc2libGUnKTtcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoaXRlbXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIGluZGV4ID0gaXRlbXMuaW5kZXhPZihldmVudC50YXJnZXQpO1xuXG4gICAgICBpZiAoZXZlbnQud2hpY2ggPT09IEFSUk9XX1VQX0tFWUNPREUgJiYgaW5kZXggPiAwKSB7XG4gICAgICAgIC8vIFVwXG4gICAgICAgIGluZGV4LS07XG4gICAgICB9XG5cbiAgICAgIGlmIChldmVudC53aGljaCA9PT0gQVJST1dfRE9XTl9LRVlDT0RFICYmIGluZGV4IDwgaXRlbXMubGVuZ3RoIC0gMSkge1xuICAgICAgICAvLyBEb3duXG4gICAgICAgIGluZGV4Kys7XG4gICAgICB9XG5cbiAgICAgIGlmIChpbmRleCA8IDApIHtcbiAgICAgICAgaW5kZXggPSAwO1xuICAgICAgfVxuXG4gICAgICBpdGVtc1tpbmRleF0uZm9jdXMoKTtcbiAgICB9O1xuXG4gICAgX2NyZWF0ZUNsYXNzKERyb3Bkb3duLCBudWxsLCBbe1xuICAgICAga2V5OiBcIlZFUlNJT05cIixcbiAgICAgIGdldDogZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgICByZXR1cm4gVkVSU0lPTiQ2O1xuICAgICAgfVxuICAgIH0sIHtcbiAgICAgIGtleTogXCJEZWZhdWx0XCIsXG4gICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgcmV0dXJuIERlZmF1bHQkNTtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiRGVmYXVsdFR5cGVcIixcbiAgICAgIGdldDogZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgICByZXR1cm4gRGVmYXVsdFR5cGUkNTtcbiAgICAgIH1cbiAgICB9XSk7XG5cbiAgICByZXR1cm4gRHJvcGRvd247XG4gIH0oKTtcbiAgLyoqXG4gICAqIERhdGEgQVBJIGltcGxlbWVudGF0aW9uXG4gICAqL1xuXG5cbiAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZG9jdW1lbnQpLm9uKEVWRU5UX0tFWURPV05fREFUQV9BUEksIFNFTEVDVE9SX0RBVEFfVE9HR0xFJDIsIERyb3Bkb3duLl9kYXRhQXBpS2V5ZG93bkhhbmRsZXIpLm9uKEVWRU5UX0tFWURPV05fREFUQV9BUEksIFNFTEVDVE9SX01FTlUsIERyb3Bkb3duLl9kYXRhQXBpS2V5ZG93bkhhbmRsZXIpLm9uKEVWRU5UX0NMSUNLX0RBVEFfQVBJJDIgKyBcIiBcIiArIEVWRU5UX0tFWVVQX0RBVEFfQVBJLCBEcm9wZG93bi5fY2xlYXJNZW51cykub24oRVZFTlRfQ0xJQ0tfREFUQV9BUEkkMiwgU0VMRUNUT1JfREFUQV9UT0dHTEUkMiwgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcblxuICAgIERyb3Bkb3duLl9qUXVlcnlJbnRlcmZhY2UuY2FsbCgkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzKSwgJ3RvZ2dsZScpO1xuICB9KS5vbihFVkVOVF9DTElDS19EQVRBX0FQSSQyLCBTRUxFQ1RPUl9GT1JNX0NISUxELCBmdW5jdGlvbiAoZSkge1xuICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gIH0pO1xuICAvKipcbiAgICogalF1ZXJ5XG4gICAqL1xuXG4gICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuW05BTUUkNl0gPSBEcm9wZG93bi5falF1ZXJ5SW50ZXJmYWNlO1xuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDZdLkNvbnN0cnVjdG9yID0gRHJvcGRvd247XG5cbiAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQ2XS5ub0NvbmZsaWN0ID0gZnVuY3Rpb24gKCkge1xuICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuW05BTUUkNl0gPSBKUVVFUllfTk9fQ09ORkxJQ1QkNjtcbiAgICByZXR1cm4gRHJvcGRvd24uX2pRdWVyeUludGVyZmFjZTtcbiAgfTtcblxuICAvKipcbiAgICogQ29uc3RhbnRzXG4gICAqL1xuXG4gIHZhciBOQU1FJDUgPSAnbW9kYWwnO1xuICB2YXIgVkVSU0lPTiQ1ID0gJzQuNi4xJztcbiAgdmFyIERBVEFfS0VZJDUgPSAnYnMubW9kYWwnO1xuICB2YXIgRVZFTlRfS0VZJDUgPSBcIi5cIiArIERBVEFfS0VZJDU7XG4gIHZhciBEQVRBX0FQSV9LRVkkMiA9ICcuZGF0YS1hcGknO1xuICB2YXIgSlFVRVJZX05PX0NPTkZMSUNUJDUgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDVdO1xuICB2YXIgRVNDQVBFX0tFWUNPREUgPSAyNzsgLy8gS2V5Ym9hcmRFdmVudC53aGljaCB2YWx1ZSBmb3IgRXNjYXBlIChFc2MpIGtleVxuXG4gIHZhciBDTEFTU19OQU1FX1NDUk9MTEFCTEUgPSAnbW9kYWwtZGlhbG9nLXNjcm9sbGFibGUnO1xuICB2YXIgQ0xBU1NfTkFNRV9TQ1JPTExCQVJfTUVBU1VSRVIgPSAnbW9kYWwtc2Nyb2xsYmFyLW1lYXN1cmUnO1xuICB2YXIgQ0xBU1NfTkFNRV9CQUNLRFJPUCA9ICdtb2RhbC1iYWNrZHJvcCc7XG4gIHZhciBDTEFTU19OQU1FX09QRU4gPSAnbW9kYWwtb3Blbic7XG4gIHZhciBDTEFTU19OQU1FX0ZBREUkNCA9ICdmYWRlJztcbiAgdmFyIENMQVNTX05BTUVfU0hPVyQ0ID0gJ3Nob3cnO1xuICB2YXIgQ0xBU1NfTkFNRV9TVEFUSUMgPSAnbW9kYWwtc3RhdGljJztcbiAgdmFyIEVWRU5UX0hJREUkMiA9IFwiaGlkZVwiICsgRVZFTlRfS0VZJDU7XG4gIHZhciBFVkVOVF9ISURFX1BSRVZFTlRFRCA9IFwiaGlkZVByZXZlbnRlZFwiICsgRVZFTlRfS0VZJDU7XG4gIHZhciBFVkVOVF9ISURERU4kMiA9IFwiaGlkZGVuXCIgKyBFVkVOVF9LRVkkNTtcbiAgdmFyIEVWRU5UX1NIT1ckMiA9IFwic2hvd1wiICsgRVZFTlRfS0VZJDU7XG4gIHZhciBFVkVOVF9TSE9XTiQyID0gXCJzaG93blwiICsgRVZFTlRfS0VZJDU7XG4gIHZhciBFVkVOVF9GT0NVU0lOID0gXCJmb2N1c2luXCIgKyBFVkVOVF9LRVkkNTtcbiAgdmFyIEVWRU5UX1JFU0laRSA9IFwicmVzaXplXCIgKyBFVkVOVF9LRVkkNTtcbiAgdmFyIEVWRU5UX0NMSUNLX0RJU01JU1MkMSA9IFwiY2xpY2suZGlzbWlzc1wiICsgRVZFTlRfS0VZJDU7XG4gIHZhciBFVkVOVF9LRVlET1dOX0RJU01JU1MgPSBcImtleWRvd24uZGlzbWlzc1wiICsgRVZFTlRfS0VZJDU7XG4gIHZhciBFVkVOVF9NT1VTRVVQX0RJU01JU1MgPSBcIm1vdXNldXAuZGlzbWlzc1wiICsgRVZFTlRfS0VZJDU7XG4gIHZhciBFVkVOVF9NT1VTRURPV05fRElTTUlTUyA9IFwibW91c2Vkb3duLmRpc21pc3NcIiArIEVWRU5UX0tFWSQ1O1xuICB2YXIgRVZFTlRfQ0xJQ0tfREFUQV9BUEkkMSA9IFwiY2xpY2tcIiArIEVWRU5UX0tFWSQ1ICsgREFUQV9BUElfS0VZJDI7XG4gIHZhciBTRUxFQ1RPUl9ESUFMT0cgPSAnLm1vZGFsLWRpYWxvZyc7XG4gIHZhciBTRUxFQ1RPUl9NT0RBTF9CT0RZID0gJy5tb2RhbC1ib2R5JztcbiAgdmFyIFNFTEVDVE9SX0RBVEFfVE9HR0xFJDEgPSAnW2RhdGEtdG9nZ2xlPVwibW9kYWxcIl0nO1xuICB2YXIgU0VMRUNUT1JfREFUQV9ESVNNSVNTJDEgPSAnW2RhdGEtZGlzbWlzcz1cIm1vZGFsXCJdJztcbiAgdmFyIFNFTEVDVE9SX0ZJWEVEX0NPTlRFTlQgPSAnLmZpeGVkLXRvcCwgLmZpeGVkLWJvdHRvbSwgLmlzLWZpeGVkLCAuc3RpY2t5LXRvcCc7XG4gIHZhciBTRUxFQ1RPUl9TVElDS1lfQ09OVEVOVCA9ICcuc3RpY2t5LXRvcCc7XG4gIHZhciBEZWZhdWx0JDQgPSB7XG4gICAgYmFja2Ryb3A6IHRydWUsXG4gICAga2V5Ym9hcmQ6IHRydWUsXG4gICAgZm9jdXM6IHRydWUsXG4gICAgc2hvdzogdHJ1ZVxuICB9O1xuICB2YXIgRGVmYXVsdFR5cGUkNCA9IHtcbiAgICBiYWNrZHJvcDogJyhib29sZWFufHN0cmluZyknLFxuICAgIGtleWJvYXJkOiAnYm9vbGVhbicsXG4gICAgZm9jdXM6ICdib29sZWFuJyxcbiAgICBzaG93OiAnYm9vbGVhbidcbiAgfTtcbiAgLyoqXG4gICAqIENsYXNzIGRlZmluaXRpb25cbiAgICovXG5cbiAgdmFyIE1vZGFsID0gLyojX19QVVJFX18qL2Z1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBNb2RhbChlbGVtZW50LCBjb25maWcpIHtcbiAgICAgIHRoaXMuX2NvbmZpZyA9IHRoaXMuX2dldENvbmZpZyhjb25maWcpO1xuICAgICAgdGhpcy5fZWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgICB0aGlzLl9kaWFsb2cgPSBlbGVtZW50LnF1ZXJ5U2VsZWN0b3IoU0VMRUNUT1JfRElBTE9HKTtcbiAgICAgIHRoaXMuX2JhY2tkcm9wID0gbnVsbDtcbiAgICAgIHRoaXMuX2lzU2hvd24gPSBmYWxzZTtcbiAgICAgIHRoaXMuX2lzQm9keU92ZXJmbG93aW5nID0gZmFsc2U7XG4gICAgICB0aGlzLl9pZ25vcmVCYWNrZHJvcENsaWNrID0gZmFsc2U7XG4gICAgICB0aGlzLl9pc1RyYW5zaXRpb25pbmcgPSBmYWxzZTtcbiAgICAgIHRoaXMuX3Njcm9sbGJhcldpZHRoID0gMDtcbiAgICB9IC8vIEdldHRlcnNcblxuXG4gICAgdmFyIF9wcm90byA9IE1vZGFsLnByb3RvdHlwZTtcblxuICAgIC8vIFB1YmxpY1xuICAgIF9wcm90by50b2dnbGUgPSBmdW5jdGlvbiB0b2dnbGUocmVsYXRlZFRhcmdldCkge1xuICAgICAgcmV0dXJuIHRoaXMuX2lzU2hvd24gPyB0aGlzLmhpZGUoKSA6IHRoaXMuc2hvdyhyZWxhdGVkVGFyZ2V0KTtcbiAgICB9O1xuXG4gICAgX3Byb3RvLnNob3cgPSBmdW5jdGlvbiBzaG93KHJlbGF0ZWRUYXJnZXQpIHtcbiAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgIGlmICh0aGlzLl9pc1Nob3duIHx8IHRoaXMuX2lzVHJhbnNpdGlvbmluZykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHZhciBzaG93RXZlbnQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5FdmVudChFVkVOVF9TSE9XJDIsIHtcbiAgICAgICAgcmVsYXRlZFRhcmdldDogcmVsYXRlZFRhcmdldFxuICAgICAgfSk7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS50cmlnZ2VyKHNob3dFdmVudCk7XG5cbiAgICAgIGlmIChzaG93RXZlbnQuaXNEZWZhdWx0UHJldmVudGVkKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLl9pc1Nob3duID0gdHJ1ZTtcblxuICAgICAgaWYgKCRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLmhhc0NsYXNzKENMQVNTX05BTUVfRkFERSQ0KSkge1xuICAgICAgICB0aGlzLl9pc1RyYW5zaXRpb25pbmcgPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICB0aGlzLl9jaGVja1Njcm9sbGJhcigpO1xuXG4gICAgICB0aGlzLl9zZXRTY3JvbGxiYXIoKTtcblxuICAgICAgdGhpcy5fYWRqdXN0RGlhbG9nKCk7XG5cbiAgICAgIHRoaXMuX3NldEVzY2FwZUV2ZW50KCk7XG5cbiAgICAgIHRoaXMuX3NldFJlc2l6ZUV2ZW50KCk7XG5cbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLm9uKEVWRU5UX0NMSUNLX0RJU01JU1MkMSwgU0VMRUNUT1JfREFUQV9ESVNNSVNTJDEsIGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICByZXR1cm4gX3RoaXMuaGlkZShldmVudCk7XG4gICAgICB9KTtcbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2RpYWxvZykub24oRVZFTlRfTU9VU0VET1dOX0RJU01JU1MsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oX3RoaXMuX2VsZW1lbnQpLm9uZShFVkVOVF9NT1VTRVVQX0RJU01JU1MsIGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAgIGlmICgkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShldmVudC50YXJnZXQpLmlzKF90aGlzLl9lbGVtZW50KSkge1xuICAgICAgICAgICAgX3RoaXMuX2lnbm9yZUJhY2tkcm9wQ2xpY2sgPSB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgdGhpcy5fc2hvd0JhY2tkcm9wKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIF90aGlzLl9zaG93RWxlbWVudChyZWxhdGVkVGFyZ2V0KTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICBfcHJvdG8uaGlkZSA9IGZ1bmN0aW9uIGhpZGUoZXZlbnQpIHtcbiAgICAgIHZhciBfdGhpczIgPSB0aGlzO1xuXG4gICAgICBpZiAoZXZlbnQpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCF0aGlzLl9pc1Nob3duIHx8IHRoaXMuX2lzVHJhbnNpdGlvbmluZykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHZhciBoaWRlRXZlbnQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5FdmVudChFVkVOVF9ISURFJDIpO1xuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkudHJpZ2dlcihoaWRlRXZlbnQpO1xuXG4gICAgICBpZiAoIXRoaXMuX2lzU2hvd24gfHwgaGlkZUV2ZW50LmlzRGVmYXVsdFByZXZlbnRlZCgpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5faXNTaG93biA9IGZhbHNlO1xuICAgICAgdmFyIHRyYW5zaXRpb24gPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5oYXNDbGFzcyhDTEFTU19OQU1FX0ZBREUkNCk7XG5cbiAgICAgIGlmICh0cmFuc2l0aW9uKSB7XG4gICAgICAgIHRoaXMuX2lzVHJhbnNpdGlvbmluZyA9IHRydWU7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuX3NldEVzY2FwZUV2ZW50KCk7XG5cbiAgICAgIHRoaXMuX3NldFJlc2l6ZUV2ZW50KCk7XG5cbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGRvY3VtZW50KS5vZmYoRVZFTlRfRk9DVVNJTik7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5yZW1vdmVDbGFzcyhDTEFTU19OQU1FX1NIT1ckNCk7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5vZmYoRVZFTlRfQ0xJQ0tfRElTTUlTUyQxKTtcbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2RpYWxvZykub2ZmKEVWRU5UX01PVVNFRE9XTl9ESVNNSVNTKTtcblxuICAgICAgaWYgKHRyYW5zaXRpb24pIHtcbiAgICAgICAgdmFyIHRyYW5zaXRpb25EdXJhdGlvbiA9IFV0aWwuZ2V0VHJhbnNpdGlvbkR1cmF0aW9uRnJvbUVsZW1lbnQodGhpcy5fZWxlbWVudCk7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLm9uZShVdGlsLlRSQU5TSVRJT05fRU5ELCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICByZXR1cm4gX3RoaXMyLl9oaWRlTW9kYWwoZXZlbnQpO1xuICAgICAgICB9KS5lbXVsYXRlVHJhbnNpdGlvbkVuZCh0cmFuc2l0aW9uRHVyYXRpb24pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5faGlkZU1vZGFsKCk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIF9wcm90by5kaXNwb3NlID0gZnVuY3Rpb24gZGlzcG9zZSgpIHtcbiAgICAgIFt3aW5kb3csIHRoaXMuX2VsZW1lbnQsIHRoaXMuX2RpYWxvZ10uZm9yRWFjaChmdW5jdGlvbiAoaHRtbEVsZW1lbnQpIHtcbiAgICAgICAgcmV0dXJuICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGh0bWxFbGVtZW50KS5vZmYoRVZFTlRfS0VZJDUpO1xuICAgICAgfSk7XG4gICAgICAvKipcbiAgICAgICAqIGBkb2N1bWVudGAgaGFzIDIgZXZlbnRzIGBFVkVOVF9GT0NVU0lOYCBhbmQgYEVWRU5UX0NMSUNLX0RBVEFfQVBJYFxuICAgICAgICogRG8gbm90IG1vdmUgYGRvY3VtZW50YCBpbiBgaHRtbEVsZW1lbnRzYCBhcnJheVxuICAgICAgICogSXQgd2lsbCByZW1vdmUgYEVWRU5UX0NMSUNLX0RBVEFfQVBJYCBldmVudCB0aGF0IHNob3VsZCByZW1haW5cbiAgICAgICAqL1xuXG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShkb2N1bWVudCkub2ZmKEVWRU5UX0ZPQ1VTSU4pO1xuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0ucmVtb3ZlRGF0YSh0aGlzLl9lbGVtZW50LCBEQVRBX0tFWSQ1KTtcbiAgICAgIHRoaXMuX2NvbmZpZyA9IG51bGw7XG4gICAgICB0aGlzLl9lbGVtZW50ID0gbnVsbDtcbiAgICAgIHRoaXMuX2RpYWxvZyA9IG51bGw7XG4gICAgICB0aGlzLl9iYWNrZHJvcCA9IG51bGw7XG4gICAgICB0aGlzLl9pc1Nob3duID0gbnVsbDtcbiAgICAgIHRoaXMuX2lzQm9keU92ZXJmbG93aW5nID0gbnVsbDtcbiAgICAgIHRoaXMuX2lnbm9yZUJhY2tkcm9wQ2xpY2sgPSBudWxsO1xuICAgICAgdGhpcy5faXNUcmFuc2l0aW9uaW5nID0gbnVsbDtcbiAgICAgIHRoaXMuX3Njcm9sbGJhcldpZHRoID0gbnVsbDtcbiAgICB9O1xuXG4gICAgX3Byb3RvLmhhbmRsZVVwZGF0ZSA9IGZ1bmN0aW9uIGhhbmRsZVVwZGF0ZSgpIHtcbiAgICAgIHRoaXMuX2FkanVzdERpYWxvZygpO1xuICAgIH0gLy8gUHJpdmF0ZVxuICAgIDtcblxuICAgIF9wcm90by5fZ2V0Q29uZmlnID0gZnVuY3Rpb24gX2dldENvbmZpZyhjb25maWcpIHtcbiAgICAgIGNvbmZpZyA9IF9leHRlbmRzKHt9LCBEZWZhdWx0JDQsIGNvbmZpZyk7XG4gICAgICBVdGlsLnR5cGVDaGVja0NvbmZpZyhOQU1FJDUsIGNvbmZpZywgRGVmYXVsdFR5cGUkNCk7XG4gICAgICByZXR1cm4gY29uZmlnO1xuICAgIH07XG5cbiAgICBfcHJvdG8uX3RyaWdnZXJCYWNrZHJvcFRyYW5zaXRpb24gPSBmdW5jdGlvbiBfdHJpZ2dlckJhY2tkcm9wVHJhbnNpdGlvbigpIHtcbiAgICAgIHZhciBfdGhpczMgPSB0aGlzO1xuXG4gICAgICB2YXIgaGlkZUV2ZW50UHJldmVudGVkID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uRXZlbnQoRVZFTlRfSElERV9QUkVWRU5URUQpO1xuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkudHJpZ2dlcihoaWRlRXZlbnRQcmV2ZW50ZWQpO1xuXG4gICAgICBpZiAoaGlkZUV2ZW50UHJldmVudGVkLmlzRGVmYXVsdFByZXZlbnRlZCgpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIGlzTW9kYWxPdmVyZmxvd2luZyA9IHRoaXMuX2VsZW1lbnQuc2Nyb2xsSGVpZ2h0ID4gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodDtcblxuICAgICAgaWYgKCFpc01vZGFsT3ZlcmZsb3dpbmcpIHtcbiAgICAgICAgdGhpcy5fZWxlbWVudC5zdHlsZS5vdmVyZmxvd1kgPSAnaGlkZGVuJztcbiAgICAgIH1cblxuICAgICAgdGhpcy5fZWxlbWVudC5jbGFzc0xpc3QuYWRkKENMQVNTX05BTUVfU1RBVElDKTtcblxuICAgICAgdmFyIG1vZGFsVHJhbnNpdGlvbkR1cmF0aW9uID0gVXRpbC5nZXRUcmFuc2l0aW9uRHVyYXRpb25Gcm9tRWxlbWVudCh0aGlzLl9kaWFsb2cpO1xuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkub2ZmKFV0aWwuVFJBTlNJVElPTl9FTkQpO1xuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkub25lKFV0aWwuVFJBTlNJVElPTl9FTkQsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgX3RoaXMzLl9lbGVtZW50LmNsYXNzTGlzdC5yZW1vdmUoQ0xBU1NfTkFNRV9TVEFUSUMpO1xuXG4gICAgICAgIGlmICghaXNNb2RhbE92ZXJmbG93aW5nKSB7XG4gICAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oX3RoaXMzLl9lbGVtZW50KS5vbmUoVXRpbC5UUkFOU0lUSU9OX0VORCwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgX3RoaXMzLl9lbGVtZW50LnN0eWxlLm92ZXJmbG93WSA9ICcnO1xuICAgICAgICAgIH0pLmVtdWxhdGVUcmFuc2l0aW9uRW5kKF90aGlzMy5fZWxlbWVudCwgbW9kYWxUcmFuc2l0aW9uRHVyYXRpb24pO1xuICAgICAgICB9XG4gICAgICB9KS5lbXVsYXRlVHJhbnNpdGlvbkVuZChtb2RhbFRyYW5zaXRpb25EdXJhdGlvbik7XG5cbiAgICAgIHRoaXMuX2VsZW1lbnQuZm9jdXMoKTtcbiAgICB9O1xuXG4gICAgX3Byb3RvLl9zaG93RWxlbWVudCA9IGZ1bmN0aW9uIF9zaG93RWxlbWVudChyZWxhdGVkVGFyZ2V0KSB7XG4gICAgICB2YXIgX3RoaXM0ID0gdGhpcztcblxuICAgICAgdmFyIHRyYW5zaXRpb24gPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5oYXNDbGFzcyhDTEFTU19OQU1FX0ZBREUkNCk7XG4gICAgICB2YXIgbW9kYWxCb2R5ID0gdGhpcy5fZGlhbG9nID8gdGhpcy5fZGlhbG9nLnF1ZXJ5U2VsZWN0b3IoU0VMRUNUT1JfTU9EQUxfQk9EWSkgOiBudWxsO1xuXG4gICAgICBpZiAoIXRoaXMuX2VsZW1lbnQucGFyZW50Tm9kZSB8fCB0aGlzLl9lbGVtZW50LnBhcmVudE5vZGUubm9kZVR5cGUgIT09IE5vZGUuRUxFTUVOVF9OT0RFKSB7XG4gICAgICAgIC8vIERvbid0IG1vdmUgbW9kYWwncyBET00gcG9zaXRpb25cbiAgICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZCh0aGlzLl9lbGVtZW50KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5fZWxlbWVudC5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcblxuICAgICAgdGhpcy5fZWxlbWVudC5yZW1vdmVBdHRyaWJ1dGUoJ2FyaWEtaGlkZGVuJyk7XG5cbiAgICAgIHRoaXMuX2VsZW1lbnQuc2V0QXR0cmlidXRlKCdhcmlhLW1vZGFsJywgdHJ1ZSk7XG5cbiAgICAgIHRoaXMuX2VsZW1lbnQuc2V0QXR0cmlidXRlKCdyb2xlJywgJ2RpYWxvZycpO1xuXG4gICAgICBpZiAoJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZGlhbG9nKS5oYXNDbGFzcyhDTEFTU19OQU1FX1NDUk9MTEFCTEUpICYmIG1vZGFsQm9keSkge1xuICAgICAgICBtb2RhbEJvZHkuc2Nyb2xsVG9wID0gMDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuX2VsZW1lbnQuc2Nyb2xsVG9wID0gMDtcbiAgICAgIH1cblxuICAgICAgaWYgKHRyYW5zaXRpb24pIHtcbiAgICAgICAgVXRpbC5yZWZsb3codGhpcy5fZWxlbWVudCk7XG4gICAgICB9XG5cbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLmFkZENsYXNzKENMQVNTX05BTUVfU0hPVyQ0KTtcblxuICAgICAgaWYgKHRoaXMuX2NvbmZpZy5mb2N1cykge1xuICAgICAgICB0aGlzLl9lbmZvcmNlRm9jdXMoKTtcbiAgICAgIH1cblxuICAgICAgdmFyIHNob3duRXZlbnQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5FdmVudChFVkVOVF9TSE9XTiQyLCB7XG4gICAgICAgIHJlbGF0ZWRUYXJnZXQ6IHJlbGF0ZWRUYXJnZXRcbiAgICAgIH0pO1xuXG4gICAgICB2YXIgdHJhbnNpdGlvbkNvbXBsZXRlID0gZnVuY3Rpb24gdHJhbnNpdGlvbkNvbXBsZXRlKCkge1xuICAgICAgICBpZiAoX3RoaXM0Ll9jb25maWcuZm9jdXMpIHtcbiAgICAgICAgICBfdGhpczQuX2VsZW1lbnQuZm9jdXMoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIF90aGlzNC5faXNUcmFuc2l0aW9uaW5nID0gZmFsc2U7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKF90aGlzNC5fZWxlbWVudCkudHJpZ2dlcihzaG93bkV2ZW50KTtcbiAgICAgIH07XG5cbiAgICAgIGlmICh0cmFuc2l0aW9uKSB7XG4gICAgICAgIHZhciB0cmFuc2l0aW9uRHVyYXRpb24gPSBVdGlsLmdldFRyYW5zaXRpb25EdXJhdGlvbkZyb21FbGVtZW50KHRoaXMuX2RpYWxvZyk7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2RpYWxvZykub25lKFV0aWwuVFJBTlNJVElPTl9FTkQsIHRyYW5zaXRpb25Db21wbGV0ZSkuZW11bGF0ZVRyYW5zaXRpb25FbmQodHJhbnNpdGlvbkR1cmF0aW9uKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRyYW5zaXRpb25Db21wbGV0ZSgpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBfcHJvdG8uX2VuZm9yY2VGb2N1cyA9IGZ1bmN0aW9uIF9lbmZvcmNlRm9jdXMoKSB7XG4gICAgICB2YXIgX3RoaXM1ID0gdGhpcztcblxuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZG9jdW1lbnQpLm9mZihFVkVOVF9GT0NVU0lOKSAvLyBHdWFyZCBhZ2FpbnN0IGluZmluaXRlIGZvY3VzIGxvb3BcbiAgICAgIC5vbihFVkVOVF9GT0NVU0lOLCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgaWYgKGRvY3VtZW50ICE9PSBldmVudC50YXJnZXQgJiYgX3RoaXM1Ll9lbGVtZW50ICE9PSBldmVudC50YXJnZXQgJiYgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oX3RoaXM1Ll9lbGVtZW50KS5oYXMoZXZlbnQudGFyZ2V0KS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICBfdGhpczUuX2VsZW1lbnQuZm9jdXMoKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIF9wcm90by5fc2V0RXNjYXBlRXZlbnQgPSBmdW5jdGlvbiBfc2V0RXNjYXBlRXZlbnQoKSB7XG4gICAgICB2YXIgX3RoaXM2ID0gdGhpcztcblxuICAgICAgaWYgKHRoaXMuX2lzU2hvd24pIHtcbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkub24oRVZFTlRfS0VZRE9XTl9ESVNNSVNTLCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICBpZiAoX3RoaXM2Ll9jb25maWcua2V5Ym9hcmQgJiYgZXZlbnQud2hpY2ggPT09IEVTQ0FQRV9LRVlDT0RFKSB7XG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICAgICAgICBfdGhpczYuaGlkZSgpO1xuICAgICAgICAgIH0gZWxzZSBpZiAoIV90aGlzNi5fY29uZmlnLmtleWJvYXJkICYmIGV2ZW50LndoaWNoID09PSBFU0NBUEVfS0VZQ09ERSkge1xuICAgICAgICAgICAgX3RoaXM2Ll90cmlnZ2VyQmFja2Ryb3BUcmFuc2l0aW9uKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSBpZiAoIXRoaXMuX2lzU2hvd24pIHtcbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkub2ZmKEVWRU5UX0tFWURPV05fRElTTUlTUyk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIF9wcm90by5fc2V0UmVzaXplRXZlbnQgPSBmdW5jdGlvbiBfc2V0UmVzaXplRXZlbnQoKSB7XG4gICAgICB2YXIgX3RoaXM3ID0gdGhpcztcblxuICAgICAgaWYgKHRoaXMuX2lzU2hvd24pIHtcbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0od2luZG93KS5vbihFVkVOVF9SRVNJWkUsIGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAgIHJldHVybiBfdGhpczcuaGFuZGxlVXBkYXRlKGV2ZW50KTtcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh3aW5kb3cpLm9mZihFVkVOVF9SRVNJWkUpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBfcHJvdG8uX2hpZGVNb2RhbCA9IGZ1bmN0aW9uIF9oaWRlTW9kYWwoKSB7XG4gICAgICB2YXIgX3RoaXM4ID0gdGhpcztcblxuICAgICAgdGhpcy5fZWxlbWVudC5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuXG4gICAgICB0aGlzLl9lbGVtZW50LnNldEF0dHJpYnV0ZSgnYXJpYS1oaWRkZW4nLCB0cnVlKTtcblxuICAgICAgdGhpcy5fZWxlbWVudC5yZW1vdmVBdHRyaWJ1dGUoJ2FyaWEtbW9kYWwnKTtcblxuICAgICAgdGhpcy5fZWxlbWVudC5yZW1vdmVBdHRyaWJ1dGUoJ3JvbGUnKTtcblxuICAgICAgdGhpcy5faXNUcmFuc2l0aW9uaW5nID0gZmFsc2U7XG5cbiAgICAgIHRoaXMuX3Nob3dCYWNrZHJvcChmdW5jdGlvbiAoKSB7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGRvY3VtZW50LmJvZHkpLnJlbW92ZUNsYXNzKENMQVNTX05BTUVfT1BFTik7XG5cbiAgICAgICAgX3RoaXM4Ll9yZXNldEFkanVzdG1lbnRzKCk7XG5cbiAgICAgICAgX3RoaXM4Ll9yZXNldFNjcm9sbGJhcigpO1xuXG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKF90aGlzOC5fZWxlbWVudCkudHJpZ2dlcihFVkVOVF9ISURERU4kMik7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgX3Byb3RvLl9yZW1vdmVCYWNrZHJvcCA9IGZ1bmN0aW9uIF9yZW1vdmVCYWNrZHJvcCgpIHtcbiAgICAgIGlmICh0aGlzLl9iYWNrZHJvcCkge1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9iYWNrZHJvcCkucmVtb3ZlKCk7XG4gICAgICAgIHRoaXMuX2JhY2tkcm9wID0gbnVsbDtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgX3Byb3RvLl9zaG93QmFja2Ryb3AgPSBmdW5jdGlvbiBfc2hvd0JhY2tkcm9wKGNhbGxiYWNrKSB7XG4gICAgICB2YXIgX3RoaXM5ID0gdGhpcztcblxuICAgICAgdmFyIGFuaW1hdGUgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5oYXNDbGFzcyhDTEFTU19OQU1FX0ZBREUkNCkgPyBDTEFTU19OQU1FX0ZBREUkNCA6ICcnO1xuXG4gICAgICBpZiAodGhpcy5faXNTaG93biAmJiB0aGlzLl9jb25maWcuYmFja2Ryb3ApIHtcbiAgICAgICAgdGhpcy5fYmFja2Ryb3AgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICAgICAgdGhpcy5fYmFja2Ryb3AuY2xhc3NOYW1lID0gQ0xBU1NfTkFNRV9CQUNLRFJPUDtcblxuICAgICAgICBpZiAoYW5pbWF0ZSkge1xuICAgICAgICAgIHRoaXMuX2JhY2tkcm9wLmNsYXNzTGlzdC5hZGQoYW5pbWF0ZSk7XG4gICAgICAgIH1cblxuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9iYWNrZHJvcCkuYXBwZW5kVG8oZG9jdW1lbnQuYm9keSk7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLm9uKEVWRU5UX0NMSUNLX0RJU01JU1MkMSwgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgaWYgKF90aGlzOS5faWdub3JlQmFja2Ryb3BDbGljaykge1xuICAgICAgICAgICAgX3RoaXM5Ll9pZ25vcmVCYWNrZHJvcENsaWNrID0gZmFsc2U7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKGV2ZW50LnRhcmdldCAhPT0gZXZlbnQuY3VycmVudFRhcmdldCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChfdGhpczkuX2NvbmZpZy5iYWNrZHJvcCA9PT0gJ3N0YXRpYycpIHtcbiAgICAgICAgICAgIF90aGlzOS5fdHJpZ2dlckJhY2tkcm9wVHJhbnNpdGlvbigpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBfdGhpczkuaGlkZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKGFuaW1hdGUpIHtcbiAgICAgICAgICBVdGlsLnJlZmxvdyh0aGlzLl9iYWNrZHJvcCk7XG4gICAgICAgIH1cblxuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9iYWNrZHJvcCkuYWRkQ2xhc3MoQ0xBU1NfTkFNRV9TSE9XJDQpO1xuXG4gICAgICAgIGlmICghY2FsbGJhY2spIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWFuaW1hdGUpIHtcbiAgICAgICAgICBjYWxsYmFjaygpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBiYWNrZHJvcFRyYW5zaXRpb25EdXJhdGlvbiA9IFV0aWwuZ2V0VHJhbnNpdGlvbkR1cmF0aW9uRnJvbUVsZW1lbnQodGhpcy5fYmFja2Ryb3ApO1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9iYWNrZHJvcCkub25lKFV0aWwuVFJBTlNJVElPTl9FTkQsIGNhbGxiYWNrKS5lbXVsYXRlVHJhbnNpdGlvbkVuZChiYWNrZHJvcFRyYW5zaXRpb25EdXJhdGlvbik7XG4gICAgICB9IGVsc2UgaWYgKCF0aGlzLl9pc1Nob3duICYmIHRoaXMuX2JhY2tkcm9wKSB7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2JhY2tkcm9wKS5yZW1vdmVDbGFzcyhDTEFTU19OQU1FX1NIT1ckNCk7XG5cbiAgICAgICAgdmFyIGNhbGxiYWNrUmVtb3ZlID0gZnVuY3Rpb24gY2FsbGJhY2tSZW1vdmUoKSB7XG4gICAgICAgICAgX3RoaXM5Ll9yZW1vdmVCYWNrZHJvcCgpO1xuXG4gICAgICAgICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICAgICAgICBjYWxsYmFjaygpO1xuICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBpZiAoJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkuaGFzQ2xhc3MoQ0xBU1NfTkFNRV9GQURFJDQpKSB7XG4gICAgICAgICAgdmFyIF9iYWNrZHJvcFRyYW5zaXRpb25EdXJhdGlvbiA9IFV0aWwuZ2V0VHJhbnNpdGlvbkR1cmF0aW9uRnJvbUVsZW1lbnQodGhpcy5fYmFja2Ryb3ApO1xuXG4gICAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fYmFja2Ryb3ApLm9uZShVdGlsLlRSQU5TSVRJT05fRU5ELCBjYWxsYmFja1JlbW92ZSkuZW11bGF0ZVRyYW5zaXRpb25FbmQoX2JhY2tkcm9wVHJhbnNpdGlvbkR1cmF0aW9uKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjYWxsYmFja1JlbW92ZSgpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKGNhbGxiYWNrKSB7XG4gICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICB9XG4gICAgfSAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gdGhlIGZvbGxvd2luZyBtZXRob2RzIGFyZSB1c2VkIHRvIGhhbmRsZSBvdmVyZmxvd2luZyBtb2RhbHNcbiAgICAvLyB0b2RvIChmYXQpOiB0aGVzZSBzaG91bGQgcHJvYmFibHkgYmUgcmVmYWN0b3JlZCBvdXQgb2YgbW9kYWwuanNcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgO1xuXG4gICAgX3Byb3RvLl9hZGp1c3REaWFsb2cgPSBmdW5jdGlvbiBfYWRqdXN0RGlhbG9nKCkge1xuICAgICAgdmFyIGlzTW9kYWxPdmVyZmxvd2luZyA9IHRoaXMuX2VsZW1lbnQuc2Nyb2xsSGVpZ2h0ID4gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodDtcblxuICAgICAgaWYgKCF0aGlzLl9pc0JvZHlPdmVyZmxvd2luZyAmJiBpc01vZGFsT3ZlcmZsb3dpbmcpIHtcbiAgICAgICAgdGhpcy5fZWxlbWVudC5zdHlsZS5wYWRkaW5nTGVmdCA9IHRoaXMuX3Njcm9sbGJhcldpZHRoICsgXCJweFwiO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5faXNCb2R5T3ZlcmZsb3dpbmcgJiYgIWlzTW9kYWxPdmVyZmxvd2luZykge1xuICAgICAgICB0aGlzLl9lbGVtZW50LnN0eWxlLnBhZGRpbmdSaWdodCA9IHRoaXMuX3Njcm9sbGJhcldpZHRoICsgXCJweFwiO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBfcHJvdG8uX3Jlc2V0QWRqdXN0bWVudHMgPSBmdW5jdGlvbiBfcmVzZXRBZGp1c3RtZW50cygpIHtcbiAgICAgIHRoaXMuX2VsZW1lbnQuc3R5bGUucGFkZGluZ0xlZnQgPSAnJztcbiAgICAgIHRoaXMuX2VsZW1lbnQuc3R5bGUucGFkZGluZ1JpZ2h0ID0gJyc7XG4gICAgfTtcblxuICAgIF9wcm90by5fY2hlY2tTY3JvbGxiYXIgPSBmdW5jdGlvbiBfY2hlY2tTY3JvbGxiYXIoKSB7XG4gICAgICB2YXIgcmVjdCA9IGRvY3VtZW50LmJvZHkuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICB0aGlzLl9pc0JvZHlPdmVyZmxvd2luZyA9IE1hdGgucm91bmQocmVjdC5sZWZ0ICsgcmVjdC5yaWdodCkgPCB3aW5kb3cuaW5uZXJXaWR0aDtcbiAgICAgIHRoaXMuX3Njcm9sbGJhcldpZHRoID0gdGhpcy5fZ2V0U2Nyb2xsYmFyV2lkdGgoKTtcbiAgICB9O1xuXG4gICAgX3Byb3RvLl9zZXRTY3JvbGxiYXIgPSBmdW5jdGlvbiBfc2V0U2Nyb2xsYmFyKCkge1xuICAgICAgdmFyIF90aGlzMTAgPSB0aGlzO1xuXG4gICAgICBpZiAodGhpcy5faXNCb2R5T3ZlcmZsb3dpbmcpIHtcbiAgICAgICAgLy8gTm90ZTogRE9NTm9kZS5zdHlsZS5wYWRkaW5nUmlnaHQgcmV0dXJucyB0aGUgYWN0dWFsIHZhbHVlIG9yICcnIGlmIG5vdCBzZXRcbiAgICAgICAgLy8gICB3aGlsZSAkKERPTU5vZGUpLmNzcygncGFkZGluZy1yaWdodCcpIHJldHVybnMgdGhlIGNhbGN1bGF0ZWQgdmFsdWUgb3IgMCBpZiBub3Qgc2V0XG4gICAgICAgIHZhciBmaXhlZENvbnRlbnQgPSBbXS5zbGljZS5jYWxsKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoU0VMRUNUT1JfRklYRURfQ09OVEVOVCkpO1xuICAgICAgICB2YXIgc3RpY2t5Q29udGVudCA9IFtdLnNsaWNlLmNhbGwoZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbChTRUxFQ1RPUl9TVElDS1lfQ09OVEVOVCkpOyAvLyBBZGp1c3QgZml4ZWQgY29udGVudCBwYWRkaW5nXG5cbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZml4ZWRDb250ZW50KS5lYWNoKGZ1bmN0aW9uIChpbmRleCwgZWxlbWVudCkge1xuICAgICAgICAgIHZhciBhY3R1YWxQYWRkaW5nID0gZWxlbWVudC5zdHlsZS5wYWRkaW5nUmlnaHQ7XG4gICAgICAgICAgdmFyIGNhbGN1bGF0ZWRQYWRkaW5nID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZWxlbWVudCkuY3NzKCdwYWRkaW5nLXJpZ2h0Jyk7XG4gICAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZWxlbWVudCkuZGF0YSgncGFkZGluZy1yaWdodCcsIGFjdHVhbFBhZGRpbmcpLmNzcygncGFkZGluZy1yaWdodCcsIHBhcnNlRmxvYXQoY2FsY3VsYXRlZFBhZGRpbmcpICsgX3RoaXMxMC5fc2Nyb2xsYmFyV2lkdGggKyBcInB4XCIpO1xuICAgICAgICB9KTsgLy8gQWRqdXN0IHN0aWNreSBjb250ZW50IG1hcmdpblxuXG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHN0aWNreUNvbnRlbnQpLmVhY2goZnVuY3Rpb24gKGluZGV4LCBlbGVtZW50KSB7XG4gICAgICAgICAgdmFyIGFjdHVhbE1hcmdpbiA9IGVsZW1lbnQuc3R5bGUubWFyZ2luUmlnaHQ7XG4gICAgICAgICAgdmFyIGNhbGN1bGF0ZWRNYXJnaW4gPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShlbGVtZW50KS5jc3MoJ21hcmdpbi1yaWdodCcpO1xuICAgICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGVsZW1lbnQpLmRhdGEoJ21hcmdpbi1yaWdodCcsIGFjdHVhbE1hcmdpbikuY3NzKCdtYXJnaW4tcmlnaHQnLCBwYXJzZUZsb2F0KGNhbGN1bGF0ZWRNYXJnaW4pIC0gX3RoaXMxMC5fc2Nyb2xsYmFyV2lkdGggKyBcInB4XCIpO1xuICAgICAgICB9KTsgLy8gQWRqdXN0IGJvZHkgcGFkZGluZ1xuXG4gICAgICAgIHZhciBhY3R1YWxQYWRkaW5nID0gZG9jdW1lbnQuYm9keS5zdHlsZS5wYWRkaW5nUmlnaHQ7XG4gICAgICAgIHZhciBjYWxjdWxhdGVkUGFkZGluZyA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGRvY3VtZW50LmJvZHkpLmNzcygncGFkZGluZy1yaWdodCcpO1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShkb2N1bWVudC5ib2R5KS5kYXRhKCdwYWRkaW5nLXJpZ2h0JywgYWN0dWFsUGFkZGluZykuY3NzKCdwYWRkaW5nLXJpZ2h0JywgcGFyc2VGbG9hdChjYWxjdWxhdGVkUGFkZGluZykgKyB0aGlzLl9zY3JvbGxiYXJXaWR0aCArIFwicHhcIik7XG4gICAgICB9XG5cbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGRvY3VtZW50LmJvZHkpLmFkZENsYXNzKENMQVNTX05BTUVfT1BFTik7XG4gICAgfTtcblxuICAgIF9wcm90by5fcmVzZXRTY3JvbGxiYXIgPSBmdW5jdGlvbiBfcmVzZXRTY3JvbGxiYXIoKSB7XG4gICAgICAvLyBSZXN0b3JlIGZpeGVkIGNvbnRlbnQgcGFkZGluZ1xuICAgICAgdmFyIGZpeGVkQ29udGVudCA9IFtdLnNsaWNlLmNhbGwoZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbChTRUxFQ1RPUl9GSVhFRF9DT05URU5UKSk7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShmaXhlZENvbnRlbnQpLmVhY2goZnVuY3Rpb24gKGluZGV4LCBlbGVtZW50KSB7XG4gICAgICAgIHZhciBwYWRkaW5nID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZWxlbWVudCkuZGF0YSgncGFkZGluZy1yaWdodCcpO1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShlbGVtZW50KS5yZW1vdmVEYXRhKCdwYWRkaW5nLXJpZ2h0Jyk7XG4gICAgICAgIGVsZW1lbnQuc3R5bGUucGFkZGluZ1JpZ2h0ID0gcGFkZGluZyA/IHBhZGRpbmcgOiAnJztcbiAgICAgIH0pOyAvLyBSZXN0b3JlIHN0aWNreSBjb250ZW50XG5cbiAgICAgIHZhciBlbGVtZW50cyA9IFtdLnNsaWNlLmNhbGwoZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbChcIlwiICsgU0VMRUNUT1JfU1RJQ0tZX0NPTlRFTlQpKTtcbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGVsZW1lbnRzKS5lYWNoKGZ1bmN0aW9uIChpbmRleCwgZWxlbWVudCkge1xuICAgICAgICB2YXIgbWFyZ2luID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZWxlbWVudCkuZGF0YSgnbWFyZ2luLXJpZ2h0Jyk7XG5cbiAgICAgICAgaWYgKHR5cGVvZiBtYXJnaW4gIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZWxlbWVudCkuY3NzKCdtYXJnaW4tcmlnaHQnLCBtYXJnaW4pLnJlbW92ZURhdGEoJ21hcmdpbi1yaWdodCcpO1xuICAgICAgICB9XG4gICAgICB9KTsgLy8gUmVzdG9yZSBib2R5IHBhZGRpbmdcblxuICAgICAgdmFyIHBhZGRpbmcgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShkb2N1bWVudC5ib2R5KS5kYXRhKCdwYWRkaW5nLXJpZ2h0Jyk7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShkb2N1bWVudC5ib2R5KS5yZW1vdmVEYXRhKCdwYWRkaW5nLXJpZ2h0Jyk7XG4gICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnBhZGRpbmdSaWdodCA9IHBhZGRpbmcgPyBwYWRkaW5nIDogJyc7XG4gICAgfTtcblxuICAgIF9wcm90by5fZ2V0U2Nyb2xsYmFyV2lkdGggPSBmdW5jdGlvbiBfZ2V0U2Nyb2xsYmFyV2lkdGgoKSB7XG4gICAgICAvLyB0aHggZC53YWxzaFxuICAgICAgdmFyIHNjcm9sbERpdiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgICAgc2Nyb2xsRGl2LmNsYXNzTmFtZSA9IENMQVNTX05BTUVfU0NST0xMQkFSX01FQVNVUkVSO1xuICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChzY3JvbGxEaXYpO1xuICAgICAgdmFyIHNjcm9sbGJhcldpZHRoID0gc2Nyb2xsRGl2LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLndpZHRoIC0gc2Nyb2xsRGl2LmNsaWVudFdpZHRoO1xuICAgICAgZG9jdW1lbnQuYm9keS5yZW1vdmVDaGlsZChzY3JvbGxEaXYpO1xuICAgICAgcmV0dXJuIHNjcm9sbGJhcldpZHRoO1xuICAgIH0gLy8gU3RhdGljXG4gICAgO1xuXG4gICAgTW9kYWwuX2pRdWVyeUludGVyZmFjZSA9IGZ1bmN0aW9uIF9qUXVlcnlJbnRlcmZhY2UoY29uZmlnLCByZWxhdGVkVGFyZ2V0KSB7XG4gICAgICByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGRhdGEgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzKS5kYXRhKERBVEFfS0VZJDUpO1xuXG4gICAgICAgIHZhciBfY29uZmlnID0gX2V4dGVuZHMoe30sIERlZmF1bHQkNCwgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcykuZGF0YSgpLCB0eXBlb2YgY29uZmlnID09PSAnb2JqZWN0JyAmJiBjb25maWcgPyBjb25maWcgOiB7fSk7XG5cbiAgICAgICAgaWYgKCFkYXRhKSB7XG4gICAgICAgICAgZGF0YSA9IG5ldyBNb2RhbCh0aGlzLCBfY29uZmlnKTtcbiAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzKS5kYXRhKERBVEFfS0VZJDUsIGRhdGEpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBjb25maWcgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgaWYgKHR5cGVvZiBkYXRhW2NvbmZpZ10gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiTm8gbWV0aG9kIG5hbWVkIFxcXCJcIiArIGNvbmZpZyArIFwiXFxcIlwiKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBkYXRhW2NvbmZpZ10ocmVsYXRlZFRhcmdldCk7XG4gICAgICAgIH0gZWxzZSBpZiAoX2NvbmZpZy5zaG93KSB7XG4gICAgICAgICAgZGF0YS5zaG93KHJlbGF0ZWRUYXJnZXQpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgX2NyZWF0ZUNsYXNzKE1vZGFsLCBudWxsLCBbe1xuICAgICAga2V5OiBcIlZFUlNJT05cIixcbiAgICAgIGdldDogZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgICByZXR1cm4gVkVSU0lPTiQ1O1xuICAgICAgfVxuICAgIH0sIHtcbiAgICAgIGtleTogXCJEZWZhdWx0XCIsXG4gICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgcmV0dXJuIERlZmF1bHQkNDtcbiAgICAgIH1cbiAgICB9XSk7XG5cbiAgICByZXR1cm4gTW9kYWw7XG4gIH0oKTtcbiAgLyoqXG4gICAqIERhdGEgQVBJIGltcGxlbWVudGF0aW9uXG4gICAqL1xuXG5cbiAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZG9jdW1lbnQpLm9uKEVWRU5UX0NMSUNLX0RBVEFfQVBJJDEsIFNFTEVDVE9SX0RBVEFfVE9HR0xFJDEsIGZ1bmN0aW9uIChldmVudCkge1xuICAgIHZhciBfdGhpczExID0gdGhpcztcblxuICAgIHZhciB0YXJnZXQ7XG4gICAgdmFyIHNlbGVjdG9yID0gVXRpbC5nZXRTZWxlY3RvckZyb21FbGVtZW50KHRoaXMpO1xuXG4gICAgaWYgKHNlbGVjdG9yKSB7XG4gICAgICB0YXJnZXQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHNlbGVjdG9yKTtcbiAgICB9XG5cbiAgICB2YXIgY29uZmlnID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGFyZ2V0KS5kYXRhKERBVEFfS0VZJDUpID8gJ3RvZ2dsZScgOiBfZXh0ZW5kcyh7fSwgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGFyZ2V0KS5kYXRhKCksICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMpLmRhdGEoKSk7XG5cbiAgICBpZiAodGhpcy50YWdOYW1lID09PSAnQScgfHwgdGhpcy50YWdOYW1lID09PSAnQVJFQScpIHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuXG4gICAgdmFyICR0YXJnZXQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0YXJnZXQpLm9uZShFVkVOVF9TSE9XJDIsIGZ1bmN0aW9uIChzaG93RXZlbnQpIHtcbiAgICAgIGlmIChzaG93RXZlbnQuaXNEZWZhdWx0UHJldmVudGVkKCkpIHtcbiAgICAgICAgLy8gT25seSByZWdpc3RlciBmb2N1cyByZXN0b3JlciBpZiBtb2RhbCB3aWxsIGFjdHVhbGx5IGdldCBzaG93blxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgICR0YXJnZXQub25lKEVWRU5UX0hJRERFTiQyLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICgkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShfdGhpczExKS5pcygnOnZpc2libGUnKSkge1xuICAgICAgICAgIF90aGlzMTEuZm9jdXMoKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBNb2RhbC5falF1ZXJ5SW50ZXJmYWNlLmNhbGwoJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGFyZ2V0KSwgY29uZmlnLCB0aGlzKTtcbiAgfSk7XG4gIC8qKlxuICAgKiBqUXVlcnlcbiAgICovXG5cbiAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQ1XSA9IE1vZGFsLl9qUXVlcnlJbnRlcmZhY2U7XG4gICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuW05BTUUkNV0uQ29uc3RydWN0b3IgPSBNb2RhbDtcblxuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDVdLm5vQ29uZmxpY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQ1XSA9IEpRVUVSWV9OT19DT05GTElDVCQ1O1xuICAgIHJldHVybiBNb2RhbC5falF1ZXJ5SW50ZXJmYWNlO1xuICB9O1xuXG4gIC8qKlxuICAgKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgKiBCb290c3RyYXAgKHY0LjYuMSk6IHRvb2xzL3Nhbml0aXplci5qc1xuICAgKiBMaWNlbnNlZCB1bmRlciBNSVQgKGh0dHBzOi8vZ2l0aHViLmNvbS90d2JzL2Jvb3RzdHJhcC9ibG9iL21haW4vTElDRU5TRSlcbiAgICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICovXG4gIHZhciB1cmlBdHRycyA9IFsnYmFja2dyb3VuZCcsICdjaXRlJywgJ2hyZWYnLCAnaXRlbXR5cGUnLCAnbG9uZ2Rlc2MnLCAncG9zdGVyJywgJ3NyYycsICd4bGluazpocmVmJ107XG4gIHZhciBBUklBX0FUVFJJQlVURV9QQVRURVJOID0gL15hcmlhLVtcXHctXSokL2k7XG4gIHZhciBEZWZhdWx0V2hpdGVsaXN0ID0ge1xuICAgIC8vIEdsb2JhbCBhdHRyaWJ1dGVzIGFsbG93ZWQgb24gYW55IHN1cHBsaWVkIGVsZW1lbnQgYmVsb3cuXG4gICAgJyonOiBbJ2NsYXNzJywgJ2RpcicsICdpZCcsICdsYW5nJywgJ3JvbGUnLCBBUklBX0FUVFJJQlVURV9QQVRURVJOXSxcbiAgICBhOiBbJ3RhcmdldCcsICdocmVmJywgJ3RpdGxlJywgJ3JlbCddLFxuICAgIGFyZWE6IFtdLFxuICAgIGI6IFtdLFxuICAgIGJyOiBbXSxcbiAgICBjb2w6IFtdLFxuICAgIGNvZGU6IFtdLFxuICAgIGRpdjogW10sXG4gICAgZW06IFtdLFxuICAgIGhyOiBbXSxcbiAgICBoMTogW10sXG4gICAgaDI6IFtdLFxuICAgIGgzOiBbXSxcbiAgICBoNDogW10sXG4gICAgaDU6IFtdLFxuICAgIGg2OiBbXSxcbiAgICBpOiBbXSxcbiAgICBpbWc6IFsnc3JjJywgJ3NyY3NldCcsICdhbHQnLCAndGl0bGUnLCAnd2lkdGgnLCAnaGVpZ2h0J10sXG4gICAgbGk6IFtdLFxuICAgIG9sOiBbXSxcbiAgICBwOiBbXSxcbiAgICBwcmU6IFtdLFxuICAgIHM6IFtdLFxuICAgIHNtYWxsOiBbXSxcbiAgICBzcGFuOiBbXSxcbiAgICBzdWI6IFtdLFxuICAgIHN1cDogW10sXG4gICAgc3Ryb25nOiBbXSxcbiAgICB1OiBbXSxcbiAgICB1bDogW11cbiAgfTtcbiAgLyoqXG4gICAqIEEgcGF0dGVybiB0aGF0IHJlY29nbml6ZXMgYSBjb21tb25seSB1c2VmdWwgc3Vic2V0IG9mIFVSTHMgdGhhdCBhcmUgc2FmZS5cbiAgICpcbiAgICogU2hvdXRvdXQgdG8gQW5ndWxhciBodHRwczovL2dpdGh1Yi5jb20vYW5ndWxhci9hbmd1bGFyL2Jsb2IvMTIuMi54L3BhY2thZ2VzL2NvcmUvc3JjL3Nhbml0aXphdGlvbi91cmxfc2FuaXRpemVyLnRzXG4gICAqL1xuXG4gIHZhciBTQUZFX1VSTF9QQVRURVJOID0gL14oPzooPzpodHRwcz98bWFpbHRvfGZ0cHx0ZWx8ZmlsZXxzbXMpOnxbXiMmLzo/XSooPzpbIy8/XXwkKSkvaTtcbiAgLyoqXG4gICAqIEEgcGF0dGVybiB0aGF0IG1hdGNoZXMgc2FmZSBkYXRhIFVSTHMuIE9ubHkgbWF0Y2hlcyBpbWFnZSwgdmlkZW8gYW5kIGF1ZGlvIHR5cGVzLlxuICAgKlxuICAgKiBTaG91dG91dCB0byBBbmd1bGFyIGh0dHBzOi8vZ2l0aHViLmNvbS9hbmd1bGFyL2FuZ3VsYXIvYmxvYi8xMi4yLngvcGFja2FnZXMvY29yZS9zcmMvc2FuaXRpemF0aW9uL3VybF9zYW5pdGl6ZXIudHNcbiAgICovXG5cbiAgdmFyIERBVEFfVVJMX1BBVFRFUk4gPSAvXmRhdGE6KD86aW1hZ2VcXC8oPzpibXB8Z2lmfGpwZWd8anBnfHBuZ3x0aWZmfHdlYnApfHZpZGVvXFwvKD86bXBlZ3xtcDR8b2dnfHdlYm0pfGF1ZGlvXFwvKD86bXAzfG9nYXxvZ2d8b3B1cykpO2Jhc2U2NCxbXFxkKy9hLXpdKz0qJC9pO1xuXG4gIGZ1bmN0aW9uIGFsbG93ZWRBdHRyaWJ1dGUoYXR0ciwgYWxsb3dlZEF0dHJpYnV0ZUxpc3QpIHtcbiAgICB2YXIgYXR0ck5hbWUgPSBhdHRyLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7XG5cbiAgICBpZiAoYWxsb3dlZEF0dHJpYnV0ZUxpc3QuaW5kZXhPZihhdHRyTmFtZSkgIT09IC0xKSB7XG4gICAgICBpZiAodXJpQXR0cnMuaW5kZXhPZihhdHRyTmFtZSkgIT09IC0xKSB7XG4gICAgICAgIHJldHVybiBCb29sZWFuKFNBRkVfVVJMX1BBVFRFUk4udGVzdChhdHRyLm5vZGVWYWx1ZSkgfHwgREFUQV9VUkxfUEFUVEVSTi50ZXN0KGF0dHIubm9kZVZhbHVlKSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHZhciByZWdFeHAgPSBhbGxvd2VkQXR0cmlidXRlTGlzdC5maWx0ZXIoZnVuY3Rpb24gKGF0dHJSZWdleCkge1xuICAgICAgcmV0dXJuIGF0dHJSZWdleCBpbnN0YW5jZW9mIFJlZ0V4cDtcbiAgICB9KTsgLy8gQ2hlY2sgaWYgYSByZWd1bGFyIGV4cHJlc3Npb24gdmFsaWRhdGVzIHRoZSBhdHRyaWJ1dGUuXG5cbiAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gcmVnRXhwLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICBpZiAocmVnRXhwW2ldLnRlc3QoYXR0ck5hbWUpKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHNhbml0aXplSHRtbCh1bnNhZmVIdG1sLCB3aGl0ZUxpc3QsIHNhbml0aXplRm4pIHtcbiAgICBpZiAodW5zYWZlSHRtbC5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiB1bnNhZmVIdG1sO1xuICAgIH1cblxuICAgIGlmIChzYW5pdGl6ZUZuICYmIHR5cGVvZiBzYW5pdGl6ZUZuID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICByZXR1cm4gc2FuaXRpemVGbih1bnNhZmVIdG1sKTtcbiAgICB9XG5cbiAgICB2YXIgZG9tUGFyc2VyID0gbmV3IHdpbmRvdy5ET01QYXJzZXIoKTtcbiAgICB2YXIgY3JlYXRlZERvY3VtZW50ID0gZG9tUGFyc2VyLnBhcnNlRnJvbVN0cmluZyh1bnNhZmVIdG1sLCAndGV4dC9odG1sJyk7XG4gICAgdmFyIHdoaXRlbGlzdEtleXMgPSBPYmplY3Qua2V5cyh3aGl0ZUxpc3QpO1xuICAgIHZhciBlbGVtZW50cyA9IFtdLnNsaWNlLmNhbGwoY3JlYXRlZERvY3VtZW50LmJvZHkucXVlcnlTZWxlY3RvckFsbCgnKicpKTtcblxuICAgIHZhciBfbG9vcCA9IGZ1bmN0aW9uIF9sb29wKGksIGxlbikge1xuICAgICAgdmFyIGVsID0gZWxlbWVudHNbaV07XG4gICAgICB2YXIgZWxOYW1lID0gZWwubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtcblxuICAgICAgaWYgKHdoaXRlbGlzdEtleXMuaW5kZXhPZihlbC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpKSA9PT0gLTEpIHtcbiAgICAgICAgZWwucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChlbCk7XG4gICAgICAgIHJldHVybiBcImNvbnRpbnVlXCI7XG4gICAgICB9XG5cbiAgICAgIHZhciBhdHRyaWJ1dGVMaXN0ID0gW10uc2xpY2UuY2FsbChlbC5hdHRyaWJ1dGVzKTsgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHVuaWNvcm4vcHJlZmVyLXNwcmVhZFxuXG4gICAgICB2YXIgd2hpdGVsaXN0ZWRBdHRyaWJ1dGVzID0gW10uY29uY2F0KHdoaXRlTGlzdFsnKiddIHx8IFtdLCB3aGl0ZUxpc3RbZWxOYW1lXSB8fCBbXSk7XG4gICAgICBhdHRyaWJ1dGVMaXN0LmZvckVhY2goZnVuY3Rpb24gKGF0dHIpIHtcbiAgICAgICAgaWYgKCFhbGxvd2VkQXR0cmlidXRlKGF0dHIsIHdoaXRlbGlzdGVkQXR0cmlidXRlcykpIHtcbiAgICAgICAgICBlbC5yZW1vdmVBdHRyaWJ1dGUoYXR0ci5ub2RlTmFtZSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gZWxlbWVudHMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgIHZhciBfcmV0ID0gX2xvb3AoaSk7XG5cbiAgICAgIGlmIChfcmV0ID09PSBcImNvbnRpbnVlXCIpIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIHJldHVybiBjcmVhdGVkRG9jdW1lbnQuYm9keS5pbm5lckhUTUw7XG4gIH1cblxuICAvKipcbiAgICogQ29uc3RhbnRzXG4gICAqL1xuXG4gIHZhciBOQU1FJDQgPSAndG9vbHRpcCc7XG4gIHZhciBWRVJTSU9OJDQgPSAnNC42LjEnO1xuICB2YXIgREFUQV9LRVkkNCA9ICdicy50b29sdGlwJztcbiAgdmFyIEVWRU5UX0tFWSQ0ID0gXCIuXCIgKyBEQVRBX0tFWSQ0O1xuICB2YXIgSlFVRVJZX05PX0NPTkZMSUNUJDQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDRdO1xuICB2YXIgQ0xBU1NfUFJFRklYJDEgPSAnYnMtdG9vbHRpcCc7XG4gIHZhciBCU0NMU19QUkVGSVhfUkVHRVgkMSA9IG5ldyBSZWdFeHAoXCIoXnxcXFxccylcIiArIENMQVNTX1BSRUZJWCQxICsgXCJcXFxcUytcIiwgJ2cnKTtcbiAgdmFyIERJU0FMTE9XRURfQVRUUklCVVRFUyA9IFsnc2FuaXRpemUnLCAnd2hpdGVMaXN0JywgJ3Nhbml0aXplRm4nXTtcbiAgdmFyIENMQVNTX05BTUVfRkFERSQzID0gJ2ZhZGUnO1xuICB2YXIgQ0xBU1NfTkFNRV9TSE9XJDMgPSAnc2hvdyc7XG4gIHZhciBIT1ZFUl9TVEFURV9TSE9XID0gJ3Nob3cnO1xuICB2YXIgSE9WRVJfU1RBVEVfT1VUID0gJ291dCc7XG4gIHZhciBTRUxFQ1RPUl9UT09MVElQX0lOTkVSID0gJy50b29sdGlwLWlubmVyJztcbiAgdmFyIFNFTEVDVE9SX0FSUk9XID0gJy5hcnJvdyc7XG4gIHZhciBUUklHR0VSX0hPVkVSID0gJ2hvdmVyJztcbiAgdmFyIFRSSUdHRVJfRk9DVVMgPSAnZm9jdXMnO1xuICB2YXIgVFJJR0dFUl9DTElDSyA9ICdjbGljayc7XG4gIHZhciBUUklHR0VSX01BTlVBTCA9ICdtYW51YWwnO1xuICB2YXIgQXR0YWNobWVudE1hcCA9IHtcbiAgICBBVVRPOiAnYXV0bycsXG4gICAgVE9QOiAndG9wJyxcbiAgICBSSUdIVDogJ3JpZ2h0JyxcbiAgICBCT1RUT006ICdib3R0b20nLFxuICAgIExFRlQ6ICdsZWZ0J1xuICB9O1xuICB2YXIgRGVmYXVsdCQzID0ge1xuICAgIGFuaW1hdGlvbjogdHJ1ZSxcbiAgICB0ZW1wbGF0ZTogJzxkaXYgY2xhc3M9XCJ0b29sdGlwXCIgcm9sZT1cInRvb2x0aXBcIj4nICsgJzxkaXYgY2xhc3M9XCJhcnJvd1wiPjwvZGl2PicgKyAnPGRpdiBjbGFzcz1cInRvb2x0aXAtaW5uZXJcIj48L2Rpdj48L2Rpdj4nLFxuICAgIHRyaWdnZXI6ICdob3ZlciBmb2N1cycsXG4gICAgdGl0bGU6ICcnLFxuICAgIGRlbGF5OiAwLFxuICAgIGh0bWw6IGZhbHNlLFxuICAgIHNlbGVjdG9yOiBmYWxzZSxcbiAgICBwbGFjZW1lbnQ6ICd0b3AnLFxuICAgIG9mZnNldDogMCxcbiAgICBjb250YWluZXI6IGZhbHNlLFxuICAgIGZhbGxiYWNrUGxhY2VtZW50OiAnZmxpcCcsXG4gICAgYm91bmRhcnk6ICdzY3JvbGxQYXJlbnQnLFxuICAgIGN1c3RvbUNsYXNzOiAnJyxcbiAgICBzYW5pdGl6ZTogdHJ1ZSxcbiAgICBzYW5pdGl6ZUZuOiBudWxsLFxuICAgIHdoaXRlTGlzdDogRGVmYXVsdFdoaXRlbGlzdCxcbiAgICBwb3BwZXJDb25maWc6IG51bGxcbiAgfTtcbiAgdmFyIERlZmF1bHRUeXBlJDMgPSB7XG4gICAgYW5pbWF0aW9uOiAnYm9vbGVhbicsXG4gICAgdGVtcGxhdGU6ICdzdHJpbmcnLFxuICAgIHRpdGxlOiAnKHN0cmluZ3xlbGVtZW50fGZ1bmN0aW9uKScsXG4gICAgdHJpZ2dlcjogJ3N0cmluZycsXG4gICAgZGVsYXk6ICcobnVtYmVyfG9iamVjdCknLFxuICAgIGh0bWw6ICdib29sZWFuJyxcbiAgICBzZWxlY3RvcjogJyhzdHJpbmd8Ym9vbGVhbiknLFxuICAgIHBsYWNlbWVudDogJyhzdHJpbmd8ZnVuY3Rpb24pJyxcbiAgICBvZmZzZXQ6ICcobnVtYmVyfHN0cmluZ3xmdW5jdGlvbiknLFxuICAgIGNvbnRhaW5lcjogJyhzdHJpbmd8ZWxlbWVudHxib29sZWFuKScsXG4gICAgZmFsbGJhY2tQbGFjZW1lbnQ6ICcoc3RyaW5nfGFycmF5KScsXG4gICAgYm91bmRhcnk6ICcoc3RyaW5nfGVsZW1lbnQpJyxcbiAgICBjdXN0b21DbGFzczogJyhzdHJpbmd8ZnVuY3Rpb24pJyxcbiAgICBzYW5pdGl6ZTogJ2Jvb2xlYW4nLFxuICAgIHNhbml0aXplRm46ICcobnVsbHxmdW5jdGlvbiknLFxuICAgIHdoaXRlTGlzdDogJ29iamVjdCcsXG4gICAgcG9wcGVyQ29uZmlnOiAnKG51bGx8b2JqZWN0KSdcbiAgfTtcbiAgdmFyIEV2ZW50JDEgPSB7XG4gICAgSElERTogXCJoaWRlXCIgKyBFVkVOVF9LRVkkNCxcbiAgICBISURERU46IFwiaGlkZGVuXCIgKyBFVkVOVF9LRVkkNCxcbiAgICBTSE9XOiBcInNob3dcIiArIEVWRU5UX0tFWSQ0LFxuICAgIFNIT1dOOiBcInNob3duXCIgKyBFVkVOVF9LRVkkNCxcbiAgICBJTlNFUlRFRDogXCJpbnNlcnRlZFwiICsgRVZFTlRfS0VZJDQsXG4gICAgQ0xJQ0s6IFwiY2xpY2tcIiArIEVWRU5UX0tFWSQ0LFxuICAgIEZPQ1VTSU46IFwiZm9jdXNpblwiICsgRVZFTlRfS0VZJDQsXG4gICAgRk9DVVNPVVQ6IFwiZm9jdXNvdXRcIiArIEVWRU5UX0tFWSQ0LFxuICAgIE1PVVNFRU5URVI6IFwibW91c2VlbnRlclwiICsgRVZFTlRfS0VZJDQsXG4gICAgTU9VU0VMRUFWRTogXCJtb3VzZWxlYXZlXCIgKyBFVkVOVF9LRVkkNFxuICB9O1xuICAvKipcbiAgICogQ2xhc3MgZGVmaW5pdGlvblxuICAgKi9cblxuICB2YXIgVG9vbHRpcCA9IC8qI19fUFVSRV9fKi9mdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gVG9vbHRpcChlbGVtZW50LCBjb25maWcpIHtcbiAgICAgIGlmICh0eXBlb2YgUG9wcGVyX19kZWZhdWx0W1wiZGVmYXVsdFwiXSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQm9vdHN0cmFwXFwncyB0b29sdGlwcyByZXF1aXJlIFBvcHBlciAoaHR0cHM6Ly9wb3BwZXIuanMub3JnKScpO1xuICAgICAgfSAvLyBQcml2YXRlXG5cblxuICAgICAgdGhpcy5faXNFbmFibGVkID0gdHJ1ZTtcbiAgICAgIHRoaXMuX3RpbWVvdXQgPSAwO1xuICAgICAgdGhpcy5faG92ZXJTdGF0ZSA9ICcnO1xuICAgICAgdGhpcy5fYWN0aXZlVHJpZ2dlciA9IHt9O1xuICAgICAgdGhpcy5fcG9wcGVyID0gbnVsbDsgLy8gUHJvdGVjdGVkXG5cbiAgICAgIHRoaXMuZWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgICB0aGlzLmNvbmZpZyA9IHRoaXMuX2dldENvbmZpZyhjb25maWcpO1xuICAgICAgdGhpcy50aXAgPSBudWxsO1xuXG4gICAgICB0aGlzLl9zZXRMaXN0ZW5lcnMoKTtcbiAgICB9IC8vIEdldHRlcnNcblxuXG4gICAgdmFyIF9wcm90byA9IFRvb2x0aXAucHJvdG90eXBlO1xuXG4gICAgLy8gUHVibGljXG4gICAgX3Byb3RvLmVuYWJsZSA9IGZ1bmN0aW9uIGVuYWJsZSgpIHtcbiAgICAgIHRoaXMuX2lzRW5hYmxlZCA9IHRydWU7XG4gICAgfTtcblxuICAgIF9wcm90by5kaXNhYmxlID0gZnVuY3Rpb24gZGlzYWJsZSgpIHtcbiAgICAgIHRoaXMuX2lzRW5hYmxlZCA9IGZhbHNlO1xuICAgIH07XG5cbiAgICBfcHJvdG8udG9nZ2xlRW5hYmxlZCA9IGZ1bmN0aW9uIHRvZ2dsZUVuYWJsZWQoKSB7XG4gICAgICB0aGlzLl9pc0VuYWJsZWQgPSAhdGhpcy5faXNFbmFibGVkO1xuICAgIH07XG5cbiAgICBfcHJvdG8udG9nZ2xlID0gZnVuY3Rpb24gdG9nZ2xlKGV2ZW50KSB7XG4gICAgICBpZiAoIXRoaXMuX2lzRW5hYmxlZCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChldmVudCkge1xuICAgICAgICB2YXIgZGF0YUtleSA9IHRoaXMuY29uc3RydWN0b3IuREFUQV9LRVk7XG4gICAgICAgIHZhciBjb250ZXh0ID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZXZlbnQuY3VycmVudFRhcmdldCkuZGF0YShkYXRhS2V5KTtcblxuICAgICAgICBpZiAoIWNvbnRleHQpIHtcbiAgICAgICAgICBjb250ZXh0ID0gbmV3IHRoaXMuY29uc3RydWN0b3IoZXZlbnQuY3VycmVudFRhcmdldCwgdGhpcy5fZ2V0RGVsZWdhdGVDb25maWcoKSk7XG4gICAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZXZlbnQuY3VycmVudFRhcmdldCkuZGF0YShkYXRhS2V5LCBjb250ZXh0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnRleHQuX2FjdGl2ZVRyaWdnZXIuY2xpY2sgPSAhY29udGV4dC5fYWN0aXZlVHJpZ2dlci5jbGljaztcblxuICAgICAgICBpZiAoY29udGV4dC5faXNXaXRoQWN0aXZlVHJpZ2dlcigpKSB7XG4gICAgICAgICAgY29udGV4dC5fZW50ZXIobnVsbCwgY29udGV4dCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29udGV4dC5fbGVhdmUobnVsbCwgY29udGV4dCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmICgkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLmdldFRpcEVsZW1lbnQoKSkuaGFzQ2xhc3MoQ0xBU1NfTkFNRV9TSE9XJDMpKSB7XG4gICAgICAgICAgdGhpcy5fbGVhdmUobnVsbCwgdGhpcyk7XG5cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9lbnRlcihudWxsLCB0aGlzKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgX3Byb3RvLmRpc3Bvc2UgPSBmdW5jdGlvbiBkaXNwb3NlKCkge1xuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuX3RpbWVvdXQpO1xuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0ucmVtb3ZlRGF0YSh0aGlzLmVsZW1lbnQsIHRoaXMuY29uc3RydWN0b3IuREFUQV9LRVkpO1xuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5lbGVtZW50KS5vZmYodGhpcy5jb25zdHJ1Y3Rvci5FVkVOVF9LRVkpO1xuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5lbGVtZW50KS5jbG9zZXN0KCcubW9kYWwnKS5vZmYoJ2hpZGUuYnMubW9kYWwnLCB0aGlzLl9oaWRlTW9kYWxIYW5kbGVyKTtcblxuICAgICAgaWYgKHRoaXMudGlwKSB7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMudGlwKS5yZW1vdmUoKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5faXNFbmFibGVkID0gbnVsbDtcbiAgICAgIHRoaXMuX3RpbWVvdXQgPSBudWxsO1xuICAgICAgdGhpcy5faG92ZXJTdGF0ZSA9IG51bGw7XG4gICAgICB0aGlzLl9hY3RpdmVUcmlnZ2VyID0gbnVsbDtcblxuICAgICAgaWYgKHRoaXMuX3BvcHBlcikge1xuICAgICAgICB0aGlzLl9wb3BwZXIuZGVzdHJveSgpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLl9wb3BwZXIgPSBudWxsO1xuICAgICAgdGhpcy5lbGVtZW50ID0gbnVsbDtcbiAgICAgIHRoaXMuY29uZmlnID0gbnVsbDtcbiAgICAgIHRoaXMudGlwID0gbnVsbDtcbiAgICB9O1xuXG4gICAgX3Byb3RvLnNob3cgPSBmdW5jdGlvbiBzaG93KCkge1xuICAgICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgICAgaWYgKCRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuZWxlbWVudCkuY3NzKCdkaXNwbGF5JykgPT09ICdub25lJykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSB1c2Ugc2hvdyBvbiB2aXNpYmxlIGVsZW1lbnRzJyk7XG4gICAgICB9XG5cbiAgICAgIHZhciBzaG93RXZlbnQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5FdmVudCh0aGlzLmNvbnN0cnVjdG9yLkV2ZW50LlNIT1cpO1xuXG4gICAgICBpZiAodGhpcy5pc1dpdGhDb250ZW50KCkgJiYgdGhpcy5faXNFbmFibGVkKSB7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuZWxlbWVudCkudHJpZ2dlcihzaG93RXZlbnQpO1xuICAgICAgICB2YXIgc2hhZG93Um9vdCA9IFV0aWwuZmluZFNoYWRvd1Jvb3QodGhpcy5lbGVtZW50KTtcbiAgICAgICAgdmFyIGlzSW5UaGVEb20gPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5jb250YWlucyhzaGFkb3dSb290ICE9PSBudWxsID8gc2hhZG93Um9vdCA6IHRoaXMuZWxlbWVudC5vd25lckRvY3VtZW50LmRvY3VtZW50RWxlbWVudCwgdGhpcy5lbGVtZW50KTtcblxuICAgICAgICBpZiAoc2hvd0V2ZW50LmlzRGVmYXVsdFByZXZlbnRlZCgpIHx8ICFpc0luVGhlRG9tKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHRpcCA9IHRoaXMuZ2V0VGlwRWxlbWVudCgpO1xuICAgICAgICB2YXIgdGlwSWQgPSBVdGlsLmdldFVJRCh0aGlzLmNvbnN0cnVjdG9yLk5BTUUpO1xuICAgICAgICB0aXAuc2V0QXR0cmlidXRlKCdpZCcsIHRpcElkKTtcbiAgICAgICAgdGhpcy5lbGVtZW50LnNldEF0dHJpYnV0ZSgnYXJpYS1kZXNjcmliZWRieScsIHRpcElkKTtcbiAgICAgICAgdGhpcy5zZXRDb250ZW50KCk7XG5cbiAgICAgICAgaWYgKHRoaXMuY29uZmlnLmFuaW1hdGlvbikge1xuICAgICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRpcCkuYWRkQ2xhc3MoQ0xBU1NfTkFNRV9GQURFJDMpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHBsYWNlbWVudCA9IHR5cGVvZiB0aGlzLmNvbmZpZy5wbGFjZW1lbnQgPT09ICdmdW5jdGlvbicgPyB0aGlzLmNvbmZpZy5wbGFjZW1lbnQuY2FsbCh0aGlzLCB0aXAsIHRoaXMuZWxlbWVudCkgOiB0aGlzLmNvbmZpZy5wbGFjZW1lbnQ7XG5cbiAgICAgICAgdmFyIGF0dGFjaG1lbnQgPSB0aGlzLl9nZXRBdHRhY2htZW50KHBsYWNlbWVudCk7XG5cbiAgICAgICAgdGhpcy5hZGRBdHRhY2htZW50Q2xhc3MoYXR0YWNobWVudCk7XG5cbiAgICAgICAgdmFyIGNvbnRhaW5lciA9IHRoaXMuX2dldENvbnRhaW5lcigpO1xuXG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRpcCkuZGF0YSh0aGlzLmNvbnN0cnVjdG9yLkRBVEFfS0VZLCB0aGlzKTtcblxuICAgICAgICBpZiAoISRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmNvbnRhaW5zKHRoaXMuZWxlbWVudC5vd25lckRvY3VtZW50LmRvY3VtZW50RWxlbWVudCwgdGhpcy50aXApKSB7XG4gICAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGlwKS5hcHBlbmRUbyhjb250YWluZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5lbGVtZW50KS50cmlnZ2VyKHRoaXMuY29uc3RydWN0b3IuRXZlbnQuSU5TRVJURUQpO1xuICAgICAgICB0aGlzLl9wb3BwZXIgPSBuZXcgUG9wcGVyX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLmVsZW1lbnQsIHRpcCwgdGhpcy5fZ2V0UG9wcGVyQ29uZmlnKGF0dGFjaG1lbnQpKTtcbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGlwKS5hZGRDbGFzcyhDTEFTU19OQU1FX1NIT1ckMyk7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRpcCkuYWRkQ2xhc3ModGhpcy5jb25maWcuY3VzdG9tQ2xhc3MpOyAvLyBJZiB0aGlzIGlzIGEgdG91Y2gtZW5hYmxlZCBkZXZpY2Ugd2UgYWRkIGV4dHJhXG4gICAgICAgIC8vIGVtcHR5IG1vdXNlb3ZlciBsaXN0ZW5lcnMgdG8gdGhlIGJvZHkncyBpbW1lZGlhdGUgY2hpbGRyZW47XG4gICAgICAgIC8vIG9ubHkgbmVlZGVkIGJlY2F1c2Ugb2YgYnJva2VuIGV2ZW50IGRlbGVnYXRpb24gb24gaU9TXG4gICAgICAgIC8vIGh0dHBzOi8vd3d3LnF1aXJrc21vZGUub3JnL2Jsb2cvYXJjaGl2ZXMvMjAxNC8wMi9tb3VzZV9ldmVudF9idWIuaHRtbFxuXG4gICAgICAgIGlmICgnb250b3VjaHN0YXJ0JyBpbiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQpIHtcbiAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShkb2N1bWVudC5ib2R5KS5jaGlsZHJlbigpLm9uKCdtb3VzZW92ZXInLCBudWxsLCAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5ub29wKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBjb21wbGV0ZSA9IGZ1bmN0aW9uIGNvbXBsZXRlKCkge1xuICAgICAgICAgIGlmIChfdGhpcy5jb25maWcuYW5pbWF0aW9uKSB7XG4gICAgICAgICAgICBfdGhpcy5fZml4VHJhbnNpdGlvbigpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHZhciBwcmV2SG92ZXJTdGF0ZSA9IF90aGlzLl9ob3ZlclN0YXRlO1xuICAgICAgICAgIF90aGlzLl9ob3ZlclN0YXRlID0gbnVsbDtcbiAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShfdGhpcy5lbGVtZW50KS50cmlnZ2VyKF90aGlzLmNvbnN0cnVjdG9yLkV2ZW50LlNIT1dOKTtcblxuICAgICAgICAgIGlmIChwcmV2SG92ZXJTdGF0ZSA9PT0gSE9WRVJfU1RBVEVfT1VUKSB7XG4gICAgICAgICAgICBfdGhpcy5fbGVhdmUobnVsbCwgX3RoaXMpO1xuICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBpZiAoJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy50aXApLmhhc0NsYXNzKENMQVNTX05BTUVfRkFERSQzKSkge1xuICAgICAgICAgIHZhciB0cmFuc2l0aW9uRHVyYXRpb24gPSBVdGlsLmdldFRyYW5zaXRpb25EdXJhdGlvbkZyb21FbGVtZW50KHRoaXMudGlwKTtcbiAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLnRpcCkub25lKFV0aWwuVFJBTlNJVElPTl9FTkQsIGNvbXBsZXRlKS5lbXVsYXRlVHJhbnNpdGlvbkVuZCh0cmFuc2l0aW9uRHVyYXRpb24pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbXBsZXRlKCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgX3Byb3RvLmhpZGUgPSBmdW5jdGlvbiBoaWRlKGNhbGxiYWNrKSB7XG4gICAgICB2YXIgX3RoaXMyID0gdGhpcztcblxuICAgICAgdmFyIHRpcCA9IHRoaXMuZ2V0VGlwRWxlbWVudCgpO1xuICAgICAgdmFyIGhpZGVFdmVudCA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLkV2ZW50KHRoaXMuY29uc3RydWN0b3IuRXZlbnQuSElERSk7XG5cbiAgICAgIHZhciBjb21wbGV0ZSA9IGZ1bmN0aW9uIGNvbXBsZXRlKCkge1xuICAgICAgICBpZiAoX3RoaXMyLl9ob3ZlclN0YXRlICE9PSBIT1ZFUl9TVEFURV9TSE9XICYmIHRpcC5wYXJlbnROb2RlKSB7XG4gICAgICAgICAgdGlwLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQodGlwKTtcbiAgICAgICAgfVxuXG4gICAgICAgIF90aGlzMi5fY2xlYW5UaXBDbGFzcygpO1xuXG4gICAgICAgIF90aGlzMi5lbGVtZW50LnJlbW92ZUF0dHJpYnV0ZSgnYXJpYS1kZXNjcmliZWRieScpO1xuXG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKF90aGlzMi5lbGVtZW50KS50cmlnZ2VyKF90aGlzMi5jb25zdHJ1Y3Rvci5FdmVudC5ISURERU4pO1xuXG4gICAgICAgIGlmIChfdGhpczIuX3BvcHBlciAhPT0gbnVsbCkge1xuICAgICAgICAgIF90aGlzMi5fcG9wcGVyLmRlc3Ryb3koKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuZWxlbWVudCkudHJpZ2dlcihoaWRlRXZlbnQpO1xuXG4gICAgICBpZiAoaGlkZUV2ZW50LmlzRGVmYXVsdFByZXZlbnRlZCgpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGlwKS5yZW1vdmVDbGFzcyhDTEFTU19OQU1FX1NIT1ckMyk7IC8vIElmIHRoaXMgaXMgYSB0b3VjaC1lbmFibGVkIGRldmljZSB3ZSByZW1vdmUgdGhlIGV4dHJhXG4gICAgICAvLyBlbXB0eSBtb3VzZW92ZXIgbGlzdGVuZXJzIHdlIGFkZGVkIGZvciBpT1Mgc3VwcG9ydFxuXG4gICAgICBpZiAoJ29udG91Y2hzdGFydCcgaW4gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50KSB7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGRvY3VtZW50LmJvZHkpLmNoaWxkcmVuKCkub2ZmKCdtb3VzZW92ZXInLCBudWxsLCAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5ub29wKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5fYWN0aXZlVHJpZ2dlcltUUklHR0VSX0NMSUNLXSA9IGZhbHNlO1xuICAgICAgdGhpcy5fYWN0aXZlVHJpZ2dlcltUUklHR0VSX0ZPQ1VTXSA9IGZhbHNlO1xuICAgICAgdGhpcy5fYWN0aXZlVHJpZ2dlcltUUklHR0VSX0hPVkVSXSA9IGZhbHNlO1xuXG4gICAgICBpZiAoJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy50aXApLmhhc0NsYXNzKENMQVNTX05BTUVfRkFERSQzKSkge1xuICAgICAgICB2YXIgdHJhbnNpdGlvbkR1cmF0aW9uID0gVXRpbC5nZXRUcmFuc2l0aW9uRHVyYXRpb25Gcm9tRWxlbWVudCh0aXApO1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aXApLm9uZShVdGlsLlRSQU5TSVRJT05fRU5ELCBjb21wbGV0ZSkuZW11bGF0ZVRyYW5zaXRpb25FbmQodHJhbnNpdGlvbkR1cmF0aW9uKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbXBsZXRlKCk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuX2hvdmVyU3RhdGUgPSAnJztcbiAgICB9O1xuXG4gICAgX3Byb3RvLnVwZGF0ZSA9IGZ1bmN0aW9uIHVwZGF0ZSgpIHtcbiAgICAgIGlmICh0aGlzLl9wb3BwZXIgIT09IG51bGwpIHtcbiAgICAgICAgdGhpcy5fcG9wcGVyLnNjaGVkdWxlVXBkYXRlKCk7XG4gICAgICB9XG4gICAgfSAvLyBQcm90ZWN0ZWRcbiAgICA7XG5cbiAgICBfcHJvdG8uaXNXaXRoQ29udGVudCA9IGZ1bmN0aW9uIGlzV2l0aENvbnRlbnQoKSB7XG4gICAgICByZXR1cm4gQm9vbGVhbih0aGlzLmdldFRpdGxlKCkpO1xuICAgIH07XG5cbiAgICBfcHJvdG8uYWRkQXR0YWNobWVudENsYXNzID0gZnVuY3Rpb24gYWRkQXR0YWNobWVudENsYXNzKGF0dGFjaG1lbnQpIHtcbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuZ2V0VGlwRWxlbWVudCgpKS5hZGRDbGFzcyhDTEFTU19QUkVGSVgkMSArIFwiLVwiICsgYXR0YWNobWVudCk7XG4gICAgfTtcblxuICAgIF9wcm90by5nZXRUaXBFbGVtZW50ID0gZnVuY3Rpb24gZ2V0VGlwRWxlbWVudCgpIHtcbiAgICAgIHRoaXMudGlwID0gdGhpcy50aXAgfHwgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5jb25maWcudGVtcGxhdGUpWzBdO1xuICAgICAgcmV0dXJuIHRoaXMudGlwO1xuICAgIH07XG5cbiAgICBfcHJvdG8uc2V0Q29udGVudCA9IGZ1bmN0aW9uIHNldENvbnRlbnQoKSB7XG4gICAgICB2YXIgdGlwID0gdGhpcy5nZXRUaXBFbGVtZW50KCk7XG4gICAgICB0aGlzLnNldEVsZW1lbnRDb250ZW50KCRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRpcC5xdWVyeVNlbGVjdG9yQWxsKFNFTEVDVE9SX1RPT0xUSVBfSU5ORVIpKSwgdGhpcy5nZXRUaXRsZSgpKTtcbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRpcCkucmVtb3ZlQ2xhc3MoQ0xBU1NfTkFNRV9GQURFJDMgKyBcIiBcIiArIENMQVNTX05BTUVfU0hPVyQzKTtcbiAgICB9O1xuXG4gICAgX3Byb3RvLnNldEVsZW1lbnRDb250ZW50ID0gZnVuY3Rpb24gc2V0RWxlbWVudENvbnRlbnQoJGVsZW1lbnQsIGNvbnRlbnQpIHtcbiAgICAgIGlmICh0eXBlb2YgY29udGVudCA9PT0gJ29iamVjdCcgJiYgKGNvbnRlbnQubm9kZVR5cGUgfHwgY29udGVudC5qcXVlcnkpKSB7XG4gICAgICAgIC8vIENvbnRlbnQgaXMgYSBET00gbm9kZSBvciBhIGpRdWVyeVxuICAgICAgICBpZiAodGhpcy5jb25maWcuaHRtbCkge1xuICAgICAgICAgIGlmICghJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oY29udGVudCkucGFyZW50KCkuaXMoJGVsZW1lbnQpKSB7XG4gICAgICAgICAgICAkZWxlbWVudC5lbXB0eSgpLmFwcGVuZChjb250ZW50KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgJGVsZW1lbnQudGV4dCgkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShjb250ZW50KS50ZXh0KCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5jb25maWcuaHRtbCkge1xuICAgICAgICBpZiAodGhpcy5jb25maWcuc2FuaXRpemUpIHtcbiAgICAgICAgICBjb250ZW50ID0gc2FuaXRpemVIdG1sKGNvbnRlbnQsIHRoaXMuY29uZmlnLndoaXRlTGlzdCwgdGhpcy5jb25maWcuc2FuaXRpemVGbik7XG4gICAgICAgIH1cblxuICAgICAgICAkZWxlbWVudC5odG1sKGNvbnRlbnQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgJGVsZW1lbnQudGV4dChjb250ZW50KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgX3Byb3RvLmdldFRpdGxlID0gZnVuY3Rpb24gZ2V0VGl0bGUoKSB7XG4gICAgICB2YXIgdGl0bGUgPSB0aGlzLmVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLW9yaWdpbmFsLXRpdGxlJyk7XG5cbiAgICAgIGlmICghdGl0bGUpIHtcbiAgICAgICAgdGl0bGUgPSB0eXBlb2YgdGhpcy5jb25maWcudGl0bGUgPT09ICdmdW5jdGlvbicgPyB0aGlzLmNvbmZpZy50aXRsZS5jYWxsKHRoaXMuZWxlbWVudCkgOiB0aGlzLmNvbmZpZy50aXRsZTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRpdGxlO1xuICAgIH0gLy8gUHJpdmF0ZVxuICAgIDtcblxuICAgIF9wcm90by5fZ2V0UG9wcGVyQ29uZmlnID0gZnVuY3Rpb24gX2dldFBvcHBlckNvbmZpZyhhdHRhY2htZW50KSB7XG4gICAgICB2YXIgX3RoaXMzID0gdGhpcztcblxuICAgICAgdmFyIGRlZmF1bHRCc0NvbmZpZyA9IHtcbiAgICAgICAgcGxhY2VtZW50OiBhdHRhY2htZW50LFxuICAgICAgICBtb2RpZmllcnM6IHtcbiAgICAgICAgICBvZmZzZXQ6IHRoaXMuX2dldE9mZnNldCgpLFxuICAgICAgICAgIGZsaXA6IHtcbiAgICAgICAgICAgIGJlaGF2aW9yOiB0aGlzLmNvbmZpZy5mYWxsYmFja1BsYWNlbWVudFxuICAgICAgICAgIH0sXG4gICAgICAgICAgYXJyb3c6IHtcbiAgICAgICAgICAgIGVsZW1lbnQ6IFNFTEVDVE9SX0FSUk9XXG4gICAgICAgICAgfSxcbiAgICAgICAgICBwcmV2ZW50T3ZlcmZsb3c6IHtcbiAgICAgICAgICAgIGJvdW5kYXJpZXNFbGVtZW50OiB0aGlzLmNvbmZpZy5ib3VuZGFyeVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgb25DcmVhdGU6IGZ1bmN0aW9uIG9uQ3JlYXRlKGRhdGEpIHtcbiAgICAgICAgICBpZiAoZGF0YS5vcmlnaW5hbFBsYWNlbWVudCAhPT0gZGF0YS5wbGFjZW1lbnQpIHtcbiAgICAgICAgICAgIF90aGlzMy5faGFuZGxlUG9wcGVyUGxhY2VtZW50Q2hhbmdlKGRhdGEpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgb25VcGRhdGU6IGZ1bmN0aW9uIG9uVXBkYXRlKGRhdGEpIHtcbiAgICAgICAgICByZXR1cm4gX3RoaXMzLl9oYW5kbGVQb3BwZXJQbGFjZW1lbnRDaGFuZ2UoZGF0YSk7XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgICByZXR1cm4gX2V4dGVuZHMoe30sIGRlZmF1bHRCc0NvbmZpZywgdGhpcy5jb25maWcucG9wcGVyQ29uZmlnKTtcbiAgICB9O1xuXG4gICAgX3Byb3RvLl9nZXRPZmZzZXQgPSBmdW5jdGlvbiBfZ2V0T2Zmc2V0KCkge1xuICAgICAgdmFyIF90aGlzNCA9IHRoaXM7XG5cbiAgICAgIHZhciBvZmZzZXQgPSB7fTtcblxuICAgICAgaWYgKHR5cGVvZiB0aGlzLmNvbmZpZy5vZmZzZXQgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgb2Zmc2V0LmZuID0gZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgICAgICBkYXRhLm9mZnNldHMgPSBfZXh0ZW5kcyh7fSwgZGF0YS5vZmZzZXRzLCBfdGhpczQuY29uZmlnLm9mZnNldChkYXRhLm9mZnNldHMsIF90aGlzNC5lbGVtZW50KSk7XG4gICAgICAgICAgcmV0dXJuIGRhdGE7XG4gICAgICAgIH07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBvZmZzZXQub2Zmc2V0ID0gdGhpcy5jb25maWcub2Zmc2V0O1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gb2Zmc2V0O1xuICAgIH07XG5cbiAgICBfcHJvdG8uX2dldENvbnRhaW5lciA9IGZ1bmN0aW9uIF9nZXRDb250YWluZXIoKSB7XG4gICAgICBpZiAodGhpcy5jb25maWcuY29udGFpbmVyID09PSBmYWxzZSkge1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQuYm9keTtcbiAgICAgIH1cblxuICAgICAgaWYgKFV0aWwuaXNFbGVtZW50KHRoaXMuY29uZmlnLmNvbnRhaW5lcikpIHtcbiAgICAgICAgcmV0dXJuICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuY29uZmlnLmNvbnRhaW5lcik7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShkb2N1bWVudCkuZmluZCh0aGlzLmNvbmZpZy5jb250YWluZXIpO1xuICAgIH07XG5cbiAgICBfcHJvdG8uX2dldEF0dGFjaG1lbnQgPSBmdW5jdGlvbiBfZ2V0QXR0YWNobWVudChwbGFjZW1lbnQpIHtcbiAgICAgIHJldHVybiBBdHRhY2htZW50TWFwW3BsYWNlbWVudC50b1VwcGVyQ2FzZSgpXTtcbiAgICB9O1xuXG4gICAgX3Byb3RvLl9zZXRMaXN0ZW5lcnMgPSBmdW5jdGlvbiBfc2V0TGlzdGVuZXJzKCkge1xuICAgICAgdmFyIF90aGlzNSA9IHRoaXM7XG5cbiAgICAgIHZhciB0cmlnZ2VycyA9IHRoaXMuY29uZmlnLnRyaWdnZXIuc3BsaXQoJyAnKTtcbiAgICAgIHRyaWdnZXJzLmZvckVhY2goZnVuY3Rpb24gKHRyaWdnZXIpIHtcbiAgICAgICAgaWYgKHRyaWdnZXIgPT09ICdjbGljaycpIHtcbiAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShfdGhpczUuZWxlbWVudCkub24oX3RoaXM1LmNvbnN0cnVjdG9yLkV2ZW50LkNMSUNLLCBfdGhpczUuY29uZmlnLnNlbGVjdG9yLCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIHJldHVybiBfdGhpczUudG9nZ2xlKGV2ZW50KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmICh0cmlnZ2VyICE9PSBUUklHR0VSX01BTlVBTCkge1xuICAgICAgICAgIHZhciBldmVudEluID0gdHJpZ2dlciA9PT0gVFJJR0dFUl9IT1ZFUiA/IF90aGlzNS5jb25zdHJ1Y3Rvci5FdmVudC5NT1VTRUVOVEVSIDogX3RoaXM1LmNvbnN0cnVjdG9yLkV2ZW50LkZPQ1VTSU47XG4gICAgICAgICAgdmFyIGV2ZW50T3V0ID0gdHJpZ2dlciA9PT0gVFJJR0dFUl9IT1ZFUiA/IF90aGlzNS5jb25zdHJ1Y3Rvci5FdmVudC5NT1VTRUxFQVZFIDogX3RoaXM1LmNvbnN0cnVjdG9yLkV2ZW50LkZPQ1VTT1VUO1xuICAgICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKF90aGlzNS5lbGVtZW50KS5vbihldmVudEluLCBfdGhpczUuY29uZmlnLnNlbGVjdG9yLCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIHJldHVybiBfdGhpczUuX2VudGVyKGV2ZW50KTtcbiAgICAgICAgICB9KS5vbihldmVudE91dCwgX3RoaXM1LmNvbmZpZy5zZWxlY3RvciwgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgICByZXR1cm4gX3RoaXM1Ll9sZWF2ZShldmVudCk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICB0aGlzLl9oaWRlTW9kYWxIYW5kbGVyID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoX3RoaXM1LmVsZW1lbnQpIHtcbiAgICAgICAgICBfdGhpczUuaGlkZSgpO1xuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLmVsZW1lbnQpLmNsb3Nlc3QoJy5tb2RhbCcpLm9uKCdoaWRlLmJzLm1vZGFsJywgdGhpcy5faGlkZU1vZGFsSGFuZGxlcik7XG5cbiAgICAgIGlmICh0aGlzLmNvbmZpZy5zZWxlY3Rvcikge1xuICAgICAgICB0aGlzLmNvbmZpZyA9IF9leHRlbmRzKHt9LCB0aGlzLmNvbmZpZywge1xuICAgICAgICAgIHRyaWdnZXI6ICdtYW51YWwnLFxuICAgICAgICAgIHNlbGVjdG9yOiAnJ1xuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuX2ZpeFRpdGxlKCk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIF9wcm90by5fZml4VGl0bGUgPSBmdW5jdGlvbiBfZml4VGl0bGUoKSB7XG4gICAgICB2YXIgdGl0bGVUeXBlID0gdHlwZW9mIHRoaXMuZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtb3JpZ2luYWwtdGl0bGUnKTtcblxuICAgICAgaWYgKHRoaXMuZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ3RpdGxlJykgfHwgdGl0bGVUeXBlICE9PSAnc3RyaW5nJykge1xuICAgICAgICB0aGlzLmVsZW1lbnQuc2V0QXR0cmlidXRlKCdkYXRhLW9yaWdpbmFsLXRpdGxlJywgdGhpcy5lbGVtZW50LmdldEF0dHJpYnV0ZSgndGl0bGUnKSB8fCAnJyk7XG4gICAgICAgIHRoaXMuZWxlbWVudC5zZXRBdHRyaWJ1dGUoJ3RpdGxlJywgJycpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBfcHJvdG8uX2VudGVyID0gZnVuY3Rpb24gX2VudGVyKGV2ZW50LCBjb250ZXh0KSB7XG4gICAgICB2YXIgZGF0YUtleSA9IHRoaXMuY29uc3RydWN0b3IuREFUQV9LRVk7XG4gICAgICBjb250ZXh0ID0gY29udGV4dCB8fCAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShldmVudC5jdXJyZW50VGFyZ2V0KS5kYXRhKGRhdGFLZXkpO1xuXG4gICAgICBpZiAoIWNvbnRleHQpIHtcbiAgICAgICAgY29udGV4dCA9IG5ldyB0aGlzLmNvbnN0cnVjdG9yKGV2ZW50LmN1cnJlbnRUYXJnZXQsIHRoaXMuX2dldERlbGVnYXRlQ29uZmlnKCkpO1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShldmVudC5jdXJyZW50VGFyZ2V0KS5kYXRhKGRhdGFLZXksIGNvbnRleHQpO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXZlbnQpIHtcbiAgICAgICAgY29udGV4dC5fYWN0aXZlVHJpZ2dlcltldmVudC50eXBlID09PSAnZm9jdXNpbicgPyBUUklHR0VSX0ZPQ1VTIDogVFJJR0dFUl9IT1ZFUl0gPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICBpZiAoJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oY29udGV4dC5nZXRUaXBFbGVtZW50KCkpLmhhc0NsYXNzKENMQVNTX05BTUVfU0hPVyQzKSB8fCBjb250ZXh0Ll9ob3ZlclN0YXRlID09PSBIT1ZFUl9TVEFURV9TSE9XKSB7XG4gICAgICAgIGNvbnRleHQuX2hvdmVyU3RhdGUgPSBIT1ZFUl9TVEFURV9TSE9XO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNsZWFyVGltZW91dChjb250ZXh0Ll90aW1lb3V0KTtcbiAgICAgIGNvbnRleHQuX2hvdmVyU3RhdGUgPSBIT1ZFUl9TVEFURV9TSE9XO1xuXG4gICAgICBpZiAoIWNvbnRleHQuY29uZmlnLmRlbGF5IHx8ICFjb250ZXh0LmNvbmZpZy5kZWxheS5zaG93KSB7XG4gICAgICAgIGNvbnRleHQuc2hvdygpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnRleHQuX3RpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKGNvbnRleHQuX2hvdmVyU3RhdGUgPT09IEhPVkVSX1NUQVRFX1NIT1cpIHtcbiAgICAgICAgICBjb250ZXh0LnNob3coKTtcbiAgICAgICAgfVxuICAgICAgfSwgY29udGV4dC5jb25maWcuZGVsYXkuc2hvdyk7XG4gICAgfTtcblxuICAgIF9wcm90by5fbGVhdmUgPSBmdW5jdGlvbiBfbGVhdmUoZXZlbnQsIGNvbnRleHQpIHtcbiAgICAgIHZhciBkYXRhS2V5ID0gdGhpcy5jb25zdHJ1Y3Rvci5EQVRBX0tFWTtcbiAgICAgIGNvbnRleHQgPSBjb250ZXh0IHx8ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGV2ZW50LmN1cnJlbnRUYXJnZXQpLmRhdGEoZGF0YUtleSk7XG5cbiAgICAgIGlmICghY29udGV4dCkge1xuICAgICAgICBjb250ZXh0ID0gbmV3IHRoaXMuY29uc3RydWN0b3IoZXZlbnQuY3VycmVudFRhcmdldCwgdGhpcy5fZ2V0RGVsZWdhdGVDb25maWcoKSk7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGV2ZW50LmN1cnJlbnRUYXJnZXQpLmRhdGEoZGF0YUtleSwgY29udGV4dCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChldmVudCkge1xuICAgICAgICBjb250ZXh0Ll9hY3RpdmVUcmlnZ2VyW2V2ZW50LnR5cGUgPT09ICdmb2N1c291dCcgPyBUUklHR0VSX0ZPQ1VTIDogVFJJR0dFUl9IT1ZFUl0gPSBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgaWYgKGNvbnRleHQuX2lzV2l0aEFjdGl2ZVRyaWdnZXIoKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNsZWFyVGltZW91dChjb250ZXh0Ll90aW1lb3V0KTtcbiAgICAgIGNvbnRleHQuX2hvdmVyU3RhdGUgPSBIT1ZFUl9TVEFURV9PVVQ7XG5cbiAgICAgIGlmICghY29udGV4dC5jb25maWcuZGVsYXkgfHwgIWNvbnRleHQuY29uZmlnLmRlbGF5LmhpZGUpIHtcbiAgICAgICAgY29udGV4dC5oaWRlKCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29udGV4dC5fdGltZW91dCA9IHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoY29udGV4dC5faG92ZXJTdGF0ZSA9PT0gSE9WRVJfU1RBVEVfT1VUKSB7XG4gICAgICAgICAgY29udGV4dC5oaWRlKCk7XG4gICAgICAgIH1cbiAgICAgIH0sIGNvbnRleHQuY29uZmlnLmRlbGF5LmhpZGUpO1xuICAgIH07XG5cbiAgICBfcHJvdG8uX2lzV2l0aEFjdGl2ZVRyaWdnZXIgPSBmdW5jdGlvbiBfaXNXaXRoQWN0aXZlVHJpZ2dlcigpIHtcbiAgICAgIGZvciAodmFyIHRyaWdnZXIgaW4gdGhpcy5fYWN0aXZlVHJpZ2dlcikge1xuICAgICAgICBpZiAodGhpcy5fYWN0aXZlVHJpZ2dlclt0cmlnZ2VyXSkge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9O1xuXG4gICAgX3Byb3RvLl9nZXRDb25maWcgPSBmdW5jdGlvbiBfZ2V0Q29uZmlnKGNvbmZpZykge1xuICAgICAgdmFyIGRhdGFBdHRyaWJ1dGVzID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5lbGVtZW50KS5kYXRhKCk7XG4gICAgICBPYmplY3Qua2V5cyhkYXRhQXR0cmlidXRlcykuZm9yRWFjaChmdW5jdGlvbiAoZGF0YUF0dHIpIHtcbiAgICAgICAgaWYgKERJU0FMTE9XRURfQVRUUklCVVRFUy5pbmRleE9mKGRhdGFBdHRyKSAhPT0gLTEpIHtcbiAgICAgICAgICBkZWxldGUgZGF0YUF0dHJpYnV0ZXNbZGF0YUF0dHJdO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIGNvbmZpZyA9IF9leHRlbmRzKHt9LCB0aGlzLmNvbnN0cnVjdG9yLkRlZmF1bHQsIGRhdGFBdHRyaWJ1dGVzLCB0eXBlb2YgY29uZmlnID09PSAnb2JqZWN0JyAmJiBjb25maWcgPyBjb25maWcgOiB7fSk7XG5cbiAgICAgIGlmICh0eXBlb2YgY29uZmlnLmRlbGF5ID09PSAnbnVtYmVyJykge1xuICAgICAgICBjb25maWcuZGVsYXkgPSB7XG4gICAgICAgICAgc2hvdzogY29uZmlnLmRlbGF5LFxuICAgICAgICAgIGhpZGU6IGNvbmZpZy5kZWxheVxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBpZiAodHlwZW9mIGNvbmZpZy50aXRsZSA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgY29uZmlnLnRpdGxlID0gY29uZmlnLnRpdGxlLnRvU3RyaW5nKCk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0eXBlb2YgY29uZmlnLmNvbnRlbnQgPT09ICdudW1iZXInKSB7XG4gICAgICAgIGNvbmZpZy5jb250ZW50ID0gY29uZmlnLmNvbnRlbnQudG9TdHJpbmcoKTtcbiAgICAgIH1cblxuICAgICAgVXRpbC50eXBlQ2hlY2tDb25maWcoTkFNRSQ0LCBjb25maWcsIHRoaXMuY29uc3RydWN0b3IuRGVmYXVsdFR5cGUpO1xuXG4gICAgICBpZiAoY29uZmlnLnNhbml0aXplKSB7XG4gICAgICAgIGNvbmZpZy50ZW1wbGF0ZSA9IHNhbml0aXplSHRtbChjb25maWcudGVtcGxhdGUsIGNvbmZpZy53aGl0ZUxpc3QsIGNvbmZpZy5zYW5pdGl6ZUZuKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGNvbmZpZztcbiAgICB9O1xuXG4gICAgX3Byb3RvLl9nZXREZWxlZ2F0ZUNvbmZpZyA9IGZ1bmN0aW9uIF9nZXREZWxlZ2F0ZUNvbmZpZygpIHtcbiAgICAgIHZhciBjb25maWcgPSB7fTtcblxuICAgICAgaWYgKHRoaXMuY29uZmlnKSB7XG4gICAgICAgIGZvciAodmFyIGtleSBpbiB0aGlzLmNvbmZpZykge1xuICAgICAgICAgIGlmICh0aGlzLmNvbnN0cnVjdG9yLkRlZmF1bHRba2V5XSAhPT0gdGhpcy5jb25maWdba2V5XSkge1xuICAgICAgICAgICAgY29uZmlnW2tleV0gPSB0aGlzLmNvbmZpZ1trZXldO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gY29uZmlnO1xuICAgIH07XG5cbiAgICBfcHJvdG8uX2NsZWFuVGlwQ2xhc3MgPSBmdW5jdGlvbiBfY2xlYW5UaXBDbGFzcygpIHtcbiAgICAgIHZhciAkdGlwID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5nZXRUaXBFbGVtZW50KCkpO1xuICAgICAgdmFyIHRhYkNsYXNzID0gJHRpcC5hdHRyKCdjbGFzcycpLm1hdGNoKEJTQ0xTX1BSRUZJWF9SRUdFWCQxKTtcblxuICAgICAgaWYgKHRhYkNsYXNzICE9PSBudWxsICYmIHRhYkNsYXNzLmxlbmd0aCkge1xuICAgICAgICAkdGlwLnJlbW92ZUNsYXNzKHRhYkNsYXNzLmpvaW4oJycpKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgX3Byb3RvLl9oYW5kbGVQb3BwZXJQbGFjZW1lbnRDaGFuZ2UgPSBmdW5jdGlvbiBfaGFuZGxlUG9wcGVyUGxhY2VtZW50Q2hhbmdlKHBvcHBlckRhdGEpIHtcbiAgICAgIHRoaXMudGlwID0gcG9wcGVyRGF0YS5pbnN0YW5jZS5wb3BwZXI7XG5cbiAgICAgIHRoaXMuX2NsZWFuVGlwQ2xhc3MoKTtcblxuICAgICAgdGhpcy5hZGRBdHRhY2htZW50Q2xhc3ModGhpcy5fZ2V0QXR0YWNobWVudChwb3BwZXJEYXRhLnBsYWNlbWVudCkpO1xuICAgIH07XG5cbiAgICBfcHJvdG8uX2ZpeFRyYW5zaXRpb24gPSBmdW5jdGlvbiBfZml4VHJhbnNpdGlvbigpIHtcbiAgICAgIHZhciB0aXAgPSB0aGlzLmdldFRpcEVsZW1lbnQoKTtcbiAgICAgIHZhciBpbml0Q29uZmlnQW5pbWF0aW9uID0gdGhpcy5jb25maWcuYW5pbWF0aW9uO1xuXG4gICAgICBpZiAodGlwLmdldEF0dHJpYnV0ZSgneC1wbGFjZW1lbnQnKSAhPT0gbnVsbCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRpcCkucmVtb3ZlQ2xhc3MoQ0xBU1NfTkFNRV9GQURFJDMpO1xuICAgICAgdGhpcy5jb25maWcuYW5pbWF0aW9uID0gZmFsc2U7XG4gICAgICB0aGlzLmhpZGUoKTtcbiAgICAgIHRoaXMuc2hvdygpO1xuICAgICAgdGhpcy5jb25maWcuYW5pbWF0aW9uID0gaW5pdENvbmZpZ0FuaW1hdGlvbjtcbiAgICB9IC8vIFN0YXRpY1xuICAgIDtcblxuICAgIFRvb2x0aXAuX2pRdWVyeUludGVyZmFjZSA9IGZ1bmN0aW9uIF9qUXVlcnlJbnRlcmZhY2UoY29uZmlnKSB7XG4gICAgICByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyICRlbGVtZW50ID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcyk7XG4gICAgICAgIHZhciBkYXRhID0gJGVsZW1lbnQuZGF0YShEQVRBX0tFWSQ0KTtcblxuICAgICAgICB2YXIgX2NvbmZpZyA9IHR5cGVvZiBjb25maWcgPT09ICdvYmplY3QnICYmIGNvbmZpZztcblxuICAgICAgICBpZiAoIWRhdGEgJiYgL2Rpc3Bvc2V8aGlkZS8udGVzdChjb25maWcpKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFkYXRhKSB7XG4gICAgICAgICAgZGF0YSA9IG5ldyBUb29sdGlwKHRoaXMsIF9jb25maWcpO1xuICAgICAgICAgICRlbGVtZW50LmRhdGEoREFUQV9LRVkkNCwgZGF0YSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIGNvbmZpZyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICBpZiAodHlwZW9mIGRhdGFbY29uZmlnXSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJObyBtZXRob2QgbmFtZWQgXFxcIlwiICsgY29uZmlnICsgXCJcXFwiXCIpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGRhdGFbY29uZmlnXSgpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgX2NyZWF0ZUNsYXNzKFRvb2x0aXAsIG51bGwsIFt7XG4gICAgICBrZXk6IFwiVkVSU0lPTlwiLFxuICAgICAgZ2V0OiBmdW5jdGlvbiBnZXQoKSB7XG4gICAgICAgIHJldHVybiBWRVJTSU9OJDQ7XG4gICAgICB9XG4gICAgfSwge1xuICAgICAga2V5OiBcIkRlZmF1bHRcIixcbiAgICAgIGdldDogZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgICByZXR1cm4gRGVmYXVsdCQzO1xuICAgICAgfVxuICAgIH0sIHtcbiAgICAgIGtleTogXCJOQU1FXCIsXG4gICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgcmV0dXJuIE5BTUUkNDtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiREFUQV9LRVlcIixcbiAgICAgIGdldDogZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgICByZXR1cm4gREFUQV9LRVkkNDtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiRXZlbnRcIixcbiAgICAgIGdldDogZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgICByZXR1cm4gRXZlbnQkMTtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiRVZFTlRfS0VZXCIsXG4gICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgcmV0dXJuIEVWRU5UX0tFWSQ0O1xuICAgICAgfVxuICAgIH0sIHtcbiAgICAgIGtleTogXCJEZWZhdWx0VHlwZVwiLFxuICAgICAgZ2V0OiBmdW5jdGlvbiBnZXQoKSB7XG4gICAgICAgIHJldHVybiBEZWZhdWx0VHlwZSQzO1xuICAgICAgfVxuICAgIH1dKTtcblxuICAgIHJldHVybiBUb29sdGlwO1xuICB9KCk7XG4gIC8qKlxuICAgKiBqUXVlcnlcbiAgICovXG5cblxuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDRdID0gVG9vbHRpcC5falF1ZXJ5SW50ZXJmYWNlO1xuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDRdLkNvbnN0cnVjdG9yID0gVG9vbHRpcDtcblxuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDRdLm5vQ29uZmxpY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQ0XSA9IEpRVUVSWV9OT19DT05GTElDVCQ0O1xuICAgIHJldHVybiBUb29sdGlwLl9qUXVlcnlJbnRlcmZhY2U7XG4gIH07XG5cbiAgLyoqXG4gICAqIENvbnN0YW50c1xuICAgKi9cblxuICB2YXIgTkFNRSQzID0gJ3BvcG92ZXInO1xuICB2YXIgVkVSU0lPTiQzID0gJzQuNi4xJztcbiAgdmFyIERBVEFfS0VZJDMgPSAnYnMucG9wb3Zlcic7XG4gIHZhciBFVkVOVF9LRVkkMyA9IFwiLlwiICsgREFUQV9LRVkkMztcbiAgdmFyIEpRVUVSWV9OT19DT05GTElDVCQzID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQzXTtcbiAgdmFyIENMQVNTX1BSRUZJWCA9ICdicy1wb3BvdmVyJztcbiAgdmFyIEJTQ0xTX1BSRUZJWF9SRUdFWCA9IG5ldyBSZWdFeHAoXCIoXnxcXFxccylcIiArIENMQVNTX1BSRUZJWCArIFwiXFxcXFMrXCIsICdnJyk7XG4gIHZhciBDTEFTU19OQU1FX0ZBREUkMiA9ICdmYWRlJztcbiAgdmFyIENMQVNTX05BTUVfU0hPVyQyID0gJ3Nob3cnO1xuICB2YXIgU0VMRUNUT1JfVElUTEUgPSAnLnBvcG92ZXItaGVhZGVyJztcbiAgdmFyIFNFTEVDVE9SX0NPTlRFTlQgPSAnLnBvcG92ZXItYm9keSc7XG5cbiAgdmFyIERlZmF1bHQkMiA9IF9leHRlbmRzKHt9LCBUb29sdGlwLkRlZmF1bHQsIHtcbiAgICBwbGFjZW1lbnQ6ICdyaWdodCcsXG4gICAgdHJpZ2dlcjogJ2NsaWNrJyxcbiAgICBjb250ZW50OiAnJyxcbiAgICB0ZW1wbGF0ZTogJzxkaXYgY2xhc3M9XCJwb3BvdmVyXCIgcm9sZT1cInRvb2x0aXBcIj4nICsgJzxkaXYgY2xhc3M9XCJhcnJvd1wiPjwvZGl2PicgKyAnPGgzIGNsYXNzPVwicG9wb3Zlci1oZWFkZXJcIj48L2gzPicgKyAnPGRpdiBjbGFzcz1cInBvcG92ZXItYm9keVwiPjwvZGl2PjwvZGl2PidcbiAgfSk7XG5cbiAgdmFyIERlZmF1bHRUeXBlJDIgPSBfZXh0ZW5kcyh7fSwgVG9vbHRpcC5EZWZhdWx0VHlwZSwge1xuICAgIGNvbnRlbnQ6ICcoc3RyaW5nfGVsZW1lbnR8ZnVuY3Rpb24pJ1xuICB9KTtcblxuICB2YXIgRXZlbnQgPSB7XG4gICAgSElERTogXCJoaWRlXCIgKyBFVkVOVF9LRVkkMyxcbiAgICBISURERU46IFwiaGlkZGVuXCIgKyBFVkVOVF9LRVkkMyxcbiAgICBTSE9XOiBcInNob3dcIiArIEVWRU5UX0tFWSQzLFxuICAgIFNIT1dOOiBcInNob3duXCIgKyBFVkVOVF9LRVkkMyxcbiAgICBJTlNFUlRFRDogXCJpbnNlcnRlZFwiICsgRVZFTlRfS0VZJDMsXG4gICAgQ0xJQ0s6IFwiY2xpY2tcIiArIEVWRU5UX0tFWSQzLFxuICAgIEZPQ1VTSU46IFwiZm9jdXNpblwiICsgRVZFTlRfS0VZJDMsXG4gICAgRk9DVVNPVVQ6IFwiZm9jdXNvdXRcIiArIEVWRU5UX0tFWSQzLFxuICAgIE1PVVNFRU5URVI6IFwibW91c2VlbnRlclwiICsgRVZFTlRfS0VZJDMsXG4gICAgTU9VU0VMRUFWRTogXCJtb3VzZWxlYXZlXCIgKyBFVkVOVF9LRVkkM1xuICB9O1xuICAvKipcbiAgICogQ2xhc3MgZGVmaW5pdGlvblxuICAgKi9cblxuICB2YXIgUG9wb3ZlciA9IC8qI19fUFVSRV9fKi9mdW5jdGlvbiAoX1Rvb2x0aXApIHtcbiAgICBfaW5oZXJpdHNMb29zZShQb3BvdmVyLCBfVG9vbHRpcCk7XG5cbiAgICBmdW5jdGlvbiBQb3BvdmVyKCkge1xuICAgICAgcmV0dXJuIF9Ub29sdGlwLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykgfHwgdGhpcztcbiAgICB9XG5cbiAgICB2YXIgX3Byb3RvID0gUG9wb3Zlci5wcm90b3R5cGU7XG5cbiAgICAvLyBPdmVycmlkZXNcbiAgICBfcHJvdG8uaXNXaXRoQ29udGVudCA9IGZ1bmN0aW9uIGlzV2l0aENvbnRlbnQoKSB7XG4gICAgICByZXR1cm4gdGhpcy5nZXRUaXRsZSgpIHx8IHRoaXMuX2dldENvbnRlbnQoKTtcbiAgICB9O1xuXG4gICAgX3Byb3RvLmFkZEF0dGFjaG1lbnRDbGFzcyA9IGZ1bmN0aW9uIGFkZEF0dGFjaG1lbnRDbGFzcyhhdHRhY2htZW50KSB7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLmdldFRpcEVsZW1lbnQoKSkuYWRkQ2xhc3MoQ0xBU1NfUFJFRklYICsgXCItXCIgKyBhdHRhY2htZW50KTtcbiAgICB9O1xuXG4gICAgX3Byb3RvLmdldFRpcEVsZW1lbnQgPSBmdW5jdGlvbiBnZXRUaXBFbGVtZW50KCkge1xuICAgICAgdGhpcy50aXAgPSB0aGlzLnRpcCB8fCAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLmNvbmZpZy50ZW1wbGF0ZSlbMF07XG4gICAgICByZXR1cm4gdGhpcy50aXA7XG4gICAgfTtcblxuICAgIF9wcm90by5zZXRDb250ZW50ID0gZnVuY3Rpb24gc2V0Q29udGVudCgpIHtcbiAgICAgIHZhciAkdGlwID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5nZXRUaXBFbGVtZW50KCkpOyAvLyBXZSB1c2UgYXBwZW5kIGZvciBodG1sIG9iamVjdHMgdG8gbWFpbnRhaW4ganMgZXZlbnRzXG5cbiAgICAgIHRoaXMuc2V0RWxlbWVudENvbnRlbnQoJHRpcC5maW5kKFNFTEVDVE9SX1RJVExFKSwgdGhpcy5nZXRUaXRsZSgpKTtcblxuICAgICAgdmFyIGNvbnRlbnQgPSB0aGlzLl9nZXRDb250ZW50KCk7XG5cbiAgICAgIGlmICh0eXBlb2YgY29udGVudCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBjb250ZW50ID0gY29udGVudC5jYWxsKHRoaXMuZWxlbWVudCk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0RWxlbWVudENvbnRlbnQoJHRpcC5maW5kKFNFTEVDVE9SX0NPTlRFTlQpLCBjb250ZW50KTtcbiAgICAgICR0aXAucmVtb3ZlQ2xhc3MoQ0xBU1NfTkFNRV9GQURFJDIgKyBcIiBcIiArIENMQVNTX05BTUVfU0hPVyQyKTtcbiAgICB9IC8vIFByaXZhdGVcbiAgICA7XG5cbiAgICBfcHJvdG8uX2dldENvbnRlbnQgPSBmdW5jdGlvbiBfZ2V0Q29udGVudCgpIHtcbiAgICAgIHJldHVybiB0aGlzLmVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLWNvbnRlbnQnKSB8fCB0aGlzLmNvbmZpZy5jb250ZW50O1xuICAgIH07XG5cbiAgICBfcHJvdG8uX2NsZWFuVGlwQ2xhc3MgPSBmdW5jdGlvbiBfY2xlYW5UaXBDbGFzcygpIHtcbiAgICAgIHZhciAkdGlwID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5nZXRUaXBFbGVtZW50KCkpO1xuICAgICAgdmFyIHRhYkNsYXNzID0gJHRpcC5hdHRyKCdjbGFzcycpLm1hdGNoKEJTQ0xTX1BSRUZJWF9SRUdFWCk7XG5cbiAgICAgIGlmICh0YWJDbGFzcyAhPT0gbnVsbCAmJiB0YWJDbGFzcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICR0aXAucmVtb3ZlQ2xhc3ModGFiQ2xhc3Muam9pbignJykpO1xuICAgICAgfVxuICAgIH0gLy8gU3RhdGljXG4gICAgO1xuXG4gICAgUG9wb3Zlci5falF1ZXJ5SW50ZXJmYWNlID0gZnVuY3Rpb24gX2pRdWVyeUludGVyZmFjZShjb25maWcpIHtcbiAgICAgIHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgZGF0YSA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMpLmRhdGEoREFUQV9LRVkkMyk7XG5cbiAgICAgICAgdmFyIF9jb25maWcgPSB0eXBlb2YgY29uZmlnID09PSAnb2JqZWN0JyA/IGNvbmZpZyA6IG51bGw7XG5cbiAgICAgICAgaWYgKCFkYXRhICYmIC9kaXNwb3NlfGhpZGUvLnRlc3QoY29uZmlnKSkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghZGF0YSkge1xuICAgICAgICAgIGRhdGEgPSBuZXcgUG9wb3Zlcih0aGlzLCBfY29uZmlnKTtcbiAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzKS5kYXRhKERBVEFfS0VZJDMsIGRhdGEpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBjb25maWcgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgaWYgKHR5cGVvZiBkYXRhW2NvbmZpZ10gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiTm8gbWV0aG9kIG5hbWVkIFxcXCJcIiArIGNvbmZpZyArIFwiXFxcIlwiKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBkYXRhW2NvbmZpZ10oKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIF9jcmVhdGVDbGFzcyhQb3BvdmVyLCBudWxsLCBbe1xuICAgICAga2V5OiBcIlZFUlNJT05cIixcbiAgICAgIGdldDogLy8gR2V0dGVyc1xuICAgICAgZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgICByZXR1cm4gVkVSU0lPTiQzO1xuICAgICAgfVxuICAgIH0sIHtcbiAgICAgIGtleTogXCJEZWZhdWx0XCIsXG4gICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgcmV0dXJuIERlZmF1bHQkMjtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiTkFNRVwiLFxuICAgICAgZ2V0OiBmdW5jdGlvbiBnZXQoKSB7XG4gICAgICAgIHJldHVybiBOQU1FJDM7XG4gICAgICB9XG4gICAgfSwge1xuICAgICAga2V5OiBcIkRBVEFfS0VZXCIsXG4gICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgcmV0dXJuIERBVEFfS0VZJDM7XG4gICAgICB9XG4gICAgfSwge1xuICAgICAga2V5OiBcIkV2ZW50XCIsXG4gICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgcmV0dXJuIEV2ZW50O1xuICAgICAgfVxuICAgIH0sIHtcbiAgICAgIGtleTogXCJFVkVOVF9LRVlcIixcbiAgICAgIGdldDogZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgICByZXR1cm4gRVZFTlRfS0VZJDM7XG4gICAgICB9XG4gICAgfSwge1xuICAgICAga2V5OiBcIkRlZmF1bHRUeXBlXCIsXG4gICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgcmV0dXJuIERlZmF1bHRUeXBlJDI7XG4gICAgICB9XG4gICAgfV0pO1xuXG4gICAgcmV0dXJuIFBvcG92ZXI7XG4gIH0oVG9vbHRpcCk7XG4gIC8qKlxuICAgKiBqUXVlcnlcbiAgICovXG5cblxuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDNdID0gUG9wb3Zlci5falF1ZXJ5SW50ZXJmYWNlO1xuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDNdLkNvbnN0cnVjdG9yID0gUG9wb3ZlcjtcblxuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDNdLm5vQ29uZmxpY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQzXSA9IEpRVUVSWV9OT19DT05GTElDVCQzO1xuICAgIHJldHVybiBQb3BvdmVyLl9qUXVlcnlJbnRlcmZhY2U7XG4gIH07XG5cbiAgLyoqXG4gICAqIENvbnN0YW50c1xuICAgKi9cblxuICB2YXIgTkFNRSQyID0gJ3Njcm9sbHNweSc7XG4gIHZhciBWRVJTSU9OJDIgPSAnNC42LjEnO1xuICB2YXIgREFUQV9LRVkkMiA9ICdicy5zY3JvbGxzcHknO1xuICB2YXIgRVZFTlRfS0VZJDIgPSBcIi5cIiArIERBVEFfS0VZJDI7XG4gIHZhciBEQVRBX0FQSV9LRVkkMSA9ICcuZGF0YS1hcGknO1xuICB2YXIgSlFVRVJZX05PX0NPTkZMSUNUJDIgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDJdO1xuICB2YXIgQ0xBU1NfTkFNRV9EUk9QRE9XTl9JVEVNID0gJ2Ryb3Bkb3duLWl0ZW0nO1xuICB2YXIgQ0xBU1NfTkFNRV9BQ1RJVkUkMSA9ICdhY3RpdmUnO1xuICB2YXIgRVZFTlRfQUNUSVZBVEUgPSBcImFjdGl2YXRlXCIgKyBFVkVOVF9LRVkkMjtcbiAgdmFyIEVWRU5UX1NDUk9MTCA9IFwic2Nyb2xsXCIgKyBFVkVOVF9LRVkkMjtcbiAgdmFyIEVWRU5UX0xPQURfREFUQV9BUEkgPSBcImxvYWRcIiArIEVWRU5UX0tFWSQyICsgREFUQV9BUElfS0VZJDE7XG4gIHZhciBNRVRIT0RfT0ZGU0VUID0gJ29mZnNldCc7XG4gIHZhciBNRVRIT0RfUE9TSVRJT04gPSAncG9zaXRpb24nO1xuICB2YXIgU0VMRUNUT1JfREFUQV9TUFkgPSAnW2RhdGEtc3B5PVwic2Nyb2xsXCJdJztcbiAgdmFyIFNFTEVDVE9SX05BVl9MSVNUX0dST1VQJDEgPSAnLm5hdiwgLmxpc3QtZ3JvdXAnO1xuICB2YXIgU0VMRUNUT1JfTkFWX0xJTktTID0gJy5uYXYtbGluayc7XG4gIHZhciBTRUxFQ1RPUl9OQVZfSVRFTVMgPSAnLm5hdi1pdGVtJztcbiAgdmFyIFNFTEVDVE9SX0xJU1RfSVRFTVMgPSAnLmxpc3QtZ3JvdXAtaXRlbSc7XG4gIHZhciBTRUxFQ1RPUl9EUk9QRE9XTiQxID0gJy5kcm9wZG93bic7XG4gIHZhciBTRUxFQ1RPUl9EUk9QRE9XTl9JVEVNUyA9ICcuZHJvcGRvd24taXRlbSc7XG4gIHZhciBTRUxFQ1RPUl9EUk9QRE9XTl9UT0dHTEUkMSA9ICcuZHJvcGRvd24tdG9nZ2xlJztcbiAgdmFyIERlZmF1bHQkMSA9IHtcbiAgICBvZmZzZXQ6IDEwLFxuICAgIG1ldGhvZDogJ2F1dG8nLFxuICAgIHRhcmdldDogJydcbiAgfTtcbiAgdmFyIERlZmF1bHRUeXBlJDEgPSB7XG4gICAgb2Zmc2V0OiAnbnVtYmVyJyxcbiAgICBtZXRob2Q6ICdzdHJpbmcnLFxuICAgIHRhcmdldDogJyhzdHJpbmd8ZWxlbWVudCknXG4gIH07XG4gIC8qKlxuICAgKiBDbGFzcyBkZWZpbml0aW9uXG4gICAqL1xuXG4gIHZhciBTY3JvbGxTcHkgPSAvKiNfX1BVUkVfXyovZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIFNjcm9sbFNweShlbGVtZW50LCBjb25maWcpIHtcbiAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgIHRoaXMuX2VsZW1lbnQgPSBlbGVtZW50O1xuICAgICAgdGhpcy5fc2Nyb2xsRWxlbWVudCA9IGVsZW1lbnQudGFnTmFtZSA9PT0gJ0JPRFknID8gd2luZG93IDogZWxlbWVudDtcbiAgICAgIHRoaXMuX2NvbmZpZyA9IHRoaXMuX2dldENvbmZpZyhjb25maWcpO1xuICAgICAgdGhpcy5fc2VsZWN0b3IgPSB0aGlzLl9jb25maWcudGFyZ2V0ICsgXCIgXCIgKyBTRUxFQ1RPUl9OQVZfTElOS1MgKyBcIixcIiArICh0aGlzLl9jb25maWcudGFyZ2V0ICsgXCIgXCIgKyBTRUxFQ1RPUl9MSVNUX0lURU1TICsgXCIsXCIpICsgKHRoaXMuX2NvbmZpZy50YXJnZXQgKyBcIiBcIiArIFNFTEVDVE9SX0RST1BET1dOX0lURU1TKTtcbiAgICAgIHRoaXMuX29mZnNldHMgPSBbXTtcbiAgICAgIHRoaXMuX3RhcmdldHMgPSBbXTtcbiAgICAgIHRoaXMuX2FjdGl2ZVRhcmdldCA9IG51bGw7XG4gICAgICB0aGlzLl9zY3JvbGxIZWlnaHQgPSAwO1xuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fc2Nyb2xsRWxlbWVudCkub24oRVZFTlRfU0NST0xMLCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgcmV0dXJuIF90aGlzLl9wcm9jZXNzKGV2ZW50KTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5yZWZyZXNoKCk7XG5cbiAgICAgIHRoaXMuX3Byb2Nlc3MoKTtcbiAgICB9IC8vIEdldHRlcnNcblxuXG4gICAgdmFyIF9wcm90byA9IFNjcm9sbFNweS5wcm90b3R5cGU7XG5cbiAgICAvLyBQdWJsaWNcbiAgICBfcHJvdG8ucmVmcmVzaCA9IGZ1bmN0aW9uIHJlZnJlc2goKSB7XG4gICAgICB2YXIgX3RoaXMyID0gdGhpcztcblxuICAgICAgdmFyIGF1dG9NZXRob2QgPSB0aGlzLl9zY3JvbGxFbGVtZW50ID09PSB0aGlzLl9zY3JvbGxFbGVtZW50LndpbmRvdyA/IE1FVEhPRF9PRkZTRVQgOiBNRVRIT0RfUE9TSVRJT047XG4gICAgICB2YXIgb2Zmc2V0TWV0aG9kID0gdGhpcy5fY29uZmlnLm1ldGhvZCA9PT0gJ2F1dG8nID8gYXV0b01ldGhvZCA6IHRoaXMuX2NvbmZpZy5tZXRob2Q7XG4gICAgICB2YXIgb2Zmc2V0QmFzZSA9IG9mZnNldE1ldGhvZCA9PT0gTUVUSE9EX1BPU0lUSU9OID8gdGhpcy5fZ2V0U2Nyb2xsVG9wKCkgOiAwO1xuICAgICAgdGhpcy5fb2Zmc2V0cyA9IFtdO1xuICAgICAgdGhpcy5fdGFyZ2V0cyA9IFtdO1xuICAgICAgdGhpcy5fc2Nyb2xsSGVpZ2h0ID0gdGhpcy5fZ2V0U2Nyb2xsSGVpZ2h0KCk7XG4gICAgICB2YXIgdGFyZ2V0cyA9IFtdLnNsaWNlLmNhbGwoZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCh0aGlzLl9zZWxlY3RvcikpO1xuICAgICAgdGFyZ2V0cy5tYXAoZnVuY3Rpb24gKGVsZW1lbnQpIHtcbiAgICAgICAgdmFyIHRhcmdldDtcbiAgICAgICAgdmFyIHRhcmdldFNlbGVjdG9yID0gVXRpbC5nZXRTZWxlY3RvckZyb21FbGVtZW50KGVsZW1lbnQpO1xuXG4gICAgICAgIGlmICh0YXJnZXRTZWxlY3Rvcikge1xuICAgICAgICAgIHRhcmdldCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGFyZ2V0U2VsZWN0b3IpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRhcmdldCkge1xuICAgICAgICAgIHZhciB0YXJnZXRCQ1IgPSB0YXJnZXQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cbiAgICAgICAgICBpZiAodGFyZ2V0QkNSLndpZHRoIHx8IHRhcmdldEJDUi5oZWlnaHQpIHtcbiAgICAgICAgICAgIC8vIFRPRE8gKGZhdCk6IHJlbW92ZSBza2V0Y2ggcmVsaWFuY2Ugb24galF1ZXJ5IHBvc2l0aW9uL29mZnNldFxuICAgICAgICAgICAgcmV0dXJuIFskX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0YXJnZXQpW29mZnNldE1ldGhvZF0oKS50b3AgKyBvZmZzZXRCYXNlLCB0YXJnZXRTZWxlY3Rvcl07XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9KS5maWx0ZXIoZnVuY3Rpb24gKGl0ZW0pIHtcbiAgICAgICAgcmV0dXJuIGl0ZW07XG4gICAgICB9KS5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHJldHVybiBhWzBdIC0gYlswXTtcbiAgICAgIH0pLmZvckVhY2goZnVuY3Rpb24gKGl0ZW0pIHtcbiAgICAgICAgX3RoaXMyLl9vZmZzZXRzLnB1c2goaXRlbVswXSk7XG5cbiAgICAgICAgX3RoaXMyLl90YXJnZXRzLnB1c2goaXRlbVsxXSk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgX3Byb3RvLmRpc3Bvc2UgPSBmdW5jdGlvbiBkaXNwb3NlKCkge1xuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0ucmVtb3ZlRGF0YSh0aGlzLl9lbGVtZW50LCBEQVRBX0tFWSQyKTtcbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX3Njcm9sbEVsZW1lbnQpLm9mZihFVkVOVF9LRVkkMik7XG4gICAgICB0aGlzLl9lbGVtZW50ID0gbnVsbDtcbiAgICAgIHRoaXMuX3Njcm9sbEVsZW1lbnQgPSBudWxsO1xuICAgICAgdGhpcy5fY29uZmlnID0gbnVsbDtcbiAgICAgIHRoaXMuX3NlbGVjdG9yID0gbnVsbDtcbiAgICAgIHRoaXMuX29mZnNldHMgPSBudWxsO1xuICAgICAgdGhpcy5fdGFyZ2V0cyA9IG51bGw7XG4gICAgICB0aGlzLl9hY3RpdmVUYXJnZXQgPSBudWxsO1xuICAgICAgdGhpcy5fc2Nyb2xsSGVpZ2h0ID0gbnVsbDtcbiAgICB9IC8vIFByaXZhdGVcbiAgICA7XG5cbiAgICBfcHJvdG8uX2dldENvbmZpZyA9IGZ1bmN0aW9uIF9nZXRDb25maWcoY29uZmlnKSB7XG4gICAgICBjb25maWcgPSBfZXh0ZW5kcyh7fSwgRGVmYXVsdCQxLCB0eXBlb2YgY29uZmlnID09PSAnb2JqZWN0JyAmJiBjb25maWcgPyBjb25maWcgOiB7fSk7XG5cbiAgICAgIGlmICh0eXBlb2YgY29uZmlnLnRhcmdldCAhPT0gJ3N0cmluZycgJiYgVXRpbC5pc0VsZW1lbnQoY29uZmlnLnRhcmdldCkpIHtcbiAgICAgICAgdmFyIGlkID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oY29uZmlnLnRhcmdldCkuYXR0cignaWQnKTtcblxuICAgICAgICBpZiAoIWlkKSB7XG4gICAgICAgICAgaWQgPSBVdGlsLmdldFVJRChOQU1FJDIpO1xuICAgICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGNvbmZpZy50YXJnZXQpLmF0dHIoJ2lkJywgaWQpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uZmlnLnRhcmdldCA9IFwiI1wiICsgaWQ7XG4gICAgICB9XG5cbiAgICAgIFV0aWwudHlwZUNoZWNrQ29uZmlnKE5BTUUkMiwgY29uZmlnLCBEZWZhdWx0VHlwZSQxKTtcbiAgICAgIHJldHVybiBjb25maWc7XG4gICAgfTtcblxuICAgIF9wcm90by5fZ2V0U2Nyb2xsVG9wID0gZnVuY3Rpb24gX2dldFNjcm9sbFRvcCgpIHtcbiAgICAgIHJldHVybiB0aGlzLl9zY3JvbGxFbGVtZW50ID09PSB3aW5kb3cgPyB0aGlzLl9zY3JvbGxFbGVtZW50LnBhZ2VZT2Zmc2V0IDogdGhpcy5fc2Nyb2xsRWxlbWVudC5zY3JvbGxUb3A7XG4gICAgfTtcblxuICAgIF9wcm90by5fZ2V0U2Nyb2xsSGVpZ2h0ID0gZnVuY3Rpb24gX2dldFNjcm9sbEhlaWdodCgpIHtcbiAgICAgIHJldHVybiB0aGlzLl9zY3JvbGxFbGVtZW50LnNjcm9sbEhlaWdodCB8fCBNYXRoLm1heChkb2N1bWVudC5ib2R5LnNjcm9sbEhlaWdodCwgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbEhlaWdodCk7XG4gICAgfTtcblxuICAgIF9wcm90by5fZ2V0T2Zmc2V0SGVpZ2h0ID0gZnVuY3Rpb24gX2dldE9mZnNldEhlaWdodCgpIHtcbiAgICAgIHJldHVybiB0aGlzLl9zY3JvbGxFbGVtZW50ID09PSB3aW5kb3cgPyB3aW5kb3cuaW5uZXJIZWlnaHQgOiB0aGlzLl9zY3JvbGxFbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmhlaWdodDtcbiAgICB9O1xuXG4gICAgX3Byb3RvLl9wcm9jZXNzID0gZnVuY3Rpb24gX3Byb2Nlc3MoKSB7XG4gICAgICB2YXIgc2Nyb2xsVG9wID0gdGhpcy5fZ2V0U2Nyb2xsVG9wKCkgKyB0aGlzLl9jb25maWcub2Zmc2V0O1xuXG4gICAgICB2YXIgc2Nyb2xsSGVpZ2h0ID0gdGhpcy5fZ2V0U2Nyb2xsSGVpZ2h0KCk7XG5cbiAgICAgIHZhciBtYXhTY3JvbGwgPSB0aGlzLl9jb25maWcub2Zmc2V0ICsgc2Nyb2xsSGVpZ2h0IC0gdGhpcy5fZ2V0T2Zmc2V0SGVpZ2h0KCk7XG5cbiAgICAgIGlmICh0aGlzLl9zY3JvbGxIZWlnaHQgIT09IHNjcm9sbEhlaWdodCkge1xuICAgICAgICB0aGlzLnJlZnJlc2goKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHNjcm9sbFRvcCA+PSBtYXhTY3JvbGwpIHtcbiAgICAgICAgdmFyIHRhcmdldCA9IHRoaXMuX3RhcmdldHNbdGhpcy5fdGFyZ2V0cy5sZW5ndGggLSAxXTtcblxuICAgICAgICBpZiAodGhpcy5fYWN0aXZlVGFyZ2V0ICE9PSB0YXJnZXQpIHtcbiAgICAgICAgICB0aGlzLl9hY3RpdmF0ZSh0YXJnZXQpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5fYWN0aXZlVGFyZ2V0ICYmIHNjcm9sbFRvcCA8IHRoaXMuX29mZnNldHNbMF0gJiYgdGhpcy5fb2Zmc2V0c1swXSA+IDApIHtcbiAgICAgICAgdGhpcy5fYWN0aXZlVGFyZ2V0ID0gbnVsbDtcblxuICAgICAgICB0aGlzLl9jbGVhcigpO1xuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgZm9yICh2YXIgaSA9IHRoaXMuX29mZnNldHMubGVuZ3RoOyBpLS07KSB7XG4gICAgICAgIHZhciBpc0FjdGl2ZVRhcmdldCA9IHRoaXMuX2FjdGl2ZVRhcmdldCAhPT0gdGhpcy5fdGFyZ2V0c1tpXSAmJiBzY3JvbGxUb3AgPj0gdGhpcy5fb2Zmc2V0c1tpXSAmJiAodHlwZW9mIHRoaXMuX29mZnNldHNbaSArIDFdID09PSAndW5kZWZpbmVkJyB8fCBzY3JvbGxUb3AgPCB0aGlzLl9vZmZzZXRzW2kgKyAxXSk7XG5cbiAgICAgICAgaWYgKGlzQWN0aXZlVGFyZ2V0KSB7XG4gICAgICAgICAgdGhpcy5fYWN0aXZhdGUodGhpcy5fdGFyZ2V0c1tpXSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgX3Byb3RvLl9hY3RpdmF0ZSA9IGZ1bmN0aW9uIF9hY3RpdmF0ZSh0YXJnZXQpIHtcbiAgICAgIHRoaXMuX2FjdGl2ZVRhcmdldCA9IHRhcmdldDtcblxuICAgICAgdGhpcy5fY2xlYXIoKTtcblxuICAgICAgdmFyIHF1ZXJpZXMgPSB0aGlzLl9zZWxlY3Rvci5zcGxpdCgnLCcpLm1hcChmdW5jdGlvbiAoc2VsZWN0b3IpIHtcbiAgICAgICAgcmV0dXJuIHNlbGVjdG9yICsgXCJbZGF0YS10YXJnZXQ9XFxcIlwiICsgdGFyZ2V0ICsgXCJcXFwiXSxcIiArIHNlbGVjdG9yICsgXCJbaHJlZj1cXFwiXCIgKyB0YXJnZXQgKyBcIlxcXCJdXCI7XG4gICAgICB9KTtcblxuICAgICAgdmFyICRsaW5rID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oW10uc2xpY2UuY2FsbChkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKHF1ZXJpZXMuam9pbignLCcpKSkpO1xuXG4gICAgICBpZiAoJGxpbmsuaGFzQ2xhc3MoQ0xBU1NfTkFNRV9EUk9QRE9XTl9JVEVNKSkge1xuICAgICAgICAkbGluay5jbG9zZXN0KFNFTEVDVE9SX0RST1BET1dOJDEpLmZpbmQoU0VMRUNUT1JfRFJPUERPV05fVE9HR0xFJDEpLmFkZENsYXNzKENMQVNTX05BTUVfQUNUSVZFJDEpO1xuICAgICAgICAkbGluay5hZGRDbGFzcyhDTEFTU19OQU1FX0FDVElWRSQxKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIFNldCB0cmlnZ2VyZWQgbGluayBhcyBhY3RpdmVcbiAgICAgICAgJGxpbmsuYWRkQ2xhc3MoQ0xBU1NfTkFNRV9BQ1RJVkUkMSk7IC8vIFNldCB0cmlnZ2VyZWQgbGlua3MgcGFyZW50cyBhcyBhY3RpdmVcbiAgICAgICAgLy8gV2l0aCBib3RoIDx1bD4gYW5kIDxuYXY+IG1hcmt1cCBhIHBhcmVudCBpcyB0aGUgcHJldmlvdXMgc2libGluZyBvZiBhbnkgbmF2IGFuY2VzdG9yXG5cbiAgICAgICAgJGxpbmsucGFyZW50cyhTRUxFQ1RPUl9OQVZfTElTVF9HUk9VUCQxKS5wcmV2KFNFTEVDVE9SX05BVl9MSU5LUyArIFwiLCBcIiArIFNFTEVDVE9SX0xJU1RfSVRFTVMpLmFkZENsYXNzKENMQVNTX05BTUVfQUNUSVZFJDEpOyAvLyBIYW5kbGUgc3BlY2lhbCBjYXNlIHdoZW4gLm5hdi1saW5rIGlzIGluc2lkZSAubmF2LWl0ZW1cblxuICAgICAgICAkbGluay5wYXJlbnRzKFNFTEVDVE9SX05BVl9MSVNUX0dST1VQJDEpLnByZXYoU0VMRUNUT1JfTkFWX0lURU1TKS5jaGlsZHJlbihTRUxFQ1RPUl9OQVZfTElOS1MpLmFkZENsYXNzKENMQVNTX05BTUVfQUNUSVZFJDEpO1xuICAgICAgfVxuXG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9zY3JvbGxFbGVtZW50KS50cmlnZ2VyKEVWRU5UX0FDVElWQVRFLCB7XG4gICAgICAgIHJlbGF0ZWRUYXJnZXQ6IHRhcmdldFxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIF9wcm90by5fY2xlYXIgPSBmdW5jdGlvbiBfY2xlYXIoKSB7XG4gICAgICBbXS5zbGljZS5jYWxsKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwodGhpcy5fc2VsZWN0b3IpKS5maWx0ZXIoZnVuY3Rpb24gKG5vZGUpIHtcbiAgICAgICAgcmV0dXJuIG5vZGUuY2xhc3NMaXN0LmNvbnRhaW5zKENMQVNTX05BTUVfQUNUSVZFJDEpO1xuICAgICAgfSkuZm9yRWFjaChmdW5jdGlvbiAobm9kZSkge1xuICAgICAgICByZXR1cm4gbm9kZS5jbGFzc0xpc3QucmVtb3ZlKENMQVNTX05BTUVfQUNUSVZFJDEpO1xuICAgICAgfSk7XG4gICAgfSAvLyBTdGF0aWNcbiAgICA7XG5cbiAgICBTY3JvbGxTcHkuX2pRdWVyeUludGVyZmFjZSA9IGZ1bmN0aW9uIF9qUXVlcnlJbnRlcmZhY2UoY29uZmlnKSB7XG4gICAgICByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGRhdGEgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzKS5kYXRhKERBVEFfS0VZJDIpO1xuXG4gICAgICAgIHZhciBfY29uZmlnID0gdHlwZW9mIGNvbmZpZyA9PT0gJ29iamVjdCcgJiYgY29uZmlnO1xuXG4gICAgICAgIGlmICghZGF0YSkge1xuICAgICAgICAgIGRhdGEgPSBuZXcgU2Nyb2xsU3B5KHRoaXMsIF9jb25maWcpO1xuICAgICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMpLmRhdGEoREFUQV9LRVkkMiwgZGF0YSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIGNvbmZpZyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICBpZiAodHlwZW9mIGRhdGFbY29uZmlnXSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJObyBtZXRob2QgbmFtZWQgXFxcIlwiICsgY29uZmlnICsgXCJcXFwiXCIpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGRhdGFbY29uZmlnXSgpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgX2NyZWF0ZUNsYXNzKFNjcm9sbFNweSwgbnVsbCwgW3tcbiAgICAgIGtleTogXCJWRVJTSU9OXCIsXG4gICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgcmV0dXJuIFZFUlNJT04kMjtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiRGVmYXVsdFwiLFxuICAgICAgZ2V0OiBmdW5jdGlvbiBnZXQoKSB7XG4gICAgICAgIHJldHVybiBEZWZhdWx0JDE7XG4gICAgICB9XG4gICAgfV0pO1xuXG4gICAgcmV0dXJuIFNjcm9sbFNweTtcbiAgfSgpO1xuICAvKipcbiAgICogRGF0YSBBUEkgaW1wbGVtZW50YXRpb25cbiAgICovXG5cblxuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh3aW5kb3cpLm9uKEVWRU5UX0xPQURfREFUQV9BUEksIGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgc2Nyb2xsU3B5cyA9IFtdLnNsaWNlLmNhbGwoZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbChTRUxFQ1RPUl9EQVRBX1NQWSkpO1xuICAgIHZhciBzY3JvbGxTcHlzTGVuZ3RoID0gc2Nyb2xsU3B5cy5sZW5ndGg7XG5cbiAgICBmb3IgKHZhciBpID0gc2Nyb2xsU3B5c0xlbmd0aDsgaS0tOykge1xuICAgICAgdmFyICRzcHkgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShzY3JvbGxTcHlzW2ldKTtcblxuICAgICAgU2Nyb2xsU3B5Ll9qUXVlcnlJbnRlcmZhY2UuY2FsbCgkc3B5LCAkc3B5LmRhdGEoKSk7XG4gICAgfVxuICB9KTtcbiAgLyoqXG4gICAqIGpRdWVyeVxuICAgKi9cblxuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDJdID0gU2Nyb2xsU3B5Ll9qUXVlcnlJbnRlcmZhY2U7XG4gICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuW05BTUUkMl0uQ29uc3RydWN0b3IgPSBTY3JvbGxTcHk7XG5cbiAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQyXS5ub0NvbmZsaWN0ID0gZnVuY3Rpb24gKCkge1xuICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuW05BTUUkMl0gPSBKUVVFUllfTk9fQ09ORkxJQ1QkMjtcbiAgICByZXR1cm4gU2Nyb2xsU3B5Ll9qUXVlcnlJbnRlcmZhY2U7XG4gIH07XG5cbiAgLyoqXG4gICAqIENvbnN0YW50c1xuICAgKi9cblxuICB2YXIgTkFNRSQxID0gJ3RhYic7XG4gIHZhciBWRVJTSU9OJDEgPSAnNC42LjEnO1xuICB2YXIgREFUQV9LRVkkMSA9ICdicy50YWInO1xuICB2YXIgRVZFTlRfS0VZJDEgPSBcIi5cIiArIERBVEFfS0VZJDE7XG4gIHZhciBEQVRBX0FQSV9LRVkgPSAnLmRhdGEtYXBpJztcbiAgdmFyIEpRVUVSWV9OT19DT05GTElDVCQxID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQxXTtcbiAgdmFyIENMQVNTX05BTUVfRFJPUERPV05fTUVOVSA9ICdkcm9wZG93bi1tZW51JztcbiAgdmFyIENMQVNTX05BTUVfQUNUSVZFID0gJ2FjdGl2ZSc7XG4gIHZhciBDTEFTU19OQU1FX0RJU0FCTEVEID0gJ2Rpc2FibGVkJztcbiAgdmFyIENMQVNTX05BTUVfRkFERSQxID0gJ2ZhZGUnO1xuICB2YXIgQ0xBU1NfTkFNRV9TSE9XJDEgPSAnc2hvdyc7XG4gIHZhciBFVkVOVF9ISURFJDEgPSBcImhpZGVcIiArIEVWRU5UX0tFWSQxO1xuICB2YXIgRVZFTlRfSElEREVOJDEgPSBcImhpZGRlblwiICsgRVZFTlRfS0VZJDE7XG4gIHZhciBFVkVOVF9TSE9XJDEgPSBcInNob3dcIiArIEVWRU5UX0tFWSQxO1xuICB2YXIgRVZFTlRfU0hPV04kMSA9IFwic2hvd25cIiArIEVWRU5UX0tFWSQxO1xuICB2YXIgRVZFTlRfQ0xJQ0tfREFUQV9BUEkgPSBcImNsaWNrXCIgKyBFVkVOVF9LRVkkMSArIERBVEFfQVBJX0tFWTtcbiAgdmFyIFNFTEVDVE9SX0RST1BET1dOID0gJy5kcm9wZG93bic7XG4gIHZhciBTRUxFQ1RPUl9OQVZfTElTVF9HUk9VUCA9ICcubmF2LCAubGlzdC1ncm91cCc7XG4gIHZhciBTRUxFQ1RPUl9BQ1RJVkUgPSAnLmFjdGl2ZSc7XG4gIHZhciBTRUxFQ1RPUl9BQ1RJVkVfVUwgPSAnPiBsaSA+IC5hY3RpdmUnO1xuICB2YXIgU0VMRUNUT1JfREFUQV9UT0dHTEUgPSAnW2RhdGEtdG9nZ2xlPVwidGFiXCJdLCBbZGF0YS10b2dnbGU9XCJwaWxsXCJdLCBbZGF0YS10b2dnbGU9XCJsaXN0XCJdJztcbiAgdmFyIFNFTEVDVE9SX0RST1BET1dOX1RPR0dMRSA9ICcuZHJvcGRvd24tdG9nZ2xlJztcbiAgdmFyIFNFTEVDVE9SX0RST1BET1dOX0FDVElWRV9DSElMRCA9ICc+IC5kcm9wZG93bi1tZW51IC5hY3RpdmUnO1xuICAvKipcbiAgICogQ2xhc3MgZGVmaW5pdGlvblxuICAgKi9cblxuICB2YXIgVGFiID0gLyojX19QVVJFX18qL2Z1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBUYWIoZWxlbWVudCkge1xuICAgICAgdGhpcy5fZWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgfSAvLyBHZXR0ZXJzXG5cblxuICAgIHZhciBfcHJvdG8gPSBUYWIucHJvdG90eXBlO1xuXG4gICAgLy8gUHVibGljXG4gICAgX3Byb3RvLnNob3cgPSBmdW5jdGlvbiBzaG93KCkge1xuICAgICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgICAgaWYgKHRoaXMuX2VsZW1lbnQucGFyZW50Tm9kZSAmJiB0aGlzLl9lbGVtZW50LnBhcmVudE5vZGUubm9kZVR5cGUgPT09IE5vZGUuRUxFTUVOVF9OT0RFICYmICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLmhhc0NsYXNzKENMQVNTX05BTUVfQUNUSVZFKSB8fCAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5oYXNDbGFzcyhDTEFTU19OQU1FX0RJU0FCTEVEKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHZhciB0YXJnZXQ7XG4gICAgICB2YXIgcHJldmlvdXM7XG4gICAgICB2YXIgbGlzdEVsZW1lbnQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5jbG9zZXN0KFNFTEVDVE9SX05BVl9MSVNUX0dST1VQKVswXTtcbiAgICAgIHZhciBzZWxlY3RvciA9IFV0aWwuZ2V0U2VsZWN0b3JGcm9tRWxlbWVudCh0aGlzLl9lbGVtZW50KTtcblxuICAgICAgaWYgKGxpc3RFbGVtZW50KSB7XG4gICAgICAgIHZhciBpdGVtU2VsZWN0b3IgPSBsaXN0RWxlbWVudC5ub2RlTmFtZSA9PT0gJ1VMJyB8fCBsaXN0RWxlbWVudC5ub2RlTmFtZSA9PT0gJ09MJyA/IFNFTEVDVE9SX0FDVElWRV9VTCA6IFNFTEVDVE9SX0FDVElWRTtcbiAgICAgICAgcHJldmlvdXMgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5tYWtlQXJyYXkoJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0obGlzdEVsZW1lbnQpLmZpbmQoaXRlbVNlbGVjdG9yKSk7XG4gICAgICAgIHByZXZpb3VzID0gcHJldmlvdXNbcHJldmlvdXMubGVuZ3RoIC0gMV07XG4gICAgICB9XG5cbiAgICAgIHZhciBoaWRlRXZlbnQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5FdmVudChFVkVOVF9ISURFJDEsIHtcbiAgICAgICAgcmVsYXRlZFRhcmdldDogdGhpcy5fZWxlbWVudFxuICAgICAgfSk7XG4gICAgICB2YXIgc2hvd0V2ZW50ID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uRXZlbnQoRVZFTlRfU0hPVyQxLCB7XG4gICAgICAgIHJlbGF0ZWRUYXJnZXQ6IHByZXZpb3VzXG4gICAgICB9KTtcblxuICAgICAgaWYgKHByZXZpb3VzKSB7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHByZXZpb3VzKS50cmlnZ2VyKGhpZGVFdmVudCk7XG4gICAgICB9XG5cbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLnRyaWdnZXIoc2hvd0V2ZW50KTtcblxuICAgICAgaWYgKHNob3dFdmVudC5pc0RlZmF1bHRQcmV2ZW50ZWQoKSB8fCBoaWRlRXZlbnQuaXNEZWZhdWx0UHJldmVudGVkKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoc2VsZWN0b3IpIHtcbiAgICAgICAgdGFyZ2V0ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihzZWxlY3Rvcik7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuX2FjdGl2YXRlKHRoaXMuX2VsZW1lbnQsIGxpc3RFbGVtZW50KTtcblxuICAgICAgdmFyIGNvbXBsZXRlID0gZnVuY3Rpb24gY29tcGxldGUoKSB7XG4gICAgICAgIHZhciBoaWRkZW5FdmVudCA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLkV2ZW50KEVWRU5UX0hJRERFTiQxLCB7XG4gICAgICAgICAgcmVsYXRlZFRhcmdldDogX3RoaXMuX2VsZW1lbnRcbiAgICAgICAgfSk7XG4gICAgICAgIHZhciBzaG93bkV2ZW50ID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uRXZlbnQoRVZFTlRfU0hPV04kMSwge1xuICAgICAgICAgIHJlbGF0ZWRUYXJnZXQ6IHByZXZpb3VzXG4gICAgICAgIH0pO1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShwcmV2aW91cykudHJpZ2dlcihoaWRkZW5FdmVudCk7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKF90aGlzLl9lbGVtZW50KS50cmlnZ2VyKHNob3duRXZlbnQpO1xuICAgICAgfTtcblxuICAgICAgaWYgKHRhcmdldCkge1xuICAgICAgICB0aGlzLl9hY3RpdmF0ZSh0YXJnZXQsIHRhcmdldC5wYXJlbnROb2RlLCBjb21wbGV0ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb21wbGV0ZSgpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBfcHJvdG8uZGlzcG9zZSA9IGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5yZW1vdmVEYXRhKHRoaXMuX2VsZW1lbnQsIERBVEFfS0VZJDEpO1xuICAgICAgdGhpcy5fZWxlbWVudCA9IG51bGw7XG4gICAgfSAvLyBQcml2YXRlXG4gICAgO1xuXG4gICAgX3Byb3RvLl9hY3RpdmF0ZSA9IGZ1bmN0aW9uIF9hY3RpdmF0ZShlbGVtZW50LCBjb250YWluZXIsIGNhbGxiYWNrKSB7XG4gICAgICB2YXIgX3RoaXMyID0gdGhpcztcblxuICAgICAgdmFyIGFjdGl2ZUVsZW1lbnRzID0gY29udGFpbmVyICYmIChjb250YWluZXIubm9kZU5hbWUgPT09ICdVTCcgfHwgY29udGFpbmVyLm5vZGVOYW1lID09PSAnT0wnKSA/ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGNvbnRhaW5lcikuZmluZChTRUxFQ1RPUl9BQ1RJVkVfVUwpIDogJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oY29udGFpbmVyKS5jaGlsZHJlbihTRUxFQ1RPUl9BQ1RJVkUpO1xuICAgICAgdmFyIGFjdGl2ZSA9IGFjdGl2ZUVsZW1lbnRzWzBdO1xuICAgICAgdmFyIGlzVHJhbnNpdGlvbmluZyA9IGNhbGxiYWNrICYmIGFjdGl2ZSAmJiAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShhY3RpdmUpLmhhc0NsYXNzKENMQVNTX05BTUVfRkFERSQxKTtcblxuICAgICAgdmFyIGNvbXBsZXRlID0gZnVuY3Rpb24gY29tcGxldGUoKSB7XG4gICAgICAgIHJldHVybiBfdGhpczIuX3RyYW5zaXRpb25Db21wbGV0ZShlbGVtZW50LCBhY3RpdmUsIGNhbGxiYWNrKTtcbiAgICAgIH07XG5cbiAgICAgIGlmIChhY3RpdmUgJiYgaXNUcmFuc2l0aW9uaW5nKSB7XG4gICAgICAgIHZhciB0cmFuc2l0aW9uRHVyYXRpb24gPSBVdGlsLmdldFRyYW5zaXRpb25EdXJhdGlvbkZyb21FbGVtZW50KGFjdGl2ZSk7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGFjdGl2ZSkucmVtb3ZlQ2xhc3MoQ0xBU1NfTkFNRV9TSE9XJDEpLm9uZShVdGlsLlRSQU5TSVRJT05fRU5ELCBjb21wbGV0ZSkuZW11bGF0ZVRyYW5zaXRpb25FbmQodHJhbnNpdGlvbkR1cmF0aW9uKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbXBsZXRlKCk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIF9wcm90by5fdHJhbnNpdGlvbkNvbXBsZXRlID0gZnVuY3Rpb24gX3RyYW5zaXRpb25Db21wbGV0ZShlbGVtZW50LCBhY3RpdmUsIGNhbGxiYWNrKSB7XG4gICAgICBpZiAoYWN0aXZlKSB7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGFjdGl2ZSkucmVtb3ZlQ2xhc3MoQ0xBU1NfTkFNRV9BQ1RJVkUpO1xuICAgICAgICB2YXIgZHJvcGRvd25DaGlsZCA9ICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGFjdGl2ZS5wYXJlbnROb2RlKS5maW5kKFNFTEVDVE9SX0RST1BET1dOX0FDVElWRV9DSElMRClbMF07XG5cbiAgICAgICAgaWYgKGRyb3Bkb3duQ2hpbGQpIHtcbiAgICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShkcm9wZG93bkNoaWxkKS5yZW1vdmVDbGFzcyhDTEFTU19OQU1FX0FDVElWRSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoYWN0aXZlLmdldEF0dHJpYnV0ZSgncm9sZScpID09PSAndGFiJykge1xuICAgICAgICAgIGFjdGl2ZS5zZXRBdHRyaWJ1dGUoJ2FyaWEtc2VsZWN0ZWQnLCBmYWxzZSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZWxlbWVudCkuYWRkQ2xhc3MoQ0xBU1NfTkFNRV9BQ1RJVkUpO1xuXG4gICAgICBpZiAoZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ3JvbGUnKSA9PT0gJ3RhYicpIHtcbiAgICAgICAgZWxlbWVudC5zZXRBdHRyaWJ1dGUoJ2FyaWEtc2VsZWN0ZWQnLCB0cnVlKTtcbiAgICAgIH1cblxuICAgICAgVXRpbC5yZWZsb3coZWxlbWVudCk7XG5cbiAgICAgIGlmIChlbGVtZW50LmNsYXNzTGlzdC5jb250YWlucyhDTEFTU19OQU1FX0ZBREUkMSkpIHtcbiAgICAgICAgZWxlbWVudC5jbGFzc0xpc3QuYWRkKENMQVNTX05BTUVfU0hPVyQxKTtcbiAgICAgIH1cblxuICAgICAgdmFyIHBhcmVudCA9IGVsZW1lbnQucGFyZW50Tm9kZTtcblxuICAgICAgaWYgKHBhcmVudCAmJiBwYXJlbnQubm9kZU5hbWUgPT09ICdMSScpIHtcbiAgICAgICAgcGFyZW50ID0gcGFyZW50LnBhcmVudE5vZGU7XG4gICAgICB9XG5cbiAgICAgIGlmIChwYXJlbnQgJiYgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0ocGFyZW50KS5oYXNDbGFzcyhDTEFTU19OQU1FX0RST1BET1dOX01FTlUpKSB7XG4gICAgICAgIHZhciBkcm9wZG93bkVsZW1lbnQgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXShlbGVtZW50KS5jbG9zZXN0KFNFTEVDVE9SX0RST1BET1dOKVswXTtcblxuICAgICAgICBpZiAoZHJvcGRvd25FbGVtZW50KSB7XG4gICAgICAgICAgdmFyIGRyb3Bkb3duVG9nZ2xlTGlzdCA9IFtdLnNsaWNlLmNhbGwoZHJvcGRvd25FbGVtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoU0VMRUNUT1JfRFJPUERPV05fVE9HR0xFKSk7XG4gICAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oZHJvcGRvd25Ub2dnbGVMaXN0KS5hZGRDbGFzcyhDTEFTU19OQU1FX0FDVElWRSk7XG4gICAgICAgIH1cblxuICAgICAgICBlbGVtZW50LnNldEF0dHJpYnV0ZSgnYXJpYS1leHBhbmRlZCcsIHRydWUpO1xuICAgICAgfVxuXG4gICAgICBpZiAoY2FsbGJhY2spIHtcbiAgICAgICAgY2FsbGJhY2soKTtcbiAgICAgIH1cbiAgICB9IC8vIFN0YXRpY1xuICAgIDtcblxuICAgIFRhYi5falF1ZXJ5SW50ZXJmYWNlID0gZnVuY3Rpb24gX2pRdWVyeUludGVyZmFjZShjb25maWcpIHtcbiAgICAgIHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgJHRoaXMgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzKTtcbiAgICAgICAgdmFyIGRhdGEgPSAkdGhpcy5kYXRhKERBVEFfS0VZJDEpO1xuXG4gICAgICAgIGlmICghZGF0YSkge1xuICAgICAgICAgIGRhdGEgPSBuZXcgVGFiKHRoaXMpO1xuICAgICAgICAgICR0aGlzLmRhdGEoREFUQV9LRVkkMSwgZGF0YSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIGNvbmZpZyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICBpZiAodHlwZW9mIGRhdGFbY29uZmlnXSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJObyBtZXRob2QgbmFtZWQgXFxcIlwiICsgY29uZmlnICsgXCJcXFwiXCIpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGRhdGFbY29uZmlnXSgpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgX2NyZWF0ZUNsYXNzKFRhYiwgbnVsbCwgW3tcbiAgICAgIGtleTogXCJWRVJTSU9OXCIsXG4gICAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgICAgcmV0dXJuIFZFUlNJT04kMTtcbiAgICAgIH1cbiAgICB9XSk7XG5cbiAgICByZXR1cm4gVGFiO1xuICB9KCk7XG4gIC8qKlxuICAgKiBEYXRhIEFQSSBpbXBsZW1lbnRhdGlvblxuICAgKi9cblxuXG4gICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGRvY3VtZW50KS5vbihFVkVOVF9DTElDS19EQVRBX0FQSSwgU0VMRUNUT1JfREFUQV9UT0dHTEUsIGZ1bmN0aW9uIChldmVudCkge1xuICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICBUYWIuX2pRdWVyeUludGVyZmFjZS5jYWxsKCRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMpLCAnc2hvdycpO1xuICB9KTtcbiAgLyoqXG4gICAqIGpRdWVyeVxuICAgKi9cblxuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FJDFdID0gVGFiLl9qUXVlcnlJbnRlcmZhY2U7XG4gICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuW05BTUUkMV0uQ29uc3RydWN0b3IgPSBUYWI7XG5cbiAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRSQxXS5ub0NvbmZsaWN0ID0gZnVuY3Rpb24gKCkge1xuICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuW05BTUUkMV0gPSBKUVVFUllfTk9fQ09ORkxJQ1QkMTtcbiAgICByZXR1cm4gVGFiLl9qUXVlcnlJbnRlcmZhY2U7XG4gIH07XG5cbiAgLyoqXG4gICAqIENvbnN0YW50c1xuICAgKi9cblxuICB2YXIgTkFNRSA9ICd0b2FzdCc7XG4gIHZhciBWRVJTSU9OID0gJzQuNi4xJztcbiAgdmFyIERBVEFfS0VZID0gJ2JzLnRvYXN0JztcbiAgdmFyIEVWRU5UX0tFWSA9IFwiLlwiICsgREFUQV9LRVk7XG4gIHZhciBKUVVFUllfTk9fQ09ORkxJQ1QgPSAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FXTtcbiAgdmFyIENMQVNTX05BTUVfRkFERSA9ICdmYWRlJztcbiAgdmFyIENMQVNTX05BTUVfSElERSA9ICdoaWRlJztcbiAgdmFyIENMQVNTX05BTUVfU0hPVyA9ICdzaG93JztcbiAgdmFyIENMQVNTX05BTUVfU0hPV0lORyA9ICdzaG93aW5nJztcbiAgdmFyIEVWRU5UX0NMSUNLX0RJU01JU1MgPSBcImNsaWNrLmRpc21pc3NcIiArIEVWRU5UX0tFWTtcbiAgdmFyIEVWRU5UX0hJREUgPSBcImhpZGVcIiArIEVWRU5UX0tFWTtcbiAgdmFyIEVWRU5UX0hJRERFTiA9IFwiaGlkZGVuXCIgKyBFVkVOVF9LRVk7XG4gIHZhciBFVkVOVF9TSE9XID0gXCJzaG93XCIgKyBFVkVOVF9LRVk7XG4gIHZhciBFVkVOVF9TSE9XTiA9IFwic2hvd25cIiArIEVWRU5UX0tFWTtcbiAgdmFyIFNFTEVDVE9SX0RBVEFfRElTTUlTUyA9ICdbZGF0YS1kaXNtaXNzPVwidG9hc3RcIl0nO1xuICB2YXIgRGVmYXVsdCA9IHtcbiAgICBhbmltYXRpb246IHRydWUsXG4gICAgYXV0b2hpZGU6IHRydWUsXG4gICAgZGVsYXk6IDUwMFxuICB9O1xuICB2YXIgRGVmYXVsdFR5cGUgPSB7XG4gICAgYW5pbWF0aW9uOiAnYm9vbGVhbicsXG4gICAgYXV0b2hpZGU6ICdib29sZWFuJyxcbiAgICBkZWxheTogJ251bWJlcidcbiAgfTtcbiAgLyoqXG4gICAqIENsYXNzIGRlZmluaXRpb25cbiAgICovXG5cbiAgdmFyIFRvYXN0ID0gLyojX19QVVJFX18qL2Z1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBUb2FzdChlbGVtZW50LCBjb25maWcpIHtcbiAgICAgIHRoaXMuX2VsZW1lbnQgPSBlbGVtZW50O1xuICAgICAgdGhpcy5fY29uZmlnID0gdGhpcy5fZ2V0Q29uZmlnKGNvbmZpZyk7XG4gICAgICB0aGlzLl90aW1lb3V0ID0gbnVsbDtcblxuICAgICAgdGhpcy5fc2V0TGlzdGVuZXJzKCk7XG4gICAgfSAvLyBHZXR0ZXJzXG5cblxuICAgIHZhciBfcHJvdG8gPSBUb2FzdC5wcm90b3R5cGU7XG5cbiAgICAvLyBQdWJsaWNcbiAgICBfcHJvdG8uc2hvdyA9IGZ1bmN0aW9uIHNob3coKSB7XG4gICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICB2YXIgc2hvd0V2ZW50ID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uRXZlbnQoRVZFTlRfU0hPVyk7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS50cmlnZ2VyKHNob3dFdmVudCk7XG5cbiAgICAgIGlmIChzaG93RXZlbnQuaXNEZWZhdWx0UHJldmVudGVkKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLl9jbGVhclRpbWVvdXQoKTtcblxuICAgICAgaWYgKHRoaXMuX2NvbmZpZy5hbmltYXRpb24pIHtcbiAgICAgICAgdGhpcy5fZWxlbWVudC5jbGFzc0xpc3QuYWRkKENMQVNTX05BTUVfRkFERSk7XG4gICAgICB9XG5cbiAgICAgIHZhciBjb21wbGV0ZSA9IGZ1bmN0aW9uIGNvbXBsZXRlKCkge1xuICAgICAgICBfdGhpcy5fZWxlbWVudC5jbGFzc0xpc3QucmVtb3ZlKENMQVNTX05BTUVfU0hPV0lORyk7XG5cbiAgICAgICAgX3RoaXMuX2VsZW1lbnQuY2xhc3NMaXN0LmFkZChDTEFTU19OQU1FX1NIT1cpO1xuXG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKF90aGlzLl9lbGVtZW50KS50cmlnZ2VyKEVWRU5UX1NIT1dOKTtcblxuICAgICAgICBpZiAoX3RoaXMuX2NvbmZpZy5hdXRvaGlkZSkge1xuICAgICAgICAgIF90aGlzLl90aW1lb3V0ID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBfdGhpcy5oaWRlKCk7XG4gICAgICAgICAgfSwgX3RoaXMuX2NvbmZpZy5kZWxheSk7XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIHRoaXMuX2VsZW1lbnQuY2xhc3NMaXN0LnJlbW92ZShDTEFTU19OQU1FX0hJREUpO1xuXG4gICAgICBVdGlsLnJlZmxvdyh0aGlzLl9lbGVtZW50KTtcblxuICAgICAgdGhpcy5fZWxlbWVudC5jbGFzc0xpc3QuYWRkKENMQVNTX05BTUVfU0hPV0lORyk7XG5cbiAgICAgIGlmICh0aGlzLl9jb25maWcuYW5pbWF0aW9uKSB7XG4gICAgICAgIHZhciB0cmFuc2l0aW9uRHVyYXRpb24gPSBVdGlsLmdldFRyYW5zaXRpb25EdXJhdGlvbkZyb21FbGVtZW50KHRoaXMuX2VsZW1lbnQpO1xuICAgICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5vbmUoVXRpbC5UUkFOU0lUSU9OX0VORCwgY29tcGxldGUpLmVtdWxhdGVUcmFuc2l0aW9uRW5kKHRyYW5zaXRpb25EdXJhdGlvbik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb21wbGV0ZSgpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBfcHJvdG8uaGlkZSA9IGZ1bmN0aW9uIGhpZGUoKSB7XG4gICAgICBpZiAoIXRoaXMuX2VsZW1lbnQuY2xhc3NMaXN0LmNvbnRhaW5zKENMQVNTX05BTUVfU0hPVykpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB2YXIgaGlkZUV2ZW50ID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uRXZlbnQoRVZFTlRfSElERSk7XG4gICAgICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS50cmlnZ2VyKGhpZGVFdmVudCk7XG5cbiAgICAgIGlmIChoaWRlRXZlbnQuaXNEZWZhdWx0UHJldmVudGVkKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLl9jbG9zZSgpO1xuICAgIH07XG5cbiAgICBfcHJvdG8uZGlzcG9zZSA9IGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XG4gICAgICB0aGlzLl9jbGVhclRpbWVvdXQoKTtcblxuICAgICAgaWYgKHRoaXMuX2VsZW1lbnQuY2xhc3NMaXN0LmNvbnRhaW5zKENMQVNTX05BTUVfU0hPVykpIHtcbiAgICAgICAgdGhpcy5fZWxlbWVudC5jbGFzc0xpc3QucmVtb3ZlKENMQVNTX05BTUVfU0hPVyk7XG4gICAgICB9XG5cbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLm9mZihFVkVOVF9DTElDS19ESVNNSVNTKTtcbiAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLnJlbW92ZURhdGEodGhpcy5fZWxlbWVudCwgREFUQV9LRVkpO1xuICAgICAgdGhpcy5fZWxlbWVudCA9IG51bGw7XG4gICAgICB0aGlzLl9jb25maWcgPSBudWxsO1xuICAgIH0gLy8gUHJpdmF0ZVxuICAgIDtcblxuICAgIF9wcm90by5fZ2V0Q29uZmlnID0gZnVuY3Rpb24gX2dldENvbmZpZyhjb25maWcpIHtcbiAgICAgIGNvbmZpZyA9IF9leHRlbmRzKHt9LCBEZWZhdWx0LCAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXSh0aGlzLl9lbGVtZW50KS5kYXRhKCksIHR5cGVvZiBjb25maWcgPT09ICdvYmplY3QnICYmIGNvbmZpZyA/IGNvbmZpZyA6IHt9KTtcbiAgICAgIFV0aWwudHlwZUNoZWNrQ29uZmlnKE5BTUUsIGNvbmZpZywgdGhpcy5jb25zdHJ1Y3Rvci5EZWZhdWx0VHlwZSk7XG4gICAgICByZXR1cm4gY29uZmlnO1xuICAgIH07XG5cbiAgICBfcHJvdG8uX3NldExpc3RlbmVycyA9IGZ1bmN0aW9uIF9zZXRMaXN0ZW5lcnMoKSB7XG4gICAgICB2YXIgX3RoaXMyID0gdGhpcztcblxuICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcy5fZWxlbWVudCkub24oRVZFTlRfQ0xJQ0tfRElTTUlTUywgU0VMRUNUT1JfREFUQV9ESVNNSVNTLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBfdGhpczIuaGlkZSgpO1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIF9wcm90by5fY2xvc2UgPSBmdW5jdGlvbiBfY2xvc2UoKSB7XG4gICAgICB2YXIgX3RoaXMzID0gdGhpcztcblxuICAgICAgdmFyIGNvbXBsZXRlID0gZnVuY3Rpb24gY29tcGxldGUoKSB7XG4gICAgICAgIF90aGlzMy5fZWxlbWVudC5jbGFzc0xpc3QuYWRkKENMQVNTX05BTUVfSElERSk7XG5cbiAgICAgICAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0oX3RoaXMzLl9lbGVtZW50KS50cmlnZ2VyKEVWRU5UX0hJRERFTik7XG4gICAgICB9O1xuXG4gICAgICB0aGlzLl9lbGVtZW50LmNsYXNzTGlzdC5yZW1vdmUoQ0xBU1NfTkFNRV9TSE9XKTtcblxuICAgICAgaWYgKHRoaXMuX2NvbmZpZy5hbmltYXRpb24pIHtcbiAgICAgICAgdmFyIHRyYW5zaXRpb25EdXJhdGlvbiA9IFV0aWwuZ2V0VHJhbnNpdGlvbkR1cmF0aW9uRnJvbUVsZW1lbnQodGhpcy5fZWxlbWVudCk7XG4gICAgICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKHRoaXMuX2VsZW1lbnQpLm9uZShVdGlsLlRSQU5TSVRJT05fRU5ELCBjb21wbGV0ZSkuZW11bGF0ZVRyYW5zaXRpb25FbmQodHJhbnNpdGlvbkR1cmF0aW9uKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbXBsZXRlKCk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIF9wcm90by5fY2xlYXJUaW1lb3V0ID0gZnVuY3Rpb24gX2NsZWFyVGltZW91dCgpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLl90aW1lb3V0KTtcbiAgICAgIHRoaXMuX3RpbWVvdXQgPSBudWxsO1xuICAgIH0gLy8gU3RhdGljXG4gICAgO1xuXG4gICAgVG9hc3QuX2pRdWVyeUludGVyZmFjZSA9IGZ1bmN0aW9uIF9qUXVlcnlJbnRlcmZhY2UoY29uZmlnKSB7XG4gICAgICByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyICRlbGVtZW50ID0gJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0odGhpcyk7XG4gICAgICAgIHZhciBkYXRhID0gJGVsZW1lbnQuZGF0YShEQVRBX0tFWSk7XG5cbiAgICAgICAgdmFyIF9jb25maWcgPSB0eXBlb2YgY29uZmlnID09PSAnb2JqZWN0JyAmJiBjb25maWc7XG5cbiAgICAgICAgaWYgKCFkYXRhKSB7XG4gICAgICAgICAgZGF0YSA9IG5ldyBUb2FzdCh0aGlzLCBfY29uZmlnKTtcbiAgICAgICAgICAkZWxlbWVudC5kYXRhKERBVEFfS0VZLCBkYXRhKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgY29uZmlnID09PSAnc3RyaW5nJykge1xuICAgICAgICAgIGlmICh0eXBlb2YgZGF0YVtjb25maWddID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIk5vIG1ldGhvZCBuYW1lZCBcXFwiXCIgKyBjb25maWcgKyBcIlxcXCJcIik7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZGF0YVtjb25maWddKHRoaXMpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgX2NyZWF0ZUNsYXNzKFRvYXN0LCBudWxsLCBbe1xuICAgICAga2V5OiBcIlZFUlNJT05cIixcbiAgICAgIGdldDogZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgICByZXR1cm4gVkVSU0lPTjtcbiAgICAgIH1cbiAgICB9LCB7XG4gICAgICBrZXk6IFwiRGVmYXVsdFR5cGVcIixcbiAgICAgIGdldDogZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgICByZXR1cm4gRGVmYXVsdFR5cGU7XG4gICAgICB9XG4gICAgfSwge1xuICAgICAga2V5OiBcIkRlZmF1bHRcIixcbiAgICAgIGdldDogZnVuY3Rpb24gZ2V0KCkge1xuICAgICAgICByZXR1cm4gRGVmYXVsdDtcbiAgICAgIH1cbiAgICB9XSk7XG5cbiAgICByZXR1cm4gVG9hc3Q7XG4gIH0oKTtcbiAgLyoqXG4gICAqIGpRdWVyeVxuICAgKi9cblxuXG4gICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuW05BTUVdID0gVG9hc3QuX2pRdWVyeUludGVyZmFjZTtcbiAgJF9fZGVmYXVsdFtcImRlZmF1bHRcIl0uZm5bTkFNRV0uQ29uc3RydWN0b3IgPSBUb2FzdDtcblxuICAkX19kZWZhdWx0W1wiZGVmYXVsdFwiXS5mbltOQU1FXS5ub0NvbmZsaWN0ID0gZnVuY3Rpb24gKCkge1xuICAgICRfX2RlZmF1bHRbXCJkZWZhdWx0XCJdLmZuW05BTUVdID0gSlFVRVJZX05PX0NPTkZMSUNUO1xuICAgIHJldHVybiBUb2FzdC5falF1ZXJ5SW50ZXJmYWNlO1xuICB9O1xuXG4gIGV4cG9ydHMuQWxlcnQgPSBBbGVydDtcbiAgZXhwb3J0cy5CdXR0b24gPSBCdXR0b247XG4gIGV4cG9ydHMuQ2Fyb3VzZWwgPSBDYXJvdXNlbDtcbiAgZXhwb3J0cy5Db2xsYXBzZSA9IENvbGxhcHNlO1xuICBleHBvcnRzLkRyb3Bkb3duID0gRHJvcGRvd247XG4gIGV4cG9ydHMuTW9kYWwgPSBNb2RhbDtcbiAgZXhwb3J0cy5Qb3BvdmVyID0gUG9wb3ZlcjtcbiAgZXhwb3J0cy5TY3JvbGxzcHkgPSBTY3JvbGxTcHk7XG4gIGV4cG9ydHMuVGFiID0gVGFiO1xuICBleHBvcnRzLlRvYXN0ID0gVG9hc3Q7XG4gIGV4cG9ydHMuVG9vbHRpcCA9IFRvb2x0aXA7XG4gIGV4cG9ydHMuVXRpbCA9IFV0aWw7XG5cbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogdHJ1ZSB9KTtcblxufSkpO1xuLy8jIHNvdXJjZU1hcHBpbmdVUkw9Ym9vdHN0cmFwLmpzLm1hcFxuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./node_modules/bootstrap/dist/js/bootstrap.js\n");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./node_modules/datatables.net-bs4/js/dataTables.bootstrap4.js":
|
|
/*!*********************************************************************!*\
|
|
!*** ./node_modules/datatables.net-bs4/js/dataTables.bootstrap4.js ***!
|
|
\*********************************************************************/
|
|
/***/ ((module, exports, __webpack_require__) => {
|
|
|
|
eval("var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! DataTables Bootstrap 4 integration\n * ©2011-2017 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for Bootstrap 4. This requires Bootstrap 4 and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap\n * for further information.\n */\n(function( factory ){\n\tif ( true ) {\n\t\t// AMD\n\t\t!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\"), __webpack_require__(/*! datatables.net */ \"./node_modules/datatables.net/js/jquery.dataTables.js\")], __WEBPACK_AMD_DEFINE_RESULT__ = (function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),\n\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n\t}\n\telse {}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t\"<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>>\" +\n\t\t\"<'row'<'col-sm-12'tr>>\" +\n\t\t\"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>\",\n\trenderer: 'bootstrap'\n} );\n\n\n/* Default class modification */\n$.extend( DataTable.ext.classes, {\n\tsWrapper: \"dataTables_wrapper dt-bootstrap4\",\n\tsFilterInput: \"form-control form-control-sm\",\n\tsLengthSelect: \"custom-select custom-select-sm form-control form-control-sm\",\n\tsProcessing: \"dataTables_processing card\",\n\tsPageButton: \"paginate_button page-item\"\n} );\n\n\n/* Bootstrap paging button renderer */\nDataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) {\n\tvar api = new DataTable.Api( settings );\n\tvar classes = settings.oClasses;\n\tvar lang = settings.oLanguage.oPaginate;\n\tvar aria = settings.oLanguage.oAria.paginate || {};\n\tvar btnDisplay, btnClass, counter=0;\n\n\tvar attach = function( container, buttons ) {\n\t\tvar i, ien, node, button;\n\t\tvar clickHandler = function ( e ) {\n\t\t\te.preventDefault();\n\t\t\tif ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) {\n\t\t\t\tapi.page( e.data.action ).draw( 'page' );\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( Array.isArray( button ) ) {\n\t\t\t\tattach( container, button );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbtnDisplay = '';\n\t\t\t\tbtnClass = '';\n\n\t\t\t\tswitch ( button ) {\n\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\tbtnDisplay = '…';\n\t\t\t\t\t\tbtnClass = 'disabled';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'first':\n\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'last':\n\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t'active' : '';\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\tnode = $('<li>', {\n\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append( $('<a>', {\n\t\t\t\t\t\t\t\t'href': '#',\n\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t\t'class': 'page-link'\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\tsettings.oApi._fnBindAction(\n\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t);\n\n\t\t\t\t\tcounter++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t// inside an iframe or frame. \n\tvar activeEl;\n\n\ttry {\n\t\t// Because this approach is destroying and recreating the paging\n\t\t// elements, focus is lost on the select button which is bad for\n\t\t// accessibility. So we want to restore focus once the draw has\n\t\t// completed\n\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t}\n\tcatch (e) {}\n\n\tattach(\n\t\t$(host).empty().html('<ul class=\"pagination\"/>').children('ul'),\n\t\tbuttons\n\t);\n\n\tif ( activeEl !== undefined ) {\n\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus');\n\t}\n};\n\n\nreturn DataTable;\n}));\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvZGF0YXRhYmxlcy5uZXQtYnM0L2pzL2RhdGFUYWJsZXMuYm9vdHN0cmFwNC5qcy5qcyIsIm1hcHBpbmdzIjoiQUFBQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTSxJQUEwQztBQUNoRDtBQUNBLEVBQUUsaUNBQVEsQ0FBQyx5RUFBUSxFQUFFLGtHQUFnQixDQUFDLG1DQUFFO0FBQ3hDO0FBQ0EsR0FBRztBQUFBLGtHQUFFO0FBQ0w7QUFDQSxNQUFNLEVBb0JKO0FBQ0YsQ0FBQztBQUNEO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7O0FBR0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOzs7QUFHRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGtDQUFrQyxRQUFRO0FBQzFDOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsNEJBQTRCO0FBQzVCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGFBQWEsZUFBZTtBQUM1Qjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBLENBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvZGF0YXRhYmxlcy5uZXQtYnM0L2pzL2RhdGFUYWJsZXMuYm9vdHN0cmFwNC5qcz81Y2Y2Il0sInNvdXJjZXNDb250ZW50IjpbIi8qISBEYXRhVGFibGVzIEJvb3RzdHJhcCA0IGludGVncmF0aW9uXG4gKiDCqTIwMTEtMjAxNyBTcHJ5TWVkaWEgTHRkIC0gZGF0YXRhYmxlcy5uZXQvbGljZW5zZVxuICovXG5cbi8qKlxuICogRGF0YVRhYmxlcyBpbnRlZ3JhdGlvbiBmb3IgQm9vdHN0cmFwIDQuIFRoaXMgcmVxdWlyZXMgQm9vdHN0cmFwIDQgYW5kXG4gKiBEYXRhVGFibGVzIDEuMTAgb3IgbmV3ZXIuXG4gKlxuICogVGhpcyBmaWxlIHNldHMgdGhlIGRlZmF1bHRzIGFuZCBhZGRzIG9wdGlvbnMgdG8gRGF0YVRhYmxlcyB0byBzdHlsZSBpdHNcbiAqIGNvbnRyb2xzIHVzaW5nIEJvb3RzdHJhcC4gU2VlIGh0dHA6Ly9kYXRhdGFibGVzLm5ldC9tYW51YWwvc3R5bGluZy9ib290c3RyYXBcbiAqIGZvciBmdXJ0aGVyIGluZm9ybWF0aW9uLlxuICovXG4oZnVuY3Rpb24oIGZhY3RvcnkgKXtcblx0aWYgKCB0eXBlb2YgZGVmaW5lID09PSAnZnVuY3Rpb24nICYmIGRlZmluZS5hbWQgKSB7XG5cdFx0Ly8gQU1EXG5cdFx0ZGVmaW5lKCBbJ2pxdWVyeScsICdkYXRhdGFibGVzLm5ldCddLCBmdW5jdGlvbiAoICQgKSB7XG5cdFx0XHRyZXR1cm4gZmFjdG9yeSggJCwgd2luZG93LCBkb2N1bWVudCApO1xuXHRcdH0gKTtcblx0fVxuXHRlbHNlIGlmICggdHlwZW9mIGV4cG9ydHMgPT09ICdvYmplY3QnICkge1xuXHRcdC8vIENvbW1vbkpTXG5cdFx0bW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAocm9vdCwgJCkge1xuXHRcdFx0aWYgKCAhIHJvb3QgKSB7XG5cdFx0XHRcdHJvb3QgPSB3aW5kb3c7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggISAkIHx8ICEgJC5mbi5kYXRhVGFibGUgKSB7XG5cdFx0XHRcdC8vIFJlcXVpcmUgRGF0YVRhYmxlcywgd2hpY2ggYXR0YWNoZXMgdG8galF1ZXJ5LCBpbmNsdWRpbmdcblx0XHRcdFx0Ly8galF1ZXJ5IGlmIG5lZWRlZCBhbmQgaGF2ZSBhICQgcHJvcGVydHkgc28gd2UgY2FuIGFjY2VzcyB0aGVcblx0XHRcdFx0Ly8galF1ZXJ5IG9iamVjdCB0aGF0IGlzIHVzZWRcblx0XHRcdFx0JCA9IHJlcXVpcmUoJ2RhdGF0YWJsZXMubmV0Jykocm9vdCwgJCkuJDtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGZhY3RvcnkoICQsIHJvb3QsIHJvb3QuZG9jdW1lbnQgKTtcblx0XHR9O1xuXHR9XG5cdGVsc2Uge1xuXHRcdC8vIEJyb3dzZXJcblx0XHRmYWN0b3J5KCBqUXVlcnksIHdpbmRvdywgZG9jdW1lbnQgKTtcblx0fVxufShmdW5jdGlvbiggJCwgd2luZG93LCBkb2N1bWVudCwgdW5kZWZpbmVkICkge1xuJ3VzZSBzdHJpY3QnO1xudmFyIERhdGFUYWJsZSA9ICQuZm4uZGF0YVRhYmxlO1xuXG5cbi8qIFNldCB0aGUgZGVmYXVsdHMgZm9yIERhdGFUYWJsZXMgaW5pdGlhbGlzYXRpb24gKi9cbiQuZXh0ZW5kKCB0cnVlLCBEYXRhVGFibGUuZGVmYXVsdHMsIHtcblx0ZG9tOlxuXHRcdFwiPCdyb3cnPCdjb2wtc20tMTIgY29sLW1kLTYnbD48J2NvbC1zbS0xMiBjb2wtbWQtNidmPj5cIiArXG5cdFx0XCI8J3Jvdyc8J2NvbC1zbS0xMid0cj4+XCIgK1xuXHRcdFwiPCdyb3cnPCdjb2wtc20tMTIgY29sLW1kLTUnaT48J2NvbC1zbS0xMiBjb2wtbWQtNydwPj5cIixcblx0cmVuZGVyZXI6ICdib290c3RyYXAnXG59ICk7XG5cblxuLyogRGVmYXVsdCBjbGFzcyBtb2RpZmljYXRpb24gKi9cbiQuZXh0ZW5kKCBEYXRhVGFibGUuZXh0LmNsYXNzZXMsIHtcblx0c1dyYXBwZXI6ICAgICAgXCJkYXRhVGFibGVzX3dyYXBwZXIgZHQtYm9vdHN0cmFwNFwiLFxuXHRzRmlsdGVySW5wdXQ6ICBcImZvcm0tY29udHJvbCBmb3JtLWNvbnRyb2wtc21cIixcblx0c0xlbmd0aFNlbGVjdDogXCJjdXN0b20tc2VsZWN0IGN1c3RvbS1zZWxlY3Qtc20gZm9ybS1jb250cm9sIGZvcm0tY29udHJvbC1zbVwiLFxuXHRzUHJvY2Vzc2luZzogICBcImRhdGFUYWJsZXNfcHJvY2Vzc2luZyBjYXJkXCIsXG5cdHNQYWdlQnV0dG9uOiAgIFwicGFnaW5hdGVfYnV0dG9uIHBhZ2UtaXRlbVwiXG59ICk7XG5cblxuLyogQm9vdHN0cmFwIHBhZ2luZyBidXR0b24gcmVuZGVyZXIgKi9cbkRhdGFUYWJsZS5leHQucmVuZGVyZXIucGFnZUJ1dHRvbi5ib290c3RyYXAgPSBmdW5jdGlvbiAoIHNldHRpbmdzLCBob3N0LCBpZHgsIGJ1dHRvbnMsIHBhZ2UsIHBhZ2VzICkge1xuXHR2YXIgYXBpICAgICA9IG5ldyBEYXRhVGFibGUuQXBpKCBzZXR0aW5ncyApO1xuXHR2YXIgY2xhc3NlcyA9IHNldHRpbmdzLm9DbGFzc2VzO1xuXHR2YXIgbGFuZyAgICA9IHNldHRpbmdzLm9MYW5ndWFnZS5vUGFnaW5hdGU7XG5cdHZhciBhcmlhID0gc2V0dGluZ3Mub0xhbmd1YWdlLm9BcmlhLnBhZ2luYXRlIHx8IHt9O1xuXHR2YXIgYnRuRGlzcGxheSwgYnRuQ2xhc3MsIGNvdW50ZXI9MDtcblxuXHR2YXIgYXR0YWNoID0gZnVuY3Rpb24oIGNvbnRhaW5lciwgYnV0dG9ucyApIHtcblx0XHR2YXIgaSwgaWVuLCBub2RlLCBidXR0b247XG5cdFx0dmFyIGNsaWNrSGFuZGxlciA9IGZ1bmN0aW9uICggZSApIHtcblx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRcdGlmICggISQoZS5jdXJyZW50VGFyZ2V0KS5oYXNDbGFzcygnZGlzYWJsZWQnKSAmJiBhcGkucGFnZSgpICE9IGUuZGF0YS5hY3Rpb24gKSB7XG5cdFx0XHRcdGFwaS5wYWdlKCBlLmRhdGEuYWN0aW9uICkuZHJhdyggJ3BhZ2UnICk7XG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdGZvciAoIGk9MCwgaWVuPWJ1dHRvbnMubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRidXR0b24gPSBidXR0b25zW2ldO1xuXG5cdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIGJ1dHRvbiApICkge1xuXHRcdFx0XHRhdHRhY2goIGNvbnRhaW5lciwgYnV0dG9uICk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0YnRuRGlzcGxheSA9ICcnO1xuXHRcdFx0XHRidG5DbGFzcyA9ICcnO1xuXG5cdFx0XHRcdHN3aXRjaCAoIGJ1dHRvbiApIHtcblx0XHRcdFx0XHRjYXNlICdlbGxpcHNpcyc6XG5cdFx0XHRcdFx0XHRidG5EaXNwbGF5ID0gJyYjeDIwMjY7Jztcblx0XHRcdFx0XHRcdGJ0bkNsYXNzID0gJ2Rpc2FibGVkJztcblx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0Y2FzZSAnZmlyc3QnOlxuXHRcdFx0XHRcdFx0YnRuRGlzcGxheSA9IGxhbmcuc0ZpcnN0O1xuXHRcdFx0XHRcdFx0YnRuQ2xhc3MgPSBidXR0b24gKyAocGFnZSA+IDAgP1xuXHRcdFx0XHRcdFx0XHQnJyA6ICcgZGlzYWJsZWQnKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0Y2FzZSAncHJldmlvdXMnOlxuXHRcdFx0XHRcdFx0YnRuRGlzcGxheSA9IGxhbmcuc1ByZXZpb3VzO1xuXHRcdFx0XHRcdFx0YnRuQ2xhc3MgPSBidXR0b24gKyAocGFnZSA+IDAgP1xuXHRcdFx0XHRcdFx0XHQnJyA6ICcgZGlzYWJsZWQnKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0Y2FzZSAnbmV4dCc6XG5cdFx0XHRcdFx0XHRidG5EaXNwbGF5ID0gbGFuZy5zTmV4dDtcblx0XHRcdFx0XHRcdGJ0bkNsYXNzID0gYnV0dG9uICsgKHBhZ2UgPCBwYWdlcy0xID9cblx0XHRcdFx0XHRcdFx0JycgOiAnIGRpc2FibGVkJyk7XG5cdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdGNhc2UgJ2xhc3QnOlxuXHRcdFx0XHRcdFx0YnRuRGlzcGxheSA9IGxhbmcuc0xhc3Q7XG5cdFx0XHRcdFx0XHRidG5DbGFzcyA9IGJ1dHRvbiArIChwYWdlIDwgcGFnZXMtMSA/XG5cdFx0XHRcdFx0XHRcdCcnIDogJyBkaXNhYmxlZCcpO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdFx0YnRuRGlzcGxheSA9IGJ1dHRvbiArIDE7XG5cdFx0XHRcdFx0XHRidG5DbGFzcyA9IHBhZ2UgPT09IGJ1dHRvbiA/XG5cdFx0XHRcdFx0XHRcdCdhY3RpdmUnIDogJyc7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggYnRuRGlzcGxheSApIHtcblx0XHRcdFx0XHRub2RlID0gJCgnPGxpPicsIHtcblx0XHRcdFx0XHRcdFx0J2NsYXNzJzogY2xhc3Nlcy5zUGFnZUJ1dHRvbisnICcrYnRuQ2xhc3MsXG5cdFx0XHRcdFx0XHRcdCdpZCc6IGlkeCA9PT0gMCAmJiB0eXBlb2YgYnV0dG9uID09PSAnc3RyaW5nJyA/XG5cdFx0XHRcdFx0XHRcdFx0c2V0dGluZ3Muc1RhYmxlSWQgKydfJysgYnV0dG9uIDpcblx0XHRcdFx0XHRcdFx0XHRudWxsXG5cdFx0XHRcdFx0XHR9IClcblx0XHRcdFx0XHRcdC5hcHBlbmQoICQoJzxhPicsIHtcblx0XHRcdFx0XHRcdFx0XHQnaHJlZic6ICcjJyxcblx0XHRcdFx0XHRcdFx0XHQnYXJpYS1jb250cm9scyc6IHNldHRpbmdzLnNUYWJsZUlkLFxuXHRcdFx0XHRcdFx0XHRcdCdhcmlhLWxhYmVsJzogYXJpYVsgYnV0dG9uIF0sXG5cdFx0XHRcdFx0XHRcdFx0J2RhdGEtZHQtaWR4JzogY291bnRlcixcblx0XHRcdFx0XHRcdFx0XHQndGFiaW5kZXgnOiBzZXR0aW5ncy5pVGFiSW5kZXgsXG5cdFx0XHRcdFx0XHRcdFx0J2NsYXNzJzogJ3BhZ2UtbGluaydcblx0XHRcdFx0XHRcdFx0fSApXG5cdFx0XHRcdFx0XHRcdC5odG1sKCBidG5EaXNwbGF5IClcblx0XHRcdFx0XHRcdClcblx0XHRcdFx0XHRcdC5hcHBlbmRUbyggY29udGFpbmVyICk7XG5cblx0XHRcdFx0XHRzZXR0aW5ncy5vQXBpLl9mbkJpbmRBY3Rpb24oXG5cdFx0XHRcdFx0XHRub2RlLCB7YWN0aW9uOiBidXR0b259LCBjbGlja0hhbmRsZXJcblx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0Y291bnRlcisrO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9O1xuXG5cdC8vIElFOSB0aHJvd3MgYW4gJ3Vua25vd24gZXJyb3InIGlmIGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQgaXMgdXNlZFxuXHQvLyBpbnNpZGUgYW4gaWZyYW1lIG9yIGZyYW1lLiBcblx0dmFyIGFjdGl2ZUVsO1xuXG5cdHRyeSB7XG5cdFx0Ly8gQmVjYXVzZSB0aGlzIGFwcHJvYWNoIGlzIGRlc3Ryb3lpbmcgYW5kIHJlY3JlYXRpbmcgdGhlIHBhZ2luZ1xuXHRcdC8vIGVsZW1lbnRzLCBmb2N1cyBpcyBsb3N0IG9uIHRoZSBzZWxlY3QgYnV0dG9uIHdoaWNoIGlzIGJhZCBmb3Jcblx0XHQvLyBhY2Nlc3NpYmlsaXR5LiBTbyB3ZSB3YW50IHRvIHJlc3RvcmUgZm9jdXMgb25jZSB0aGUgZHJhdyBoYXNcblx0XHQvLyBjb21wbGV0ZWRcblx0XHRhY3RpdmVFbCA9ICQoaG9zdCkuZmluZChkb2N1bWVudC5hY3RpdmVFbGVtZW50KS5kYXRhKCdkdC1pZHgnKTtcblx0fVxuXHRjYXRjaCAoZSkge31cblxuXHRhdHRhY2goXG5cdFx0JChob3N0KS5lbXB0eSgpLmh0bWwoJzx1bCBjbGFzcz1cInBhZ2luYXRpb25cIi8+JykuY2hpbGRyZW4oJ3VsJyksXG5cdFx0YnV0dG9uc1xuXHQpO1xuXG5cdGlmICggYWN0aXZlRWwgIT09IHVuZGVmaW5lZCApIHtcblx0XHQkKGhvc3QpLmZpbmQoICdbZGF0YS1kdC1pZHg9JythY3RpdmVFbCsnXScgKS50cmlnZ2VyKCdmb2N1cycpO1xuXHR9XG59O1xuXG5cbnJldHVybiBEYXRhVGFibGU7XG59KSk7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/datatables.net-bs4/js/dataTables.bootstrap4.js\n");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./node_modules/datatables.net/js/jquery.dataTables.js":
|
|
/*!*************************************************************!*\
|
|
!*** ./node_modules/datatables.net/js/jquery.dataTables.js ***!
|
|
\*************************************************************/
|
|
/***/ ((module, exports, __webpack_require__) => {
|
|
|
|
eval("var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! DataTables 1.11.3\n * ©2008-2021 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary DataTables\n * @description Paginate, search and order HTML tables\n * @version 1.11.3\n * @file jquery.dataTables.js\n * @author SpryMedia Ltd\n * @contact www.datatables.net\n * @copyright Copyright 2008-2021 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n * MIT license - http://datatables.net/license\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n/*jslint evil: true, undef: true, browser: true */\n/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/\n\n(function( factory ) {\n\t\"use strict\";\n\n\tif ( true ) {\n\t\t// AMD\n\t\t!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\")], __WEBPACK_AMD_DEFINE_RESULT__ = (function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),\n\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n\t}\n\telse {}\n}\n(function( $, window, document, undefined ) {\n\t\"use strict\";\n\n\t/**\n\t * DataTables is a plug-in for the jQuery Javascript library. It is a highly\n\t * flexible tool, based upon the foundations of progressive enhancement,\n\t * which will add advanced interaction controls to any HTML table. For a\n\t * full list of features please refer to\n\t * [DataTables.net](href=\"http://datatables.net).\n\t *\n\t * Note that the `DataTable` object is not a global variable but is aliased\n\t * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may\n\t * be accessed.\n\t *\n\t * @class\n\t * @param {object} [init={}] Configuration object for DataTables. Options\n\t * are defined by {@link DataTable.defaults}\n\t * @requires jQuery 1.7+\n\t *\n\t * @example\n\t * // Basic initialisation\n\t * $(document).ready( function {\n\t * $('#example').dataTable();\n\t * } );\n\t *\n\t * @example\n\t * // Initialisation with configuration options - in this case, disable\n\t * // pagination and sorting.\n\t * $(document).ready( function {\n\t * $('#example').dataTable( {\n\t * \"paginate\": false,\n\t * \"sort\": false\n\t * } );\n\t * } );\n\t */\n\tvar DataTable = function ( selector, options )\n\t{\n\t\t// When creating with `new`, create a new DataTable, returning the API instance\n\t\tif (this instanceof DataTable) {\n\t\t\treturn $(selector).DataTable(options);\n\t\t}\n\t\telse {\n\t\t\t// Argument switching\n\t\t\toptions = selector;\n\t\t}\n\n\t\t/**\n\t\t * Perform a jQuery selector action on the table's TR elements (from the tbody) and\n\t\t * return the resulting jQuery object.\n\t\t * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t * @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter\n\t\t * criterion (\"applied\") or all TR elements (i.e. no filter).\n\t\t * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.\n\t\t * Can be either 'current', whereby the current sorting of the table is used, or\n\t\t * 'original' whereby the original order the data was read into the table is used.\n\t\t * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t * (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t * 'current' and filter is 'applied', regardless of what they might be given as.\n\t\t * @returns {object} jQuery object, filtered by the given selector.\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t *\n\t\t * // Highlight every second row\n\t\t * oTable.$('tr:odd').css('backgroundColor', 'blue');\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t *\n\t\t * // Filter to rows with 'Webkit' in them, add a background colour and then\n\t\t * // remove the filter, thus highlighting the 'Webkit' rows only.\n\t\t * oTable.fnFilter('Webkit');\n\t\t * oTable.$('tr', {\"search\": \"applied\"}).css('backgroundColor', 'blue');\n\t\t * oTable.fnFilter('');\n\t\t * } );\n\t\t */\n\t\tthis.$ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).$( sSelector, oOpts );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Almost identical to $ in operation, but in this case returns the data for the matched\n\t\t * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes\n\t\t * rather than any descendants, so the data can be obtained for the row/cell. If matching\n\t\t * rows are found, the data returned is the original data array/object that was used to\n\t\t * create the row (or a generated array if from a DOM source).\n\t\t *\n\t\t * This method is often useful in-combination with $ where both functions are given the\n\t\t * same parameters and the array indexes will match identically.\n\t\t * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t * @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t * @param {string} [oOpts.filter=none] Select elements that meet the current filter\n\t\t * criterion (\"applied\") or all elements (i.e. no filter).\n\t\t * @param {string} [oOpts.order=current] Order of the data in the processed array.\n\t\t * Can be either 'current', whereby the current sorting of the table is used, or\n\t\t * 'original' whereby the original order the data was read into the table is used.\n\t\t * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t * (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t * 'current' and filter is 'applied', regardless of what they might be given as.\n\t\t * @returns {array} Data for the matched elements. If any elements, as a result of the\n\t\t * selector, were not TR, TD or TH elements in the DataTable, they will have a null\n\t\t * entry in the array.\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t *\n\t\t * // Get the data from the first row in the table\n\t\t * var data = oTable._('tr:first');\n\t\t *\n\t\t * // Do something useful with the data\n\t\t * alert( \"First cell is: \"+data[0] );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t *\n\t\t * // Filter to 'Webkit' and get all data for\n\t\t * oTable.fnFilter('Webkit');\n\t\t * var data = oTable._('tr', {\"search\": \"applied\"});\n\t\t *\n\t\t * // Do something with the data\n\t\t * alert( data.length+\" rows matched the search\" );\n\t\t * } );\n\t\t */\n\t\tthis._ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).rows( sSelector, oOpts ).data();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Create a DataTables Api instance, with the currently selected tables for\n\t\t * the Api's context.\n\t\t * @param {boolean} [traditional=false] Set the API instance's context to be\n\t\t * only the table referred to by the `DataTable.ext.iApiIndex` option, as was\n\t\t * used in the API presented by DataTables 1.9- (i.e. the traditional mode),\n\t\t * or if all tables captured in the jQuery object should be used.\n\t\t * @return {DataTables.Api}\n\t\t */\n\t\tthis.api = function ( traditional )\n\t\t{\n\t\t\treturn traditional ?\n\t\t\t\tnew _Api(\n\t\t\t\t\t_fnSettingsFromNode( this[ _ext.iApiIndex ] )\n\t\t\t\t) :\n\t\t\t\tnew _Api( this );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Add a single new row or multiple rows of data to the table. Please note\n\t\t * that this is suitable for client-side processing only - if you are using\n\t\t * server-side processing (i.e. \"bServerSide\": true), then to add data, you\n\t\t * must add it to the data source, i.e. the server-side, through an Ajax call.\n\t\t * @param {array|object} data The data to be added to the table. This can be:\n\t\t * <ul>\n\t\t * <li>1D array of data - add a single row with the data provided</li>\n\t\t * <li>2D array of arrays - add multiple rows in a single call</li>\n\t\t * <li>object - data object when using <i>mData</i></li>\n\t\t * <li>array of objects - multiple data objects when using <i>mData</i></li>\n\t\t * </ul>\n\t\t * @param {bool} [redraw=true] redraw the table or not\n\t\t * @returns {array} An array of integers, representing the list of indexes in\n\t\t * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to\n\t\t * the table.\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * // Global var for counter\n\t\t * var giCount = 2;\n\t\t *\n\t\t * $(document).ready(function() {\n\t\t * $('#example').dataTable();\n\t\t * } );\n\t\t *\n\t\t * function fnClickAddRow() {\n\t\t * $('#example').dataTable().fnAddData( [\n\t\t * giCount+\".1\",\n\t\t * giCount+\".2\",\n\t\t * giCount+\".3\",\n\t\t * giCount+\".4\" ]\n\t\t * );\n\t\t *\n\t\t * giCount++;\n\t\t * }\n\t\t */\n\t\tthis.fnAddData = function( data, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\t/* Check if we want to add multiple rows or not */\n\t\t\tvar rows = Array.isArray(data) && ( Array.isArray(data[0]) || $.isPlainObject(data[0]) ) ?\n\t\t\t\tapi.rows.add( data ) :\n\t\t\t\tapi.row.add( data );\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn rows.flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will make DataTables recalculate the column sizes, based on the data\n\t\t * contained in the table and the sizes applied to the columns (in the DOM, CSS or\n\t\t * through the sWidth parameter). This can be useful when the width of the table's\n\t\t * parent element changes (for example a window resize).\n\t\t * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable( {\n\t\t * \"sScrollY\": \"200px\",\n\t\t * \"bPaginate\": false\n\t\t * } );\n\t\t *\n\t\t * $(window).on('resize', function () {\n\t\t * oTable.fnAdjustColumnSizing();\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\tthis.fnAdjustColumnSizing = function ( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).columns.adjust();\n\t\t\tvar settings = api.settings()[0];\n\t\t\tvar scroll = settings.oScroll;\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw( false );\n\t\t\t}\n\t\t\telse if ( scroll.sX !== \"\" || scroll.sY !== \"\" ) {\n\t\t\t\t/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */\n\t\t\t\t_fnScrollDraw( settings );\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Quickly and simply clear a table\n\t\t * @param {bool} [bRedraw=true] redraw the table or not\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t *\n\t\t * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)\n\t\t * oTable.fnClearTable();\n\t\t * } );\n\t\t */\n\t\tthis.fnClearTable = function( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).clear();\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * The exact opposite of 'opening' a row, this function will close any rows which\n\t\t * are currently 'open'.\n\t\t * @param {node} nTr the table row to 'close'\n\t\t * @returns {int} 0 on success, or 1 if failed (can't find the row)\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable;\n\t\t *\n\t\t * // 'open' an information row when a row is clicked on\n\t\t * $('#example tbody tr').click( function () {\n\t\t * if ( oTable.fnIsOpen(this) ) {\n\t\t * oTable.fnClose( this );\n\t\t * } else {\n\t\t * oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t * }\n\t\t * } );\n\t\t *\n\t\t * oTable = $('#example').dataTable();\n\t\t * } );\n\t\t */\n\t\tthis.fnClose = function( nTr )\n\t\t{\n\t\t\tthis.api( true ).row( nTr ).child.hide();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Remove a row for the table\n\t\t * @param {mixed} target The index of the row from aoData to be deleted, or\n\t\t * the TR element you want to delete\n\t\t * @param {function|null} [callBack] Callback function\n\t\t * @param {bool} [redraw=true] Redraw the table or not\n\t\t * @returns {array} The row that was deleted\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t *\n\t\t * // Immediately remove the first row\n\t\t * oTable.fnDeleteRow( 0 );\n\t\t * } );\n\t\t */\n\t\tthis.fnDeleteRow = function( target, callback, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar rows = api.rows( target );\n\t\t\tvar settings = rows.settings()[0];\n\t\t\tvar data = settings.aoData[ rows[0][0] ];\n\t\t\n\t\t\trows.remove();\n\t\t\n\t\t\tif ( callback ) {\n\t\t\t\tcallback.call( this, settings, data );\n\t\t\t}\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn data;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Restore the table to it's original state in the DOM by removing all of DataTables\n\t\t * enhancements, alterations to the DOM structure of the table and event listeners.\n\t\t * @param {boolean} [remove=false] Completely remove the table from the DOM\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * // This example is fairly pointless in reality, but shows how fnDestroy can be used\n\t\t * var oTable = $('#example').dataTable();\n\t\t * oTable.fnDestroy();\n\t\t * } );\n\t\t */\n\t\tthis.fnDestroy = function ( remove )\n\t\t{\n\t\t\tthis.api( true ).destroy( remove );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Redraw the table\n\t\t * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t *\n\t\t * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)\n\t\t * oTable.fnDraw();\n\t\t * } );\n\t\t */\n\t\tthis.fnDraw = function( complete )\n\t\t{\n\t\t\t// Note that this isn't an exact match to the old call to _fnDraw - it takes\n\t\t\t// into account the new data, but can hold position.\n\t\t\tthis.api( true ).draw( complete );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Filter the input based on data\n\t\t * @param {string} sInput String to filter the table on\n\t\t * @param {int|null} [iColumn] Column to limit filtering to\n\t\t * @param {bool} [bRegex=false] Treat as regular expression or not\n\t\t * @param {bool} [bSmart=true] Perform smart filtering or not\n\t\t * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)\n\t\t * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t *\n\t\t * // Sometime later - filter...\n\t\t * oTable.fnFilter( 'test string' );\n\t\t * } );\n\t\t */\n\t\tthis.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === null || iColumn === undefined ) {\n\t\t\t\tapi.search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\n\t\t\tapi.draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the data for the whole table, an individual row or an individual cell based on the\n\t\t * provided parameters.\n\t\t * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as\n\t\t * a TR node then the data source for the whole row will be returned. If given as a\n\t\t * TD/TH cell node then iCol will be automatically calculated and the data for the\n\t\t * cell returned. If given as an integer, then this is treated as the aoData internal\n\t\t * data index for the row (see fnGetPosition) and the data for that row used.\n\t\t * @param {int} [col] Optional column index that you want the data of.\n\t\t * @returns {array|object|string} If mRow is undefined, then the data for all rows is\n\t\t * returned. If mRow is defined, just data for that row, and is iCol is\n\t\t * defined, only data for the designated cell is returned.\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * // Row data\n\t\t * $(document).ready(function() {\n\t\t * oTable = $('#example').dataTable();\n\t\t *\n\t\t * oTable.$('tr').click( function () {\n\t\t * var data = oTable.fnGetData( this );\n\t\t * // ... do something with the array / object of data for the row\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Individual cell data\n\t\t * $(document).ready(function() {\n\t\t * oTable = $('#example').dataTable();\n\t\t *\n\t\t * oTable.$('td').click( function () {\n\t\t * var sData = oTable.fnGetData( this );\n\t\t * alert( 'The cell clicked on had the value of '+sData );\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\tthis.fnGetData = function( src, col )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( src !== undefined ) {\n\t\t\t\tvar type = src.nodeName ? src.nodeName.toLowerCase() : '';\n\t\t\n\t\t\t\treturn col !== undefined || type == 'td' || type == 'th' ?\n\t\t\t\t\tapi.cell( src, col ).data() :\n\t\t\t\t\tapi.row( src ).data() || null;\n\t\t\t}\n\t\t\n\t\t\treturn api.data().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get an array of the TR nodes that are used in the table's body. Note that you will\n\t\t * typically want to use the '$' API method in preference to this as it is more\n\t\t * flexible.\n\t\t * @param {int} [iRow] Optional row index for the TR element you want\n\t\t * @returns {array|node} If iRow is undefined, returns an array of all TR elements\n\t\t * in the table's body, or iRow is defined, just the TR element requested.\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t *\n\t\t * // Get the nodes from the table\n\t\t * var nNodes = oTable.fnGetNodes( );\n\t\t * } );\n\t\t */\n\t\tthis.fnGetNodes = function( iRow )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\treturn iRow !== undefined ?\n\t\t\t\tapi.row( iRow ).node() :\n\t\t\t\tapi.rows().nodes().flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the array indexes of a particular cell from it's DOM element\n\t\t * and column index including hidden columns\n\t\t * @param {node} node this can either be a TR, TD or TH in the table's body\n\t\t * @returns {int} If nNode is given as a TR, then a single index is returned, or\n\t\t * if given as a cell, an array of [row index, column index (visible),\n\t\t * column index (all)] is given.\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * $('#example tbody td').click( function () {\n\t\t * // Get the position of the current data from the node\n\t\t * var aPos = oTable.fnGetPosition( this );\n\t\t *\n\t\t * // Get the data array for this row\n\t\t * var aData = oTable.fnGetData( aPos[0] );\n\t\t *\n\t\t * // Update the data array and return the value\n\t\t * aData[ aPos[1] ] = 'clicked';\n\t\t * this.innerHTML = 'clicked';\n\t\t * } );\n\t\t *\n\t\t * // Init DataTables\n\t\t * oTable = $('#example').dataTable();\n\t\t * } );\n\t\t */\n\t\tthis.fnGetPosition = function( node )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar nodeName = node.nodeName.toUpperCase();\n\t\t\n\t\t\tif ( nodeName == 'TR' ) {\n\t\t\t\treturn api.row( node ).index();\n\t\t\t}\n\t\t\telse if ( nodeName == 'TD' || nodeName == 'TH' ) {\n\t\t\t\tvar cell = api.cell( node ).index();\n\t\t\n\t\t\t\treturn [\n\t\t\t\t\tcell.row,\n\t\t\t\t\tcell.columnVisible,\n\t\t\t\t\tcell.column\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Check to see if a row is 'open' or not.\n\t\t * @param {node} nTr the table row to check\n\t\t * @returns {boolean} true if the row is currently open, false otherwise\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable;\n\t\t *\n\t\t * // 'open' an information row when a row is clicked on\n\t\t * $('#example tbody tr').click( function () {\n\t\t * if ( oTable.fnIsOpen(this) ) {\n\t\t * oTable.fnClose( this );\n\t\t * } else {\n\t\t * oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t * }\n\t\t * } );\n\t\t *\n\t\t * oTable = $('#example').dataTable();\n\t\t * } );\n\t\t */\n\t\tthis.fnIsOpen = function( nTr )\n\t\t{\n\t\t\treturn this.api( true ).row( nTr ).child.isShown();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will place a new row directly after a row which is currently\n\t\t * on display on the page, with the HTML contents that is passed into the\n\t\t * function. This can be used, for example, to ask for confirmation that a\n\t\t * particular record should be deleted.\n\t\t * @param {node} nTr The table row to 'open'\n\t\t * @param {string|node|jQuery} mHtml The HTML to put into the row\n\t\t * @param {string} sClass Class to give the new TD cell\n\t\t * @returns {node} The row opened. Note that if the table row passed in as the\n\t\t * first parameter, is not found in the table, this method will silently\n\t\t * return.\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable;\n\t\t *\n\t\t * // 'open' an information row when a row is clicked on\n\t\t * $('#example tbody tr').click( function () {\n\t\t * if ( oTable.fnIsOpen(this) ) {\n\t\t * oTable.fnClose( this );\n\t\t * } else {\n\t\t * oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t * }\n\t\t * } );\n\t\t *\n\t\t * oTable = $('#example').dataTable();\n\t\t * } );\n\t\t */\n\t\tthis.fnOpen = function( nTr, mHtml, sClass )\n\t\t{\n\t\t\treturn this.api( true )\n\t\t\t\t.row( nTr )\n\t\t\t\t.child( mHtml, sClass )\n\t\t\t\t.show()\n\t\t\t\t.child()[0];\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Change the pagination - provides the internal logic for pagination in a simple API\n\t\t * function. With this function you can have a DataTables table go to the next,\n\t\t * previous, first or last pages.\n\t\t * @param {string|int} mAction Paging action to take: \"first\", \"previous\", \"next\" or \"last\"\n\t\t * or page number to jump to (integer), note that page 0 is the first page.\n\t\t * @param {bool} [bRedraw=true] Redraw the table or not\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t * oTable.fnPageChange( 'next' );\n\t\t * } );\n\t\t */\n\t\tthis.fnPageChange = function ( mAction, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).page( mAction );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw(false);\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Show a particular column\n\t\t * @param {int} iCol The column whose display should be changed\n\t\t * @param {bool} bShow Show (true) or hide (false) the column\n\t\t * @param {bool} [bRedraw=true] Redraw the table or not\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t *\n\t\t * // Hide the second column after initialisation\n\t\t * oTable.fnSetColumnVis( 1, false );\n\t\t * } );\n\t\t */\n\t\tthis.fnSetColumnVis = function ( iCol, bShow, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).column( iCol ).visible( bShow );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.columns.adjust().draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the settings for a particular table for external manipulation\n\t\t * @returns {object} DataTables settings object. See\n\t\t * {@link DataTable.models.oSettings}\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t * var oSettings = oTable.fnSettings();\n\t\t *\n\t\t * // Show an example parameter from the settings\n\t\t * alert( oSettings._iDisplayStart );\n\t\t * } );\n\t\t */\n\t\tthis.fnSettings = function()\n\t\t{\n\t\t\treturn _fnSettingsFromNode( this[_ext.iApiIndex] );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Sort the table by a particular column\n\t\t * @param {int} iCol the data index to sort on. Note that this will not match the\n\t\t * 'display index' if you have hidden data entries\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t *\n\t\t * // Sort immediately with columns 0 and 1\n\t\t * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );\n\t\t * } );\n\t\t */\n\t\tthis.fnSort = function( aaSort )\n\t\t{\n\t\t\tthis.api( true ).order( aaSort ).draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Attach a sort listener to an element for a given column\n\t\t * @param {node} nNode the element to attach the sort listener to\n\t\t * @param {int} iColumn the column that a click on this node will sort on\n\t\t * @param {function} [fnCallback] callback function when sort is run\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t *\n\t\t * // Sort on column 1, when 'sorter' is clicked on\n\t\t * oTable.fnSortListener( document.getElementById('sorter'), 1 );\n\t\t * } );\n\t\t */\n\t\tthis.fnSortListener = function( nNode, iColumn, fnCallback )\n\t\t{\n\t\t\tthis.api( true ).order.listener( nNode, iColumn, fnCallback );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Update a table cell or row - this method will accept either a single value to\n\t\t * update the cell with, an array of values with one element for each column or\n\t\t * an object in the same format as the original data source. The function is\n\t\t * self-referencing in order to make the multi column updates easier.\n\t\t * @param {object|array|string} mData Data to update the cell/row with\n\t\t * @param {node|int} mRow TR element you want to update or the aoData index\n\t\t * @param {int} [iColumn] The column to update, give as null or undefined to\n\t\t * update a whole row.\n\t\t * @param {bool} [bRedraw=true] Redraw the table or not\n\t\t * @param {bool} [bAction=true] Perform pre-draw actions or not\n\t\t * @returns {int} 0 on success, 1 on error\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell\n\t\t * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row\n\t\t * } );\n\t\t */\n\t\tthis.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === undefined || iColumn === null ) {\n\t\t\t\tapi.row( mRow ).data( mData );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.cell( mRow, iColumn ).data( mData );\n\t\t\t}\n\t\t\n\t\t\tif ( bAction === undefined || bAction ) {\n\t\t\t\tapi.columns.adjust();\n\t\t\t}\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Provide a common method for plug-ins to check the version of DataTables being used, in order\n\t\t * to ensure compatibility.\n\t\t * @param {string} sVersion Version string to check for, in the format \"X.Y.Z\". Note that the\n\t\t * formats \"X\" and \"X.Y\" are also acceptable.\n\t\t * @returns {boolean} true if this version of DataTables is greater or equal to the required\n\t\t * version, or false if this version of DataTales is not suitable\n\t\t * @method\n\t\t * @dtopt API\n\t\t * @deprecated Since v1.10\n\t\t *\n\t\t * @example\n\t\t * $(document).ready(function() {\n\t\t * var oTable = $('#example').dataTable();\n\t\t * alert( oTable.fnVersionCheck( '1.9.0' ) );\n\t\t * } );\n\t\t */\n\t\tthis.fnVersionCheck = _ext.fnVersionCheck;\n\t\t\n\n\t\tvar _that = this;\n\t\tvar emptyInit = options === undefined;\n\t\tvar len = this.length;\n\n\t\tif ( emptyInit ) {\n\t\t\toptions = {};\n\t\t}\n\n\t\tthis.oApi = this.internal = _ext.internal;\n\n\t\t// Extend with old style plug-in API methods\n\t\tfor ( var fn in DataTable.ext.internal ) {\n\t\t\tif ( fn ) {\n\t\t\t\tthis[fn] = _fnExternApiFunc(fn);\n\t\t\t}\n\t\t}\n\n\t\tthis.each(function() {\n\t\t\t// For each initialisation we want to give it a clean initialisation\n\t\t\t// object that can be bashed around\n\t\t\tvar o = {};\n\t\t\tvar oInit = len > 1 ? // optimisation for single table case\n\t\t\t\t_fnExtend( o, options, true ) :\n\t\t\t\toptions;\n\n\t\t\t/*global oInit,_that,emptyInit*/\n\t\t\tvar i=0, iLen, j, jLen, k, kLen;\n\t\t\tvar sId = this.getAttribute( 'id' );\n\t\t\tvar bInitHandedOff = false;\n\t\t\tvar defaults = DataTable.defaults;\n\t\t\tvar $this = $(this);\n\t\t\t\n\t\t\t\n\t\t\t/* Sanity check */\n\t\t\tif ( this.nodeName.toLowerCase() != 'table' )\n\t\t\t{\n\t\t\t\t_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t/* Backwards compatibility for the defaults */\n\t\t\t_fnCompatOpts( defaults );\n\t\t\t_fnCompatCols( defaults.column );\n\t\t\t\n\t\t\t/* Convert the camel-case defaults to Hungarian */\n\t\t\t_fnCamelToHungarian( defaults, defaults, true );\n\t\t\t_fnCamelToHungarian( defaults.column, defaults.column, true );\n\t\t\t\n\t\t\t/* Setting up the initialisation object */\n\t\t\t_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true );\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t/* Check to see if we are re-initialising a table */\n\t\t\tvar allSettings = DataTable.settings;\n\t\t\tfor ( i=0, iLen=allSettings.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tvar s = allSettings[i];\n\t\t\t\n\t\t\t\t/* Base check on table node */\n\t\t\t\tif (\n\t\t\t\t\ts.nTable == this ||\n\t\t\t\t\t(s.nTHead && s.nTHead.parentNode == this) ||\n\t\t\t\t\t(s.nTFoot && s.nTFoot.parentNode == this)\n\t\t\t\t) {\n\t\t\t\t\tvar bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;\n\t\t\t\t\tvar bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;\n\t\t\t\n\t\t\t\t\tif ( emptyInit || bRetrieve )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn s.oInstance;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( bDestroy )\n\t\t\t\t\t{\n\t\t\t\t\t\ts.oInstance.fnDestroy();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* If the element we are initialising has the same ID as a table which was previously\n\t\t\t\t * initialised, but the table nodes don't match (from before) then we destroy the old\n\t\t\t\t * instance by simply deleting it. This is under the assumption that the table has been\n\t\t\t\t * destroyed by other methods. Anyone using non-id selectors will need to do this manually\n\t\t\t\t */\n\t\t\t\tif ( s.sTableId == this.id )\n\t\t\t\t{\n\t\t\t\t\tallSettings.splice( i, 1 );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Ensure the table has an ID - required for accessibility */\n\t\t\tif ( sId === null || sId === \"\" )\n\t\t\t{\n\t\t\t\tsId = \"DataTables_Table_\"+(DataTable.ext._unique++);\n\t\t\t\tthis.id = sId;\n\t\t\t}\n\t\t\t\n\t\t\t/* Create the settings object for this table and set some of the default parameters */\n\t\t\tvar oSettings = $.extend( true, {}, DataTable.models.oSettings, {\n\t\t\t\t\"sDestroyWidth\": $this[0].style.width,\n\t\t\t\t\"sInstance\": sId,\n\t\t\t\t\"sTableId\": sId\n\t\t\t} );\n\t\t\toSettings.nTable = this;\n\t\t\toSettings.oApi = _that.internal;\n\t\t\toSettings.oInit = oInit;\n\t\t\t\n\t\t\tallSettings.push( oSettings );\n\t\t\t\n\t\t\t// Need to add the instance after the instance after the settings object has been added\n\t\t\t// to the settings array, so we can self reference the table instance if more than one\n\t\t\toSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();\n\t\t\t\n\t\t\t// Backwards compatibility, before we apply all the defaults\n\t\t\t_fnCompatOpts( oInit );\n\t\t\t_fnLanguageCompat( oInit.oLanguage );\n\t\t\t\n\t\t\t// If the length menu is given, but the init display length is not, use the length menu\n\t\t\tif ( oInit.aLengthMenu && ! oInit.iDisplayLength )\n\t\t\t{\n\t\t\t\toInit.iDisplayLength = Array.isArray( oInit.aLengthMenu[0] ) ?\n\t\t\t\t\toInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];\n\t\t\t}\n\t\t\t\n\t\t\t// Apply the defaults and init options to make a single init object will all\n\t\t\t// options defined from defaults and instance options.\n\t\t\toInit = _fnExtend( $.extend( true, {}, defaults ), oInit );\n\t\t\t\n\t\t\t\n\t\t\t// Map the initialisation options onto the settings object\n\t\t\t_fnMap( oSettings.oFeatures, oInit, [\n\t\t\t\t\"bPaginate\",\n\t\t\t\t\"bLengthChange\",\n\t\t\t\t\"bFilter\",\n\t\t\t\t\"bSort\",\n\t\t\t\t\"bSortMulti\",\n\t\t\t\t\"bInfo\",\n\t\t\t\t\"bProcessing\",\n\t\t\t\t\"bAutoWidth\",\n\t\t\t\t\"bSortClasses\",\n\t\t\t\t\"bServerSide\",\n\t\t\t\t\"bDeferRender\"\n\t\t\t] );\n\t\t\t_fnMap( oSettings, oInit, [\n\t\t\t\t\"asStripeClasses\",\n\t\t\t\t\"ajax\",\n\t\t\t\t\"fnServerData\",\n\t\t\t\t\"fnFormatNumber\",\n\t\t\t\t\"sServerMethod\",\n\t\t\t\t\"aaSorting\",\n\t\t\t\t\"aaSortingFixed\",\n\t\t\t\t\"aLengthMenu\",\n\t\t\t\t\"sPaginationType\",\n\t\t\t\t\"sAjaxSource\",\n\t\t\t\t\"sAjaxDataProp\",\n\t\t\t\t\"iStateDuration\",\n\t\t\t\t\"sDom\",\n\t\t\t\t\"bSortCellsTop\",\n\t\t\t\t\"iTabIndex\",\n\t\t\t\t\"fnStateLoadCallback\",\n\t\t\t\t\"fnStateSaveCallback\",\n\t\t\t\t\"renderer\",\n\t\t\t\t\"searchDelay\",\n\t\t\t\t\"rowId\",\n\t\t\t\t[ \"iCookieDuration\", \"iStateDuration\" ], // backwards compat\n\t\t\t\t[ \"oSearch\", \"oPreviousSearch\" ],\n\t\t\t\t[ \"aoSearchCols\", \"aoPreSearchCols\" ],\n\t\t\t\t[ \"iDisplayLength\", \"_iDisplayLength\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oScroll, oInit, [\n\t\t\t\t[ \"sScrollX\", \"sX\" ],\n\t\t\t\t[ \"sScrollXInner\", \"sXInner\" ],\n\t\t\t\t[ \"sScrollY\", \"sY\" ],\n\t\t\t\t[ \"bScrollCollapse\", \"bCollapse\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oLanguage, oInit, \"fnInfoCallback\" );\n\t\t\t\n\t\t\t/* Callback functions which are array driven */\n\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );\n\t\t\t\n\t\t\toSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );\n\t\t\t\n\t\t\t/* Browser support detection */\n\t\t\t_fnBrowserDetect( oSettings );\n\t\t\t\n\t\t\tvar oClasses = oSettings.oClasses;\n\t\t\t\n\t\t\t$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );\n\t\t\t$this.addClass( oClasses.sTable );\n\t\t\t\n\t\t\t\n\t\t\tif ( oSettings.iInitDisplayStart === undefined )\n\t\t\t{\n\t\t\t\t/* Display start point, taking into account the save saving */\n\t\t\t\toSettings.iInitDisplayStart = oInit.iDisplayStart;\n\t\t\t\toSettings._iDisplayStart = oInit.iDisplayStart;\n\t\t\t}\n\t\t\t\n\t\t\tif ( oInit.iDeferLoading !== null )\n\t\t\t{\n\t\t\t\toSettings.bDeferLoading = true;\n\t\t\t\tvar tmp = Array.isArray( oInit.iDeferLoading );\n\t\t\t\toSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;\n\t\t\t\toSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;\n\t\t\t}\n\t\t\t\n\t\t\t/* Language definitions */\n\t\t\tvar oLanguage = oSettings.oLanguage;\n\t\t\t$.extend( true, oLanguage, oInit.oLanguage );\n\t\t\t\n\t\t\tif ( oLanguage.sUrl )\n\t\t\t{\n\t\t\t\t/* Get the language definitions from a file - because this Ajax call makes the language\n\t\t\t\t * get async to the remainder of this function we use bInitHandedOff to indicate that\n\t\t\t\t * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor\n\t\t\t\t */\n\t\t\t\t$.ajax( {\n\t\t\t\t\tdataType: 'json',\n\t\t\t\t\turl: oLanguage.sUrl,\n\t\t\t\t\tsuccess: function ( json ) {\n\t\t\t\t\t\t_fnCamelToHungarian( defaults.oLanguage, json );\n\t\t\t\t\t\t_fnLanguageCompat( json );\n\t\t\t\t\t\t$.extend( true, oLanguage, json );\n\t\t\t\n\t\t\t\t\t\t_fnCallbackFire( oSettings, null, 'i18n', [oSettings]);\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t},\n\t\t\t\t\terror: function () {\n\t\t\t\t\t\t// Error occurred loading language file, continue on as best we can\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\tbInitHandedOff = true;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnCallbackFire( oSettings, null, 'i18n', [oSettings]);\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Stripes\n\t\t\t */\n\t\t\tif ( oInit.asStripeClasses === null )\n\t\t\t{\n\t\t\t\toSettings.asStripeClasses =[\n\t\t\t\t\toClasses.sStripeOdd,\n\t\t\t\t\toClasses.sStripeEven\n\t\t\t\t];\n\t\t\t}\n\t\t\t\n\t\t\t/* Remove row stripe classes if they are already on the table row */\n\t\t\tvar stripeClasses = oSettings.asStripeClasses;\n\t\t\tvar rowOne = $this.children('tbody').find('tr').eq(0);\n\t\t\tif ( $.inArray( true, $.map( stripeClasses, function(el, i) {\n\t\t\t\treturn rowOne.hasClass(el);\n\t\t\t} ) ) !== -1 ) {\n\t\t\t\t$('tbody tr', this).removeClass( stripeClasses.join(' ') );\n\t\t\t\toSettings.asDestroyStripes = stripeClasses.slice();\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Columns\n\t\t\t * See if we should load columns automatically or use defined ones\n\t\t\t */\n\t\t\tvar anThs = [];\n\t\t\tvar aoColumnsInit;\n\t\t\tvar nThead = this.getElementsByTagName('thead');\n\t\t\tif ( nThead.length !== 0 )\n\t\t\t{\n\t\t\t\t_fnDetectHeader( oSettings.aoHeader, nThead[0] );\n\t\t\t\tanThs = _fnGetUniqueThs( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* If not given a column array, generate one with nulls */\n\t\t\tif ( oInit.aoColumns === null )\n\t\t\t{\n\t\t\t\taoColumnsInit = [];\n\t\t\t\tfor ( i=0, iLen=anThs.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\taoColumnsInit.push( null );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taoColumnsInit = oInit.aoColumns;\n\t\t\t}\n\t\t\t\n\t\t\t/* Add the columns */\n\t\t\tfor ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t_fnAddColumn( oSettings, anThs ? anThs[i] : null );\n\t\t\t}\n\t\t\t\n\t\t\t/* Apply the column definitions */\n\t\t\t_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {\n\t\t\t\t_fnColumnOptions( oSettings, iCol, oDef );\n\t\t\t} );\n\t\t\t\n\t\t\t/* HTML5 attribute detection - build an mData object automatically if the\n\t\t\t * attributes are found\n\t\t\t */\n\t\t\tif ( rowOne.length ) {\n\t\t\t\tvar a = function ( cell, name ) {\n\t\t\t\t\treturn cell.getAttribute( 'data-'+name ) !== null ? name : null;\n\t\t\t\t};\n\t\t\t\n\t\t\t\t$( rowOne[0] ).children('th, td').each( function (i, cell) {\n\t\t\t\t\tvar col = oSettings.aoColumns[i];\n\t\t\t\n\t\t\t\t\tif ( col.mData === i ) {\n\t\t\t\t\t\tvar sort = a( cell, 'sort' ) || a( cell, 'order' );\n\t\t\t\t\t\tvar filter = a( cell, 'filter' ) || a( cell, 'search' );\n\t\t\t\n\t\t\t\t\t\tif ( sort !== null || filter !== null ) {\n\t\t\t\t\t\t\tcol.mData = {\n\t\t\t\t\t\t\t\t_: i+'.display',\n\t\t\t\t\t\t\t\tsort: sort !== null ? i+'.@data-'+sort : undefined,\n\t\t\t\t\t\t\t\ttype: sort !== null ? i+'.@data-'+sort : undefined,\n\t\t\t\t\t\t\t\tfilter: filter !== null ? i+'.@data-'+filter : undefined\n\t\t\t\t\t\t\t};\n\t\t\t\n\t\t\t\t\t\t\t_fnColumnOptions( oSettings, i );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\t\n\t\t\tvar features = oSettings.oFeatures;\n\t\t\tvar loadedInit = function () {\n\t\t\t\t/*\n\t\t\t\t * Sorting\n\t\t\t\t * @todo For modularisation (1.11) this needs to do into a sort start up handler\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// If aaSorting is not defined, then we use the first indicator in asSorting\n\t\t\t\t// in case that has been altered, so the default sort reflects that option\n\t\t\t\tif ( oInit.aaSorting === undefined ) {\n\t\t\t\t\tvar sorting = oSettings.aaSorting;\n\t\t\t\t\tfor ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {\n\t\t\t\t\t\tsorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Do a first pass on the sorting classes (allows any size changes to be taken into\n\t\t\t\t * account, and also will apply sorting disabled classes if disabled\n\t\t\t\t */\n\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\n\t\t\t\tif ( features.bSort ) {\n\t\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\t\tif ( oSettings.bSorted ) {\n\t\t\t\t\t\t\tvar aSort = _fnSortFlatten( oSettings );\n\t\t\t\t\t\t\tvar sortedColumns = {};\n\t\t\t\n\t\t\t\t\t\t\t$.each( aSort, function (i, val) {\n\t\t\t\t\t\t\t\tsortedColumns[ val.src ] = val.dir;\n\t\t\t\t\t\t\t} );\n\t\t\t\n\t\t\t\t\t\t\t_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );\n\t\t\t\t\t\t\t_fnSortAria( oSettings );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\tif ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {\n\t\t\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\t\t}\n\t\t\t\t}, 'sc' );\n\t\t\t\n\t\t\t\n\t\t\t\t/*\n\t\t\t\t * Final init\n\t\t\t\t * Cache the header, body and footer as required, creating them if needed\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// Work around for Webkit bug 83867 - store the caption-side before removing from doc\n\t\t\t\tvar captions = $this.children('caption').each( function () {\n\t\t\t\t\tthis._captionSide = $(this).css('caption-side');\n\t\t\t\t} );\n\t\t\t\n\t\t\t\tvar thead = $this.children('thead');\n\t\t\t\tif ( thead.length === 0 ) {\n\t\t\t\t\tthead = $('<thead/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTHead = thead[0];\n\t\t\t\n\t\t\t\tvar tbody = $this.children('tbody');\n\t\t\t\tif ( tbody.length === 0 ) {\n\t\t\t\t\ttbody = $('<tbody/>').insertAfter(thead);\n\t\t\t\t}\n\t\t\t\toSettings.nTBody = tbody[0];\n\t\t\t\n\t\t\t\tvar tfoot = $this.children('tfoot');\n\t\t\t\tif ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== \"\" || oSettings.oScroll.sY !== \"\") ) {\n\t\t\t\t\t// If we are a scrolling table, and no footer has been given, then we need to create\n\t\t\t\t\t// a tfoot element for the caption element to be appended to\n\t\t\t\t\ttfoot = $('<tfoot/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( tfoot.length === 0 || tfoot.children().length === 0 ) {\n\t\t\t\t\t$this.addClass( oClasses.sNoFooter );\n\t\t\t\t}\n\t\t\t\telse if ( tfoot.length > 0 ) {\n\t\t\t\t\toSettings.nTFoot = tfoot[0];\n\t\t\t\t\t_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Check if there is data passing into the constructor */\n\t\t\t\tif ( oInit.aaData ) {\n\t\t\t\t\tfor ( i=0 ; i<oInit.aaData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( oSettings, oInit.aaData[ i ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {\n\t\t\t\t\t/* Grab the data from the page - only do this when deferred loading or no Ajax\n\t\t\t\t\t * source since there is no point in reading the DOM data if we are then going\n\t\t\t\t\t * to replace it with Ajax data\n\t\t\t\t\t */\n\t\t\t\t\t_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Copy the data index array */\n\t\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\n\t\t\t\t/* Initialisation complete - table can be drawn */\n\t\t\t\toSettings.bInitialised = true;\n\t\t\t\n\t\t\t\t/* Check if we need to initialise the table (it might not have been handed off to the\n\t\t\t\t * language processor)\n\t\t\t\t */\n\t\t\t\tif ( bInitHandedOff === false ) {\n\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t}\n\t\t\t};\n\t\t\t\n\t\t\t/* Must be done after everything which can be overridden by the state saving! */\n\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );\n\t\t\t\n\t\t\tif ( oInit.bStateSave )\n\t\t\t{\n\t\t\t\tfeatures.bStateSave = true;\n\t\t\t\t_fnLoadState( oSettings, oInit, loadedInit );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadedInit();\n\t\t\t}\n\t\t\t\n\t\t} );\n\t\t_that = null;\n\t\treturn this;\n\t};\n\n\t\n\t/*\n\t * It is useful to have variables which are scoped locally so only the\n\t * DataTables functions can access them and they don't leak into global space.\n\t * At the same time these functions are often useful over multiple files in the\n\t * core and API, so we list, or at least document, all variables which are used\n\t * by DataTables as private variables here. This also ensures that there is no\n\t * clashing of variable names and that they can easily referenced for reuse.\n\t */\n\t\n\t\n\t// Defined else where\n\t// _selector_run\n\t// _selector_opts\n\t// _selector_first\n\t// _selector_row_indexes\n\t\n\tvar _ext; // DataTable.ext\n\tvar _Api; // DataTable.Api\n\tvar _api_register; // DataTable.Api.register\n\tvar _api_registerPlural; // DataTable.Api.registerPlural\n\t\n\tvar _re_dic = {};\n\tvar _re_new_lines = /[\\r\\n\\u2028]/g;\n\tvar _re_html = /<.*?>/g;\n\t\n\t// This is not strict ISO8601 - Date.parse() is quite lax, although\n\t// implementations differ between browsers.\n\tvar _re_date = /^\\d{2,4}[\\.\\/\\-]\\d{1,2}[\\.\\/\\-]\\d{1,2}([T ]{1}\\d{1,2}[:\\.]\\d{2}([\\.:]\\d{2})?)?$/;\n\t\n\t// Escape regular expression special characters\n\tvar _re_escape_regex = new RegExp( '(\\\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\\\', '$', '^', '-' ].join('|\\\\') + ')', 'g' );\n\t\n\t// http://en.wikipedia.org/wiki/Foreign_exchange_market\n\t// - \\u20BD - Russian ruble.\n\t// - \\u20a9 - South Korean Won\n\t// - \\u20BA - Turkish Lira\n\t// - \\u20B9 - Indian Rupee\n\t// - R - Brazil (R$) and South Africa\n\t// - fr - Swiss Franc\n\t// - kr - Swedish krona, Norwegian krone and Danish krone\n\t// - \\u2009 is thin space and \\u202F is narrow no-break space, both used in many\n\t// - Ƀ - Bitcoin\n\t// - Ξ - Ethereum\n\t// standards as thousands separators.\n\tvar _re_formatted_numeric = /['\\u00A0,$£€¥%\\u2009\\u202F\\u20BD\\u20a9\\u20BArfkɃΞ]/gi;\n\t\n\t\n\tvar _empty = function ( d ) {\n\t\treturn !d || d === true || d === '-' ? true : false;\n\t};\n\t\n\t\n\tvar _intVal = function ( s ) {\n\t\tvar integer = parseInt( s, 10 );\n\t\treturn !isNaN(integer) && isFinite(s) ? integer : null;\n\t};\n\t\n\t// Convert from a formatted number with characters other than `.` as the\n\t// decimal place, to a Javascript number\n\tvar _numToDecimal = function ( num, decimalPoint ) {\n\t\t// Cache created regular expressions for speed as this function is called often\n\t\tif ( ! _re_dic[ decimalPoint ] ) {\n\t\t\t_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );\n\t\t}\n\t\treturn typeof num === 'string' && decimalPoint !== '.' ?\n\t\t\tnum.replace( /\\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :\n\t\t\tnum;\n\t};\n\t\n\t\n\tvar _isNumber = function ( d, decimalPoint, formatted ) {\n\t\tvar strType = typeof d === 'string';\n\t\n\t\t// If empty return immediately so there must be a number if it is a\n\t\t// formatted string (this stops the string \"k\", or \"kr\", etc being detected\n\t\t// as a formatted number for currency\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tif ( decimalPoint && strType ) {\n\t\t\td = _numToDecimal( d, decimalPoint );\n\t\t}\n\t\n\t\tif ( formatted && strType ) {\n\t\t\td = d.replace( _re_formatted_numeric, '' );\n\t\t}\n\t\n\t\treturn !isNaN( parseFloat(d) ) && isFinite( d );\n\t};\n\t\n\t\n\t// A string without HTML in it can be considered to be HTML still\n\tvar _isHtml = function ( d ) {\n\t\treturn _empty( d ) || typeof d === 'string';\n\t};\n\t\n\t\n\tvar _htmlNumeric = function ( d, decimalPoint, formatted ) {\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tvar html = _isHtml( d );\n\t\treturn ! html ?\n\t\t\tnull :\n\t\t\t_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?\n\t\t\t\ttrue :\n\t\t\t\tnull;\n\t};\n\t\n\t\n\tvar _pluck = function ( a, prop, prop2 ) {\n\t\tvar out = [];\n\t\tvar i=0, ien=a.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] && a[i][ prop ] ) {\n\t\t\t\t\tout.push( a[i][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] ) {\n\t\t\t\t\tout.push( a[i][ prop ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t// Basically the same as _pluck, but rather than looping over `a` we use `order`\n\t// as the indexes to pick from `a`\n\tvar _pluck_order = function ( a, order, prop, prop2 )\n\t{\n\t\tvar out = [];\n\t\tvar i=0, ien=order.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[ order[i] ][ prop ] ) {\n\t\t\t\t\tout.push( a[ order[i] ][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tout.push( a[ order[i] ][ prop ] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _range = function ( len, start )\n\t{\n\t\tvar out = [];\n\t\tvar end;\n\t\n\t\tif ( start === undefined ) {\n\t\t\tstart = 0;\n\t\t\tend = len;\n\t\t}\n\t\telse {\n\t\t\tend = start;\n\t\t\tstart = len;\n\t\t}\n\t\n\t\tfor ( var i=start ; i<end ; i++ ) {\n\t\t\tout.push( i );\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _removeEmpty = function ( a )\n\t{\n\t\tvar out = [];\n\t\n\t\tfor ( var i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\tif ( a[i] ) { // careful - will remove all falsy values!\n\t\t\t\tout.push( a[i] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _stripHtml = function ( d ) {\n\t\treturn d.replace( _re_html, '' );\n\t};\n\t\n\t\n\t/**\n\t * Determine if all values in the array are unique. This means we can short\n\t * cut the _unique method at the cost of a single loop. A sorted array is used\n\t * to easily check the values.\n\t *\n\t * @param {array} src Source array\n\t * @return {boolean} true if all unique, false otherwise\n\t * @ignore\n\t */\n\tvar _areAllUnique = function ( src ) {\n\t\tif ( src.length < 2 ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tvar sorted = src.slice().sort();\n\t\tvar last = sorted[0];\n\t\n\t\tfor ( var i=1, ien=sorted.length ; i<ien ; i++ ) {\n\t\t\tif ( sorted[i] === last ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\n\t\t\tlast = sorted[i];\n\t\t}\n\t\n\t\treturn true;\n\t};\n\t\n\t\n\t/**\n\t * Find the unique elements in a source array.\n\t *\n\t * @param {array} src Source array\n\t * @return {array} Array of unique items\n\t * @ignore\n\t */\n\tvar _unique = function ( src )\n\t{\n\t\tif ( _areAllUnique( src ) ) {\n\t\t\treturn src.slice();\n\t\t}\n\t\n\t\t// A faster unique method is to use object keys to identify used values,\n\t\t// but this doesn't work with arrays or objects, which we must also\n\t\t// consider. See jsperf.com/compare-array-unique-versions/4 for more\n\t\t// information.\n\t\tvar\n\t\t\tout = [],\n\t\t\tval,\n\t\t\ti, ien=src.length,\n\t\t\tj, k=0;\n\t\n\t\tagain: for ( i=0 ; i<ien ; i++ ) {\n\t\t\tval = src[i];\n\t\n\t\t\tfor ( j=0 ; j<k ; j++ ) {\n\t\t\t\tif ( out[j] === val ) {\n\t\t\t\t\tcontinue again;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tout.push( val );\n\t\t\tk++;\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t// Surprisingly this is faster than [].concat.apply\n\t// https://jsperf.com/flatten-an-array-loop-vs-reduce/2\n\tvar _flatten = function (out, val) {\n\t\tif (Array.isArray(val)) {\n\t\t\tfor (var i=0 ; i<val.length ; i++) {\n\t\t\t\t_flatten(out, val[i]);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tout.push(val);\n\t\t}\n\t \n\t\treturn out;\n\t}\n\t\n\tvar _includes = function (search, start) {\n\t\tif (start === undefined) {\n\t\t\tstart = 0;\n\t\t}\n\t\n\t\treturn this.indexOf(search, start) !== -1;\t\n\t};\n\t\n\t// Array.isArray polyfill.\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray\n\tif (! Array.isArray) {\n\t Array.isArray = function(arg) {\n\t return Object.prototype.toString.call(arg) === '[object Array]';\n\t };\n\t}\n\t\n\tif (! Array.prototype.includes) {\n\t\tArray.prototype.includes = _includes;\n\t}\n\t\n\t// .trim() polyfill\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim\n\tif (!String.prototype.trim) {\n\t String.prototype.trim = function () {\n\t return this.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n\t };\n\t}\n\t\n\tif (! String.prototype.includes) {\n\t\tString.prototype.includes = _includes;\n\t}\n\t\n\t/**\n\t * DataTables utility methods\n\t * \n\t * This namespace provides helper methods that DataTables uses internally to\n\t * create a DataTable, but which are not exclusively used only for DataTables.\n\t * These methods can be used by extension authors to save the duplication of\n\t * code.\n\t *\n\t * @namespace\n\t */\n\tDataTable.util = {\n\t\t/**\n\t\t * Throttle the calls to a function. Arguments and context are maintained\n\t\t * for the throttled function.\n\t\t *\n\t\t * @param {function} fn Function to be called\n\t\t * @param {integer} freq Call frequency in mS\n\t\t * @return {function} Wrapped function\n\t\t */\n\t\tthrottle: function ( fn, freq ) {\n\t\t\tvar\n\t\t\t\tfrequency = freq !== undefined ? freq : 200,\n\t\t\t\tlast,\n\t\t\t\ttimer;\n\t\n\t\t\treturn function () {\n\t\t\t\tvar\n\t\t\t\t\tthat = this,\n\t\t\t\t\tnow = +new Date(),\n\t\t\t\t\targs = arguments;\n\t\n\t\t\t\tif ( last && now < last + frequency ) {\n\t\t\t\t\tclearTimeout( timer );\n\t\n\t\t\t\t\ttimer = setTimeout( function () {\n\t\t\t\t\t\tlast = undefined;\n\t\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t\t}, frequency );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlast = now;\n\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Escape a string such that it can be used in a regular expression\n\t\t *\n\t\t * @param {string} val string to escape\n\t\t * @returns {string} escaped string\n\t\t */\n\t\tescapeRegex: function ( val ) {\n\t\t\treturn val.replace( _re_escape_regex, '\\\\$1' );\n\t\t},\n\t\n\t\t/**\n\t\t * Create a function that will write to a nested object or array\n\t\t * @param {*} source JSON notation string\n\t\t * @returns Write function\n\t\t */\n\t\tset: function ( source ) {\n\t\t\tif ( $.isPlainObject( source ) ) {\n\t\t\t\t/* Unlike get, only the underscore (global) option is used for for\n\t\t\t\t * setting data since we don't know the type here. This is why an object\n\t\t\t\t * option is not documented for `mData` (which is read/write), but it is\n\t\t\t\t * for `mRender` which is read only.\n\t\t\t\t */\n\t\t\t\treturn DataTable.util.set( source._ );\n\t\t\t}\n\t\t\telse if ( source === null ) {\n\t\t\t\t// Nothing to do when the data source is null\n\t\t\t\treturn function () {};\n\t\t\t}\n\t\t\telse if ( typeof source === 'function' ) {\n\t\t\t\treturn function (data, val, meta) {\n\t\t\t\t\tsource( data, 'set', val, meta );\n\t\t\t\t};\n\t\t\t}\n\t\t\telse if ( typeof source === 'string' && (source.indexOf('.') !== -1 ||\n\t\t\t\t\t source.indexOf('[') !== -1 || source.indexOf('(') !== -1) )\n\t\t\t{\n\t\t\t\t// Like the get, we need to get data from a nested object\n\t\t\t\tvar setData = function (data, val, src) {\n\t\t\t\t\tvar a = _fnSplitObjNotation( src ), b;\n\t\t\t\t\tvar aLast = a[a.length-1];\n\t\t\t\t\tvar arrayNotation, funcNotation, o, innerSrc;\n\t\t\n\t\t\t\t\tfor ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) {\n\t\t\t\t\t\t// Protect against prototype pollution\n\t\t\t\t\t\tif (a[i] === '__proto__' || a[i] === 'constructor') {\n\t\t\t\t\t\t\tthrow new Error('Cannot set prototype values');\n\t\t\t\t\t\t}\n\t\t\n\t\t\t\t\t\t// Check if we are dealing with an array notation request\n\t\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\t\n\t\t\t\t\t\tif ( arrayNotation ) {\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\t\t\t\t\t\tdata[ a[i] ] = [];\n\t\t\n\t\t\t\t\t\t\t// Get the remainder of the nested object to set so we can recurse\n\t\t\t\t\t\t\tb = a.slice();\n\t\t\t\t\t\t\tb.splice( 0, i+1 );\n\t\t\t\t\t\t\tinnerSrc = b.join('.');\n\t\t\n\t\t\t\t\t\t\t// Traverse each entry in the array setting the properties requested\n\t\t\t\t\t\t\tif ( Array.isArray( val ) ) {\n\t\t\t\t\t\t\t\tfor ( var j=0, jLen=val.length ; j<jLen ; j++ ) {\n\t\t\t\t\t\t\t\t\to = {};\n\t\t\t\t\t\t\t\t\tsetData( o, val[j], innerSrc );\n\t\t\t\t\t\t\t\t\tdata[ a[i] ].push( o );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t// We've been asked to save data to an array, but it\n\t\t\t\t\t\t\t\t// isn't array data to be saved. Best that can be done\n\t\t\t\t\t\t\t\t// is to just save the value.\n\t\t\t\t\t\t\t\tdata[ a[i] ] = val;\n\t\t\t\t\t\t\t}\n\t\t\n\t\t\t\t\t\t\t// The inner call to setData has already traversed through the remainder\n\t\t\t\t\t\t\t// of the source and has set the data, thus we can exit here\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( funcNotation ) {\n\t\t\t\t\t\t\t// Function call\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\t\tdata = data[ a[i] ]( val );\n\t\t\t\t\t\t}\n\t\t\n\t\t\t\t\t\t// If the nested object doesn't currently exist - since we are\n\t\t\t\t\t\t// trying to set the value - create it\n\t\t\t\t\t\tif ( data[ a[i] ] === null || data[ a[i] ] === undefined ) {\n\t\t\t\t\t\t\tdata[ a[i] ] = {};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t}\n\t\t\n\t\t\t\t\t// Last item in the input - i.e, the actual set\n\t\t\t\t\tif ( aLast.match(__reFn ) ) {\n\t\t\t\t\t\t// Function call\n\t\t\t\t\t\tdata = data[ aLast.replace(__reFn, '') ]( val );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// If array notation is used, we just want to strip it and use the property name\n\t\t\t\t\t\t// and assign the value. If it isn't used, then we get the result we want anyway\n\t\t\t\t\t\tdata[ aLast.replace(__reArray, '') ] = val;\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\n\t\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\t\treturn setData( data, val, source );\n\t\t\t\t};\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Array or flat object mapping\n\t\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\t\tdata[source] = val;\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t\n\t\t/**\n\t\t * Create a function that will read nested objects from arrays, based on JSON notation\n\t\t * @param {*} source JSON notation string\n\t\t * @returns Value read\n\t\t */\n\t\tget: function ( source ) {\n\t\t\tif ( $.isPlainObject( source ) ) {\n\t\t\t\t// Build an object of get functions, and wrap them in a single call\n\t\t\t\tvar o = {};\n\t\t\t\t$.each( source, function (key, val) {\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\to[key] = DataTable.util.get( val );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\n\t\t\t\treturn function (data, type, row, meta) {\n\t\t\t\t\tvar t = o[type] || o._;\n\t\t\t\t\treturn t !== undefined ?\n\t\t\t\t\t\tt(data, type, row, meta) :\n\t\t\t\t\t\tdata;\n\t\t\t\t};\n\t\t\t}\n\t\t\telse if ( source === null ) {\n\t\t\t\t// Give an empty string for rendering / sorting etc\n\t\t\t\treturn function (data) { // type, row and meta also passed, but not used\n\t\t\t\t\treturn data;\n\t\t\t\t};\n\t\t\t}\n\t\t\telse if ( typeof source === 'function' ) {\n\t\t\t\treturn function (data, type, row, meta) {\n\t\t\t\t\treturn source( data, type, row, meta );\n\t\t\t\t};\n\t\t\t}\n\t\t\telse if ( typeof source === 'string' && (source.indexOf('.') !== -1 ||\n\t\t\t\t\t source.indexOf('[') !== -1 || source.indexOf('(') !== -1) )\n\t\t\t{\n\t\t\t\t/* If there is a . in the source string then the data source is in a\n\t\t\t\t * nested object so we loop over the data for each level to get the next\n\t\t\t\t * level down. On each loop we test for undefined, and if found immediately\n\t\t\t\t * return. This allows entire objects to be missing and sDefaultContent to\n\t\t\t\t * be used if defined, rather than throwing an error\n\t\t\t\t */\n\t\t\t\tvar fetchData = function (data, type, src) {\n\t\t\t\t\tvar arrayNotation, funcNotation, out, innerSrc;\n\t\t\n\t\t\t\t\tif ( src !== \"\" ) {\n\t\t\t\t\t\tvar a = _fnSplitObjNotation( src );\n\t\t\n\t\t\t\t\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ ) {\n\t\t\t\t\t\t\t// Check if we are dealing with special notation\n\t\t\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\t\n\t\t\t\t\t\t\tif ( arrayNotation ) {\n\t\t\t\t\t\t\t\t// Array notation\n\t\t\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\t\n\t\t\t\t\t\t\t\t// Condition allows simply [] to be passed in\n\t\t\t\t\t\t\t\tif ( a[i] !== \"\" ) {\n\t\t\t\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tout = [];\n\t\t\n\t\t\t\t\t\t\t\t// Get the remainder of the nested object to get\n\t\t\t\t\t\t\t\ta.splice( 0, i+1 );\n\t\t\t\t\t\t\t\tinnerSrc = a.join('.');\n\t\t\n\t\t\t\t\t\t\t\t// Traverse each entry in the array getting the properties requested\n\t\t\t\t\t\t\t\tif ( Array.isArray( data ) ) {\n\t\t\t\t\t\t\t\t\tfor ( var j=0, jLen=data.length ; j<jLen ; j++ ) {\n\t\t\t\t\t\t\t\t\t\tout.push( fetchData( data[j], type, innerSrc ) );\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\n\t\t\t\t\t\t\t\t// If a string is given in between the array notation indicators, that\n\t\t\t\t\t\t\t\t// is used to join the strings together, otherwise an array is returned\n\t\t\t\t\t\t\t\tvar join = arrayNotation[0].substring(1, arrayNotation[0].length-1);\n\t\t\t\t\t\t\t\tdata = (join===\"\") ? out : out.join(join);\n\t\t\n\t\t\t\t\t\t\t\t// The inner call to fetchData has already traversed through the remainder\n\t\t\t\t\t\t\t\t// of the source requested, so we exit from the loop\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if ( funcNotation ) {\n\t\t\t\t\t\t\t\t// Function call\n\t\t\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\t\t\tdata = data[ a[i] ]();\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\n\t\t\t\t\t\t\tif ( data === null || data[ a[i] ] === undefined ) {\n\t\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\n\t\t\t\t\treturn data;\n\t\t\t\t};\n\t\t\n\t\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\t\treturn fetchData( data, type, source );\n\t\t\t\t};\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Array or flat object mapping\n\t\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\t\treturn data[source];\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\t\n\t/**\n\t * Create a mapping object that allows camel case parameters to be looked up\n\t * for their Hungarian counterparts. The mapping is stored in a private\n\t * parameter called `_hungarianMap` which can be accessed on the source object.\n\t * @param {object} o\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnHungarianMap ( o )\n\t{\n\t\tvar\n\t\t\thungarian = 'a aa ai ao as b fn i m o s ',\n\t\t\tmatch,\n\t\t\tnewKey,\n\t\t\tmap = {};\n\t\n\t\t$.each( o, function (key, val) {\n\t\t\tmatch = key.match(/^([^A-Z]+?)([A-Z])/);\n\t\n\t\t\tif ( match && hungarian.indexOf(match[1]+' ') !== -1 )\n\t\t\t{\n\t\t\t\tnewKey = key.replace( match[0], match[2].toLowerCase() );\n\t\t\t\tmap[ newKey ] = key;\n\t\n\t\t\t\tif ( match[1] === 'o' )\n\t\t\t\t{\n\t\t\t\t\t_fnHungarianMap( o[key] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t\n\t\to._hungarianMap = map;\n\t}\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian, based on a Hungarian map\n\t * created by _fnHungarianMap.\n\t * @param {object} src The model object which holds all parameters that can be\n\t * mapped.\n\t * @param {object} user The object to convert from camel case to Hungarian.\n\t * @param {boolean} force When set to `true`, properties which already have a\n\t * Hungarian value in the `user` object will be overwritten. Otherwise they\n\t * won't be.\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnCamelToHungarian ( src, user, force )\n\t{\n\t\tif ( ! src._hungarianMap ) {\n\t\t\t_fnHungarianMap( src );\n\t\t}\n\t\n\t\tvar hungarianKey;\n\t\n\t\t$.each( user, function (key, val) {\n\t\t\thungarianKey = src._hungarianMap[ key ];\n\t\n\t\t\tif ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )\n\t\t\t{\n\t\t\t\t// For objects, we need to buzz down into the object to copy parameters\n\t\t\t\tif ( hungarianKey.charAt(0) === 'o' )\n\t\t\t\t{\n\t\t\t\t\t// Copy the camelCase options over to the hungarian\n\t\t\t\t\tif ( ! user[ hungarianKey ] ) {\n\t\t\t\t\t\tuser[ hungarianKey ] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, user[hungarianKey], user[key] );\n\t\n\t\t\t\t\t_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tuser[hungarianKey] = user[ key ];\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Language compatibility - when certain options are given, and others aren't, we\n\t * need to duplicate the values over, in order to provide backwards compatibility\n\t * with older language files.\n\t * @param {object} oSettings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnLanguageCompat( lang )\n\t{\n\t\t// Note the use of the Hungarian notation for the parameters in this method as\n\t\t// this is called after the mapping of camelCase to Hungarian\n\t\tvar defaults = DataTable.defaults.oLanguage;\n\t\n\t\t// Default mapping\n\t\tvar defaultDecimal = defaults.sDecimal;\n\t\tif ( defaultDecimal ) {\n\t\t\t_addNumericSort( defaultDecimal );\n\t\t}\n\t\n\t\tif ( lang ) {\n\t\t\tvar zeroRecords = lang.sZeroRecords;\n\t\n\t\t\t// Backwards compatibility - if there is no sEmptyTable given, then use the same as\n\t\t\t// sZeroRecords - assuming that is given.\n\t\t\tif ( ! lang.sEmptyTable && zeroRecords &&\n\t\t\t\tdefaults.sEmptyTable === \"No data available in table\" )\n\t\t\t{\n\t\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );\n\t\t\t}\n\t\n\t\t\t// Likewise with loading records\n\t\t\tif ( ! lang.sLoadingRecords && zeroRecords &&\n\t\t\t\tdefaults.sLoadingRecords === \"Loading...\" )\n\t\t\t{\n\t\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );\n\t\t\t}\n\t\n\t\t\t// Old parameter name of the thousands separator mapped onto the new\n\t\t\tif ( lang.sInfoThousands ) {\n\t\t\t\tlang.sThousands = lang.sInfoThousands;\n\t\t\t}\n\t\n\t\t\tvar decimal = lang.sDecimal;\n\t\t\tif ( decimal && defaultDecimal !== decimal ) {\n\t\t\t\t_addNumericSort( decimal );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Map one parameter onto another\n\t * @param {object} o Object to map\n\t * @param {*} knew The new parameter name\n\t * @param {*} old The old parameter name\n\t */\n\tvar _fnCompatMap = function ( o, knew, old ) {\n\t\tif ( o[ knew ] !== undefined ) {\n\t\t\to[ old ] = o[ knew ];\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for the main DT options. Note that the new\n\t * options are mapped onto the old parameters, so this is an external interface\n\t * change only.\n\t * @param {object} init Object to map\n\t */\n\tfunction _fnCompatOpts ( init )\n\t{\n\t\t_fnCompatMap( init, 'ordering', 'bSort' );\n\t\t_fnCompatMap( init, 'orderMulti', 'bSortMulti' );\n\t\t_fnCompatMap( init, 'orderClasses', 'bSortClasses' );\n\t\t_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );\n\t\t_fnCompatMap( init, 'order', 'aaSorting' );\n\t\t_fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );\n\t\t_fnCompatMap( init, 'paging', 'bPaginate' );\n\t\t_fnCompatMap( init, 'pagingType', 'sPaginationType' );\n\t\t_fnCompatMap( init, 'pageLength', 'iDisplayLength' );\n\t\t_fnCompatMap( init, 'searching', 'bFilter' );\n\t\n\t\t// Boolean initialisation of x-scrolling\n\t\tif ( typeof init.sScrollX === 'boolean' ) {\n\t\t\tinit.sScrollX = init.sScrollX ? '100%' : '';\n\t\t}\n\t\tif ( typeof init.scrollX === 'boolean' ) {\n\t\t\tinit.scrollX = init.scrollX ? '100%' : '';\n\t\t}\n\t\n\t\t// Column search objects are in an array, so it needs to be converted\n\t\t// element by element\n\t\tvar searchCols = init.aoSearchCols;\n\t\n\t\tif ( searchCols ) {\n\t\t\tfor ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {\n\t\t\t\tif ( searchCols[i] ) {\n\t\t\t\t\t_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for column options. Note that the new options\n\t * are mapped onto the old parameters, so this is an external interface change\n\t * only.\n\t * @param {object} init Object to map\n\t */\n\tfunction _fnCompatCols ( init )\n\t{\n\t\t_fnCompatMap( init, 'orderable', 'bSortable' );\n\t\t_fnCompatMap( init, 'orderData', 'aDataSort' );\n\t\t_fnCompatMap( init, 'orderSequence', 'asSorting' );\n\t\t_fnCompatMap( init, 'orderDataType', 'sortDataType' );\n\t\n\t\t// orderData can be given as an integer\n\t\tvar dataSort = init.aDataSort;\n\t\tif ( typeof dataSort === 'number' && ! Array.isArray( dataSort ) ) {\n\t\t\tinit.aDataSort = [ dataSort ];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Browser feature detection for capabilities, quirks\n\t * @param {object} settings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnBrowserDetect( settings )\n\t{\n\t\t// We don't need to do this every time DataTables is constructed, the values\n\t\t// calculated are specific to the browser and OS configuration which we\n\t\t// don't expect to change between initialisations\n\t\tif ( ! DataTable.__browser ) {\n\t\t\tvar browser = {};\n\t\t\tDataTable.__browser = browser;\n\t\n\t\t\t// Scrolling feature / quirks detection\n\t\t\tvar n = $('<div/>')\n\t\t\t\t.css( {\n\t\t\t\t\tposition: 'fixed',\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tleft: $(window).scrollLeft()*-1, // allow for scrolling\n\t\t\t\t\theight: 1,\n\t\t\t\t\twidth: 1,\n\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t} )\n\t\t\t\t.append(\n\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\ttop: 1,\n\t\t\t\t\t\t\tleft: 1,\n\t\t\t\t\t\t\twidth: 100,\n\t\t\t\t\t\t\toverflow: 'scroll'\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\t\t\t\theight: 10\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t.appendTo( 'body' );\n\t\n\t\t\tvar outer = n.children();\n\t\t\tvar inner = outer.children();\n\t\n\t\t\t// Numbers below, in order, are:\n\t\t\t// inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth\n\t\t\t//\n\t\t\t// IE6 XP: 100 100 100 83\n\t\t\t// IE7 Vista: 100 100 100 83\n\t\t\t// IE 8+ Windows: 83 83 100 83\n\t\t\t// Evergreen Windows: 83 83 100 83\n\t\t\t// Evergreen Mac with scrollbars: 85 85 100 85\n\t\t\t// Evergreen Mac without scrollbars: 100 100 100 100\n\t\n\t\t\t// Get scrollbar width\n\t\t\tbrowser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;\n\t\n\t\t\t// IE6/7 will oversize a width 100% element inside a scrolling element, to\n\t\t\t// include the width of the scrollbar, while other browsers ensure the inner\n\t\t\t// element is contained without forcing scrolling\n\t\t\tbrowser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;\n\t\n\t\t\t// In rtl text layout, some browsers (most, but not all) will place the\n\t\t\t// scrollbar on the left, rather than the right.\n\t\t\tbrowser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;\n\t\n\t\t\t// IE8- don't provide height and width for getBoundingClientRect\n\t\t\tbrowser.bBounding = n[0].getBoundingClientRect().width ? true : false;\n\t\n\t\t\tn.remove();\n\t\t}\n\t\n\t\t$.extend( settings.oBrowser, DataTable.__browser );\n\t\tsettings.oScroll.iBarWidth = DataTable.__browser.barWidth;\n\t}\n\t\n\t\n\t/**\n\t * Array.prototype reduce[Right] method, used for browsers which don't support\n\t * JS 1.6. Done this way to reduce code size, since we iterate either way\n\t * @param {object} settings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnReduce ( that, fn, init, start, end, inc )\n\t{\n\t\tvar\n\t\t\ti = start,\n\t\t\tvalue,\n\t\t\tisSet = false;\n\t\n\t\tif ( init !== undefined ) {\n\t\t\tvalue = init;\n\t\t\tisSet = true;\n\t\t}\n\t\n\t\twhile ( i !== end ) {\n\t\t\tif ( ! that.hasOwnProperty(i) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\tvalue = isSet ?\n\t\t\t\tfn( value, that[i], i, that ) :\n\t\t\t\tthat[i];\n\t\n\t\t\tisSet = true;\n\t\t\ti += inc;\n\t\t}\n\t\n\t\treturn value;\n\t}\n\t\n\t/**\n\t * Add a column to the list used for the table with default values\n\t * @param {object} oSettings dataTables settings object\n\t * @param {node} nTh The th element for this column\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnAddColumn( oSettings, nTh )\n\t{\n\t\t// Add column to aoColumns array\n\t\tvar oDefaults = DataTable.defaults.column;\n\t\tvar iCol = oSettings.aoColumns.length;\n\t\tvar oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {\n\t\t\t\"nTh\": nTh ? nTh : document.createElement('th'),\n\t\t\t\"sTitle\": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',\n\t\t\t\"aDataSort\": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],\n\t\t\t\"mData\": oDefaults.mData ? oDefaults.mData : iCol,\n\t\t\tidx: iCol\n\t\t} );\n\t\toSettings.aoColumns.push( oCol );\n\t\n\t\t// Add search object for column specific search. Note that the `searchCols[ iCol ]`\n\t\t// passed into extend can be undefined. This allows the user to give a default\n\t\t// with only some of the parameters defined, and also not give a default\n\t\tvar searchCols = oSettings.aoPreSearchCols;\n\t\tsearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );\n\t\n\t\t// Use the default column options function to initialise classes etc\n\t\t_fnColumnOptions( oSettings, iCol, $(nTh).data() );\n\t}\n\t\n\t\n\t/**\n\t * Apply options for a column\n\t * @param {object} oSettings dataTables settings object\n\t * @param {int} iCol column index to consider\n\t * @param {object} oOptions object with sType, bVisible and bSearchable etc\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnOptions( oSettings, iCol, oOptions )\n\t{\n\t\tvar oCol = oSettings.aoColumns[ iCol ];\n\t\tvar oClasses = oSettings.oClasses;\n\t\tvar th = $(oCol.nTh);\n\t\n\t\t// Try to get width information from the DOM. We can't get it from CSS\n\t\t// as we'd need to parse the CSS stylesheet. `width` option can override\n\t\tif ( ! oCol.sWidthOrig ) {\n\t\t\t// Width attribute\n\t\t\toCol.sWidthOrig = th.attr('width') || null;\n\t\n\t\t\t// Style attribute\n\t\t\tvar t = (th.attr('style') || '').match(/width:\\s*(\\d+[pxem%]+)/);\n\t\t\tif ( t ) {\n\t\t\t\toCol.sWidthOrig = t[1];\n\t\t\t}\n\t\t}\n\t\n\t\t/* User specified column options */\n\t\tif ( oOptions !== undefined && oOptions !== null )\n\t\t{\n\t\t\t// Backwards compatibility\n\t\t\t_fnCompatCols( oOptions );\n\t\n\t\t\t// Map camel case parameters to their Hungarian counterparts\n\t\t\t_fnCamelToHungarian( DataTable.defaults.column, oOptions, true );\n\t\n\t\t\t/* Backwards compatibility for mDataProp */\n\t\t\tif ( oOptions.mDataProp !== undefined && !oOptions.mData )\n\t\t\t{\n\t\t\t\toOptions.mData = oOptions.mDataProp;\n\t\t\t}\n\t\n\t\t\tif ( oOptions.sType )\n\t\t\t{\n\t\t\t\toCol._sManualType = oOptions.sType;\n\t\t\t}\n\t\n\t\t\t// `class` is a reserved word in Javascript, so we need to provide\n\t\t\t// the ability to use a valid name for the camel case input\n\t\t\tif ( oOptions.className && ! oOptions.sClass )\n\t\t\t{\n\t\t\t\toOptions.sClass = oOptions.className;\n\t\t\t}\n\t\t\tif ( oOptions.sClass ) {\n\t\t\t\tth.addClass( oOptions.sClass );\n\t\t\t}\n\t\n\t\t\t$.extend( oCol, oOptions );\n\t\t\t_fnMap( oCol, oOptions, \"sWidth\", \"sWidthOrig\" );\n\t\n\t\t\t/* iDataSort to be applied (backwards compatibility), but aDataSort will take\n\t\t\t * priority if defined\n\t\t\t */\n\t\t\tif ( oOptions.iDataSort !== undefined )\n\t\t\t{\n\t\t\t\toCol.aDataSort = [ oOptions.iDataSort ];\n\t\t\t}\n\t\t\t_fnMap( oCol, oOptions, \"aDataSort\" );\n\t\t}\n\t\n\t\t/* Cache the data get and set functions for speed */\n\t\tvar mDataSrc = oCol.mData;\n\t\tvar mData = _fnGetObjectDataFn( mDataSrc );\n\t\tvar mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;\n\t\n\t\tvar attrTest = function( src ) {\n\t\t\treturn typeof src === 'string' && src.indexOf('@') !== -1;\n\t\t};\n\t\toCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (\n\t\t\tattrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)\n\t\t);\n\t\toCol._setter = null;\n\t\n\t\toCol.fnGetData = function (rowData, type, meta) {\n\t\t\tvar innerData = mData( rowData, type, undefined, meta );\n\t\n\t\t\treturn mRender && type ?\n\t\t\t\tmRender( innerData, type, rowData, meta ) :\n\t\t\t\tinnerData;\n\t\t};\n\t\toCol.fnSetData = function ( rowData, val, meta ) {\n\t\t\treturn _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );\n\t\t};\n\t\n\t\t// Indicate if DataTables should read DOM data as an object or array\n\t\t// Used in _fnGetRowElements\n\t\tif ( typeof mDataSrc !== 'number' ) {\n\t\t\toSettings._rowReadObject = true;\n\t\t}\n\t\n\t\t/* Feature sorting overrides column specific when off */\n\t\tif ( !oSettings.oFeatures.bSort )\n\t\t{\n\t\t\toCol.bSortable = false;\n\t\t\tth.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called\n\t\t}\n\t\n\t\t/* Check that the class assignment is correct for sorting */\n\t\tvar bAsc = $.inArray('asc', oCol.asSorting) !== -1;\n\t\tvar bDesc = $.inArray('desc', oCol.asSorting) !== -1;\n\t\tif ( !oCol.bSortable || (!bAsc && !bDesc) )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableNone;\n\t\t\toCol.sSortingClassJUI = \"\";\n\t\t}\n\t\telse if ( bAsc && !bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableAsc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;\n\t\t}\n\t\telse if ( !bAsc && bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableDesc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;\n\t\t}\n\t\telse\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortable;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUI;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Adjust the table column widths for new data. Note: you would probably want to\n\t * do a redraw after calling this function!\n\t * @param {object} settings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnAdjustColumnSizing ( settings )\n\t{\n\t\t/* Not interested in doing column width calculation if auto-width is disabled */\n\t\tif ( settings.oFeatures.bAutoWidth !== false )\n\t\t{\n\t\t\tvar columns = settings.aoColumns;\n\t\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t\tfor ( var i=0 , iLen=columns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tcolumns[i].nTh.style.width = columns[i].sWidth;\n\t\t\t}\n\t\t}\n\t\n\t\tvar scroll = settings.oScroll;\n\t\tif ( scroll.sY !== '' || scroll.sX !== '')\n\t\t{\n\t\t\t_fnScrollDraw( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'column-sizing', [settings] );\n\t}\n\t\n\t\n\t/**\n\t * Convert the index of a visible column to the index in the data array (take account\n\t * of hidden columns)\n\t * @param {object} oSettings dataTables settings object\n\t * @param {int} iMatch Visible column index to lookup\n\t * @returns {int} i the data index\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnVisibleToColumnIndex( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\n\t\treturn typeof aiVis[iMatch] === 'number' ?\n\t\t\taiVis[iMatch] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Convert the index of an index in the data array and convert it to the visible\n\t * column index (take account of hidden columns)\n\t * @param {int} iMatch Column index to lookup\n\t * @param {object} oSettings dataTables settings object\n\t * @returns {int} i the data index\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnIndexToVisible( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\tvar iPos = $.inArray( iMatch, aiVis );\n\t\n\t\treturn iPos !== -1 ? iPos : null;\n\t}\n\t\n\t\n\t/**\n\t * Get the number of visible columns\n\t * @param {object} oSettings dataTables settings object\n\t * @returns {int} i the number of visible columns\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnVisbleColumns( oSettings )\n\t{\n\t\tvar vis = 0;\n\t\n\t\t// No reduce in IE8, use a loop for now\n\t\t$.each( oSettings.aoColumns, function ( i, col ) {\n\t\t\tif ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {\n\t\t\t\tvis++;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn vis;\n\t}\n\t\n\t\n\t/**\n\t * Get an array of column indexes that match a given property\n\t * @param {object} oSettings dataTables settings object\n\t * @param {string} sParam Parameter in aoColumns to look for - typically\n\t * bVisible or bSearchable\n\t * @returns {array} Array of indexes with matched properties\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetColumns( oSettings, sParam )\n\t{\n\t\tvar a = [];\n\t\n\t\t$.map( oSettings.aoColumns, function(val, i) {\n\t\t\tif ( val[sParam] ) {\n\t\t\t\ta.push( i );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn a;\n\t}\n\t\n\t\n\t/**\n\t * Calculate the 'type' of a column\n\t * @param {object} settings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnTypes ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar data = settings.aoData;\n\t\tvar types = DataTable.ext.type.detect;\n\t\tvar i, ien, j, jen, k, ken;\n\t\tvar col, cell, detectedType, cache;\n\t\n\t\t// For each column, spin over the \n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcol = columns[i];\n\t\t\tcache = [];\n\t\n\t\t\tif ( ! col.sType && col._sManualType ) {\n\t\t\t\tcol.sType = col._sManualType;\n\t\t\t}\n\t\t\telse if ( ! col.sType ) {\n\t\t\t\tfor ( j=0, jen=types.length ; j<jen ; j++ ) {\n\t\t\t\t\tfor ( k=0, ken=data.length ; k<ken ; k++ ) {\n\t\t\t\t\t\t// Use a cache array so we only need to get the type data\n\t\t\t\t\t\t// from the formatter once (when using multiple detectors)\n\t\t\t\t\t\tif ( cache[k] === undefined ) {\n\t\t\t\t\t\t\tcache[k] = _fnGetCellData( settings, k, i, 'type' );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tdetectedType = types[j]( cache[k], settings );\n\t\n\t\t\t\t\t\t// If null, then this type can't apply to this column, so\n\t\t\t\t\t\t// rather than testing all cells, break out. There is an\n\t\t\t\t\t\t// exception for the last type which is `html`. We need to\n\t\t\t\t\t\t// scan all rows since it is possible to mix string and HTML\n\t\t\t\t\t\t// types\n\t\t\t\t\t\tif ( ! detectedType && j !== types.length-1 ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Only a single match is needed for html type since it is\n\t\t\t\t\t\t// bottom of the pile and very similar to string - but it\n\t\t\t\t\t\t// must not be empty\n\t\t\t\t\t\tif ( detectedType === 'html' && ! _empty(cache[k]) ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Type is valid for all data points in the column - use this\n\t\t\t\t\t// type\n\t\t\t\t\tif ( detectedType ) {\n\t\t\t\t\t\tcol.sType = detectedType;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Fall back - if no type was detected, always use string\n\t\t\t\tif ( ! col.sType ) {\n\t\t\t\t\tcol.sType = 'string';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Take the column definitions and static columns arrays and calculate how\n\t * they relate to column indexes. The callback function will then apply the\n\t * definition found for a column to a suitable configuration object.\n\t * @param {object} oSettings dataTables settings object\n\t * @param {array} aoColDefs The aoColumnDefs array that is to be applied\n\t * @param {array} aoCols The aoColumns array that defines columns individually\n\t * @param {function} fn Callback function - takes two parameters, the calculated\n\t * column index and the definition for that column.\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, def;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Column definitions with aTargets\n\t\tif ( aoColDefs )\n\t\t{\n\t\t\t/* Loop over the definitions array - loop in reverse so first instance has priority */\n\t\t\tfor ( i=aoColDefs.length-1 ; i>=0 ; i-- )\n\t\t\t{\n\t\t\t\tdef = aoColDefs[i];\n\t\n\t\t\t\t/* Each definition can target multiple columns, as it is an array */\n\t\t\t\tvar aTargets = def.targets !== undefined ?\n\t\t\t\t\tdef.targets :\n\t\t\t\t\tdef.aTargets;\n\t\n\t\t\t\tif ( ! Array.isArray( aTargets ) )\n\t\t\t\t{\n\t\t\t\t\taTargets = [ aTargets ];\n\t\t\t\t}\n\t\n\t\t\t\tfor ( j=0, jLen=aTargets.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Add columns that we don't yet know about */\n\t\t\t\t\t\twhile( columns.length <= aTargets[j] )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_fnAddColumn( oSettings );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t/* Integer, basic index */\n\t\t\t\t\t\tfn( aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Negative integer, right to left column counting */\n\t\t\t\t\t\tfn( columns.length+aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'string' )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Class name matching on TH element */\n\t\t\t\t\t\tfor ( k=0, kLen=columns.length ; k<kLen ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( aTargets[j] == \"_all\" ||\n\t\t\t\t\t\t\t $(columns[k].nTh).hasClass( aTargets[j] ) )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfn( k, def );\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\t\t\t}\n\t\t}\n\t\n\t\t// Statically defined columns array\n\t\tif ( aoCols )\n\t\t{\n\t\t\tfor ( i=0, iLen=aoCols.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfn( i, aoCols[i] );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * Add a data array to the table, creating DOM node etc. This is the parallel to\n\t * _fnGatherData, but for adding rows from a Javascript source, rather than a\n\t * DOM source.\n\t * @param {object} oSettings dataTables settings object\n\t * @param {array} aData data array to be added\n\t * @param {node} [nTr] TR element to add to the table - optional. If not given,\n\t * DataTables will create a row automatically\n\t * @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t * if nTr is.\n\t * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnAddData ( oSettings, aDataIn, nTr, anTds )\n\t{\n\t\t/* Create the object for storing information about this new row */\n\t\tvar iRow = oSettings.aoData.length;\n\t\tvar oData = $.extend( true, {}, DataTable.models.oRow, {\n\t\t\tsrc: nTr ? 'dom' : 'data',\n\t\t\tidx: iRow\n\t\t} );\n\t\n\t\toData._aData = aDataIn;\n\t\toSettings.aoData.push( oData );\n\t\n\t\t/* Create the cells */\n\t\tvar nTd, sThisType;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Invalidate the column types as the new data needs to be revalidated\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tcolumns[i].sType = null;\n\t\t}\n\t\n\t\t/* Add to the display array */\n\t\toSettings.aiDisplayMaster.push( iRow );\n\t\n\t\tvar id = oSettings.rowIdFn( aDataIn );\n\t\tif ( id !== undefined ) {\n\t\t\toSettings.aIds[ id ] = oData;\n\t\t}\n\t\n\t\t/* Create the DOM information, or register it if already present */\n\t\tif ( nTr || ! oSettings.oFeatures.bDeferRender )\n\t\t{\n\t\t\t_fnCreateTr( oSettings, iRow, nTr, anTds );\n\t\t}\n\t\n\t\treturn iRow;\n\t}\n\t\n\t\n\t/**\n\t * Add one or more TR elements to the table. Generally we'd expect to\n\t * use this for reading data from a DOM sourced table, but it could be\n\t * used for an TR element. Note that if a TR is given, it is used (i.e.\n\t * it is not cloned).\n\t * @param {object} settings dataTables settings object\n\t * @param {array|node|jQuery} trs The TR element(s) to add to the table\n\t * @returns {array} Array of indexes for the added rows\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnAddTr( settings, trs )\n\t{\n\t\tvar row;\n\t\n\t\t// Allow an individual node to be passed in\n\t\tif ( ! (trs instanceof $) ) {\n\t\t\ttrs = $(trs);\n\t\t}\n\t\n\t\treturn trs.map( function (i, el) {\n\t\t\trow = _fnGetRowElements( settings, el );\n\t\t\treturn _fnAddData( settings, row.data, el, row.cells );\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Take a TR element and convert it to an index in aoData\n\t * @param {object} oSettings dataTables settings object\n\t * @param {node} n the TR element to find\n\t * @returns {int} index if the node is found, null if not\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToDataIndex( oSettings, n )\n\t{\n\t\treturn (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;\n\t}\n\t\n\t\n\t/**\n\t * Take a TD element and convert it into a column data index (not the visible index)\n\t * @param {object} oSettings dataTables settings object\n\t * @param {int} iRow The row number the TD/TH can be found in\n\t * @param {node} n The TD/TH element to find\n\t * @returns {int} index if the node is found, -1 if not\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToColumnIndex( oSettings, iRow, n )\n\t{\n\t\treturn $.inArray( n, oSettings.aoData[ iRow ].anCells );\n\t}\n\t\n\t\n\t/**\n\t * Get the data for a given cell from the internal cache, taking into account data mapping\n\t * @param {object} settings dataTables settings object\n\t * @param {int} rowIdx aoData row id\n\t * @param {int} colIdx Column index\n\t * @param {string} type data get type ('display', 'type' 'filter|search' 'sort|order')\n\t * @returns {*} Cell data\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetCellData( settings, rowIdx, colIdx, type )\n\t{\n\t\tif (type === 'search') {\n\t\t\ttype = 'filter';\n\t\t}\n\t\telse if (type === 'order') {\n\t\t\ttype = 'sort';\n\t\t}\n\t\n\t\tvar draw = settings.iDraw;\n\t\tvar col = settings.aoColumns[colIdx];\n\t\tvar rowData = settings.aoData[rowIdx]._aData;\n\t\tvar defaultContent = col.sDefaultContent;\n\t\tvar cellData = col.fnGetData( rowData, type, {\n\t\t\tsettings: settings,\n\t\t\trow: rowIdx,\n\t\t\tcol: colIdx\n\t\t} );\n\t\n\t\tif ( cellData === undefined ) {\n\t\t\tif ( settings.iDrawError != draw && defaultContent === null ) {\n\t\t\t\t_fnLog( settings, 0, \"Requested unknown parameter \"+\n\t\t\t\t\t(typeof col.mData=='function' ? '{function}' : \"'\"+col.mData+\"'\")+\n\t\t\t\t\t\" for row \"+rowIdx+\", column \"+colIdx, 4 );\n\t\t\t\tsettings.iDrawError = draw;\n\t\t\t}\n\t\t\treturn defaultContent;\n\t\t}\n\t\n\t\t// When the data source is null and a specific data type is requested (i.e.\n\t\t// not the original data), we can use default column data\n\t\tif ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {\n\t\t\tcellData = defaultContent;\n\t\t}\n\t\telse if ( typeof cellData === 'function' ) {\n\t\t\t// If the data source is a function, then we run it and use the return,\n\t\t\t// executing in the scope of the data object (for instances)\n\t\t\treturn cellData.call( rowData );\n\t\t}\n\t\n\t\tif ( cellData === null && type === 'display' ) {\n\t\t\treturn '';\n\t\t}\n\t\n\t\tif ( type === 'filter' ) {\n\t\t\tvar fomatters = DataTable.ext.type.search;\n\t\n\t\t\tif ( fomatters[ col.sType ] ) {\n\t\t\t\tcellData = fomatters[ col.sType ]( cellData );\n\t\t\t}\n\t\t}\n\t\n\t\treturn cellData;\n\t}\n\t\n\t\n\t/**\n\t * Set the value for a specific cell, into the internal data cache\n\t * @param {object} settings dataTables settings object\n\t * @param {int} rowIdx aoData row id\n\t * @param {int} colIdx Column index\n\t * @param {*} val Value to set\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnSetCellData( settings, rowIdx, colIdx, val )\n\t{\n\t\tvar col = settings.aoColumns[colIdx];\n\t\tvar rowData = settings.aoData[rowIdx]._aData;\n\t\n\t\tcol.fnSetData( rowData, val, {\n\t\t\tsettings: settings,\n\t\t\trow: rowIdx,\n\t\t\tcol: colIdx\n\t\t} );\n\t}\n\t\n\t\n\t// Private variable that is used to match action syntax in the data property object\n\tvar __reArray = /\\[.*?\\]$/;\n\tvar __reFn = /\\(\\)$/;\n\t\n\t/**\n\t * Split string on periods, taking into account escaped periods\n\t * @param {string} str String to split\n\t * @return {array} Split string\n\t */\n\tfunction _fnSplitObjNotation( str )\n\t{\n\t\treturn $.map( str.match(/(\\\\.|[^\\.])+/g) || [''], function ( s ) {\n\t\t\treturn s.replace(/\\\\\\./g, '.');\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to get data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t * @param {string|int|function} mSource The data source for the object\n\t * @returns {function} Data get function\n\t * @memberof DataTable#oApi\n\t */\n\tvar _fnGetObjectDataFn = DataTable.util.get;\n\t\n\t\n\t/**\n\t * Return a function that can be used to set data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t * @param {string|int|function} mSource The data source for the object\n\t * @returns {function} Data set function\n\t * @memberof DataTable#oApi\n\t */\n\tvar _fnSetObjectDataFn = DataTable.util.set;\n\t\n\t\n\t/**\n\t * Return an array with the full table data\n\t * @param {object} oSettings dataTables settings object\n\t * @returns array {array} aData Master data array\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetDataMaster ( settings )\n\t{\n\t\treturn _pluck( settings.aoData, '_aData' );\n\t}\n\t\n\t\n\t/**\n\t * Nuke the table\n\t * @param {object} oSettings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnClearTable( settings )\n\t{\n\t\tsettings.aoData.length = 0;\n\t\tsettings.aiDisplayMaster.length = 0;\n\t\tsettings.aiDisplay.length = 0;\n\t\tsettings.aIds = {};\n\t}\n\t\n\t\n\t /**\n\t * Take an array of integers (index array) and remove a target integer (value - not\n\t * the key!)\n\t * @param {array} a Index array to target\n\t * @param {int} iTarget value to find\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnDeleteIndex( a, iTarget, splice )\n\t{\n\t\tvar iTargetIndex = -1;\n\t\n\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( a[i] == iTarget )\n\t\t\t{\n\t\t\t\tiTargetIndex = i;\n\t\t\t}\n\t\t\telse if ( a[i] > iTarget )\n\t\t\t{\n\t\t\t\ta[i]--;\n\t\t\t}\n\t\t}\n\t\n\t\tif ( iTargetIndex != -1 && splice === undefined )\n\t\t{\n\t\t\ta.splice( iTargetIndex, 1 );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Mark cached data as invalid such that a re-read of the data will occur when\n\t * the cached data is next requested. Also update from the data source object.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {int} rowIdx Row index to invalidate\n\t * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'\n\t * or 'data'\n\t * @param {int} [colIdx] Column index to invalidate. If undefined the whole\n\t * row will be invalidated\n\t * @memberof DataTable#oApi\n\t *\n\t * @todo For the modularisation of v1.11 this will need to become a callback, so\n\t * the sort and filter methods can subscribe to it. That will required\n\t * initialisation options for sorting, which is why it is not already baked in\n\t */\n\tfunction _fnInvalidate( settings, rowIdx, src, colIdx )\n\t{\n\t\tvar row = settings.aoData[ rowIdx ];\n\t\tvar i, ien;\n\t\tvar cellWrite = function ( cell, col ) {\n\t\t\t// This is very frustrating, but in IE if you just write directly\n\t\t\t// to innerHTML, and elements that are overwritten are GC'ed,\n\t\t\t// even if there is a reference to them elsewhere\n\t\t\twhile ( cell.childNodes.length ) {\n\t\t\t\tcell.removeChild( cell.firstChild );\n\t\t\t}\n\t\n\t\t\tcell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );\n\t\t};\n\t\n\t\t// Are we reading last data from DOM or the data object?\n\t\tif ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {\n\t\t\t// Read the data from the DOM\n\t\t\trow._aData = _fnGetRowElements(\n\t\t\t\t\tsettings, row, colIdx, colIdx === undefined ? undefined : row._aData\n\t\t\t\t)\n\t\t\t\t.data;\n\t\t}\n\t\telse {\n\t\t\t// Reading from data object, update the DOM\n\t\t\tvar cells = row.anCells;\n\t\n\t\t\tif ( cells ) {\n\t\t\t\tif ( colIdx !== undefined ) {\n\t\t\t\t\tcellWrite( cells[colIdx], colIdx );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tcellWrite( cells[i], i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// For both row and cell invalidation, the cached data for sorting and\n\t\t// filtering is nulled out\n\t\trow._aSortData = null;\n\t\trow._aFilterData = null;\n\t\n\t\t// Invalidate the type for a specific column (if given) or all columns since\n\t\t// the data might have changed\n\t\tvar cols = settings.aoColumns;\n\t\tif ( colIdx !== undefined ) {\n\t\t\tcols[ colIdx ].sType = null;\n\t\t}\n\t\telse {\n\t\t\tfor ( i=0, ien=cols.length ; i<ien ; i++ ) {\n\t\t\t\tcols[i].sType = null;\n\t\t\t}\n\t\n\t\t\t// Update DataTables special `DT_*` attributes for the row\n\t\t\t_fnRowAttributes( settings, row );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a data source object from an HTML row, reading the contents of the\n\t * cells that are in the row.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {node|object} TR element from which to read data or existing row\n\t * object from which to re-read the data from the cells\n\t * @param {int} [colIdx] Optional column index\n\t * @param {array|object} [d] Data source object. If `colIdx` is given then this\n\t * parameter should also be given and will be used to write the data into.\n\t * Only the column in question will be written\n\t * @returns {object} Object with two parameters: `data` the data read, in\n\t * document order, and `cells` and array of nodes (they can be useful to the\n\t * caller, so rather than needing a second traversal to get them, just return\n\t * them from here).\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetRowElements( settings, row, colIdx, d )\n\t{\n\t\tvar\n\t\t\ttds = [],\n\t\t\ttd = row.firstChild,\n\t\t\tname, col, o, i=0, contents,\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tobjectRead = settings._rowReadObject;\n\t\n\t\t// Allow the data object to be passed in, or construct\n\t\td = d !== undefined ?\n\t\t\td :\n\t\t\tobjectRead ?\n\t\t\t\t{} :\n\t\t\t\t[];\n\t\n\t\tvar attr = function ( str, td ) {\n\t\t\tif ( typeof str === 'string' ) {\n\t\t\t\tvar idx = str.indexOf('@');\n\t\n\t\t\t\tif ( idx !== -1 ) {\n\t\t\t\t\tvar attr = str.substring( idx+1 );\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( str );\n\t\t\t\t\tsetter( d, td.getAttribute( attr ) );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\n\t\t// Read data from a cell and store into the data object\n\t\tvar cellProcess = function ( cell ) {\n\t\t\tif ( colIdx === undefined || colIdx === i ) {\n\t\t\t\tcol = columns[i];\n\t\t\t\tcontents = (cell.innerHTML).trim();\n\t\n\t\t\t\tif ( col && col._bAttrSrc ) {\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( col.mData._ );\n\t\t\t\t\tsetter( d, contents );\n\t\n\t\t\t\t\tattr( col.mData.sort, cell );\n\t\t\t\t\tattr( col.mData.type, cell );\n\t\t\t\t\tattr( col.mData.filter, cell );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Depending on the `data` option for the columns the data can\n\t\t\t\t\t// be read to either an object or an array.\n\t\t\t\t\tif ( objectRead ) {\n\t\t\t\t\t\tif ( ! col._setter ) {\n\t\t\t\t\t\t\t// Cache the setter function\n\t\t\t\t\t\t\tcol._setter = _fnSetObjectDataFn( col.mData );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcol._setter( d, contents );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\td[i] = contents;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t};\n\t\n\t\tif ( td ) {\n\t\t\t// `tr` element was passed in\n\t\t\twhile ( td ) {\n\t\t\t\tname = td.nodeName.toUpperCase();\n\t\n\t\t\t\tif ( name == \"TD\" || name == \"TH\" ) {\n\t\t\t\t\tcellProcess( td );\n\t\t\t\t\ttds.push( td );\n\t\t\t\t}\n\t\n\t\t\t\ttd = td.nextSibling;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Existing row object passed in\n\t\t\ttds = row.anCells;\n\t\n\t\t\tfor ( var j=0, jen=tds.length ; j<jen ; j++ ) {\n\t\t\t\tcellProcess( tds[j] );\n\t\t\t}\n\t\t}\n\t\n\t\t// Read the ID from the DOM if present\n\t\tvar rowNode = row.firstChild ? row : row.nTr;\n\t\n\t\tif ( rowNode ) {\n\t\t\tvar id = rowNode.getAttribute( 'id' );\n\t\n\t\t\tif ( id ) {\n\t\t\t\t_fnSetObjectDataFn( settings.rowId )( d, id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn {\n\t\t\tdata: d,\n\t\t\tcells: tds\n\t\t};\n\t}\n\t/**\n\t * Create a new TR element (and it's TD children) for a row\n\t * @param {object} oSettings dataTables settings object\n\t * @param {int} iRow Row to consider\n\t * @param {node} [nTrIn] TR element to add to the table - optional. If not given,\n\t * DataTables will create a row automatically\n\t * @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t * if nTr is.\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnCreateTr ( oSettings, iRow, nTrIn, anTds )\n\t{\n\t\tvar\n\t\t\trow = oSettings.aoData[iRow],\n\t\t\trowData = row._aData,\n\t\t\tcells = [],\n\t\t\tnTr, nTd, oCol,\n\t\t\ti, iLen, create;\n\t\n\t\tif ( row.nTr === null )\n\t\t{\n\t\t\tnTr = nTrIn || document.createElement('tr');\n\t\n\t\t\trow.nTr = nTr;\n\t\t\trow.anCells = cells;\n\t\n\t\t\t/* Use a private property on the node to allow reserve mapping from the node\n\t\t\t * to the aoData array for fast look up\n\t\t\t */\n\t\t\tnTr._DT_RowIndex = iRow;\n\t\n\t\t\t/* Special parameters can be given by the data source to be used on the row */\n\t\t\t_fnRowAttributes( oSettings, row );\n\t\n\t\t\t/* Process each column */\n\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\toCol = oSettings.aoColumns[i];\n\t\t\t\tcreate = nTrIn ? false : true;\n\t\n\t\t\t\tnTd = create ? document.createElement( oCol.sCellType ) : anTds[i];\n\t\t\t\tnTd._DT_CellIndex = {\n\t\t\t\t\trow: iRow,\n\t\t\t\t\tcolumn: i\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tcells.push( nTd );\n\t\n\t\t\t\t// Need to create the HTML if new, or if a rendering function is defined\n\t\t\t\tif ( create || ((oCol.mRender || oCol.mData !== i) &&\n\t\t\t\t\t (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')\n\t\t\t\t)) {\n\t\t\t\t\tnTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );\n\t\t\t\t}\n\t\n\t\t\t\t/* Add user defined class */\n\t\t\t\tif ( oCol.sClass )\n\t\t\t\t{\n\t\t\t\t\tnTd.className += ' '+oCol.sClass;\n\t\t\t\t}\n\t\n\t\t\t\t// Visibility - add or remove as required\n\t\t\t\tif ( oCol.bVisible && ! nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTr.appendChild( nTd );\n\t\t\t\t}\n\t\t\t\telse if ( ! oCol.bVisible && nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTd.parentNode.removeChild( nTd );\n\t\t\t\t}\n\t\n\t\t\t\tif ( oCol.fnCreatedCell )\n\t\t\t\t{\n\t\t\t\t\toCol.fnCreatedCell.call( oSettings.oInstance,\n\t\t\t\t\t\tnTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow, cells] );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Add attributes to a row based on the special `DT_*` parameters in a data\n\t * source object.\n\t * @param {object} settings DataTables settings object\n\t * @param {object} DataTables row object for the row to be modified\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnRowAttributes( settings, row )\n\t{\n\t\tvar tr = row.nTr;\n\t\tvar data = row._aData;\n\t\n\t\tif ( tr ) {\n\t\t\tvar id = settings.rowIdFn( data );\n\t\n\t\t\tif ( id ) {\n\t\t\t\ttr.id = id;\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowClass ) {\n\t\t\t\t// Remove any classes added by DT_RowClass before\n\t\t\t\tvar a = data.DT_RowClass.split(' ');\n\t\t\t\trow.__rowc = row.__rowc ?\n\t\t\t\t\t_unique( row.__rowc.concat( a ) ) :\n\t\t\t\t\ta;\n\t\n\t\t\t\t$(tr)\n\t\t\t\t\t.removeClass( row.__rowc.join(' ') )\n\t\t\t\t\t.addClass( data.DT_RowClass );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowAttr ) {\n\t\t\t\t$(tr).attr( data.DT_RowAttr );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowData ) {\n\t\t\t\t$(tr).data( data.DT_RowData );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Create the HTML header for the table\n\t * @param {object} oSettings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnBuildHead( oSettings )\n\t{\n\t\tvar i, ien, cell, row, column;\n\t\tvar thead = oSettings.nTHead;\n\t\tvar tfoot = oSettings.nTFoot;\n\t\tvar createHeader = $('th, td', thead).length === 0;\n\t\tvar classes = oSettings.oClasses;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\tif ( createHeader ) {\n\t\t\trow = $('<tr/>').appendTo( thead );\n\t\t}\n\t\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcell = $( column.nTh ).addClass( column.sClass );\n\t\n\t\t\tif ( createHeader ) {\n\t\t\t\tcell.appendTo( row );\n\t\t\t}\n\t\n\t\t\t// 1.11 move into sorting\n\t\t\tif ( oSettings.oFeatures.bSort ) {\n\t\t\t\tcell.addClass( column.sSortingClass );\n\t\n\t\t\t\tif ( column.bSortable !== false ) {\n\t\t\t\t\tcell\n\t\t\t\t\t\t.attr( 'tabindex', oSettings.iTabIndex )\n\t\t\t\t\t\t.attr( 'aria-controls', oSettings.sTableId );\n\t\n\t\t\t\t\t_fnSortAttachListener( oSettings, column.nTh, i );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( column.sTitle != cell[0].innerHTML ) {\n\t\t\t\tcell.html( column.sTitle );\n\t\t\t}\n\t\n\t\t\t_fnRenderer( oSettings, 'header' )(\n\t\t\t\toSettings, cell, column, classes\n\t\t\t);\n\t\t}\n\t\n\t\tif ( createHeader ) {\n\t\t\t_fnDetectHeader( oSettings.aoHeader, thead );\n\t\t}\n\t\n\t\t/* Deal with the footer - add classes if required */\n\t\t$(thead).children('tr').children('th, td').addClass( classes.sHeaderTH );\n\t\t$(tfoot).children('tr').children('th, td').addClass( classes.sFooterTH );\n\t\n\t\t// Cache the footer cells. Note that we only take the cells from the first\n\t\t// row in the footer. If there is more than one row the user wants to\n\t\t// interact with, they need to use the table().foot() method. Note also this\n\t\t// allows cells to be used for multiple columns using colspan\n\t\tif ( tfoot !== null ) {\n\t\t\tvar cells = oSettings.aoFooter[0];\n\t\n\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tcolumn = columns[i];\n\t\t\t\tcolumn.nTf = cells[i].cell;\n\t\n\t\t\t\tif ( column.sClass ) {\n\t\t\t\t\t$(column.nTf).addClass( column.sClass );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the header (or footer) element based on the column visibility states. The\n\t * methodology here is to use the layout array from _fnDetectHeader, modified for\n\t * the instantaneous column visibility, to construct the new layout. The grid is\n\t * traversed over cell at a time in a rows x columns grid fashion, although each\n\t * cell insert can cover multiple elements in the grid - which is tracks using the\n\t * aApplied array. Cell inserts in the grid will only occur where there isn't\n\t * already a cell in that position.\n\t * @param {object} oSettings dataTables settings object\n\t * @param array {objects} aoSource Layout array from _fnDetectHeader\n\t * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnDrawHead( oSettings, aoSource, bIncludeHidden )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, n, nLocalTr;\n\t\tvar aoLocal = [];\n\t\tvar aApplied = [];\n\t\tvar iColumns = oSettings.aoColumns.length;\n\t\tvar iRowspan, iColspan;\n\t\n\t\tif ( ! aoSource )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( bIncludeHidden === undefined )\n\t\t{\n\t\t\tbIncludeHidden = false;\n\t\t}\n\t\n\t\t/* Make a copy of the master layout array, but without the visible columns in it */\n\t\tfor ( i=0, iLen=aoSource.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taoLocal[i] = aoSource[i].slice();\n\t\t\taoLocal[i].nTr = aoSource[i].nTr;\n\t\n\t\t\t/* Remove any columns which are currently hidden */\n\t\t\tfor ( j=iColumns-1 ; j>=0 ; j-- )\n\t\t\t{\n\t\t\t\tif ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )\n\t\t\t\t{\n\t\t\t\t\taoLocal[i].splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Prep the applied array - it needs an element for each row */\n\t\t\taApplied.push( [] );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnLocalTr = aoLocal[i].nTr;\n\t\n\t\t\t/* All cells are going to be replaced, so empty out the row */\n\t\t\tif ( nLocalTr )\n\t\t\t{\n\t\t\t\twhile( (n = nLocalTr.firstChild) )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.removeChild( n );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tfor ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tiRowspan = 1;\n\t\t\t\tiColspan = 1;\n\t\n\t\t\t\t/* Check to see if there is already a cell (row/colspan) covering our target\n\t\t\t\t * insert point. If there is, then there is nothing to do.\n\t\t\t\t */\n\t\t\t\tif ( aApplied[i][j] === undefined )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.appendChild( aoLocal[i][j].cell );\n\t\t\t\t\taApplied[i][j] = 1;\n\t\n\t\t\t\t\t/* Expand the cell to cover as many rows as needed */\n\t\t\t\t\twhile ( aoLocal[i+iRowspan] !== undefined &&\n\t\t\t\t\t aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\taApplied[i+iRowspan][j] = 1;\n\t\t\t\t\t\tiRowspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Expand the cell to cover as many columns as needed */\n\t\t\t\t\twhile ( aoLocal[i][j+iColspan] !== undefined &&\n\t\t\t\t\t aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Must update the applied array over the rows for the columns */\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taApplied[i+k][j+iColspan] = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tiColspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Do the actual expansion in the DOM */\n\t\t\t\t\t$(aoLocal[i][j].cell)\n\t\t\t\t\t\t.attr('rowspan', iRowspan)\n\t\t\t\t\t\t.attr('colspan', iColspan);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Insert the required TR nodes into the table for display\n\t * @param {object} oSettings dataTables settings object\n\t * @param ajaxComplete true after ajax call to complete rendering\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnDraw( oSettings, ajaxComplete )\n\t{\n\t\t/* Provide a pre-callback function which can be used to cancel the draw is false is returned */\n\t\tvar aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );\n\t\tif ( $.inArray( false, aPreDraw ) !== -1 )\n\t\t{\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar i, iLen, n;\n\t\tvar anRows = [];\n\t\tvar iRowCount = 0;\n\t\tvar asStripeClasses = oSettings.asStripeClasses;\n\t\tvar iStripes = asStripeClasses.length;\n\t\tvar iOpenRows = oSettings.aoOpenRows.length;\n\t\tvar oLang = oSettings.oLanguage;\n\t\tvar iInitDisplayStart = oSettings.iInitDisplayStart;\n\t\tvar bServerSide = _fnDataSource( oSettings ) == 'ssp';\n\t\tvar aiDisplay = oSettings.aiDisplay;\n\t\n\t\toSettings.bDrawing = true;\n\t\n\t\t/* Check and see if we have an initial draw position from state saving */\n\t\tif ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )\n\t\t{\n\t\t\toSettings._iDisplayStart = bServerSide ?\n\t\t\t\tiInitDisplayStart :\n\t\t\t\tiInitDisplayStart >= oSettings.fnRecordsDisplay() ?\n\t\t\t\t\t0 :\n\t\t\t\t\tiInitDisplayStart;\n\t\n\t\t\toSettings.iInitDisplayStart = -1;\n\t\t}\n\t\n\t\tvar iDisplayStart = oSettings._iDisplayStart;\n\t\tvar iDisplayEnd = oSettings.fnDisplayEnd();\n\t\n\t\t/* Server-side processing draw intercept */\n\t\tif ( oSettings.bDeferLoading )\n\t\t{\n\t\t\toSettings.bDeferLoading = false;\n\t\t\toSettings.iDraw++;\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t}\n\t\telse if ( !bServerSide )\n\t\t{\n\t\t\toSettings.iDraw++;\n\t\t}\n\t\telse if ( !oSettings.bDestroying && !ajaxComplete)\n\t\t{\n\t\t\t_fnAjaxUpdate( oSettings );\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( aiDisplay.length !== 0 )\n\t\t{\n\t\t\tvar iStart = bServerSide ? 0 : iDisplayStart;\n\t\t\tvar iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;\n\t\n\t\t\tfor ( var j=iStart ; j<iEnd ; j++ )\n\t\t\t{\n\t\t\t\tvar iDataIndex = aiDisplay[j];\n\t\t\t\tvar aoData = oSettings.aoData[ iDataIndex ];\n\t\t\t\tif ( aoData.nTr === null )\n\t\t\t\t{\n\t\t\t\t\t_fnCreateTr( oSettings, iDataIndex );\n\t\t\t\t}\n\t\n\t\t\t\tvar nRow = aoData.nTr;\n\t\n\t\t\t\t/* Remove the old striping classes and then add the new one */\n\t\t\t\tif ( iStripes !== 0 )\n\t\t\t\t{\n\t\t\t\t\tvar sStripe = asStripeClasses[ iRowCount % iStripes ];\n\t\t\t\t\tif ( aoData._sRowStripe != sStripe )\n\t\t\t\t\t{\n\t\t\t\t\t\t$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );\n\t\t\t\t\t\taoData._sRowStripe = sStripe;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Row callback functions - might want to manipulate the row\n\t\t\t\t// iRowCount and j are not currently documented. Are they at all\n\t\t\t\t// useful?\n\t\t\t\t_fnCallbackFire( oSettings, 'aoRowCallback', null,\n\t\t\t\t\t[nRow, aoData._aData, iRowCount, j, iDataIndex] );\n\t\n\t\t\t\tanRows.push( nRow );\n\t\t\t\tiRowCount++;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Table is empty - create a row with an empty message in it */\n\t\t\tvar sZero = oLang.sZeroRecords;\n\t\t\tif ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )\n\t\t\t{\n\t\t\t\tsZero = oLang.sLoadingRecords;\n\t\t\t}\n\t\t\telse if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )\n\t\t\t{\n\t\t\t\tsZero = oLang.sEmptyTable;\n\t\t\t}\n\t\n\t\t\tanRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )\n\t\t\t\t.append( $('<td />', {\n\t\t\t\t\t'valign': 'top',\n\t\t\t\t\t'colSpan': _fnVisbleColumns( oSettings ),\n\t\t\t\t\t'class': oSettings.oClasses.sRowEmpty\n\t\t\t\t} ).html( sZero ) )[0];\n\t\t}\n\t\n\t\t/* Header and footer callbacks */\n\t\t_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\t_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\tvar body = $(oSettings.nTBody);\n\t\n\t\tbody.children().detach();\n\t\tbody.append( $(anRows) );\n\t\n\t\t/* Call all required callback functions for the end of a draw */\n\t\t_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );\n\t\n\t\t/* Draw is complete, sorting and filtering must be as well */\n\t\toSettings.bSorted = false;\n\t\toSettings.bFiltered = false;\n\t\toSettings.bDrawing = false;\n\t}\n\t\n\t\n\t/**\n\t * Redraw the table - taking account of the various features which are enabled\n\t * @param {object} oSettings dataTables settings object\n\t * @param {boolean} [holdPosition] Keep the current paging position. By default\n\t * the paging is reset to the first page\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnReDraw( settings, holdPosition )\n\t{\n\t\tvar\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tsort = features.bSort,\n\t\t\tfilter = features.bFilter;\n\t\n\t\tif ( sort ) {\n\t\t\t_fnSort( settings );\n\t\t}\n\t\n\t\tif ( filter ) {\n\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch );\n\t\t}\n\t\telse {\n\t\t\t// No filtering, so we want to just use the display master\n\t\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\t}\n\t\n\t\tif ( holdPosition !== true ) {\n\t\t\tsettings._iDisplayStart = 0;\n\t\t}\n\t\n\t\t// Let any modules know about the draw hold position state (used by\n\t\t// scrolling internally)\n\t\tsettings._drawHold = holdPosition;\n\t\n\t\t_fnDraw( settings );\n\t\n\t\tsettings._drawHold = false;\n\t}\n\t\n\t\n\t/**\n\t * Add the options to the page HTML for the table\n\t * @param {object} oSettings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnAddOptionsHtml ( oSettings )\n\t{\n\t\tvar classes = oSettings.oClasses;\n\t\tvar table = $(oSettings.nTable);\n\t\tvar holding = $('<div/>').insertBefore( table ); // Holding element for speed\n\t\tvar features = oSettings.oFeatures;\n\t\n\t\t// All DataTables are wrapped in a div\n\t\tvar insert = $('<div/>', {\n\t\t\tid: oSettings.sTableId+'_wrapper',\n\t\t\t'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)\n\t\t} );\n\t\n\t\toSettings.nHolding = holding[0];\n\t\toSettings.nTableWrapper = insert[0];\n\t\toSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;\n\t\n\t\t/* Loop over the user set positioning and place the elements as needed */\n\t\tvar aDom = oSettings.sDom.split('');\n\t\tvar featureNode, cOption, nNewNode, cNext, sAttr, j;\n\t\tfor ( var i=0 ; i<aDom.length ; i++ )\n\t\t{\n\t\t\tfeatureNode = null;\n\t\t\tcOption = aDom[i];\n\t\n\t\t\tif ( cOption == '<' )\n\t\t\t{\n\t\t\t\t/* New container div */\n\t\t\t\tnNewNode = $('<div/>')[0];\n\t\n\t\t\t\t/* Check to see if we should append an id and/or a class name to the container */\n\t\t\t\tcNext = aDom[i+1];\n\t\t\t\tif ( cNext == \"'\" || cNext == '\"' )\n\t\t\t\t{\n\t\t\t\t\tsAttr = \"\";\n\t\t\t\t\tj = 2;\n\t\t\t\t\twhile ( aDom[i+j] != cNext )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr += aDom[i+j];\n\t\t\t\t\t\tj++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Replace jQuery UI constants @todo depreciated */\n\t\t\t\t\tif ( sAttr == \"H\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIHeader;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr == \"F\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIFooter;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* The attribute can be in the format of \"#id.class\", \"#id\" or \"class\" This logic\n\t\t\t\t\t * breaks the string into parts and applies them as needed\n\t\t\t\t\t */\n\t\t\t\t\tif ( sAttr.indexOf('.') != -1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar aSplit = sAttr.split('.');\n\t\t\t\t\t\tnNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);\n\t\t\t\t\t\tnNewNode.className = aSplit[1];\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr.charAt(0) == \"#\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.id = sAttr.substr(1, sAttr.length-1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.className = sAttr;\n\t\t\t\t\t}\n\t\n\t\t\t\t\ti += j; /* Move along the position array */\n\t\t\t\t}\n\t\n\t\t\t\tinsert.append( nNewNode );\n\t\t\t\tinsert = $(nNewNode);\n\t\t\t}\n\t\t\telse if ( cOption == '>' )\n\t\t\t{\n\t\t\t\t/* End container div */\n\t\t\t\tinsert = insert.parent();\n\t\t\t}\n\t\t\t// @todo Move options into their own plugins?\n\t\t\telse if ( cOption == 'l' && features.bPaginate && features.bLengthChange )\n\t\t\t{\n\t\t\t\t/* Length */\n\t\t\t\tfeatureNode = _fnFeatureHtmlLength( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'f' && features.bFilter )\n\t\t\t{\n\t\t\t\t/* Filter */\n\t\t\t\tfeatureNode = _fnFeatureHtmlFilter( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'r' && features.bProcessing )\n\t\t\t{\n\t\t\t\t/* pRocessing */\n\t\t\t\tfeatureNode = _fnFeatureHtmlProcessing( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 't' )\n\t\t\t{\n\t\t\t\t/* Table */\n\t\t\t\tfeatureNode = _fnFeatureHtmlTable( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'i' && features.bInfo )\n\t\t\t{\n\t\t\t\t/* Info */\n\t\t\t\tfeatureNode = _fnFeatureHtmlInfo( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'p' && features.bPaginate )\n\t\t\t{\n\t\t\t\t/* Pagination */\n\t\t\t\tfeatureNode = _fnFeatureHtmlPaginate( oSettings );\n\t\t\t}\n\t\t\telse if ( DataTable.ext.feature.length !== 0 )\n\t\t\t{\n\t\t\t\t/* Plug-in features */\n\t\t\t\tvar aoFeatures = DataTable.ext.feature;\n\t\t\t\tfor ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )\n\t\t\t\t{\n\t\t\t\t\tif ( cOption == aoFeatures[k].cFeature )\n\t\t\t\t\t{\n\t\t\t\t\t\tfeatureNode = aoFeatures[k].fnInit( oSettings );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Add to the 2D features array */\n\t\t\tif ( featureNode )\n\t\t\t{\n\t\t\t\tvar aanFeatures = oSettings.aanFeatures;\n\t\n\t\t\t\tif ( ! aanFeatures[cOption] )\n\t\t\t\t{\n\t\t\t\t\taanFeatures[cOption] = [];\n\t\t\t\t}\n\t\n\t\t\t\taanFeatures[cOption].push( featureNode );\n\t\t\t\tinsert.append( featureNode );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Built our DOM structure - replace the holding div with what we want */\n\t\tholding.replaceWith( insert );\n\t\toSettings.nHolding = null;\n\t}\n\t\n\t\n\t/**\n\t * Use the DOM source to create up an array of header cells. The idea here is to\n\t * create a layout grid (array) of rows x columns, which contains a reference\n\t * to the cell that that point in the grid (regardless of col/rowspan), such that\n\t * any column / row could be removed and the new grid constructed\n\t * @param array {object} aLayout Array to store the calculated layout in\n\t * @param {node} nThead The header/footer element for the table\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnDetectHeader ( aLayout, nThead )\n\t{\n\t\tvar nTrs = $(nThead).children('tr');\n\t\tvar nTr, nCell;\n\t\tvar i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;\n\t\tvar bUnique;\n\t\tvar fnShiftCol = function ( a, i, j ) {\n\t\t\tvar k = a[i];\n\t while ( k[j] ) {\n\t\t\t\tj++;\n\t\t\t}\n\t\t\treturn j;\n\t\t};\n\t\n\t\taLayout.splice( 0, aLayout.length );\n\t\n\t\t/* We know how many rows there are in the layout - so prep it */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taLayout.push( [] );\n\t\t}\n\t\n\t\t/* Calculate a layout array */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnTr = nTrs[i];\n\t\t\tiColumn = 0;\n\t\n\t\t\t/* For every cell in the row... */\n\t\t\tnCell = nTr.firstChild;\n\t\t\twhile ( nCell ) {\n\t\t\t\tif ( nCell.nodeName.toUpperCase() == \"TD\" ||\n\t\t\t\t nCell.nodeName.toUpperCase() == \"TH\" )\n\t\t\t\t{\n\t\t\t\t\t/* Get the col and rowspan attributes from the DOM and sanitise them */\n\t\t\t\t\tiColspan = nCell.getAttribute('colspan') * 1;\n\t\t\t\t\tiRowspan = nCell.getAttribute('rowspan') * 1;\n\t\t\t\t\tiColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;\n\t\t\t\t\tiRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;\n\t\n\t\t\t\t\t/* There might be colspan cells already in this row, so shift our target\n\t\t\t\t\t * accordingly\n\t\t\t\t\t */\n\t\t\t\t\tiColShifted = fnShiftCol( aLayout, i, iColumn );\n\t\n\t\t\t\t\t/* Cache calculation for unique columns */\n\t\t\t\t\tbUnique = iColspan === 1 ? true : false;\n\t\n\t\t\t\t\t/* If there is col / rowspan, copy the information into the layout grid */\n\t\t\t\t\tfor ( l=0 ; l<iColspan ; l++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taLayout[i+k][iColShifted+l] = {\n\t\t\t\t\t\t\t\t\"cell\": nCell,\n\t\t\t\t\t\t\t\t\"unique\": bUnique\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\taLayout[i+k].nTr = nTr;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnCell = nCell.nextSibling;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Get an array of unique th elements, one for each column\n\t * @param {object} oSettings dataTables settings object\n\t * @param {node} nHeader automatically detect the layout from this node - optional\n\t * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional\n\t * @returns array {node} aReturn list of unique th's\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetUniqueThs ( oSettings, nHeader, aLayout )\n\t{\n\t\tvar aReturn = [];\n\t\tif ( !aLayout )\n\t\t{\n\t\t\taLayout = oSettings.aoHeader;\n\t\t\tif ( nHeader )\n\t\t\t{\n\t\t\t\taLayout = [];\n\t\t\t\t_fnDetectHeader( aLayout, nHeader );\n\t\t\t}\n\t\t}\n\t\n\t\tfor ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tfor ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tif ( aLayout[i][j].unique &&\n\t\t\t\t\t (!aReturn[j] || !oSettings.bSortCellsTop) )\n\t\t\t\t{\n\t\t\t\t\taReturn[j] = aLayout[i][j].cell;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn aReturn;\n\t}\n\t\n\t/**\n\t * Create an Ajax call based on the table's settings, taking into account that\n\t * parameters can have multiple forms, and backwards compatibility.\n\t *\n\t * @param {object} oSettings dataTables settings object\n\t * @param {array} data Data to send to the server, required by\n\t * DataTables - may be augmented by developer callbacks\n\t * @param {function} fn Callback function to run when data is obtained\n\t */\n\tfunction _fnBuildAjax( oSettings, data, fn )\n\t{\n\t\t// Compatibility with 1.9-, allow fnServerData and event to manipulate\n\t\t_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );\n\t\n\t\t// Convert to object based for 1.10+ if using the old array scheme which can\n\t\t// come from server-side processing or serverParams\n\t\tif ( data && Array.isArray(data) ) {\n\t\t\tvar tmp = {};\n\t\t\tvar rbracket = /(.*?)\\[\\]$/;\n\t\n\t\t\t$.each( data, function (key, val) {\n\t\t\t\tvar match = val.name.match(rbracket);\n\t\n\t\t\t\tif ( match ) {\n\t\t\t\t\t// Support for arrays\n\t\t\t\t\tvar name = match[0];\n\t\n\t\t\t\t\tif ( ! tmp[ name ] ) {\n\t\t\t\t\t\ttmp[ name ] = [];\n\t\t\t\t\t}\n\t\t\t\t\ttmp[ name ].push( val.value );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttmp[val.name] = val.value;\n\t\t\t\t}\n\t\t\t} );\n\t\t\tdata = tmp;\n\t\t}\n\t\n\t\tvar ajaxData;\n\t\tvar ajax = oSettings.ajax;\n\t\tvar instance = oSettings.oInstance;\n\t\tvar callback = function ( json ) {\n\t\t\tvar status = oSettings.jqXhr\n\t\t\t\t? oSettings.jqXhr.status\n\t\t\t\t: null;\n\t\n\t\t\tif ( json === null || (typeof status === 'number' && status == 204 ) ) {\n\t\t\t\tjson = {};\n\t\t\t\t_fnAjaxDataSrc( oSettings, json, [] );\n\t\t\t}\n\t\n\t\t\tvar error = json.error || json.sError;\n\t\t\tif ( error ) {\n\t\t\t\t_fnLog( oSettings, 0, error );\n\t\t\t}\n\t\n\t\t\toSettings.json = json;\n\t\n\t\t\t_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );\n\t\t\tfn( json );\n\t\t};\n\t\n\t\tif ( $.isPlainObject( ajax ) && ajax.data )\n\t\t{\n\t\t\tajaxData = ajax.data;\n\t\n\t\t\tvar newData = typeof ajaxData === 'function' ?\n\t\t\t\tajaxData( data, oSettings ) : // fn can manipulate data or return\n\t\t\t\tajaxData; // an object object or array to merge\n\t\n\t\t\t// If the function returned something, use that alone\n\t\t\tdata = typeof ajaxData === 'function' && newData ?\n\t\t\t\tnewData :\n\t\t\t\t$.extend( true, data, newData );\n\t\n\t\t\t// Remove the data property as we've resolved it already and don't want\n\t\t\t// jQuery to do it again (it is restored at the end of the function)\n\t\t\tdelete ajax.data;\n\t\t}\n\t\n\t\tvar baseAjax = {\n\t\t\t\"data\": data,\n\t\t\t\"success\": callback,\n\t\t\t\"dataType\": \"json\",\n\t\t\t\"cache\": false,\n\t\t\t\"type\": oSettings.sServerMethod,\n\t\t\t\"error\": function (xhr, error, thrown) {\n\t\t\t\tvar ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );\n\t\n\t\t\t\tif ( $.inArray( true, ret ) === -1 ) {\n\t\t\t\t\tif ( error == \"parsererror\" ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Invalid JSON response', 1 );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( xhr.readyState === 4 ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Ajax error', 7 );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\t}\n\t\t};\n\t\n\t\t// Store the data submitted for the API\n\t\toSettings.oAjaxData = data;\n\t\n\t\t// Allow plug-ins and external processes to modify the data\n\t\t_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );\n\t\n\t\tif ( oSettings.fnServerData )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.fnServerData.call( instance,\n\t\t\t\toSettings.sAjaxSource,\n\t\t\t\t$.map( data, function (val, key) { // Need to convert back to 1.9 trad format\n\t\t\t\t\treturn { name: key, value: val };\n\t\t\t\t} ),\n\t\t\t\tcallback,\n\t\t\t\toSettings\n\t\t\t);\n\t\t}\n\t\telse if ( oSettings.sAjaxSource || typeof ajax === 'string' )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, {\n\t\t\t\turl: ajax || oSettings.sAjaxSource\n\t\t\t} ) );\n\t\t}\n\t\telse if ( typeof ajax === 'function' )\n\t\t{\n\t\t\t// Is a function - let the caller define what needs to be done\n\t\t\toSettings.jqXHR = ajax.call( instance, data, callback, oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Object to extend the base settings\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );\n\t\n\t\t\t// Restore for next time around\n\t\t\tajax.data = ajaxData;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Update the table using an Ajax call\n\t * @param {object} settings dataTables settings object\n\t * @returns {boolean} Block the table drawing or not\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdate( settings )\n\t{\n\t\tsettings.iDraw++;\n\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t_fnBuildAjax(\n\t\t\tsettings,\n\t\t\t_fnAjaxParameters( settings ),\n\t\t\tfunction(json) {\n\t\t\t\t_fnAjaxUpdateDraw( settings, json );\n\t\t\t}\n\t\t);\n\t}\n\t\n\t\n\t/**\n\t * Build up the parameters in an object needed for a server-side processing\n\t * request. Note that this is basically done twice, is different ways - a modern\n\t * method which is used by default in DataTables 1.10 which uses objects and\n\t * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if\n\t * the sAjaxSource option is used in the initialisation, or the legacyAjax\n\t * option is set.\n\t * @param {object} oSettings dataTables settings object\n\t * @returns {bool} block the table drawing or not\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxParameters( settings )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tcolumnCount = columns.length,\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tpreSearch = settings.oPreviousSearch,\n\t\t\tpreColSearch = settings.aoPreSearchCols,\n\t\t\ti, data = [], dataProp, column, columnSearch,\n\t\t\tsort = _fnSortFlatten( settings ),\n\t\t\tdisplayStart = settings._iDisplayStart,\n\t\t\tdisplayLength = features.bPaginate !== false ?\n\t\t\t\tsettings._iDisplayLength :\n\t\t\t\t-1;\n\t\n\t\tvar param = function ( name, value ) {\n\t\t\tdata.push( { 'name': name, 'value': value } );\n\t\t};\n\t\n\t\t// DataTables 1.9- compatible method\n\t\tparam( 'sEcho', settings.iDraw );\n\t\tparam( 'iColumns', columnCount );\n\t\tparam( 'sColumns', _pluck( columns, 'sName' ).join(',') );\n\t\tparam( 'iDisplayStart', displayStart );\n\t\tparam( 'iDisplayLength', displayLength );\n\t\n\t\t// DataTables 1.10+ method\n\t\tvar d = {\n\t\t\tdraw: settings.iDraw,\n\t\t\tcolumns: [],\n\t\t\torder: [],\n\t\t\tstart: displayStart,\n\t\t\tlength: displayLength,\n\t\t\tsearch: {\n\t\t\t\tvalue: preSearch.sSearch,\n\t\t\t\tregex: preSearch.bRegex\n\t\t\t}\n\t\t};\n\t\n\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcolumnSearch = preColSearch[i];\n\t\t\tdataProp = typeof column.mData==\"function\" ? 'function' : column.mData ;\n\t\n\t\t\td.columns.push( {\n\t\t\t\tdata: dataProp,\n\t\t\t\tname: column.sName,\n\t\t\t\tsearchable: column.bSearchable,\n\t\t\t\torderable: column.bSortable,\n\t\t\t\tsearch: {\n\t\t\t\t\tvalue: columnSearch.sSearch,\n\t\t\t\t\tregex: columnSearch.bRegex\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\tparam( \"mDataProp_\"+i, dataProp );\n\t\n\t\t\tif ( features.bFilter ) {\n\t\t\t\tparam( 'sSearch_'+i, columnSearch.sSearch );\n\t\t\t\tparam( 'bRegex_'+i, columnSearch.bRegex );\n\t\t\t\tparam( 'bSearchable_'+i, column.bSearchable );\n\t\t\t}\n\t\n\t\t\tif ( features.bSort ) {\n\t\t\t\tparam( 'bSortable_'+i, column.bSortable );\n\t\t\t}\n\t\t}\n\t\n\t\tif ( features.bFilter ) {\n\t\t\tparam( 'sSearch', preSearch.sSearch );\n\t\t\tparam( 'bRegex', preSearch.bRegex );\n\t\t}\n\t\n\t\tif ( features.bSort ) {\n\t\t\t$.each( sort, function ( i, val ) {\n\t\t\t\td.order.push( { column: val.col, dir: val.dir } );\n\t\n\t\t\t\tparam( 'iSortCol_'+i, val.col );\n\t\t\t\tparam( 'sSortDir_'+i, val.dir );\n\t\t\t} );\n\t\n\t\t\tparam( 'iSortingCols', sort.length );\n\t\t}\n\t\n\t\t// If the legacy.ajax parameter is null, then we automatically decide which\n\t\t// form to use, based on sAjaxSource\n\t\tvar legacy = DataTable.ext.legacy.ajax;\n\t\tif ( legacy === null ) {\n\t\t\treturn settings.sAjaxSource ? data : d;\n\t\t}\n\t\n\t\t// Otherwise, if legacy has been specified then we use that to decide on the\n\t\t// form\n\t\treturn legacy ? data : d;\n\t}\n\t\n\t\n\t/**\n\t * Data the data from the server (nuking the old) and redraw the table\n\t * @param {object} oSettings dataTables settings object\n\t * @param {object} json json data return from the server.\n\t * @param {string} json.sEcho Tracking flag for DataTables to match requests\n\t * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering\n\t * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering\n\t * @param {array} json.aaData The data to display on this page\n\t * @param {string} [json.sColumns] Column ordering (sName, comma separated)\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdateDraw ( settings, json )\n\t{\n\t\t// v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.\n\t\t// Support both\n\t\tvar compat = function ( old, modern ) {\n\t\t\treturn json[old] !== undefined ? json[old] : json[modern];\n\t\t};\n\t\n\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\tvar draw = compat( 'sEcho', 'draw' );\n\t\tvar recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );\n\t\tvar recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );\n\t\n\t\tif ( draw !== undefined ) {\n\t\t\t// Protect against out of sequence returns\n\t\t\tif ( draw*1 < settings.iDraw ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettings.iDraw = draw * 1;\n\t\t}\n\t\n\t\t// No data in returned object, so rather than an array, we show an empty table\n\t\tif ( ! data ) {\n\t\t\tdata = [];\n\t\t}\n\t\n\t\t_fnClearTable( settings );\n\t\tsettings._iRecordsTotal = parseInt(recordsTotal, 10);\n\t\tsettings._iRecordsDisplay = parseInt(recordsFiltered, 10);\n\t\n\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t_fnAddData( settings, data[i] );\n\t\t}\n\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\n\t\t_fnDraw( settings, true );\n\t\n\t\tif ( ! settings._bInitComplete ) {\n\t\t\t_fnInitComplete( settings, json );\n\t\t}\n\t\n\t\t_fnProcessingDisplay( settings, false );\n\t}\n\t\n\t\n\t/**\n\t * Get the data from the JSON data source to use for drawing a table. Using\n\t * `_fnGetObjectDataFn` allows the data to be sourced from a property of the\n\t * source object, or from a processing function.\n\t * @param {object} oSettings dataTables settings object\n\t * @param {object} json Data source object / array from the server\n\t * @return {array} Array of data to use\n\t */\n\t function _fnAjaxDataSrc ( oSettings, json, write )\n\t {\n\t\tvar dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?\n\t\t\toSettings.ajax.dataSrc :\n\t\t\toSettings.sAjaxDataProp; // Compatibility with 1.9-.\n\t\n\t\tif ( ! write ) {\n\t\t\tif ( dataSrc === 'data' ) {\n\t\t\t\t// If the default, then we still want to support the old style, and safely ignore\n\t\t\t\t// it if possible\n\t\t\t\treturn json.aaData || json[dataSrc];\n\t\t\t}\n\t\n\t\t\treturn dataSrc !== \"\" ?\n\t\t\t\t_fnGetObjectDataFn( dataSrc )( json ) :\n\t\t\t\tjson;\n\t\t}\n\t\n\t\t// set\n\t\t_fnSetObjectDataFn( dataSrc )( json, write );\n\t}\n\t\n\t/**\n\t * Generate the node required for filtering text\n\t * @returns {node} Filter control element\n\t * @param {object} oSettings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlFilter ( settings )\n\t{\n\t\tvar classes = settings.oClasses;\n\t\tvar tableId = settings.sTableId;\n\t\tvar language = settings.oLanguage;\n\t\tvar previousSearch = settings.oPreviousSearch;\n\t\tvar features = settings.aanFeatures;\n\t\tvar input = '<input type=\"search\" class=\"'+classes.sFilterInput+'\"/>';\n\t\n\t\tvar str = language.sSearch;\n\t\tstr = str.match(/_INPUT_/) ?\n\t\t\tstr.replace('_INPUT_', input) :\n\t\t\tstr+input;\n\t\n\t\tvar filter = $('<div/>', {\n\t\t\t\t'id': ! features.f ? tableId+'_filter' : null,\n\t\t\t\t'class': classes.sFilter\n\t\t\t} )\n\t\t\t.append( $('<label/>' ).append( str ) );\n\t\n\t\tvar searchFn = function(event) {\n\t\t\t/* Update all other filter input elements for the new display */\n\t\t\tvar n = features.f;\n\t\t\tvar val = !this.value ? \"\" : this.value; // mental IE8 fix :-(\n\t\t\tif(previousSearch.return && event.key !== \"Enter\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t/* Now do the filter */\n\t\t\tif ( val != previousSearch.sSearch ) {\n\t\t\t\t_fnFilterComplete( settings, {\n\t\t\t\t\t\"sSearch\": val,\n\t\t\t\t\t\"bRegex\": previousSearch.bRegex,\n\t\t\t\t\t\"bSmart\": previousSearch.bSmart ,\n\t\t\t\t\t\"bCaseInsensitive\": previousSearch.bCaseInsensitive,\n\t\t\t\t\t\"return\": previousSearch.return\n\t\t\t\t} );\n\t\n\t\t\t\t// Need to redraw, without resorting\n\t\t\t\tsettings._iDisplayStart = 0;\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t};\n\t\n\t\tvar searchDelay = settings.searchDelay !== null ?\n\t\t\tsettings.searchDelay :\n\t\t\t_fnDataSource( settings ) === 'ssp' ?\n\t\t\t\t400 :\n\t\t\t\t0;\n\t\n\t\tvar jqFilter = $('input', filter)\n\t\t\t.val( previousSearch.sSearch )\n\t\t\t.attr( 'placeholder', language.sSearchPlaceholder )\n\t\t\t.on(\n\t\t\t\t'keyup.DT search.DT input.DT paste.DT cut.DT',\n\t\t\t\tsearchDelay ?\n\t\t\t\t\t_fnThrottle( searchFn, searchDelay ) :\n\t\t\t\t\tsearchFn\n\t\t\t)\n\t\t\t.on( 'mouseup', function(e) {\n\t\t\t\t// Edge fix! Edge 17 does not trigger anything other than mouse events when clicking\n\t\t\t\t// on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`\n\t\t\t\t// checks the value to see if it has changed. In other browsers it won't have.\n\t\t\t\tsetTimeout( function () {\n\t\t\t\t\tsearchFn.call(jqFilter[0], e);\n\t\t\t\t}, 10);\n\t\t\t} )\n\t\t\t.on( 'keypress.DT', function(e) {\n\t\t\t\t/* Prevent form submission */\n\t\t\t\tif ( e.keyCode == 13 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.attr('aria-controls', tableId);\n\t\n\t\t// Update the input elements whenever the table is filtered\n\t\t$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame...\n\t\t\t\ttry {\n\t\t\t\t\tif ( jqFilter[0] !== document.activeElement ) {\n\t\t\t\t\t\tjqFilter.val( previousSearch.sSearch );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch ( e ) {}\n\t\t\t}\n\t\t} );\n\t\n\t\treturn filter[0];\n\t}\n\t\n\t\n\t/**\n\t * Filter the table using both the global filter and column based filtering\n\t * @param {object} oSettings dataTables settings object\n\t * @param {object} oSearch search information\n\t * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterComplete ( oSettings, oInput, iForce )\n\t{\n\t\tvar oPrevSearch = oSettings.oPreviousSearch;\n\t\tvar aoPrevSearch = oSettings.aoPreSearchCols;\n\t\tvar fnSaveFilter = function ( oFilter ) {\n\t\t\t/* Save the filtering values */\n\t\t\toPrevSearch.sSearch = oFilter.sSearch;\n\t\t\toPrevSearch.bRegex = oFilter.bRegex;\n\t\t\toPrevSearch.bSmart = oFilter.bSmart;\n\t\t\toPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;\n\t\t\toPrevSearch.return = oFilter.return;\n\t\t};\n\t\tvar fnRegex = function ( o ) {\n\t\t\t// Backwards compatibility with the bEscapeRegex option\n\t\t\treturn o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;\n\t\t};\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo As per sort - can this be moved into an event handler?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\t/* In server-side processing all filtering is done by the server, so no point hanging around here */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' )\n\t\t{\n\t\t\t/* Global filter */\n\t\t\t_fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive, oInput.return );\n\t\t\tfnSaveFilter( oInput );\n\t\n\t\t\t/* Now do the individual column filter */\n\t\t\tfor ( var i=0 ; i<aoPrevSearch.length ; i++ )\n\t\t\t{\n\t\t\t\t_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),\n\t\t\t\t\taoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );\n\t\t\t}\n\t\n\t\t\t/* Custom filtering */\n\t\t\t_fnFilterCustom( oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfnSaveFilter( oInput );\n\t\t}\n\t\n\t\t/* Tell the draw function we have been filtering */\n\t\toSettings.bFiltered = true;\n\t\t_fnCallbackFire( oSettings, null, 'search', [oSettings] );\n\t}\n\t\n\t\n\t/**\n\t * Apply custom filtering functions\n\t * @param {object} oSettings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCustom( settings )\n\t{\n\t\tvar filters = DataTable.ext.search;\n\t\tvar displayRows = settings.aiDisplay;\n\t\tvar row, rowIdx;\n\t\n\t\tfor ( var i=0, ien=filters.length ; i<ien ; i++ ) {\n\t\t\tvar rows = [];\n\t\n\t\t\t// Loop over each row and see if it should be included\n\t\t\tfor ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {\n\t\t\t\trowIdx = displayRows[ j ];\n\t\t\t\trow = settings.aoData[ rowIdx ];\n\t\n\t\t\t\tif ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {\n\t\t\t\t\trows.push( rowIdx );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// So the array reference doesn't break set the results into the\n\t\t\t// existing array\n\t\t\tdisplayRows.length = 0;\n\t\t\t$.merge( displayRows, rows );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Filter the table on a per-column basis\n\t * @param {object} oSettings dataTables settings object\n\t * @param {string} sInput string to filter on\n\t * @param {int} iColumn column to filter\n\t * @param {bool} bRegex treat search string as a regular expression or not\n\t * @param {bool} bSmart use smart filtering or not\n\t * @param {bool} bCaseInsensitive Do case insensitive matching or not\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )\n\t{\n\t\tif ( searchStr === '' ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar data;\n\t\tvar out = [];\n\t\tvar display = settings.aiDisplay;\n\t\tvar rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );\n\t\n\t\tfor ( var i=0 ; i<display.length ; i++ ) {\n\t\t\tdata = settings.aoData[ display[i] ]._aFilterData[ colIdx ];\n\t\n\t\t\tif ( rpSearch.test( data ) ) {\n\t\t\t\tout.push( display[i] );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aiDisplay = out;\n\t}\n\t\n\t\n\t/**\n\t * Filter the data table based on user input and draw the table\n\t * @param {object} settings dataTables settings object\n\t * @param {string} input string to filter on\n\t * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)\n\t * @param {bool} regex treat as a regular expression or not\n\t * @param {bool} smart perform smart filtering or not\n\t * @param {bool} caseInsensitive Do case insensitive matching or not\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnFilter( settings, input, force, regex, smart, caseInsensitive )\n\t{\n\t\tvar rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );\n\t\tvar prevSearch = settings.oPreviousSearch.sSearch;\n\t\tvar displayMaster = settings.aiDisplayMaster;\n\t\tvar display, invalidated, i;\n\t\tvar filtered = [];\n\t\n\t\t// Need to take account of custom filtering functions - always filter\n\t\tif ( DataTable.ext.search.length !== 0 ) {\n\t\t\tforce = true;\n\t\t}\n\t\n\t\t// Check if any of the rows were invalidated\n\t\tinvalidated = _fnFilterData( settings );\n\t\n\t\t// If the input is blank - we just want the full data set\n\t\tif ( input.length <= 0 ) {\n\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t}\n\t\telse {\n\t\t\t// New search - start from the master array\n\t\t\tif ( invalidated ||\n\t\t\t\t force ||\n\t\t\t\t regex ||\n\t\t\t\t prevSearch.length > input.length ||\n\t\t\t\t input.indexOf(prevSearch) !== 0 ||\n\t\t\t\t settings.bSorted // On resort, the display master needs to be\n\t\t\t\t // re-filtered since indexes will have changed\n\t\t\t) {\n\t\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t\t}\n\t\n\t\t\t// Search the display array\n\t\t\tdisplay = settings.aiDisplay;\n\t\n\t\t\tfor ( i=0 ; i<display.length ; i++ ) {\n\t\t\t\tif ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {\n\t\t\t\t\tfiltered.push( display[i] );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tsettings.aiDisplay = filtered;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a regular expression object suitable for searching a table\n\t * @param {string} sSearch string to search for\n\t * @param {bool} bRegex treat as a regular expression or not\n\t * @param {bool} bSmart perform smart filtering or not\n\t * @param {bool} bCaseInsensitive Do case insensitive matching or not\n\t * @returns {RegExp} constructed object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCreateSearch( search, regex, smart, caseInsensitive )\n\t{\n\t\tsearch = regex ?\n\t\t\tsearch :\n\t\t\t_fnEscapeRegex( search );\n\t\t\n\t\tif ( smart ) {\n\t\t\t/* For smart filtering we want to allow the search to work regardless of\n\t\t\t * word order. We also want double quoted text to be preserved, so word\n\t\t\t * order is important - a la google. So this is what we want to\n\t\t\t * generate:\n\t\t\t * \n\t\t\t * ^(?=.*?\\bone\\b)(?=.*?\\btwo three\\b)(?=.*?\\bfour\\b).*$\n\t\t\t */\n\t\t\tvar a = $.map( search.match( /\"[^\"]+\"|[^ ]+/g ) || [''], function ( word ) {\n\t\t\t\tif ( word.charAt(0) === '\"' ) {\n\t\t\t\t\tvar m = word.match( /^\"(.*)\"$/ );\n\t\t\t\t\tword = m ? m[1] : word;\n\t\t\t\t}\n\t\n\t\t\t\treturn word.replace('\"', '');\n\t\t\t} );\n\t\n\t\t\tsearch = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';\n\t\t}\n\t\n\t\treturn new RegExp( search, caseInsensitive ? 'i' : '' );\n\t}\n\t\n\t\n\t/**\n\t * Escape a string such that it can be used in a regular expression\n\t * @param {string} sVal string to escape\n\t * @returns {string} escaped string\n\t * @memberof DataTable#oApi\n\t */\n\tvar _fnEscapeRegex = DataTable.util.escapeRegex;\n\t\n\tvar __filter_div = $('<div>')[0];\n\tvar __filter_div_textContent = __filter_div.textContent !== undefined;\n\t\n\t// Update the filtering data for each row if needed (by invalidation or first run)\n\tfunction _fnFilterData ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar column;\n\t\tvar i, j, ien, jen, filterData, cellData, row;\n\t\tvar wasInvalidated = false;\n\t\n\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aFilterData ) {\n\t\t\t\tfilterData = [];\n\t\n\t\t\t\tfor ( j=0, jen=columns.length ; j<jen ; j++ ) {\n\t\t\t\t\tcolumn = columns[j];\n\t\n\t\t\t\t\tif ( column.bSearchable ) {\n\t\t\t\t\t\tcellData = _fnGetCellData( settings, i, j, 'filter' );\n\t\n\t\t\t\t\t\t// Search in DataTables 1.10 is string based. In 1.11 this\n\t\t\t\t\t\t// should be altered to also allow strict type checking.\n\t\t\t\t\t\tif ( cellData === null ) {\n\t\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( typeof cellData !== 'string' && cellData.toString ) {\n\t\t\t\t\t\t\tcellData = cellData.toString();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If it looks like there is an HTML entity in the string,\n\t\t\t\t\t// attempt to decode it so sorting works as expected. Note that\n\t\t\t\t\t// we could use a single line of jQuery to do this, but the DOM\n\t\t\t\t\t// method used here is much faster http://jsperf.com/html-decode\n\t\t\t\t\tif ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {\n\t\t\t\t\t\t__filter_div.innerHTML = cellData;\n\t\t\t\t\t\tcellData = __filter_div_textContent ?\n\t\t\t\t\t\t\t__filter_div.textContent :\n\t\t\t\t\t\t\t__filter_div.innerText;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tif ( cellData.replace ) {\n\t\t\t\t\t\tcellData = cellData.replace(/[\\r\\n\\u2028]/g, '');\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfilterData.push( cellData );\n\t\t\t\t}\n\t\n\t\t\t\trow._aFilterData = filterData;\n\t\t\t\trow._sFilterRow = filterData.join(' ');\n\t\t\t\twasInvalidated = true;\n\t\t\t}\n\t\t}\n\t\n\t\treturn wasInvalidated;\n\t}\n\t\n\t\n\t/**\n\t * Convert from the internal Hungarian notation to camelCase for external\n\t * interaction\n\t * @param {object} obj Object to convert\n\t * @returns {object} Inverted object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToCamel ( obj )\n\t{\n\t\treturn {\n\t\t\tsearch: obj.sSearch,\n\t\t\tsmart: obj.bSmart,\n\t\t\tregex: obj.bRegex,\n\t\t\tcaseInsensitive: obj.bCaseInsensitive\n\t\t};\n\t}\n\t\n\t\n\t\n\t/**\n\t * Convert from camelCase notation to the internal Hungarian. We could use the\n\t * Hungarian convert function here, but this is cleaner\n\t * @param {object} obj Object to convert\n\t * @returns {object} Inverted object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToHung ( obj )\n\t{\n\t\treturn {\n\t\t\tsSearch: obj.search,\n\t\t\tbSmart: obj.smart,\n\t\t\tbRegex: obj.regex,\n\t\t\tbCaseInsensitive: obj.caseInsensitive\n\t\t};\n\t}\n\t\n\t/**\n\t * Generate the node required for the info display\n\t * @param {object} oSettings dataTables settings object\n\t * @returns {node} Information element\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlInfo ( settings )\n\t{\n\t\tvar\n\t\t\ttid = settings.sTableId,\n\t\t\tnodes = settings.aanFeatures.i,\n\t\t\tn = $('<div/>', {\n\t\t\t\t'class': settings.oClasses.sInfo,\n\t\t\t\t'id': ! nodes ? tid+'_info' : null\n\t\t\t} );\n\t\n\t\tif ( ! nodes ) {\n\t\t\t// Update display on each draw\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": _fnUpdateInfo,\n\t\t\t\t\"sName\": \"information\"\n\t\t\t} );\n\t\n\t\t\tn\n\t\t\t\t.attr( 'role', 'status' )\n\t\t\t\t.attr( 'aria-live', 'polite' );\n\t\n\t\t\t// Table is described by our info div\n\t\t\t$(settings.nTable).attr( 'aria-describedby', tid+'_info' );\n\t\t}\n\t\n\t\treturn n[0];\n\t}\n\t\n\t\n\t/**\n\t * Update the information elements in the display\n\t * @param {object} settings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnUpdateInfo ( settings )\n\t{\n\t\t/* Show information about the table */\n\t\tvar nodes = settings.aanFeatures.i;\n\t\tif ( nodes.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\tlang = settings.oLanguage,\n\t\t\tstart = settings._iDisplayStart+1,\n\t\t\tend = settings.fnDisplayEnd(),\n\t\t\tmax = settings.fnRecordsTotal(),\n\t\t\ttotal = settings.fnRecordsDisplay(),\n\t\t\tout = total ?\n\t\t\t\tlang.sInfo :\n\t\t\t\tlang.sInfoEmpty;\n\t\n\t\tif ( total !== max ) {\n\t\t\t/* Record set after filtering */\n\t\t\tout += ' ' + lang.sInfoFiltered;\n\t\t}\n\t\n\t\t// Convert the macros\n\t\tout += lang.sInfoPostFix;\n\t\tout = _fnInfoMacros( settings, out );\n\t\n\t\tvar callback = lang.fnInfoCallback;\n\t\tif ( callback !== null ) {\n\t\t\tout = callback.call( settings.oInstance,\n\t\t\t\tsettings, start, end, max, total, out\n\t\t\t);\n\t\t}\n\t\n\t\t$(nodes).html( out );\n\t}\n\t\n\t\n\tfunction _fnInfoMacros ( settings, str )\n\t{\n\t\t// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only\n\t\t// internally\n\t\tvar\n\t\t\tformatter = settings.fnFormatNumber,\n\t\t\tstart = settings._iDisplayStart+1,\n\t\t\tlen = settings._iDisplayLength,\n\t\t\tvis = settings.fnRecordsDisplay(),\n\t\t\tall = len === -1;\n\t\n\t\treturn str.\n\t\t\treplace(/_START_/g, formatter.call( settings, start ) ).\n\t\t\treplace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).\n\t\t\treplace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).\n\t\t\treplace(/_TOTAL_/g, formatter.call( settings, vis ) ).\n\t\t\treplace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).\n\t\t\treplace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );\n\t}\n\t\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t * @param {object} settings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnInitialise ( settings )\n\t{\n\t\tvar i, iLen, iAjaxStart=settings.iInitDisplayStart;\n\t\tvar columns = settings.aoColumns, column;\n\t\tvar features = settings.oFeatures;\n\t\tvar deferLoading = settings.bDeferLoading; // value modified by the draw\n\t\n\t\t/* Ensure that the table data is fully initialised */\n\t\tif ( ! settings.bInitialised ) {\n\t\t\tsetTimeout( function(){ _fnInitialise( settings ); }, 200 );\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Show the display HTML options */\n\t\t_fnAddOptionsHtml( settings );\n\t\n\t\t/* Build and draw the header / footer for the table */\n\t\t_fnBuildHead( settings );\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t/* Okay to show that something is going on now */\n\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t/* Calculate sizes for columns */\n\t\tif ( features.bAutoWidth ) {\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=columns.length ; i<iLen ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\n\t\t\tif ( column.sWidth ) {\n\t\t\t\tcolumn.nTh.style.width = _fnStringToCss( column.sWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'preInit', [settings] );\n\t\n\t\t// If there is default sorting required - let's do it. The sort function\n\t\t// will do the drawing for us. Otherwise we draw the table regardless of the\n\t\t// Ajax source - this allows the table to look initialised for Ajax sourcing\n\t\t// data (show 'loading' message possibly)\n\t\t_fnReDraw( settings );\n\t\n\t\t// Server-side processing init complete is done by _fnAjaxUpdateDraw\n\t\tvar dataSrc = _fnDataSource( settings );\n\t\tif ( dataSrc != 'ssp' || deferLoading ) {\n\t\t\t// if there is an ajax source load the data\n\t\t\tif ( dataSrc == 'ajax' ) {\n\t\t\t\t_fnBuildAjax( settings, [], function(json) {\n\t\t\t\t\tvar aData = _fnAjaxDataSrc( settings, json );\n\t\n\t\t\t\t\t// Got the data - add it to the table\n\t\t\t\t\tfor ( i=0 ; i<aData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( settings, aData[i] );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Reset the init display for cookie saving. We've already done\n\t\t\t\t\t// a filter, and therefore cleared it before. So we need to make\n\t\t\t\t\t// it appear 'fresh'\n\t\t\t\t\tsettings.iInitDisplayStart = iAjaxStart;\n\t\n\t\t\t\t\t_fnReDraw( settings );\n\t\n\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t_fnInitComplete( settings, json );\n\t\t\t\t}, settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t_fnInitComplete( settings );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t * @param {object} oSettings dataTables settings object\n\t * @param {object} [json] JSON from the server that completed the table, if using Ajax source\n\t * with client-side processing (optional)\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnInitComplete ( settings, json )\n\t{\n\t\tsettings._bInitComplete = true;\n\t\n\t\t// When data was added after the initialisation (data or Ajax) we need to\n\t\t// calculate the column sizing\n\t\tif ( json || settings.oInit.aaData ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'plugin-init', [settings, json] );\n\t\t_fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );\n\t}\n\t\n\t\n\tfunction _fnLengthChange ( settings, val )\n\t{\n\t\tvar len = parseInt( val, 10 );\n\t\tsettings._iDisplayLength = len;\n\t\n\t\t_fnLengthOverflow( settings );\n\t\n\t\t// Fire length change event\n\t\t_fnCallbackFire( settings, null, 'length', [settings, len] );\n\t}\n\t\n\t\n\t/**\n\t * Generate the node required for user display length changing\n\t * @param {object} settings dataTables settings object\n\t * @returns {node} Display length feature node\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlLength ( settings )\n\t{\n\t\tvar\n\t\t\tclasses = settings.oClasses,\n\t\t\ttableId = settings.sTableId,\n\t\t\tmenu = settings.aLengthMenu,\n\t\t\td2 = Array.isArray( menu[0] ),\n\t\t\tlengths = d2 ? menu[0] : menu,\n\t\t\tlanguage = d2 ? menu[1] : menu;\n\t\n\t\tvar select = $('<select/>', {\n\t\t\t'name': tableId+'_length',\n\t\t\t'aria-controls': tableId,\n\t\t\t'class': classes.sLengthSelect\n\t\t} );\n\t\n\t\tfor ( var i=0, ien=lengths.length ; i<ien ; i++ ) {\n\t\t\tselect[0][ i ] = new Option(\n\t\t\t\ttypeof language[i] === 'number' ?\n\t\t\t\t\tsettings.fnFormatNumber( language[i] ) :\n\t\t\t\t\tlanguage[i],\n\t\t\t\tlengths[i]\n\t\t\t);\n\t\t}\n\t\n\t\tvar div = $('<div><label/></div>').addClass( classes.sLength );\n\t\tif ( ! settings.aanFeatures.l ) {\n\t\t\tdiv[0].id = tableId+'_length';\n\t\t}\n\t\n\t\tdiv.children().append(\n\t\t\tsettings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )\n\t\t);\n\t\n\t\t// Can't use `select` variable as user might provide their own and the\n\t\t// reference is broken by the use of outerHTML\n\t\t$('select', div)\n\t\t\t.val( settings._iDisplayLength )\n\t\t\t.on( 'change.DT', function(e) {\n\t\t\t\t_fnLengthChange( settings, $(this).val() );\n\t\t\t\t_fnDraw( settings );\n\t\t\t} );\n\t\n\t\t// Update node value whenever anything changes the table's length\n\t\t$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t$('select', div).val( len );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn div[0];\n\t}\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Note that most of the paging logic is done in\n\t * DataTable.ext.pager\n\t */\n\t\n\t/**\n\t * Generate the node required for default pagination\n\t * @param {object} oSettings dataTables settings object\n\t * @returns {node} Pagination feature node\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlPaginate ( settings )\n\t{\n\t\tvar\n\t\t\ttype = settings.sPaginationType,\n\t\t\tplugin = DataTable.ext.pager[ type ],\n\t\t\tmodern = typeof plugin === 'function',\n\t\t\tredraw = function( settings ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t},\n\t\t\tnode = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],\n\t\t\tfeatures = settings.aanFeatures;\n\t\n\t\tif ( ! modern ) {\n\t\t\tplugin.fnInit( settings, node, redraw );\n\t\t}\n\t\n\t\t/* Add a draw callback for the pagination on first instance, to update the paging display */\n\t\tif ( ! features.p )\n\t\t{\n\t\t\tnode.id = settings.sTableId+'_paginate';\n\t\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": function( settings ) {\n\t\t\t\t\tif ( modern ) {\n\t\t\t\t\t\tvar\n\t\t\t\t\t\t\tstart = settings._iDisplayStart,\n\t\t\t\t\t\t\tlen = settings._iDisplayLength,\n\t\t\t\t\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\t\t\t\t\tall = len === -1,\n\t\t\t\t\t\t\tpage = all ? 0 : Math.ceil( start / len ),\n\t\t\t\t\t\t\tpages = all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\t\t\t\tbuttons = plugin(page, pages),\n\t\t\t\t\t\t\ti, ien;\n\t\n\t\t\t\t\t\tfor ( i=0, ien=features.p.length ; i<ien ; i++ ) {\n\t\t\t\t\t\t\t_fnRenderer( settings, 'pageButton' )(\n\t\t\t\t\t\t\t\tsettings, features.p[i], i, buttons, page, pages\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\telse {\n\t\t\t\t\t\tplugin.fnUpdate( settings, redraw );\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"sName\": \"pagination\"\n\t\t\t} );\n\t\t}\n\t\n\t\treturn node;\n\t}\n\t\n\t\n\t/**\n\t * Alter the display settings to change the page\n\t * @param {object} settings DataTables settings object\n\t * @param {string|int} action Paging action to take: \"first\", \"previous\",\n\t * \"next\" or \"last\" or page number to jump to (integer)\n\t * @param [bool] redraw Automatically draw the update or not\n\t * @returns {bool} true page has changed, false - no change\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnPageChange ( settings, action, redraw )\n\t{\n\t\tvar\n\t\t\tstart = settings._iDisplayStart,\n\t\t\tlen = settings._iDisplayLength,\n\t\t\trecords = settings.fnRecordsDisplay();\n\t\n\t\tif ( records === 0 || len === -1 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( typeof action === \"number\" )\n\t\t{\n\t\t\tstart = action * len;\n\t\n\t\t\tif ( start > records )\n\t\t\t{\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"first\" )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( action == \"previous\" )\n\t\t{\n\t\t\tstart = len >= 0 ?\n\t\t\t\tstart - len :\n\t\t\t\t0;\n\t\n\t\t\tif ( start < 0 )\n\t\t\t{\n\t\t\t start = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"next\" )\n\t\t{\n\t\t\tif ( start + len < records )\n\t\t\t{\n\t\t\t\tstart += len;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"last\" )\n\t\t{\n\t\t\tstart = Math.floor( (records-1) / len) * len;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_fnLog( settings, 0, \"Unknown paging action: \"+action, 5 );\n\t\t}\n\t\n\t\tvar changed = settings._iDisplayStart !== start;\n\t\tsettings._iDisplayStart = start;\n\t\n\t\tif ( changed ) {\n\t\t\t_fnCallbackFire( settings, null, 'page', [settings] );\n\t\n\t\t\tif ( redraw ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t}\n\t\n\t\treturn changed;\n\t}\n\t\n\t\n\t\n\t/**\n\t * Generate the node required for the processing node\n\t * @param {object} settings dataTables settings object\n\t * @returns {node} Processing element\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlProcessing ( settings )\n\t{\n\t\treturn $('<div/>', {\n\t\t\t\t'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,\n\t\t\t\t'class': settings.oClasses.sProcessing\n\t\t\t} )\n\t\t\t.html( settings.oLanguage.sProcessing )\n\t\t\t.insertBefore( settings.nTable )[0];\n\t}\n\t\n\t\n\t/**\n\t * Display or hide the processing indicator\n\t * @param {object} settings dataTables settings object\n\t * @param {bool} show Show the processing indicator (true) or not (false)\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnProcessingDisplay ( settings, show )\n\t{\n\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t$(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'processing', [settings, show] );\n\t}\n\t\n\t/**\n\t * Add any control elements for the table - specifically scrolling\n\t * @param {object} settings dataTables settings object\n\t * @returns {node} Node to add to the DOM\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlTable ( settings )\n\t{\n\t\tvar table = $(settings.nTable);\n\t\n\t\t// Scrolling from here on in\n\t\tvar scroll = settings.oScroll;\n\t\n\t\tif ( scroll.sX === '' && scroll.sY === '' ) {\n\t\t\treturn settings.nTable;\n\t\t}\n\t\n\t\tvar scrollX = scroll.sX;\n\t\tvar scrollY = scroll.sY;\n\t\tvar classes = settings.oClasses;\n\t\tvar caption = table.children('caption');\n\t\tvar captionSide = caption.length ? caption[0]._captionSide : null;\n\t\tvar headerClone = $( table[0].cloneNode(false) );\n\t\tvar footerClone = $( table[0].cloneNode(false) );\n\t\tvar footer = table.children('tfoot');\n\t\tvar _div = '<div/>';\n\t\tvar size = function ( s ) {\n\t\t\treturn !s ? null : _fnStringToCss( s );\n\t\t};\n\t\n\t\tif ( ! footer.length ) {\n\t\t\tfooter = null;\n\t\t}\n\t\n\t\t/*\n\t\t * The HTML structure that we want to generate in this function is:\n\t\t * div - scroller\n\t\t * div - scroll head\n\t\t * div - scroll head inner\n\t\t * table - scroll head table\n\t\t * thead - thead\n\t\t * div - scroll body\n\t\t * table - table (master table)\n\t\t * thead - thead clone for sizing\n\t\t * tbody - tbody\n\t\t * div - scroll foot\n\t\t * div - scroll foot inner\n\t\t * table - scroll foot table\n\t\t * tfoot - tfoot\n\t\t */\n\t\tvar scroller = $( _div, { 'class': classes.sScrollWrapper } )\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollHead } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollHeadInner } )\n\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t'box-sizing': 'content-box',\n\t\t\t\t\t\t\t\twidth: scroll.sXInner || '100%'\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\theaderClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'top' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('thead')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t)\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollBody } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\toverflow: 'auto',\n\t\t\t\t\t\twidth: size( scrollX )\n\t\t\t\t\t} )\n\t\t\t\t\t.append( table )\n\t\t\t);\n\t\n\t\tif ( footer ) {\n\t\t\tscroller.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollFoot } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollFootInner } )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\tfooterClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'bottom' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('tfoot')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\n\t\tvar children = scroller.children();\n\t\tvar scrollHead = children[0];\n\t\tvar scrollBody = children[1];\n\t\tvar scrollFoot = footer ? children[2] : null;\n\t\n\t\t// When the body is scrolled, then we also want to scroll the headers\n\t\tif ( scrollX ) {\n\t\t\t$(scrollBody).on( 'scroll.DT', function (e) {\n\t\t\t\tvar scrollLeft = this.scrollLeft;\n\t\n\t\t\t\tscrollHead.scrollLeft = scrollLeft;\n\t\n\t\t\t\tif ( footer ) {\n\t\t\t\t\tscrollFoot.scrollLeft = scrollLeft;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\n\t\t$(scrollBody).css('max-height', scrollY);\n\t\tif (! scroll.bCollapse) {\n\t\t\t$(scrollBody).css('height', scrollY);\n\t\t}\n\t\n\t\tsettings.nScrollHead = scrollHead;\n\t\tsettings.nScrollBody = scrollBody;\n\t\tsettings.nScrollFoot = scrollFoot;\n\t\n\t\t// On redraw - align columns\n\t\tsettings.aoDrawCallback.push( {\n\t\t\t\"fn\": _fnScrollDraw,\n\t\t\t\"sName\": \"scrolling\"\n\t\t} );\n\t\n\t\treturn scroller[0];\n\t}\n\t\n\t\n\t\n\t/**\n\t * Update the header, footer and body tables for resizing - i.e. column\n\t * alignment.\n\t *\n\t * Welcome to the most horrible function DataTables. The process that this\n\t * function follows is basically:\n\t * 1. Re-create the table inside the scrolling div\n\t * 2. Take live measurements from the DOM\n\t * 3. Apply the measurements to align the columns\n\t * 4. Clean up\n\t *\n\t * @param {object} settings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnScrollDraw ( settings )\n\t{\n\t\t// Given that this is such a monster function, a lot of variables are use\n\t\t// to try and keep the minimised size as small as possible\n\t\tvar\n\t\t\tscroll = settings.oScroll,\n\t\t\tscrollX = scroll.sX,\n\t\t\tscrollXInner = scroll.sXInner,\n\t\t\tscrollY = scroll.sY,\n\t\t\tbarWidth = scroll.iBarWidth,\n\t\t\tdivHeader = $(settings.nScrollHead),\n\t\t\tdivHeaderStyle = divHeader[0].style,\n\t\t\tdivHeaderInner = divHeader.children('div'),\n\t\t\tdivHeaderInnerStyle = divHeaderInner[0].style,\n\t\t\tdivHeaderTable = divHeaderInner.children('table'),\n\t\t\tdivBodyEl = settings.nScrollBody,\n\t\t\tdivBody = $(divBodyEl),\n\t\t\tdivBodyStyle = divBodyEl.style,\n\t\t\tdivFooter = $(settings.nScrollFoot),\n\t\t\tdivFooterInner = divFooter.children('div'),\n\t\t\tdivFooterTable = divFooterInner.children('table'),\n\t\t\theader = $(settings.nTHead),\n\t\t\ttable = $(settings.nTable),\n\t\t\ttableEl = table[0],\n\t\t\ttableStyle = tableEl.style,\n\t\t\tfooter = settings.nTFoot ? $(settings.nTFoot) : null,\n\t\t\tbrowser = settings.oBrowser,\n\t\t\tie67 = browser.bScrollOversize,\n\t\t\tdtHeaderCells = _pluck( settings.aoColumns, 'nTh' ),\n\t\t\theaderTrgEls, footerTrgEls,\n\t\t\theaderSrcEls, footerSrcEls,\n\t\t\theaderCopy, footerCopy,\n\t\t\theaderWidths=[], footerWidths=[],\n\t\t\theaderContent=[], footerContent=[],\n\t\t\tidx, correction, sanityWidth,\n\t\t\tzeroOut = function(nSizer) {\n\t\t\t\tvar style = nSizer.style;\n\t\t\t\tstyle.paddingTop = \"0\";\n\t\t\t\tstyle.paddingBottom = \"0\";\n\t\t\t\tstyle.borderTopWidth = \"0\";\n\t\t\t\tstyle.borderBottomWidth = \"0\";\n\t\t\t\tstyle.height = 0;\n\t\t\t};\n\t\n\t\t// If the scrollbar visibility has changed from the last draw, we need to\n\t\t// adjust the column sizes as the table width will have changed to account\n\t\t// for the scrollbar\n\t\tvar scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;\n\t\t\n\t\tif ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t\treturn; // adjust column sizing will call this function again\n\t\t}\n\t\telse {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t}\n\t\n\t\t/*\n\t\t * 1. Re-create the table inside the scrolling div\n\t\t */\n\t\n\t\t// Remove the old minimised thead and tfoot elements in the inner table\n\t\ttable.children('thead, tfoot').remove();\n\t\n\t\tif ( footer ) {\n\t\t\tfooterCopy = footer.clone().prependTo( table );\n\t\t\tfooterTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized\n\t\t\tfooterSrcEls = footerCopy.find('tr');\n\t\t}\n\t\n\t\t// Clone the current header and footer elements and then place it into the inner table\n\t\theaderCopy = header.clone().prependTo( table );\n\t\theaderTrgEls = header.find('tr'); // original header is in its own table\n\t\theaderSrcEls = headerCopy.find('tr');\n\t\theaderCopy.find('th, td').removeAttr('tabindex');\n\t\n\t\n\t\t/*\n\t\t * 2. Take live measurements from the DOM - do not alter the DOM itself!\n\t\t */\n\t\n\t\t// Remove old sizing and apply the calculated column widths\n\t\t// Get the unique column headers in the newly created (cloned) header. We want to apply the\n\t\t// calculated sizes to this header\n\t\tif ( ! scrollX )\n\t\t{\n\t\t\tdivBodyStyle.width = '100%';\n\t\t\tdivHeader[0].style.width = '100%';\n\t\t}\n\t\n\t\t$.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {\n\t\t\tidx = _fnVisibleToColumnIndex( settings, i );\n\t\t\tel.style.width = settings.aoColumns[idx].sWidth;\n\t\t} );\n\t\n\t\tif ( footer ) {\n\t\t\t_fnApplyToChildren( function(n) {\n\t\t\t\tn.style.width = \"\";\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Size the table as a whole\n\t\tsanityWidth = table.outerWidth();\n\t\tif ( scrollX === \"\" ) {\n\t\t\t// No x scrolling\n\t\t\ttableStyle.width = \"100%\";\n\t\n\t\t\t// IE7 will make the width of the table when 100% include the scrollbar\n\t\t\t// - which is shouldn't. When there is a scrollbar we need to take this\n\t\t\t// into account.\n\t\t\tif ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);\n\t\t\t}\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\telse if ( scrollXInner !== \"\" ) {\n\t\t\t// legacy x scroll inner has been given - use it\n\t\t\ttableStyle.width = _fnStringToCss(scrollXInner);\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\n\t\t// Hidden header should have zero height, so remove padding and borders. Then\n\t\t// set the width based on the real headers\n\t\n\t\t// Apply all styles in one pass\n\t\t_fnApplyToChildren( zeroOut, headerSrcEls );\n\t\n\t\t// Read all widths in next pass\n\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\tvar style = window.getComputedStyle ?\n\t\t\t\twindow.getComputedStyle(nSizer).width :\n\t\t\t\t_fnStringToCss( $(nSizer).width() );\n\t\n\t\t\theaderContent.push( nSizer.innerHTML );\n\t\t\theaderWidths.push( style );\n\t\t}, headerSrcEls );\n\t\n\t\t// Apply all widths in final pass\n\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\tnToSize.style.width = headerWidths[i];\n\t\t}, headerTrgEls );\n\t\n\t\t$(headerSrcEls).height(0);\n\t\n\t\t/* Same again with the footer if we have one */\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( zeroOut, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\t\tfooterContent.push( nSizer.innerHTML );\n\t\t\t\tfooterWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t\t}, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t\tnToSize.style.width = footerWidths[i];\n\t\t\t}, footerTrgEls );\n\t\n\t\t\t$(footerSrcEls).height(0);\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 3. Apply the measurements\n\t\t */\n\t\n\t\t// \"Hide\" the header and footer that we used for the sizing. We need to keep\n\t\t// the content of the cell so that the width applied to the header and body\n\t\t// both match, but we want to hide it completely. We want to also fix their\n\t\t// width to what they currently are\n\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\">'+headerContent[i]+'</div>';\n\t\t\tnSizer.childNodes[0].style.height = \"0\";\n\t\t\tnSizer.childNodes[0].style.overflow = \"hidden\";\n\t\t\tnSizer.style.width = headerWidths[i];\n\t\t}, headerSrcEls );\n\t\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\">'+footerContent[i]+'</div>';\n\t\t\t\tnSizer.childNodes[0].style.height = \"0\";\n\t\t\t\tnSizer.childNodes[0].style.overflow = \"hidden\";\n\t\t\t\tnSizer.style.width = footerWidths[i];\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Sanity check that the table is of a sensible width. If not then we are going to get\n\t\t// misalignment - try to prevent this by not allowing the table to shrink below its min width\n\t\tif ( table.outerWidth() < sanityWidth )\n\t\t{\n\t\t\t// The min width depends upon if we have a vertical scrollbar visible or not */\n\t\t\tcorrection = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")) ?\n\t\t\t\t\tsanityWidth+barWidth :\n\t\t\t\t\tsanityWidth;\n\t\n\t\t\t// IE6/7 are a law unto themselves...\n\t\t\tif ( ie67 && (divBodyEl.scrollHeight >\n\t\t\t\tdivBodyEl.offsetHeight || divBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( correction-barWidth );\n\t\t\t}\n\t\n\t\t\t// And give the user a warning that we've stopped the table getting too small\n\t\t\tif ( scrollX === \"\" || scrollXInner !== \"\" ) {\n\t\t\t\t_fnLog( settings, 1, 'Possible column misalignment', 6 );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcorrection = '100%';\n\t\t}\n\t\n\t\t// Apply to the container elements\n\t\tdivBodyStyle.width = _fnStringToCss( correction );\n\t\tdivHeaderStyle.width = _fnStringToCss( correction );\n\t\n\t\tif ( footer ) {\n\t\t\tsettings.nScrollFoot.style.width = _fnStringToCss( correction );\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 4. Clean up\n\t\t */\n\t\tif ( ! scrollY ) {\n\t\t\t/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting\n\t\t\t * the scrollbar height from the visible display, rather than adding it on. We need to\n\t\t\t * set the height in order to sort this. Don't want to do it in any other browsers.\n\t\t\t */\n\t\t\tif ( ie67 ) {\n\t\t\t\tdivBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Finally set the width's of the header and footer tables */\n\t\tvar iOuterWidth = table.outerWidth();\n\t\tdivHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\tdivHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );\n\t\n\t\t// Figure out if there are scrollbar present - if so then we need a the header and footer to\n\t\t// provide a bit more space to allow \"overflow\" scrolling (i.e. past the scrollbar)\n\t\tvar bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == \"scroll\";\n\t\tvar padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );\n\t\tdivHeaderInnerStyle[ padding ] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\n\t\tif ( footer ) {\n\t\t\tdivFooterTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style[padding] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\t}\n\t\n\t\t// Correct DOM ordering for colgroup - comes before the thead\n\t\ttable.children('colgroup').insertBefore( table.children('thead') );\n\t\n\t\t/* Adjust the position of the header in case we loose the y-scrollbar */\n\t\tdivBody.trigger('scroll');\n\t\n\t\t// If sorting or filtering has occurred, jump the scrolling back to the top\n\t\t// only if we aren't holding the position\n\t\tif ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {\n\t\t\tdivBodyEl.scrollTop = 0;\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Apply a given function to the display child nodes of an element array (typically\n\t * TD children of TR rows\n\t * @param {function} fn Method to apply to the objects\n\t * @param array {nodes} an1 List of elements to look through for display children\n\t * @param array {nodes} an2 Another list (identical structure to the first) - optional\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyToChildren( fn, an1, an2 )\n\t{\n\t\tvar index=0, i=0, iLen=an1.length;\n\t\tvar nNode1, nNode2;\n\t\n\t\twhile ( i < iLen ) {\n\t\t\tnNode1 = an1[i].firstChild;\n\t\t\tnNode2 = an2 ? an2[i].firstChild : null;\n\t\n\t\t\twhile ( nNode1 ) {\n\t\t\t\tif ( nNode1.nodeType === 1 ) {\n\t\t\t\t\tif ( an2 ) {\n\t\t\t\t\t\tfn( nNode1, nNode2, index );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tfn( nNode1, index );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\n\t\t\t\tnNode1 = nNode1.nextSibling;\n\t\t\t\tnNode2 = an2 ? nNode2.nextSibling : null;\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t}\n\t}\n\t\n\t\n\t\n\tvar __re_html_remove = /<.*?>/g;\n\t\n\t\n\t/**\n\t * Calculate the width of columns for the table\n\t * @param {object} oSettings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnCalculateColumnWidths ( oSettings )\n\t{\n\t\tvar\n\t\t\ttable = oSettings.nTable,\n\t\t\tcolumns = oSettings.aoColumns,\n\t\t\tscroll = oSettings.oScroll,\n\t\t\tscrollY = scroll.sY,\n\t\t\tscrollX = scroll.sX,\n\t\t\tscrollXInner = scroll.sXInner,\n\t\t\tcolumnCount = columns.length,\n\t\t\tvisibleColumns = _fnGetColumns( oSettings, 'bVisible' ),\n\t\t\theaderCells = $('th', oSettings.nTHead),\n\t\t\ttableWidthAttr = table.getAttribute('width'), // from DOM element\n\t\t\ttableContainer = table.parentNode,\n\t\t\tuserInputs = false,\n\t\t\ti, column, columnIdx, width, outerWidth,\n\t\t\tbrowser = oSettings.oBrowser,\n\t\t\tie67 = browser.bScrollOversize;\n\t\n\t\tvar styleWidth = table.style.width;\n\t\tif ( styleWidth && styleWidth.indexOf('%') !== -1 ) {\n\t\t\ttableWidthAttr = styleWidth;\n\t\t}\n\t\n\t\t/* Convert any user input sizes into pixel sizes */\n\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\tif ( column.sWidth !== null ) {\n\t\t\t\tcolumn.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );\n\t\n\t\t\t\tuserInputs = true;\n\t\t\t}\n\t\t}\n\t\n\t\t/* If the number of columns in the DOM equals the number that we have to\n\t\t * process in DataTables, then we can use the offsets that are created by\n\t\t * the web- browser. No custom sizes can be set in order for this to happen,\n\t\t * nor scrolling used\n\t\t */\n\t\tif ( ie67 || ! userInputs && ! scrollX && ! scrollY &&\n\t\t columnCount == _fnVisbleColumns( oSettings ) &&\n\t\t columnCount == headerCells.length\n\t\t) {\n\t\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\t\tvar colIdx = _fnVisibleToColumnIndex( oSettings, i );\n\t\n\t\t\t\tif ( colIdx !== null ) {\n\t\t\t\t\tcolumns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise construct a single row, worst case, table with the widest\n\t\t\t// node in the data, assign any user defined widths, then insert it into\n\t\t\t// the DOM and allow the browser to do all the hard work of calculating\n\t\t\t// table widths\n\t\t\tvar tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table\n\t\t\t\t.css( 'visibility', 'hidden' )\n\t\t\t\t.removeAttr( 'id' );\n\t\n\t\t\t// Clean up the table body\n\t\t\ttmpTable.find('tbody tr').remove();\n\t\t\tvar tr = $('<tr/>').appendTo( tmpTable.find('tbody') );\n\t\n\t\t\t// Clone the table header and footer - we can't use the header / footer\n\t\t\t// from the cloned table, since if scrolling is active, the table's\n\t\t\t// real header and footer are contained in different table tags\n\t\t\ttmpTable.find('thead, tfoot').remove();\n\t\t\ttmpTable\n\t\t\t\t.append( $(oSettings.nTHead).clone() )\n\t\t\t\t.append( $(oSettings.nTFoot).clone() );\n\t\n\t\t\t// Remove any assigned widths from the footer (from scrolling)\n\t\t\ttmpTable.find('tfoot th, tfoot td').css('width', '');\n\t\n\t\t\t// Apply custom sizing to the cloned header\n\t\t\theaderCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );\n\t\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\t\theaderCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?\n\t\t\t\t\t_fnStringToCss( column.sWidthOrig ) :\n\t\t\t\t\t'';\n\t\n\t\t\t\t// For scrollX we need to force the column width otherwise the\n\t\t\t\t// browser will collapse it. If this width is smaller than the\n\t\t\t\t// width the column requires, then it will have no effect\n\t\t\t\tif ( column.sWidthOrig && scrollX ) {\n\t\t\t\t\t$( headerCells[i] ).append( $('<div/>').css( {\n\t\t\t\t\t\twidth: column.sWidthOrig,\n\t\t\t\t\t\tmargin: 0,\n\t\t\t\t\t\tpadding: 0,\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\theight: 1\n\t\t\t\t\t} ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Find the widest cell for each column and put it into the table\n\t\t\tif ( oSettings.aoData.length ) {\n\t\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\t\tcolumnIdx = visibleColumns[i];\n\t\t\t\t\tcolumn = columns[ columnIdx ];\n\t\n\t\t\t\t\t$( _fnGetWidestNode( oSettings, columnIdx ) )\n\t\t\t\t\t\t.clone( false )\n\t\t\t\t\t\t.append( column.sContentPadding )\n\t\t\t\t\t\t.appendTo( tr );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Tidy the temporary table - remove name attributes so there aren't\n\t\t\t// duplicated in the dom (radio elements for example)\n\t\t\t$('[name]', tmpTable).removeAttr('name');\n\t\n\t\t\t// Table has been built, attach to the document so we can work with it.\n\t\t\t// A holding element is used, positioned at the top of the container\n\t\t\t// with minimal height, so it has no effect on if the container scrolls\n\t\t\t// or not. Otherwise it might trigger scrolling when it actually isn't\n\t\t\t// needed\n\t\t\tvar holder = $('<div/>').css( scrollX || scrollY ?\n\t\t\t\t\t{\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\theight: 1,\n\t\t\t\t\t\tright: 0,\n\t\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t\t} :\n\t\t\t\t\t{}\n\t\t\t\t)\n\t\t\t\t.append( tmpTable )\n\t\t\t\t.appendTo( tableContainer );\n\t\n\t\t\t// When scrolling (X or Y) we want to set the width of the table as \n\t\t\t// appropriate. However, when not scrolling leave the table width as it\n\t\t\t// is. This results in slightly different, but I think correct behaviour\n\t\t\tif ( scrollX && scrollXInner ) {\n\t\t\t\ttmpTable.width( scrollXInner );\n\t\t\t}\n\t\t\telse if ( scrollX ) {\n\t\t\t\ttmpTable.css( 'width', 'auto' );\n\t\t\t\ttmpTable.removeAttr('width');\n\t\n\t\t\t\t// If there is no width attribute or style, then allow the table to\n\t\t\t\t// collapse\n\t\t\t\tif ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {\n\t\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( scrollY ) {\n\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t}\n\t\t\telse if ( tableWidthAttr ) {\n\t\t\t\ttmpTable.width( tableWidthAttr );\n\t\t\t}\n\t\n\t\t\t// Get the width of each column in the constructed table - we need to\n\t\t\t// know the inner width (so it can be assigned to the other table's\n\t\t\t// cells) and the outer width so we can calculate the full width of the\n\t\t\t// table. This is safe since DataTables requires a unique cell for each\n\t\t\t// column, but if ever a header can span multiple columns, this will\n\t\t\t// need to be modified.\n\t\t\tvar total = 0;\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tvar cell = $(headerCells[i]);\n\t\t\t\tvar border = cell.outerWidth() - cell.width();\n\t\n\t\t\t\t// Use getBounding... where possible (not IE8-) because it can give\n\t\t\t\t// sub-pixel accuracy, which we then want to round up!\n\t\t\t\tvar bounding = browser.bBounding ?\n\t\t\t\t\tMath.ceil( headerCells[i].getBoundingClientRect().width ) :\n\t\t\t\t\tcell.outerWidth();\n\t\n\t\t\t\t// Total is tracked to remove any sub-pixel errors as the outerWidth\n\t\t\t\t// of the table might not equal the total given here (IE!).\n\t\t\t\ttotal += bounding;\n\t\n\t\t\t\t// Width for each column to use\n\t\t\t\tcolumns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );\n\t\t\t}\n\t\n\t\t\ttable.style.width = _fnStringToCss( total );\n\t\n\t\t\t// Finished with the table - ditch it\n\t\t\tholder.remove();\n\t\t}\n\t\n\t\t// If there is a width attr, we want to attach an event listener which\n\t\t// allows the table sizing to automatically adjust when the window is\n\t\t// resized. Use the width attr rather than CSS, since we can't know if the\n\t\t// CSS is a relative value or absolute - DOM read is always px.\n\t\tif ( tableWidthAttr ) {\n\t\t\ttable.style.width = _fnStringToCss( tableWidthAttr );\n\t\t}\n\t\n\t\tif ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {\n\t\t\tvar bindResize = function () {\n\t\t\t\t$(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {\n\t\t\t\t\t_fnAdjustColumnSizing( oSettings );\n\t\t\t\t} ) );\n\t\t\t};\n\t\n\t\t\t// IE6/7 will crash if we bind a resize event handler on page load.\n\t\t\t// To be removed in 1.11 which drops IE6/7 support\n\t\t\tif ( ie67 ) {\n\t\t\t\tsetTimeout( bindResize, 1000 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbindResize();\n\t\t\t}\n\t\n\t\t\toSettings._reszEvt = true;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Throttle the calls to a function. Arguments and context are maintained for\n\t * the throttled function\n\t * @param {function} fn Function to be called\n\t * @param {int} [freq=200] call frequency in mS\n\t * @returns {function} wrapped function\n\t * @memberof DataTable#oApi\n\t */\n\tvar _fnThrottle = DataTable.util.throttle;\n\t\n\t\n\t/**\n\t * Convert a CSS unit width to pixels (e.g. 2em)\n\t * @param {string} width width to be converted\n\t * @param {node} parent parent to get the with for (required for relative widths) - optional\n\t * @returns {int} width in pixels\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnConvertToWidth ( width, parent )\n\t{\n\t\tif ( ! width ) {\n\t\t\treturn 0;\n\t\t}\n\t\n\t\tvar n = $('<div/>')\n\t\t\t.css( 'width', _fnStringToCss( width ) )\n\t\t\t.appendTo( parent || document.body );\n\t\n\t\tvar val = n[0].offsetWidth;\n\t\tn.remove();\n\t\n\t\treturn val;\n\t}\n\t\n\t\n\t/**\n\t * Get the widest node\n\t * @param {object} settings dataTables settings object\n\t * @param {int} colIdx column of interest\n\t * @returns {node} widest table node\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetWidestNode( settings, colIdx )\n\t{\n\t\tvar idx = _fnGetMaxLenString( settings, colIdx );\n\t\tif ( idx < 0 ) {\n\t\t\treturn null;\n\t\t}\n\t\n\t\tvar data = settings.aoData[ idx ];\n\t\treturn ! data.nTr ? // Might not have been created when deferred rendering\n\t\t\t$('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :\n\t\t\tdata.anCells[ colIdx ];\n\t}\n\t\n\t\n\t/**\n\t * Get the maximum strlen for each data column\n\t * @param {object} settings dataTables settings object\n\t * @param {int} colIdx column of interest\n\t * @returns {string} max string length for each column\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetMaxLenString( settings, colIdx )\n\t{\n\t\tvar s, max=-1, maxIdx = -1;\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\ts = _fnGetCellData( settings, i, colIdx, 'display' )+'';\n\t\t\ts = s.replace( __re_html_remove, '' );\n\t\t\ts = s.replace( / /g, ' ' );\n\t\n\t\t\tif ( s.length > max ) {\n\t\t\t\tmax = s.length;\n\t\t\t\tmaxIdx = i;\n\t\t\t}\n\t\t}\n\t\n\t\treturn maxIdx;\n\t}\n\t\n\t\n\t/**\n\t * Append a CSS unit (only if required) to a string\n\t * @param {string} value to css-ify\n\t * @returns {string} value with css unit\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnStringToCss( s )\n\t{\n\t\tif ( s === null ) {\n\t\t\treturn '0px';\n\t\t}\n\t\n\t\tif ( typeof s == 'number' ) {\n\t\t\treturn s < 0 ?\n\t\t\t\t'0px' :\n\t\t\t\ts+'px';\n\t\t}\n\t\n\t\t// Check it has a unit character already\n\t\treturn s.match(/\\d$/) ?\n\t\t\ts+'px' :\n\t\t\ts;\n\t}\n\t\n\t\n\t\n\tfunction _fnSortFlatten ( settings )\n\t{\n\t\tvar\n\t\t\ti, iLen, k, kLen,\n\t\t\taSort = [],\n\t\t\taiOrig = [],\n\t\t\taoColumns = settings.aoColumns,\n\t\t\taDataSort, iCol, sType, srcCol,\n\t\t\tfixed = settings.aaSortingFixed,\n\t\t\tfixedObj = $.isPlainObject( fixed ),\n\t\t\tnestedSort = [],\n\t\t\tadd = function ( a ) {\n\t\t\t\tif ( a.length && ! Array.isArray( a[0] ) ) {\n\t\t\t\t\t// 1D array\n\t\t\t\t\tnestedSort.push( a );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// 2D array\n\t\t\t\t\t$.merge( nestedSort, a );\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t// Build the sort array, with pre-fix and post-fix options if they have been\n\t\t// specified\n\t\tif ( Array.isArray( fixed ) ) {\n\t\t\tadd( fixed );\n\t\t}\n\t\n\t\tif ( fixedObj && fixed.pre ) {\n\t\t\tadd( fixed.pre );\n\t\t}\n\t\n\t\tadd( settings.aaSorting );\n\t\n\t\tif (fixedObj && fixed.post ) {\n\t\t\tadd( fixed.post );\n\t\t}\n\t\n\t\tfor ( i=0 ; i<nestedSort.length ; i++ )\n\t\t{\n\t\t\tsrcCol = nestedSort[i][0];\n\t\t\taDataSort = aoColumns[ srcCol ].aDataSort;\n\t\n\t\t\tfor ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )\n\t\t\t{\n\t\t\t\tiCol = aDataSort[k];\n\t\t\t\tsType = aoColumns[ iCol ].sType || 'string';\n\t\n\t\t\t\tif ( nestedSort[i]._idx === undefined ) {\n\t\t\t\t\tnestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );\n\t\t\t\t}\n\t\n\t\t\t\taSort.push( {\n\t\t\t\t\tsrc: srcCol,\n\t\t\t\t\tcol: iCol,\n\t\t\t\t\tdir: nestedSort[i][1],\n\t\t\t\t\tindex: nestedSort[i]._idx,\n\t\t\t\t\ttype: sType,\n\t\t\t\t\tformatter: DataTable.ext.type.order[ sType+\"-pre\" ]\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\treturn aSort;\n\t}\n\t\n\t/**\n\t * Change the order of the table\n\t * @param {object} oSettings dataTables settings object\n\t * @memberof DataTable#oApi\n\t * @todo This really needs split up!\n\t */\n\tfunction _fnSort ( oSettings )\n\t{\n\t\tvar\n\t\t\ti, ien, iLen, j, jLen, k, kLen,\n\t\t\tsDataType, nTh,\n\t\t\taiOrig = [],\n\t\t\toExtSort = DataTable.ext.type.order,\n\t\t\taoData = oSettings.aoData,\n\t\t\taoColumns = oSettings.aoColumns,\n\t\t\taDataSort, data, iCol, sType, oSort,\n\t\t\tformatters = 0,\n\t\t\tsortCol,\n\t\t\tdisplayMaster = oSettings.aiDisplayMaster,\n\t\t\taSort;\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo Can this be moved into a 'data-ready' handler which is called when\n\t\t// data is going to be used in the table?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\taSort = _fnSortFlatten( oSettings );\n\t\n\t\tfor ( i=0, ien=aSort.length ; i<ien ; i++ ) {\n\t\t\tsortCol = aSort[i];\n\t\n\t\t\t// Track if we can use the fast sort algorithm\n\t\t\tif ( sortCol.formatter ) {\n\t\t\t\tformatters++;\n\t\t\t}\n\t\n\t\t\t// Load the data needed for the sort, for each cell\n\t\t\t_fnSortData( oSettings, sortCol.col );\n\t\t}\n\t\n\t\t/* No sorting required if server-side or no sorting array */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )\n\t\t{\n\t\t\t// Create a value - key array of the current row positions such that we can use their\n\t\t\t// current position during the sort, if values match, in order to perform stable sorting\n\t\t\tfor ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {\n\t\t\t\taiOrig[ displayMaster[i] ] = i;\n\t\t\t}\n\t\n\t\t\t/* Do the sort - here we want multi-column sorting based on a given data source (column)\n\t\t\t * and sorting function (from oSort) in a certain direction. It's reasonably complex to\n\t\t\t * follow on it's own, but this is what we want (example two column sorting):\n\t\t\t * fnLocalSorting = function(a,b){\n\t\t\t * var iTest;\n\t\t\t * iTest = oSort['string-asc']('data11', 'data12');\n\t\t\t * if (iTest !== 0)\n\t\t\t * return iTest;\n\t\t\t * iTest = oSort['numeric-desc']('data21', 'data22');\n\t\t\t * if (iTest !== 0)\n\t\t\t * return iTest;\n\t\t\t * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );\n\t\t\t * }\n\t\t\t * Basically we have a test for each sorting column, if the data in that column is equal,\n\t\t\t * test the next column. If all columns match, then we use a numeric sort on the row\n\t\t\t * positions in the original data array to provide a stable sort.\n\t\t\t *\n\t\t\t * Note - I know it seems excessive to have two sorting methods, but the first is around\n\t\t\t * 15% faster, so the second is only maintained for backwards compatibility with sorting\n\t\t\t * methods which do not have a pre-sort formatting function.\n\t\t\t */\n\t\t\tif ( formatters === aSort.length ) {\n\t\t\t\t// All sort types have formatting functions\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, test, sort,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\ttest = x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn sort.dir === 'asc' ? test : -test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Depreciated - remove in 1.11 (providing a plug-in option)\n\t\t\t\t// Not all sort types have formatting methods, so we have to call their sorting\n\t\t\t\t// methods.\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, l, test, sort, fn,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\tfn = oExtSort[ sort.type+\"-\"+sort.dir ] || oExtSort[ \"string-\"+sort.dir ];\n\t\t\t\t\t\ttest = fn( x, y );\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Tell the draw function that we have sorted the data */\n\t\toSettings.bSorted = true;\n\t}\n\t\n\t\n\tfunction _fnSortAria ( settings )\n\t{\n\t\tvar label;\n\t\tvar nextSort;\n\t\tvar columns = settings.aoColumns;\n\t\tvar aSort = _fnSortFlatten( settings );\n\t\tvar oAria = settings.oLanguage.oAria;\n\t\n\t\t// ARIA attributes - need to loop all columns, to update all (removing old\n\t\t// attributes as needed)\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar col = columns[i];\n\t\t\tvar asSorting = col.asSorting;\n\t\t\tvar sTitle = col.ariaTitle || col.sTitle.replace( /<.*?>/g, \"\" );\n\t\t\tvar th = col.nTh;\n\t\n\t\t\t// IE7 is throwing an error when setting these properties with jQuery's\n\t\t\t// attr() and removeAttr() methods...\n\t\t\tth.removeAttribute('aria-sort');\n\t\n\t\t\t/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */\n\t\t\tif ( col.bSortable ) {\n\t\t\t\tif ( aSort.length > 0 && aSort[0].col == i ) {\n\t\t\t\t\tth.setAttribute('aria-sort', aSort[0].dir==\"asc\" ? \"ascending\" : \"descending\" );\n\t\t\t\t\tnextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tnextSort = asSorting[0];\n\t\t\t\t}\n\t\n\t\t\t\tlabel = sTitle + ( nextSort === \"asc\" ?\n\t\t\t\t\toAria.sSortAscending :\n\t\t\t\t\toAria.sSortDescending\n\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlabel = sTitle;\n\t\t\t}\n\t\n\t\t\tth.setAttribute('aria-label', label);\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Function to run on user sort request\n\t * @param {object} settings dataTables settings object\n\t * @param {node} attachTo node to attach the handler to\n\t * @param {int} colIdx column sorting index\n\t * @param {boolean} [append=false] Append the requested sort to the existing\n\t * sort if true (i.e. multi-column sort)\n\t * @param {function} [callback] callback function\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnSortListener ( settings, colIdx, append, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\tvar sorting = settings.aaSorting;\n\t\tvar asSorting = col.asSorting;\n\t\tvar nextSortIdx;\n\t\tvar next = function ( a, overflow ) {\n\t\t\tvar idx = a._idx;\n\t\t\tif ( idx === undefined ) {\n\t\t\t\tidx = $.inArray( a[1], asSorting );\n\t\t\t}\n\t\n\t\t\treturn idx+1 < asSorting.length ?\n\t\t\t\tidx+1 :\n\t\t\t\toverflow ?\n\t\t\t\t\tnull :\n\t\t\t\t\t0;\n\t\t};\n\t\n\t\t// Convert to 2D array if needed\n\t\tif ( typeof sorting[0] === 'number' ) {\n\t\t\tsorting = settings.aaSorting = [ sorting ];\n\t\t}\n\t\n\t\t// If appending the sort then we are multi-column sorting\n\t\tif ( append && settings.oFeatures.bSortMulti ) {\n\t\t\t// Are we already doing some kind of sort on this column?\n\t\t\tvar sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );\n\t\n\t\t\tif ( sortIdx !== -1 ) {\n\t\t\t\t// Yes, modify the sort\n\t\t\t\tnextSortIdx = next( sorting[sortIdx], true );\n\t\n\t\t\t\tif ( nextSortIdx === null && sorting.length === 1 ) {\n\t\t\t\t\tnextSortIdx = 0; // can't remove sorting completely\n\t\t\t\t}\n\t\n\t\t\t\tif ( nextSortIdx === null ) {\n\t\t\t\t\tsorting.splice( sortIdx, 1 );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tsorting[sortIdx][1] = asSorting[ nextSortIdx ];\n\t\t\t\t\tsorting[sortIdx]._idx = nextSortIdx;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// No sort on this column yet\n\t\t\t\tsorting.push( [ colIdx, asSorting[0], 0 ] );\n\t\t\t\tsorting[sorting.length-1]._idx = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( sorting.length && sorting[0][0] == colIdx ) {\n\t\t\t// Single column - already sorting on this column, modify the sort\n\t\t\tnextSortIdx = next( sorting[0] );\n\t\n\t\t\tsorting.length = 1;\n\t\t\tsorting[0][1] = asSorting[ nextSortIdx ];\n\t\t\tsorting[0]._idx = nextSortIdx;\n\t\t}\n\t\telse {\n\t\t\t// Single column - sort only on this column\n\t\t\tsorting.length = 0;\n\t\t\tsorting.push( [ colIdx, asSorting[0] ] );\n\t\t\tsorting[0]._idx = 0;\n\t\t}\n\t\n\t\t// Run the sort by calling a full redraw\n\t\t_fnReDraw( settings );\n\t\n\t\t// callback used for async user interaction\n\t\tif ( typeof callback == 'function' ) {\n\t\t\tcallback( settings );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Attach a sort handler (click) to a node\n\t * @param {object} settings dataTables settings object\n\t * @param {node} attachTo node to attach the handler to\n\t * @param {int} colIdx column sorting index\n\t * @param {function} [callback] callback function\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnSortAttachListener ( settings, attachTo, colIdx, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\n\t\t_fnBindAction( attachTo, {}, function (e) {\n\t\t\t/* If the column is not sortable - don't to anything */\n\t\t\tif ( col.bSortable === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If processing is enabled use a timeout to allow the processing\n\t\t\t// display to be shown - otherwise to it synchronously\n\t\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t\tsetTimeout( function() {\n\t\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\n\t\t\t\t\t// In server-side processing, the draw callback will remove the\n\t\t\t\t\t// processing display\n\t\t\t\t\tif ( _fnDataSource( settings ) !== 'ssp' ) {\n\t\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t}\n\t\t\t\t}, 0 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Set the sorting classes on table's body, Note: it is safe to call this function\n\t * when bSort and bSortClasses are false\n\t * @param {object} oSettings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnSortingClasses( settings )\n\t{\n\t\tvar oldSort = settings.aLastSort;\n\t\tvar sortClass = settings.oClasses.sSortColumn;\n\t\tvar sort = _fnSortFlatten( settings );\n\t\tvar features = settings.oFeatures;\n\t\tvar i, ien, colIdx;\n\t\n\t\tif ( features.bSort && features.bSortClasses ) {\n\t\t\t// Remove old sorting classes\n\t\t\tfor ( i=0, ien=oldSort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = oldSort[i].src;\n\t\n\t\t\t\t// Remove column sorting\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.removeClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\n\t\t\t// Add new column sorting\n\t\t\tfor ( i=0, ien=sort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = sort[i].src;\n\t\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.addClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aLastSort = sort;\n\t}\n\t\n\t\n\t// Get the data to sort a column, be it from cache, fresh (populating the\n\t// cache), or from a sort formatter\n\tfunction _fnSortData( settings, idx )\n\t{\n\t\t// Custom sorting function - provided by the sort data type\n\t\tvar column = settings.aoColumns[ idx ];\n\t\tvar customSort = DataTable.ext.order[ column.sSortDataType ];\n\t\tvar customData;\n\t\n\t\tif ( customSort ) {\n\t\t\tcustomData = customSort.call( settings.oInstance, settings, idx,\n\t\t\t\t_fnColumnIndexToVisible( settings, idx )\n\t\t\t);\n\t\t}\n\t\n\t\t// Use / populate cache\n\t\tvar row, cellData;\n\t\tvar formatter = DataTable.ext.type.order[ column.sType+\"-pre\" ];\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aSortData ) {\n\t\t\t\trow._aSortData = [];\n\t\t\t}\n\t\n\t\t\tif ( ! row._aSortData[idx] || customSort ) {\n\t\t\t\tcellData = customSort ?\n\t\t\t\t\tcustomData[i] : // If there was a custom sort function, use data from there\n\t\t\t\t\t_fnGetCellData( settings, i, idx, 'sort' );\n\t\n\t\t\t\trow._aSortData[ idx ] = formatter ?\n\t\t\t\t\tformatter( cellData ) :\n\t\t\t\t\tcellData;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Save the state of a table\n\t * @param {object} oSettings dataTables settings object\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnSaveState ( settings )\n\t{\n\t\tif (settings._bLoadingState) {\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Store the interesting variables */\n\t\tvar state = {\n\t\t\ttime: +new Date(),\n\t\t\tstart: settings._iDisplayStart,\n\t\t\tlength: settings._iDisplayLength,\n\t\t\torder: $.extend( true, [], settings.aaSorting ),\n\t\t\tsearch: _fnSearchToCamel( settings.oPreviousSearch ),\n\t\t\tcolumns: $.map( settings.aoColumns, function ( col, i ) {\n\t\t\t\treturn {\n\t\t\t\t\tvisible: col.bVisible,\n\t\t\t\t\tsearch: _fnSearchToCamel( settings.aoPreSearchCols[i] )\n\t\t\t\t};\n\t\t\t} )\n\t\t};\n\t\n\t\tsettings.oSavedState = state;\n\t\t_fnCallbackFire( settings, \"aoStateSaveParams\", 'stateSaveParams', [settings, state] );\n\t\t\n\t\tif ( settings.oFeatures.bStateSave && !settings.bDestroying )\n\t\t{\n\t\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, state );\n\t\t}\t\n\t}\n\t\n\t\n\t/**\n\t * Attempt to load a saved table state\n\t * @param {object} oSettings dataTables settings object\n\t * @param {object} oInit DataTables init object so we can override settings\n\t * @param {function} callback Callback to execute when the state has been loaded\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnLoadState ( settings, oInit, callback )\n\t{\n\t\tif ( ! settings.oFeatures.bStateSave ) {\n\t\t\tcallback();\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar loaded = function(state) {\n\t\t\t_fnImplementState(settings, state, callback);\n\t\t}\n\t\n\t\tvar state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );\n\t\n\t\tif ( state !== undefined ) {\n\t\t\t_fnImplementState( settings, state, callback );\n\t\t}\n\t\t// otherwise, wait for the loaded callback to be executed\n\t\n\t\treturn true;\n\t}\n\t\n\tfunction _fnImplementState ( settings, s, callback) {\n\t\tvar i, ien;\n\t\tvar columns = settings.aoColumns;\n\t\tsettings._bLoadingState = true;\n\t\n\t\t// When StateRestore was introduced the state could now be implemented at any time\n\t\t// Not just initialisation. To do this an api instance is required in some places\n\t\tvar api = settings._bInitComplete ? new DataTable.Api(settings) : null;\n\t\n\t\tif ( ! s || ! s.time ) {\n\t\t\tsettings._bLoadingState = false;\n\t\t\tcallback();\n\t\t\treturn;\n\t\t}\n\t\n\t\t// Allow custom and plug-in manipulation functions to alter the saved data set and\n\t\t// cancelling of loading by returning false\n\t\tvar abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );\n\t\tif ( $.inArray( false, abStateLoad ) !== -1 ) {\n\t\t\tsettings._bLoadingState = false;\n\t\t\tcallback();\n\t\t\treturn;\n\t\t}\n\t\n\t\t// Reject old data\n\t\tvar duration = settings.iStateDuration;\n\t\tif ( duration > 0 && s.time < +new Date() - (duration*1000) ) {\n\t\t\tsettings._bLoadingState = false;\n\t\t\tcallback();\n\t\t\treturn;\n\t\t}\n\t\n\t\t// Number of columns have changed - all bets are off, no restore of settings\n\t\tif ( s.columns && columns.length !== s.columns.length ) {\n\t\t\tsettings._bLoadingState = false;\n\t\t\tcallback();\n\t\t\treturn;\n\t\t}\n\t\n\t\t// Store the saved state so it might be accessed at any time\n\t\tsettings.oLoadedState = $.extend( true, {}, s );\n\t\n\t\t// Restore key features - todo - for 1.11 this needs to be done by\n\t\t// subscribed events\n\t\tif ( s.start !== undefined ) {\n\t\t\tsettings._iDisplayStart = s.start;\n\t\t\tif(api === null) {\n\t\t\t\tsettings.iInitDisplayStart = s.start;\n\t\t\t}\n\t\t}\n\t\tif ( s.length !== undefined ) {\n\t\t\tsettings._iDisplayLength = s.length;\n\t\t}\n\t\n\t\t// Order\n\t\tif ( s.order !== undefined ) {\n\t\t\tsettings.aaSorting = [];\n\t\t\t$.each( s.order, function ( i, col ) {\n\t\t\t\tsettings.aaSorting.push( col[0] >= columns.length ?\n\t\t\t\t\t[ 0, col[1] ] :\n\t\t\t\t\tcol\n\t\t\t\t);\n\t\t\t} );\n\t\t}\n\t\n\t\t// Search\n\t\tif ( s.search !== undefined ) {\n\t\t\t$.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );\n\t\t}\n\t\n\t\t// Columns\n\t\tif ( s.columns ) {\n\t\t\tfor ( i=0, ien=s.columns.length ; i<ien ; i++ ) {\n\t\t\t\tvar col = s.columns[i];\n\t\n\t\t\t\t// Visibility\n\t\t\t\tif ( col.visible !== undefined ) {\n\t\t\t\t\t// If the api is defined, the table has been initialised so we need to use it rather than internal settings\n\t\t\t\t\tif (api) {\n\t\t\t\t\t\t// Don't redraw the columns on every iteration of this loop, we will do this at the end instead\n\t\t\t\t\t\tapi.column(i).visible(col.visible, false);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcolumns[i].bVisible = col.visible;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Search\n\t\t\t\tif ( col.search !== undefined ) {\n\t\t\t\t\t$.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// If the api is defined then we need to adjust the columns once the visibility has been changed\n\t\t\tif (api) {\n\t\t\t\tapi.columns.adjust();\n\t\t\t}\n\t\t}\n\t\n\t\tsettings._bLoadingState = false;\n\t\t_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );\n\t\tcallback();\n\t};\n\t\n\t\n\t/**\n\t * Return the settings object for a particular table\n\t * @param {node} table table we are using as a dataTable\n\t * @returns {object} Settings object - or null if not found\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnSettingsFromNode ( table )\n\t{\n\t\tvar settings = DataTable.settings;\n\t\tvar idx = $.inArray( table, _pluck( settings, 'nTable' ) );\n\t\n\t\treturn idx !== -1 ?\n\t\t\tsettings[ idx ] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Log an error message\n\t * @param {object} settings dataTables settings object\n\t * @param {int} level log error messages, or display them to the user\n\t * @param {string} msg error message\n\t * @param {int} tn Technical note id to get more information about the error.\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnLog( settings, level, msg, tn )\n\t{\n\t\tmsg = 'DataTables warning: '+\n\t\t\t(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;\n\t\n\t\tif ( tn ) {\n\t\t\tmsg += '. For more information about this error, please see '+\n\t\t\t'http://datatables.net/tn/'+tn;\n\t\t}\n\t\n\t\tif ( ! level ) {\n\t\t\t// Backwards compatibility pre 1.10\n\t\t\tvar ext = DataTable.ext;\n\t\t\tvar type = ext.sErrMode || ext.errMode;\n\t\n\t\t\tif ( settings ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );\n\t\t\t}\n\t\n\t\t\tif ( type == 'alert' ) {\n\t\t\t\talert( msg );\n\t\t\t}\n\t\t\telse if ( type == 'throw' ) {\n\t\t\t\tthrow new Error(msg);\n\t\t\t}\n\t\t\telse if ( typeof type == 'function' ) {\n\t\t\t\ttype( settings, tn, msg );\n\t\t\t}\n\t\t}\n\t\telse if ( window.console && console.log ) {\n\t\t\tconsole.log( msg );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * See if a property is defined on one object, if so assign it to the other object\n\t * @param {object} ret target object\n\t * @param {object} src source object\n\t * @param {string} name property\n\t * @param {string} [mappedName] name to map too - optional, name used if not given\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnMap( ret, src, name, mappedName )\n\t{\n\t\tif ( Array.isArray( name ) ) {\n\t\t\t$.each( name, function (i, val) {\n\t\t\t\tif ( Array.isArray( val ) ) {\n\t\t\t\t\t_fnMap( ret, src, val[0], val[1] );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_fnMap( ret, src, val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( mappedName === undefined ) {\n\t\t\tmappedName = name;\n\t\t}\n\t\n\t\tif ( src[name] !== undefined ) {\n\t\t\tret[mappedName] = src[name];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Extend objects - very similar to jQuery.extend, but deep copy objects, and\n\t * shallow copy arrays. The reason we need to do this, is that we don't want to\n\t * deep copy array init values (such as aaSorting) since the dev wouldn't be\n\t * able to override them, but we do want to deep copy arrays.\n\t * @param {object} out Object to extend\n\t * @param {object} extender Object from which the properties will be applied to\n\t * out\n\t * @param {boolean} breakRefs If true, then arrays will be sliced to take an\n\t * independent copy with the exception of the `data` or `aaData` parameters\n\t * if they are present. This is so you can pass in a collection to\n\t * DataTables and have that used as your data source without breaking the\n\t * references\n\t * @returns {object} out Reference, just for convenience - out === the return.\n\t * @memberof DataTable#oApi\n\t * @todo This doesn't take account of arrays inside the deep copied objects.\n\t */\n\tfunction _fnExtend( out, extender, breakRefs )\n\t{\n\t\tvar val;\n\t\n\t\tfor ( var prop in extender ) {\n\t\t\tif ( extender.hasOwnProperty(prop) ) {\n\t\t\t\tval = extender[prop];\n\t\n\t\t\t\tif ( $.isPlainObject( val ) ) {\n\t\t\t\t\tif ( ! $.isPlainObject( out[prop] ) ) {\n\t\t\t\t\t\tout[prop] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, out[prop], val );\n\t\t\t\t}\n\t\t\t\telse if ( breakRefs && prop !== 'data' && prop !== 'aaData' && Array.isArray(val) ) {\n\t\t\t\t\tout[prop] = val.slice();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tout[prop] = val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t}\n\t\n\t\n\t/**\n\t * Bind an event handers to allow a click or return key to activate the callback.\n\t * This is good for accessibility since a return on the keyboard will have the\n\t * same effect as a click, if the element has focus.\n\t * @param {element} n Element to bind the action to\n\t * @param {object} oData Data object to pass to the triggered function\n\t * @param {function} fn Callback function for when the event is triggered\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnBindAction( n, oData, fn )\n\t{\n\t\t$(n)\n\t\t\t.on( 'click.DT', oData, function (e) {\n\t\t\t\t\t$(n).trigger('blur'); // Remove focus outline for mouse users\n\t\t\t\t\tfn(e);\n\t\t\t\t} )\n\t\t\t.on( 'keypress.DT', oData, function (e){\n\t\t\t\t\tif ( e.which === 13 ) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tfn(e);\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t.on( 'selectstart.DT', function () {\n\t\t\t\t\t/* Take the brutal approach to cancelling text selection */\n\t\t\t\t\treturn false;\n\t\t\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Register a callback function. Easily allows a callback function to be added to\n\t * an array store of callback functions that can then all be called together.\n\t * @param {object} oSettings dataTables settings object\n\t * @param {string} sStore Name of the array storage for the callbacks in oSettings\n\t * @param {function} fn Function to be called back\n\t * @param {string} sName Identifying name for the callback (i.e. a label)\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackReg( oSettings, sStore, fn, sName )\n\t{\n\t\tif ( fn )\n\t\t{\n\t\t\toSettings[sStore].push( {\n\t\t\t\t\"fn\": fn,\n\t\t\t\t\"sName\": sName\n\t\t\t} );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Fire callback functions and trigger events. Note that the loop over the\n\t * callback array store is done backwards! Further note that you do not want to\n\t * fire off triggers in time sensitive applications (for example cell creation)\n\t * as its slow.\n\t * @param {object} settings dataTables settings object\n\t * @param {string} callbackArr Name of the array storage for the callbacks in\n\t * oSettings\n\t * @param {string} eventName Name of the jQuery custom event to trigger. If\n\t * null no trigger is fired\n\t * @param {array} args Array of arguments to pass to the callback function /\n\t * trigger\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackFire( settings, callbackArr, eventName, args )\n\t{\n\t\tvar ret = [];\n\t\n\t\tif ( callbackArr ) {\n\t\t\tret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {\n\t\t\t\treturn val.fn.apply( settings.oInstance, args );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( eventName !== null ) {\n\t\t\tvar e = $.Event( eventName+'.dt' );\n\t\n\t\t\t$(settings.nTable).trigger( e, args );\n\t\n\t\t\tret.push( e.result );\n\t\t}\n\t\n\t\treturn ret;\n\t}\n\t\n\t\n\tfunction _fnLengthOverflow ( settings )\n\t{\n\t\tvar\n\t\t\tstart = settings._iDisplayStart,\n\t\t\tend = settings.fnDisplayEnd(),\n\t\t\tlen = settings._iDisplayLength;\n\t\n\t\t/* If we have space to show extra rows (backing up from the end point - then do so */\n\t\tif ( start >= end )\n\t\t{\n\t\t\tstart = end - len;\n\t\t}\n\t\n\t\t// Keep the start record on the current page\n\t\tstart -= (start % len);\n\t\n\t\tif ( len === -1 || start < 0 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\n\t\tsettings._iDisplayStart = start;\n\t}\n\t\n\t\n\tfunction _fnRenderer( settings, type )\n\t{\n\t\tvar renderer = settings.renderer;\n\t\tvar host = DataTable.ext.renderer[type];\n\t\n\t\tif ( $.isPlainObject( renderer ) && renderer[type] ) {\n\t\t\t// Specific renderer for this type. If available use it, otherwise use\n\t\t\t// the default.\n\t\t\treturn host[renderer[type]] || host._;\n\t\t}\n\t\telse if ( typeof renderer === 'string' ) {\n\t\t\t// Common renderer - if there is one available for this type use it,\n\t\t\t// otherwise use the default\n\t\t\treturn host[renderer] || host._;\n\t\t}\n\t\n\t\t// Use the default\n\t\treturn host._;\n\t}\n\t\n\t\n\t/**\n\t * Detect the data source being used for the table. Used to simplify the code\n\t * a little (ajax) and to make it compress a little smaller.\n\t *\n\t * @param {object} settings dataTables settings object\n\t * @returns {string} Data source\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnDataSource ( settings )\n\t{\n\t\tif ( settings.oFeatures.bServerSide ) {\n\t\t\treturn 'ssp';\n\t\t}\n\t\telse if ( settings.ajax || settings.sAjaxSource ) {\n\t\t\treturn 'ajax';\n\t\t}\n\t\treturn 'dom';\n\t}\n\t\n\n\t\n\t\n\t/**\n\t * Computed structure of the DataTables API, defined by the options passed to\n\t * `DataTable.Api.register()` when building the API.\n\t *\n\t * The structure is built in order to speed creation and extension of the Api\n\t * objects since the extensions are effectively pre-parsed.\n\t *\n\t * The array is an array of objects with the following structure, where this\n\t * base array represents the Api prototype base:\n\t *\n\t * [\n\t * {\n\t * name: 'data' -- string - Property name\n\t * val: function () {}, -- function - Api method (or undefined if just an object\n\t * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result\n\t * propExt: [ ... ] -- array - Array of Api object definitions to extend the property\n\t * },\n\t * {\n\t * name: 'row'\n\t * val: {},\n\t * methodExt: [ ... ],\n\t * propExt: [\n\t * {\n\t * name: 'data'\n\t * val: function () {},\n\t * methodExt: [ ... ],\n\t * propExt: [ ... ]\n\t * },\n\t * ...\n\t * ]\n\t * }\n\t * ]\n\t *\n\t * @type {Array}\n\t * @ignore\n\t */\n\tvar __apiStruct = [];\n\t\n\t\n\t/**\n\t * `Array.prototype` reference.\n\t *\n\t * @type object\n\t * @ignore\n\t */\n\tvar __arrayProto = Array.prototype;\n\t\n\t\n\t/**\n\t * Abstraction for `context` parameter of the `Api` constructor to allow it to\n\t * take several different forms for ease of use.\n\t *\n\t * Each of the input parameter types will be converted to a DataTables settings\n\t * object where possible.\n\t *\n\t * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one\n\t * of:\n\t *\n\t * * `string` - jQuery selector. Any DataTables' matching the given selector\n\t * with be found and used.\n\t * * `node` - `TABLE` node which has already been formed into a DataTable.\n\t * * `jQuery` - A jQuery object of `TABLE` nodes.\n\t * * `object` - DataTables settings object\n\t * * `DataTables.Api` - API instance\n\t * @return {array|null} Matching DataTables settings objects. `null` or\n\t * `undefined` is returned if no matching DataTable is found.\n\t * @ignore\n\t */\n\tvar _toSettings = function ( mixed )\n\t{\n\t\tvar idx, jq;\n\t\tvar settings = DataTable.settings;\n\t\tvar tables = $.map( settings, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\tif ( ! mixed ) {\n\t\t\treturn [];\n\t\t}\n\t\telse if ( mixed.nTable && mixed.oApi ) {\n\t\t\t// DataTables settings object\n\t\t\treturn [ mixed ];\n\t\t}\n\t\telse if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {\n\t\t\t// Table node\n\t\t\tidx = $.inArray( mixed, tables );\n\t\t\treturn idx !== -1 ? [ settings[idx] ] : null;\n\t\t}\n\t\telse if ( mixed && typeof mixed.settings === 'function' ) {\n\t\t\treturn mixed.settings().toArray();\n\t\t}\n\t\telse if ( typeof mixed === 'string' ) {\n\t\t\t// jQuery selector\n\t\t\tjq = $(mixed);\n\t\t}\n\t\telse if ( mixed instanceof $ ) {\n\t\t\t// jQuery object (also DataTables instance)\n\t\t\tjq = mixed;\n\t\t}\n\t\n\t\tif ( jq ) {\n\t\t\treturn jq.map( function(i) {\n\t\t\t\tidx = $.inArray( this, tables );\n\t\t\t\treturn idx !== -1 ? settings[idx] : null;\n\t\t\t} ).toArray();\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * DataTables API class - used to control and interface with one or more\n\t * DataTables enhanced tables.\n\t *\n\t * The API class is heavily based on jQuery, presenting a chainable interface\n\t * that you can use to interact with tables. Each instance of the API class has\n\t * a \"context\" - i.e. the tables that it will operate on. This could be a single\n\t * table, all tables on a page or a sub-set thereof.\n\t *\n\t * Additionally the API is designed to allow you to easily work with the data in\n\t * the tables, retrieving and manipulating it as required. This is done by\n\t * presenting the API class as an array like interface. The contents of the\n\t * array depend upon the actions requested by each method (for example\n\t * `rows().nodes()` will return an array of nodes, while `rows().data()` will\n\t * return an array of objects or arrays depending upon your table's\n\t * configuration). The API object has a number of array like methods (`push`,\n\t * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,\n\t * `unique` etc) to assist your working with the data held in a table.\n\t *\n\t * Most methods (those which return an Api instance) are chainable, which means\n\t * the return from a method call also has all of the methods available that the\n\t * top level object had. For example, these two calls are equivalent:\n\t *\n\t * // Not chained\n\t * api.row.add( {...} );\n\t * api.draw();\n\t *\n\t * // Chained\n\t * api.row.add( {...} ).draw();\n\t *\n\t * @class DataTable.Api\n\t * @param {array|object|string|jQuery} context DataTable identifier. This is\n\t * used to define which DataTables enhanced tables this API will operate on.\n\t * Can be one of:\n\t *\n\t * * `string` - jQuery selector. Any DataTables' matching the given selector\n\t * with be found and used.\n\t * * `node` - `TABLE` node which has already been formed into a DataTable.\n\t * * `jQuery` - A jQuery object of `TABLE` nodes.\n\t * * `object` - DataTables settings object\n\t * @param {array} [data] Data to initialise the Api instance with.\n\t *\n\t * @example\n\t * // Direct initialisation during DataTables construction\n\t * var api = $('#example').DataTable();\n\t *\n\t * @example\n\t * // Initialisation using a DataTables jQuery object\n\t * var api = $('#example').dataTable().api();\n\t *\n\t * @example\n\t * // Initialisation as a constructor\n\t * var api = new $.fn.DataTable.Api( 'table.dataTable' );\n\t */\n\t_Api = function ( context, data )\n\t{\n\t\tif ( ! (this instanceof _Api) ) {\n\t\t\treturn new _Api( context, data );\n\t\t}\n\t\n\t\tvar settings = [];\n\t\tvar ctxSettings = function ( o ) {\n\t\t\tvar a = _toSettings( o );\n\t\t\tif ( a ) {\n\t\t\t\tsettings.push.apply( settings, a );\n\t\t\t}\n\t\t};\n\t\n\t\tif ( Array.isArray( context ) ) {\n\t\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tctxSettings( context[i] );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tctxSettings( context );\n\t\t}\n\t\n\t\t// Remove duplicates\n\t\tthis.context = _unique( settings );\n\t\n\t\t// Initial data\n\t\tif ( data ) {\n\t\t\t$.merge( this, data );\n\t\t}\n\t\n\t\t// selector\n\t\tthis.selector = {\n\t\t\trows: null,\n\t\t\tcols: null,\n\t\t\topts: null\n\t\t};\n\t\n\t\t_Api.extend( this, this, __apiStruct );\n\t};\n\t\n\tDataTable.Api = _Api;\n\t\n\t// Don't destroy the existing prototype, just extend it. Required for jQuery 2's\n\t// isPlainObject.\n\t$.extend( _Api.prototype, {\n\t\tany: function ()\n\t\t{\n\t\t\treturn this.count() !== 0;\n\t\t},\n\t\n\t\n\t\tconcat: __arrayProto.concat,\n\t\n\t\n\t\tcontext: [], // array of table settings objects\n\t\n\t\n\t\tcount: function ()\n\t\t{\n\t\t\treturn this.flatten().length;\n\t\t},\n\t\n\t\n\t\teach: function ( fn )\n\t\t{\n\t\t\tfor ( var i=0, ien=this.length ; i<ien; i++ ) {\n\t\t\t\tfn.call( this, this[i], i, this );\n\t\t\t}\n\t\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\teq: function ( idx )\n\t\t{\n\t\t\tvar ctx = this.context;\n\t\n\t\t\treturn ctx.length > idx ?\n\t\t\t\tnew _Api( ctx[idx], this[idx] ) :\n\t\t\t\tnull;\n\t\t},\n\t\n\t\n\t\tfilter: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.filter ) {\n\t\t\t\ta = __arrayProto.filter.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( fn.call( this, this[i], i, this ) ) {\n\t\t\t\t\t\ta.push( this[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tflatten: function ()\n\t\t{\n\t\t\tvar a = [];\n\t\t\treturn new _Api( this.context, a.concat.apply( a, this.toArray() ) );\n\t\t},\n\t\n\t\n\t\tjoin: __arrayProto.join,\n\t\n\t\n\t\tindexOf: __arrayProto.indexOf || function (obj, start)\n\t\t{\n\t\t\tfor ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {\n\t\t\t\tif ( this[i] === obj ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn -1;\n\t\t},\n\t\n\t\titerator: function ( flatten, type, fn, alwaysNew ) {\n\t\t\tvar\n\t\t\t\ta = [], ret,\n\t\t\t\ti, ien, j, jen,\n\t\t\t\tcontext = this.context,\n\t\t\t\trows, items, item,\n\t\t\t\tselector = this.selector;\n\t\n\t\t\t// Argument shifting\n\t\t\tif ( typeof flatten === 'string' ) {\n\t\t\t\talwaysNew = fn;\n\t\t\t\tfn = type;\n\t\t\t\ttype = flatten;\n\t\t\t\tflatten = false;\n\t\t\t}\n\t\n\t\t\tfor ( i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tvar apiInst = new _Api( context[i] );\n\t\n\t\t\t\tif ( type === 'table' ) {\n\t\t\t\t\tret = fn.call( apiInst, context[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'columns' || type === 'rows' ) {\n\t\t\t\t\t// this has same length as context - one entry for each table\n\t\t\t\t\tret = fn.call( apiInst, context[i], this[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {\n\t\t\t\t\t// columns and rows share the same structure.\n\t\t\t\t\t// 'this' is an array of column indexes for each context\n\t\t\t\t\titems = this[i];\n\t\n\t\t\t\t\tif ( type === 'column-rows' ) {\n\t\t\t\t\t\trows = _selector_row_indexes( context[i], selector.opts );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfor ( j=0, jen=items.length ; j<jen ; j++ ) {\n\t\t\t\t\t\titem = items[j];\n\t\n\t\t\t\t\t\tif ( type === 'cell' ) {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item.row, item.column, i, j );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item, i, j, rows );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( a.length || alwaysNew ) {\n\t\t\t\tvar api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );\n\t\t\t\tvar apiSelector = api.selector;\n\t\t\t\tapiSelector.rows = selector.rows;\n\t\t\t\tapiSelector.cols = selector.cols;\n\t\t\t\tapiSelector.opts = selector.opts;\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\tlastIndexOf: __arrayProto.lastIndexOf || function (obj, start)\n\t\t{\n\t\t\t// Bit cheeky...\n\t\t\treturn this.indexOf.apply( this.toArray.reverse(), arguments );\n\t\t},\n\t\n\t\n\t\tlength: 0,\n\t\n\t\n\t\tmap: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.map ) {\n\t\t\t\ta = __arrayProto.map.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\ta.push( fn.call( this, this[i], i ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tpluck: function ( prop )\n\t\t{\n\t\t\treturn this.map( function ( el ) {\n\t\t\t\treturn el[ prop ];\n\t\t\t} );\n\t\t},\n\t\n\t\tpop: __arrayProto.pop,\n\t\n\t\n\t\tpush: __arrayProto.push,\n\t\n\t\n\t\t// Does not return an API instance\n\t\treduce: __arrayProto.reduce || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, 0, this.length, 1 );\n\t\t},\n\t\n\t\n\t\treduceRight: __arrayProto.reduceRight || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, this.length-1, -1, -1 );\n\t\t},\n\t\n\t\n\t\treverse: __arrayProto.reverse,\n\t\n\t\n\t\t// Object with rows, columns and opts\n\t\tselector: null,\n\t\n\t\n\t\tshift: __arrayProto.shift,\n\t\n\t\n\t\tslice: function () {\n\t\t\treturn new _Api( this.context, this );\n\t\t},\n\t\n\t\n\t\tsort: __arrayProto.sort, // ? name - order?\n\t\n\t\n\t\tsplice: __arrayProto.splice,\n\t\n\t\n\t\ttoArray: function ()\n\t\t{\n\t\t\treturn __arrayProto.slice.call( this );\n\t\t},\n\t\n\t\n\t\tto$: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\ttoJQuery: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\tunique: function ()\n\t\t{\n\t\t\treturn new _Api( this.context, _unique(this) );\n\t\t},\n\t\n\t\n\t\tunshift: __arrayProto.unshift\n\t} );\n\t\n\t\n\t_Api.extend = function ( scope, obj, ext )\n\t{\n\t\t// Only extend API instances and static properties of the API\n\t\tif ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\tstruct,\n\t\t\tmethodScoping = function ( scope, fn, struc ) {\n\t\t\t\treturn function () {\n\t\t\t\t\tvar ret = fn.apply( scope, arguments );\n\t\n\t\t\t\t\t// Method extension\n\t\t\t\t\t_Api.extend( ret, ret, struc.methodExt );\n\t\t\t\t\treturn ret;\n\t\t\t\t};\n\t\t\t};\n\t\n\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\tstruct = ext[i];\n\t\n\t\t\t// Value\n\t\t\tobj[ struct.name ] = struct.type === 'function' ?\n\t\t\t\tmethodScoping( scope, struct.val, struct ) :\n\t\t\t\tstruct.type === 'object' ?\n\t\t\t\t\t{} :\n\t\t\t\t\tstruct.val;\n\t\n\t\t\tobj[ struct.name ].__dt_wrapper = true;\n\t\n\t\t\t// Property extension\n\t\t\t_Api.extend( scope, obj[ struct.name ], struct.propExt );\n\t\t}\n\t};\n\t\n\t\n\t// @todo - Is there need for an augment function?\n\t// _Api.augment = function ( inst, name )\n\t// {\n\t// \t// Find src object in the structure from the name\n\t// \tvar parts = name.split('.');\n\t\n\t// \t_Api.extend( inst, obj );\n\t// };\n\t\n\t\n\t// [\n\t// {\n\t// name: 'data' -- string - Property name\n\t// val: function () {}, -- function - Api method (or undefined if just an object\n\t// methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result\n\t// propExt: [ ... ] -- array - Array of Api object definitions to extend the property\n\t// },\n\t// {\n\t// name: 'row'\n\t// val: {},\n\t// methodExt: [ ... ],\n\t// propExt: [\n\t// {\n\t// name: 'data'\n\t// val: function () {},\n\t// methodExt: [ ... ],\n\t// propExt: [ ... ]\n\t// },\n\t// ...\n\t// ]\n\t// }\n\t// ]\n\t\n\t_Api.register = _api_register = function ( name, val )\n\t{\n\t\tif ( Array.isArray( name ) ) {\n\t\t\tfor ( var j=0, jen=name.length ; j<jen ; j++ ) {\n\t\t\t\t_Api.register( name[j], val );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\their = name.split('.'),\n\t\t\tstruct = __apiStruct,\n\t\t\tkey, method;\n\t\n\t\tvar find = function ( src, name ) {\n\t\t\tfor ( var i=0, ien=src.length ; i<ien ; i++ ) {\n\t\t\t\tif ( src[i].name === name ) {\n\t\t\t\t\treturn src[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\n\t\tfor ( i=0, ien=heir.length ; i<ien ; i++ ) {\n\t\t\tmethod = heir[i].indexOf('()') !== -1;\n\t\t\tkey = method ?\n\t\t\t\their[i].replace('()', '') :\n\t\t\t\their[i];\n\t\n\t\t\tvar src = find( struct, key );\n\t\t\tif ( ! src ) {\n\t\t\t\tsrc = {\n\t\t\t\t\tname: key,\n\t\t\t\t\tval: {},\n\t\t\t\t\tmethodExt: [],\n\t\t\t\t\tpropExt: [],\n\t\t\t\t\ttype: 'object'\n\t\t\t\t};\n\t\t\t\tstruct.push( src );\n\t\t\t}\n\t\n\t\t\tif ( i === ien-1 ) {\n\t\t\t\tsrc.val = val;\n\t\t\t\tsrc.type = typeof val === 'function' ?\n\t\t\t\t\t'function' :\n\t\t\t\t\t$.isPlainObject( val ) ?\n\t\t\t\t\t\t'object' :\n\t\t\t\t\t\t'other';\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstruct = method ?\n\t\t\t\t\tsrc.methodExt :\n\t\t\t\t\tsrc.propExt;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {\n\t\t_Api.register( pluralName, val );\n\t\n\t\t_Api.register( singularName, function () {\n\t\t\tvar ret = val.apply( this, arguments );\n\t\n\t\t\tif ( ret === this ) {\n\t\t\t\t// Returned item is the API instance that was passed in, return it\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\telse if ( ret instanceof _Api ) {\n\t\t\t\t// New API instance returned, want the value from the first item\n\t\t\t\t// in the returned array for the singular result.\n\t\t\t\treturn ret.length ?\n\t\t\t\t\tArray.isArray( ret[0] ) ?\n\t\t\t\t\t\tnew _Api( ret.context, ret[0] ) : // Array results are 'enhanced'\n\t\t\t\t\t\tret[0] :\n\t\t\t\t\tundefined;\n\t\t\t}\n\t\n\t\t\t// Non-API return - just fire it back\n\t\t\treturn ret;\n\t\t} );\n\t};\n\t\n\t\n\t/**\n\t * Selector for HTML tables. Apply the given selector to the give array of\n\t * DataTables settings objects.\n\t *\n\t * @param {string|integer} [selector] jQuery selector string or integer\n\t * @param {array} Array of DataTables settings objects to be filtered\n\t * @return {array}\n\t * @ignore\n\t */\n\tvar __table_selector = function ( selector, a )\n\t{\n\t\tif ( Array.isArray(selector) ) {\n\t\t\treturn $.map( selector, function (item) {\n\t\t\t\treturn __table_selector(item, a);\n\t\t\t} );\n\t\t}\n\t\n\t\t// Integer is used to pick out a table by index\n\t\tif ( typeof selector === 'number' ) {\n\t\t\treturn [ a[ selector ] ];\n\t\t}\n\t\n\t\t// Perform a jQuery selector on the table nodes\n\t\tvar nodes = $.map( a, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\treturn $(nodes)\n\t\t\t.filter( selector )\n\t\t\t.map( function (i) {\n\t\t\t\t// Need to translate back from the table node to the settings\n\t\t\t\tvar idx = $.inArray( this, nodes );\n\t\t\t\treturn a[ idx ];\n\t\t\t} )\n\t\t\t.toArray();\n\t};\n\t\n\t\n\t\n\t/**\n\t * Context selector for the API's context (i.e. the tables the API instance\n\t * refers to.\n\t *\n\t * @name DataTable.Api#tables\n\t * @param {string|integer} [selector] Selector to pick which tables the iterator\n\t * should operate on. If not given, all tables in the current context are\n\t * used. This can be given as a jQuery selector (for example `':gt(0)'`) to\n\t * select multiple tables or as an integer to select a single table.\n\t * @returns {DataTable.Api} Returns a new API instance if a selector is given.\n\t */\n\t_api_register( 'tables()', function ( selector ) {\n\t\t// A new instance is created if there was a selector specified\n\t\treturn selector !== undefined && selector !== null ?\n\t\t\tnew _Api( __table_selector( selector, this.context ) ) :\n\t\t\tthis;\n\t} );\n\t\n\t\n\t_api_register( 'table()', function ( selector ) {\n\t\tvar tables = this.tables( selector );\n\t\tvar ctx = tables.context;\n\t\n\t\t// Truncate to the first matched table\n\t\treturn ctx.length ?\n\t\t\tnew _Api( ctx[0] ) :\n\t\t\ttables;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().nodes()', 'table().node()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTable;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().body()', 'table().body()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTBody;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().header()', 'table().header()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTHead;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().footer()', 'table().footer()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTFoot;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().containers()', 'table().container()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTableWrapper;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Redraw the tables in the current context.\n\t */\n\t_api_register( 'draw()', function ( paging ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( paging === 'page' ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif ( typeof paging === 'string' ) {\n\t\t\t\t\tpaging = paging === 'full-hold' ?\n\t\t\t\t\t\tfalse :\n\t\t\t\t\t\ttrue;\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, paging===false );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get the current page index.\n\t *\n\t * @return {integer} Current page index (zero based)\n\t *//**\n\t * Set the current page.\n\t *\n\t * Note that if you attempt to show a page which does not exist, DataTables will\n\t * not throw an error, but rather reset the paging.\n\t *\n\t * @param {integer|string} action The paging action to take. This can be one of:\n\t * * `integer` - The page index to jump to\n\t * * `string` - An action to take:\n\t * * `first` - Jump to first page.\n\t * * `next` - Jump to the next page\n\t * * `previous` - Jump to previous page\n\t * * `last` - Jump to the last page.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page()', function ( action ) {\n\t\tif ( action === undefined ) {\n\t\t\treturn this.page.info().page; // not an expensive call\n\t\t}\n\t\n\t\t// else, have an action to take on all tables\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnPageChange( settings, action );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Paging information for the first table in the current context.\n\t *\n\t * If you require paging information for another table, use the `table()` method\n\t * with a suitable selector.\n\t *\n\t * @return {object} Object with the following properties set:\n\t * * `page` - Current page index (zero based - i.e. the first page is `0`)\n\t * * `pages` - Total number of pages\n\t * * `start` - Display index for the first record shown on the current page\n\t * * `end` - Display index for the last record shown on the current page\n\t * * `length` - Display length (number of records). Note that generally `start\n\t * + length = end`, but this is not always true, for example if there are\n\t * only 2 records to show on the final page, with a length of 10.\n\t * * `recordsTotal` - Full data set length\n\t * * `recordsDisplay` - Data set length once the current filtering criterion\n\t * are applied.\n\t */\n\t_api_register( 'page.info()', function ( action ) {\n\t\tif ( this.context.length === 0 ) {\n\t\t\treturn undefined;\n\t\t}\n\t\n\t\tvar\n\t\t\tsettings = this.context[0],\n\t\t\tstart = settings._iDisplayStart,\n\t\t\tlen = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,\n\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\tall = len === -1;\n\t\n\t\treturn {\n\t\t\t\"page\": all ? 0 : Math.floor( start / len ),\n\t\t\t\"pages\": all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\"start\": start,\n\t\t\t\"end\": settings.fnDisplayEnd(),\n\t\t\t\"length\": len,\n\t\t\t\"recordsTotal\": settings.fnRecordsTotal(),\n\t\t\t\"recordsDisplay\": visRecords,\n\t\t\t\"serverSide\": _fnDataSource( settings ) === 'ssp'\n\t\t};\n\t} );\n\t\n\t\n\t/**\n\t * Get the current page length.\n\t *\n\t * @return {integer} Current page length. Note `-1` indicates that all records\n\t * are to be shown.\n\t *//**\n\t * Set the current page length.\n\t *\n\t * @param {integer} Page length to set. Use `-1` to show all records.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page.len()', function ( len ) {\n\t\t// Note that we can't call this function 'length()' because `length`\n\t\t// is a Javascript property of functions which defines how many arguments\n\t\t// the function expects.\n\t\tif ( len === undefined ) {\n\t\t\treturn this.context.length !== 0 ?\n\t\t\t\tthis.context[0]._iDisplayLength :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// else, set the page length\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnLengthChange( settings, len );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\tvar __reload = function ( settings, holdPosition, callback ) {\n\t\t// Use the draw event to trigger a callback\n\t\tif ( callback ) {\n\t\t\tvar api = new _Api( settings );\n\t\n\t\t\tapi.one( 'draw', function () {\n\t\t\t\tcallback( api.ajax.json() );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t_fnReDraw( settings, holdPosition );\n\t\t}\n\t\telse {\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t// Cancel an existing request\n\t\t\tvar xhr = settings.jqXHR;\n\t\t\tif ( xhr && xhr.readyState !== 4 ) {\n\t\t\t\txhr.abort();\n\t\t\t}\n\t\n\t\t\t// Trigger xhr\n\t\t\t_fnBuildAjax( settings, [], function( json ) {\n\t\t\t\t_fnClearTable( settings );\n\t\n\t\t\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\t_fnAddData( settings, data[i] );\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, holdPosition );\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Get the JSON response from the last Ajax request that DataTables made to the\n\t * server. Note that this returns the JSON from the first table in the current\n\t * context.\n\t *\n\t * @return {object} JSON received from the server.\n\t */\n\t_api_register( 'ajax.json()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].json;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Get the data submitted in the last Ajax request\n\t */\n\t_api_register( 'ajax.params()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].oAjaxData;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Reload tables from the Ajax data source. Note that this function will\n\t * automatically re-draw the table when the remote data has been loaded.\n\t *\n\t * @param {boolean} [reset=true] Reset (default) or hold the current paging\n\t * position. A full re-sort and re-filter is performed when this method is\n\t * called, which is why the pagination reset is the default action.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.reload()', function ( callback, resetPaging ) {\n\t\treturn this.iterator( 'table', function (settings) {\n\t\t\t__reload( settings, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Get the current Ajax URL. Note that this returns the URL from the first\n\t * table in the current context.\n\t *\n\t * @return {string} Current Ajax source URL\n\t *//**\n\t * Set the Ajax URL. Note that this will set the URL for all tables in the\n\t * current context.\n\t *\n\t * @param {string} url URL to set.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url()', function ( url ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( url === undefined ) {\n\t\t\t// get\n\t\t\tif ( ctx.length === 0 ) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tctx = ctx[0];\n\t\n\t\t\treturn ctx.ajax ?\n\t\t\t\t$.isPlainObject( ctx.ajax ) ?\n\t\t\t\t\tctx.ajax.url :\n\t\t\t\t\tctx.ajax :\n\t\t\t\tctx.sAjaxSource;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( $.isPlainObject( settings.ajax ) ) {\n\t\t\t\tsettings.ajax.url = url;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsettings.ajax = url;\n\t\t\t}\n\t\t\t// No need to consider sAjaxSource here since DataTables gives priority\n\t\t\t// to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any\n\t\t\t// value of `sAjaxSource` redundant.\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Load data from the newly set Ajax URL. Note that this method is only\n\t * available when `ajax.url()` is used to set a URL. Additionally, this method\n\t * has the same effect as calling `ajax.reload()` but is provided for\n\t * convenience when setting a new URL. Like `ajax.reload()` it will\n\t * automatically redraw the table once the remote data has been loaded.\n\t *\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {\n\t\t// Same as a reload, but makes sense to present it for easy access after a\n\t\t// url change\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\t__reload( ctx, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t\n\tvar _selector_run = function ( type, selector, selectFn, settings, opts )\n\t{\n\t\tvar\n\t\t\tout = [], res,\n\t\t\ta, i, ien, j, jen,\n\t\t\tselectorType = typeof selector;\n\t\n\t\t// Can't just check for isArray here, as an API or jQuery instance might be\n\t\t// given with their array like look\n\t\tif ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {\n\t\t\tselector = [ selector ];\n\t\t}\n\t\n\t\tfor ( i=0, ien=selector.length ; i<ien ; i++ ) {\n\t\t\t// Only split on simple strings - complex expressions will be jQuery selectors\n\t\t\ta = selector[i] && selector[i].split && ! selector[i].match(/[\\[\\(:]/) ?\n\t\t\t\tselector[i].split(',') :\n\t\t\t\t[ selector[i] ];\n\t\n\t\t\tfor ( j=0, jen=a.length ; j<jen ; j++ ) {\n\t\t\t\tres = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] );\n\t\n\t\t\t\tif ( res && res.length ) {\n\t\t\t\t\tout = out.concat( res );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// selector extensions\n\t\tvar ext = _ext.selector[ type ];\n\t\tif ( ext.length ) {\n\t\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\t\tout = ext[i]( settings, opts, out );\n\t\t\t}\n\t\t}\n\t\n\t\treturn _unique( out );\n\t};\n\t\n\t\n\tvar _selector_opts = function ( opts )\n\t{\n\t\tif ( ! opts ) {\n\t\t\topts = {};\n\t\t}\n\t\n\t\t// Backwards compatibility for 1.9- which used the terminology filter rather\n\t\t// than search\n\t\tif ( opts.filter && opts.search === undefined ) {\n\t\t\topts.search = opts.filter;\n\t\t}\n\t\n\t\treturn $.extend( {\n\t\t\tsearch: 'none',\n\t\t\torder: 'current',\n\t\t\tpage: 'all'\n\t\t}, opts );\n\t};\n\t\n\t\n\tvar _selector_first = function ( inst )\n\t{\n\t\t// Reduce the API instance to the first item found\n\t\tfor ( var i=0, ien=inst.length ; i<ien ; i++ ) {\n\t\t\tif ( inst[i].length > 0 ) {\n\t\t\t\t// Assign the first element to the first item in the instance\n\t\t\t\t// and truncate the instance and context\n\t\t\t\tinst[0] = inst[i];\n\t\t\t\tinst[0].length = 1;\n\t\t\t\tinst.length = 1;\n\t\t\t\tinst.context = [ inst.context[i] ];\n\t\n\t\t\t\treturn inst;\n\t\t\t}\n\t\t}\n\t\n\t\t// Not found - return an empty instance\n\t\tinst.length = 0;\n\t\treturn inst;\n\t};\n\t\n\t\n\tvar _selector_row_indexes = function ( settings, opts )\n\t{\n\t\tvar\n\t\t\ti, ien, tmp, a=[],\n\t\t\tdisplayFiltered = settings.aiDisplay,\n\t\t\tdisplayMaster = settings.aiDisplayMaster;\n\t\n\t\tvar\n\t\t\tsearch = opts.search, // none, applied, removed\n\t\t\torder = opts.order, // applied, current, index (original - compatibility with 1.9)\n\t\t\tpage = opts.page; // all, current\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t// In server-side processing mode, most options are irrelevant since\n\t\t\t// rows not shown don't exist and the index order is the applied order\n\t\t\t// Removed is a special case - for consistency just return an empty\n\t\t\t// array\n\t\t\treturn search === 'removed' ?\n\t\t\t\t[] :\n\t\t\t\t_range( 0, displayMaster.length );\n\t\t}\n\t\telse if ( page == 'current' ) {\n\t\t\t// Current page implies that order=current and filter=applied, since it is\n\t\t\t// fairly senseless otherwise, regardless of what order and search actually\n\t\t\t// are\n\t\t\tfor ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {\n\t\t\t\ta.push( displayFiltered[i] );\n\t\t\t}\n\t\t}\n\t\telse if ( order == 'current' || order == 'applied' ) {\n\t\t\tif ( search == 'none') {\n\t\t\t\ta = displayMaster.slice();\n\t\t\t}\n\t\t\telse if ( search == 'applied' ) {\n\t\t\t\ta = displayFiltered.slice();\n\t\t\t}\n\t\t\telse if ( search == 'removed' ) {\n\t\t\t\t// O(n+m) solution by creating a hash map\n\t\t\t\tvar displayFilteredMap = {};\n\t\n\t\t\t\tfor ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) {\n\t\t\t\t\tdisplayFilteredMap[displayFiltered[i]] = null;\n\t\t\t\t}\n\t\n\t\t\t\ta = $.map( displayMaster, function (el) {\n\t\t\t\t\treturn ! displayFilteredMap.hasOwnProperty(el) ?\n\t\t\t\t\t\tel :\n\t\t\t\t\t\tnull;\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\telse if ( order == 'index' || order == 'original' ) {\n\t\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tif ( search == 'none' ) {\n\t\t\t\t\ta.push( i );\n\t\t\t\t}\n\t\t\t\telse { // applied | removed\n\t\t\t\t\ttmp = $.inArray( i, displayFiltered );\n\t\n\t\t\t\t\tif ((tmp === -1 && search == 'removed') ||\n\t\t\t\t\t\t(tmp >= 0 && search == 'applied') )\n\t\t\t\t\t{\n\t\t\t\t\t\ta.push( i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn a;\n\t};\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Rows\n\t *\n\t * {} - no selector - use all available rows\n\t * {integer} - row aoData index\n\t * {node} - TR node\n\t * {string} - jQuery selector to apply to the TR elements\n\t * {array} - jQuery array of nodes, or simply an array of TR nodes\n\t *\n\t */\n\tvar __row_selector = function ( settings, selector, opts )\n\t{\n\t\tvar rows;\n\t\tvar run = function ( sel ) {\n\t\t\tvar selInt = _intVal( sel );\n\t\t\tvar i, ien;\n\t\t\tvar aoData = settings.aoData;\n\t\n\t\t\t// Short cut - selector is a number and no options provided (default is\n\t\t\t// all records, so no need to check if the index is in there, since it\n\t\t\t// must be - dev error if the index doesn't exist).\n\t\t\tif ( selInt !== null && ! opts ) {\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\n\t\t\tif ( ! rows ) {\n\t\t\t\trows = _selector_row_indexes( settings, opts );\n\t\t\t}\n\t\n\t\t\tif ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {\n\t\t\t\t// Selector - integer\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\t\telse if ( sel === null || sel === undefined || sel === '' ) {\n\t\t\t\t// Selector - none\n\t\t\t\treturn rows;\n\t\t\t}\n\t\n\t\t\t// Selector - function\n\t\t\tif ( typeof sel === 'function' ) {\n\t\t\t\treturn $.map( rows, function (idx) {\n\t\t\t\t\tvar row = aoData[ idx ];\n\t\t\t\t\treturn sel( idx, row._aData, row.nTr ) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Selector - node\n\t\t\tif ( sel.nodeName ) {\n\t\t\t\tvar rowIdx = sel._DT_RowIndex; // Property added by DT for fast lookup\n\t\t\t\tvar cellIdx = sel._DT_CellIndex;\n\t\n\t\t\t\tif ( rowIdx !== undefined ) {\n\t\t\t\t\t// Make sure that the row is actually still present in the table\n\t\t\t\t\treturn aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?\n\t\t\t\t\t\t[ rowIdx ] :\n\t\t\t\t\t\t[];\n\t\t\t\t}\n\t\t\t\telse if ( cellIdx ) {\n\t\t\t\t\treturn aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ?\n\t\t\t\t\t\t[ cellIdx.row ] :\n\t\t\t\t\t\t[];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tvar host = $(sel).closest('*[data-dt-row]');\n\t\t\t\t\treturn host.length ?\n\t\t\t\t\t\t[ host.data('dt-row') ] :\n\t\t\t\t\t\t[];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// ID selector. Want to always be able to select rows by id, regardless\n\t\t\t// of if the tr element has been created or not, so can't rely upon\n\t\t\t// jQuery here - hence a custom implementation. This does not match\n\t\t\t// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,\n\t\t\t// but to select it using a CSS selector engine (like Sizzle or\n\t\t\t// querySelect) it would need to need to be escaped for some characters.\n\t\t\t// DataTables simplifies this for row selectors since you can select\n\t\t\t// only a row. A # indicates an id any anything that follows is the id -\n\t\t\t// unescaped.\n\t\t\tif ( typeof sel === 'string' && sel.charAt(0) === '#' ) {\n\t\t\t\t// get row index from id\n\t\t\t\tvar rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];\n\t\t\t\tif ( rowObj !== undefined ) {\n\t\t\t\t\treturn [ rowObj.idx ];\n\t\t\t\t}\n\t\n\t\t\t\t// need to fall through to jQuery in case there is DOM id that\n\t\t\t\t// matches\n\t\t\t}\n\t\t\t\n\t\t\t// Get nodes in the order from the `rows` array with null values removed\n\t\t\tvar nodes = _removeEmpty(\n\t\t\t\t_pluck_order( settings.aoData, rows, 'nTr' )\n\t\t\t);\n\t\n\t\t\t// Selector - jQuery selector string, array of nodes or jQuery object/\n\t\t\t// As jQuery's .filter() allows jQuery objects to be passed in filter,\n\t\t\t// it also allows arrays, so this will cope with all three options\n\t\t\treturn $(nodes)\n\t\t\t\t.filter( sel )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn this._DT_RowIndex;\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\t};\n\t\n\t\treturn _selector_run( 'row', selector, run, settings, opts );\n\t};\n\t\n\t\n\t_api_register( 'rows()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __row_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in __row_selector?\n\t\tinst.selector.rows = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_register( 'rows().nodes()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn settings.aoData[ row ].nTr || undefined;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'rows().data()', function () {\n\t\treturn this.iterator( true, 'rows', function ( settings, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, '_aData' );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\tvar r = settings.aoData[ row ];\n\t\t\treturn type === 'search' ? r._aFilterData : r._aSortData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\t_fnInvalidate( settings, row, src );\n\t\t} );\n\t} );\n\t\n\t_api_registerPlural( 'rows().indexes()', 'row().index()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn row;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {\n\t\tvar a = [];\n\t\tvar context = this.context;\n\t\n\t\t// `iterator` will drop undefined values, but in this case we want them\n\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\tfor ( var j=0, jen=this[i].length ; j<jen ; j++ ) {\n\t\t\t\tvar id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );\n\t\t\t\ta.push( (hash === true ? '#' : '' )+ id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn new _Api( context, a );\n\t} );\n\t\n\t_api_registerPlural( 'rows().remove()', 'row().remove()', function () {\n\t\tvar that = this;\n\t\n\t\tthis.iterator( 'row', function ( settings, row, thatIdx ) {\n\t\t\tvar data = settings.aoData;\n\t\t\tvar rowData = data[ row ];\n\t\t\tvar i, ien, j, jen;\n\t\t\tvar loopRow, loopCells;\n\t\n\t\t\tdata.splice( row, 1 );\n\t\n\t\t\t// Update the cached indexes\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\tloopRow = data[i];\n\t\t\t\tloopCells = loopRow.anCells;\n\t\n\t\t\t\t// Rows\n\t\t\t\tif ( loopRow.nTr !== null ) {\n\t\t\t\t\tloopRow.nTr._DT_RowIndex = i;\n\t\t\t\t}\n\t\n\t\t\t\t// Cells\n\t\t\t\tif ( loopCells !== null ) {\n\t\t\t\t\tfor ( j=0, jen=loopCells.length ; j<jen ; j++ ) {\n\t\t\t\t\t\tloopCells[j]._DT_CellIndex.row = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Delete from the display arrays\n\t\t\t_fnDeleteIndex( settings.aiDisplayMaster, row );\n\t\t\t_fnDeleteIndex( settings.aiDisplay, row );\n\t\t\t_fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes\n\t\n\t\t\t// For server-side processing tables - subtract the deleted row from the count\n\t\t\tif ( settings._iRecordsDisplay > 0 ) {\n\t\t\t\tsettings._iRecordsDisplay--;\n\t\t\t}\n\t\n\t\t\t// Check for an 'overflow' they case for displaying the table\n\t\t\t_fnLengthOverflow( settings );\n\t\n\t\t\t// Remove the row's ID reference if there is one\n\t\t\tvar id = settings.rowIdFn( rowData._aData );\n\t\t\tif ( id !== undefined ) {\n\t\t\t\tdelete settings.aIds[ id ];\n\t\t\t}\n\t\t} );\n\t\n\t\tthis.iterator( 'table', function ( settings ) {\n\t\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tsettings.aoData[i].idx = i;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'rows.add()', function ( rows ) {\n\t\tvar newRows = this.iterator( 'table', function ( settings ) {\n\t\t\t\tvar row, i, ien;\n\t\t\t\tvar out = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\t\t\tout.push( _fnAddTr( settings, row )[0] );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tout.push( _fnAddData( settings, row ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn out;\n\t\t\t}, 1 );\n\t\n\t\t// Return an Api.rows() extended instance, so rows().nodes() etc can be used\n\t\tvar modRows = this.rows( -1 );\n\t\tmodRows.pop();\n\t\t$.merge( modRows, newRows );\n\t\n\t\treturn modRows;\n\t} );\n\t\n\t\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( 'row()', function ( selector, opts ) {\n\t\treturn _selector_first( this.rows( selector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'row().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._aData :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\tvar row = ctx[0].aoData[ this[0] ];\n\t\trow._aData = data;\n\t\n\t\t// If the DOM has an id, and the data source is an array\n\t\tif ( Array.isArray( data ) && row.nTr && row.nTr.id ) {\n\t\t\t_fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );\n\t\t}\n\t\n\t\t// Automatically invalidate\n\t\t_fnInvalidate( ctx[0], this[0], 'data' );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'row().node()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\treturn ctx.length && this.length ?\n\t\t\tctx[0].aoData[ this[0] ].nTr || null :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'row.add()', function ( row ) {\n\t\t// Allow a jQuery object to be passed in - only a single row is added from\n\t\t// it though - the first element in the set\n\t\tif ( row instanceof $ && row.length ) {\n\t\t\trow = row[0];\n\t\t}\n\t\n\t\tvar rows = this.iterator( 'table', function ( settings ) {\n\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\treturn _fnAddTr( settings, row )[0];\n\t\t\t}\n\t\t\treturn _fnAddData( settings, row );\n\t\t} );\n\t\n\t\t// Return an Api.rows() extended instance, with the newly added row selected\n\t\treturn this.row( rows[0] );\n\t} );\n\t\n\t\n\t$(document).on('plugin-init.dt', function (e, context) {\n\t\tvar api = new _Api( context );\n\t\tapi.on( 'stateSaveParams', function ( e, settings, data ) {\n\t\t\tvar indexes = api.rows().iterator( 'row', function ( settings, idx ) {\n\t\t\t\treturn settings.aoData[idx]._detailsShow ? idx : undefined;\n\t\t\t});\n\t\n\t\t\tdata.childRows = api.rows( indexes ).ids( true ).toArray();\n\t\t})\n\t\n\t\tvar loaded = api.state.loaded();\n\t\n\t\tif ( loaded && loaded.childRows ) {\n\t\t\tapi.rows( loaded.childRows ).every( function () {\n\t\t\t\t_fnCallbackFire( context, null, 'requestChild', [ this ] )\n\t\t\t})\n\t\t}\n\t})\n\t\n\tvar __details_add = function ( ctx, row, data, klass )\n\t{\n\t\t// Convert to array of TR elements\n\t\tvar rows = [];\n\t\tvar addRow = function ( r, k ) {\n\t\t\t// Recursion to allow for arrays of jQuery objects\n\t\t\tif ( Array.isArray( r ) || r instanceof $ ) {\n\t\t\t\tfor ( var i=0, ien=r.length ; i<ien ; i++ ) {\n\t\t\t\t\taddRow( r[i], k );\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If we get a TR element, then just add it directly - up to the dev\n\t\t\t// to add the correct number of columns etc\n\t\t\tif ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {\n\t\t\t\trows.push( r );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Otherwise create a row with a wrapper\n\t\t\t\tvar created = $('<tr><td></td></tr>').addClass( k );\n\t\t\t\t$('td', created)\n\t\t\t\t\t.addClass( k )\n\t\t\t\t\t.html( r )\n\t\t\t\t\t[0].colSpan = _fnVisbleColumns( ctx );\n\t\n\t\t\t\trows.push( created[0] );\n\t\t\t}\n\t\t};\n\t\n\t\taddRow( data, klass );\n\t\n\t\tif ( row._details ) {\n\t\t\trow._details.detach();\n\t\t}\n\t\n\t\trow._details = $(rows);\n\t\n\t\t// If the children were already shown, that state should be retained\n\t\tif ( row._detailsShow ) {\n\t\t\trow._details.insertAfter( row.nTr );\n\t\t}\n\t};\n\t\n\t\n\tvar __details_remove = function ( api, idx )\n\t{\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length ) {\n\t\t\tvar row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];\n\t\n\t\t\tif ( row && row._details ) {\n\t\t\t\trow._details.remove();\n\t\n\t\t\t\trow._detailsShow = undefined;\n\t\t\t\trow._details = undefined;\n\t\t\t\t$( row.nTr ).removeClass( 'dt-hasChild' );\n\t\t\t\t_fnSaveState( ctx[0] );\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_display = function ( api, show ) {\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length && api.length ) {\n\t\t\tvar row = ctx[0].aoData[ api[0] ];\n\t\n\t\t\tif ( row._details ) {\n\t\t\t\trow._detailsShow = show;\n\t\n\t\t\t\tif ( show ) {\n\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t\t$( row.nTr ).addClass( 'dt-hasChild' );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\trow._details.detach();\n\t\t\t\t\t$( row.nTr ).removeClass( 'dt-hasChild' );\n\t\t\t\t}\n\t\n\t\t\t\t_fnCallbackFire( ctx[0], null, 'childRow', [ show, api.row( api[0] ) ] )\n\t\n\t\t\t\t__details_events( ctx[0] );\n\t\t\t\t_fnSaveState( ctx[0] );\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_events = function ( settings )\n\t{\n\t\tvar api = new _Api( settings );\n\t\tvar namespace = '.dt.DT_details';\n\t\tvar drawEvent = 'draw'+namespace;\n\t\tvar colvisEvent = 'column-visibility'+namespace;\n\t\tvar destroyEvent = 'destroy'+namespace;\n\t\tvar data = settings.aoData;\n\t\n\t\tapi.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );\n\t\n\t\tif ( _pluck( data, '_details' ).length > 0 ) {\n\t\t\t// On each draw, insert the required elements into the document\n\t\t\tapi.on( drawEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tapi.rows( {page:'current'} ).eq(0).each( function (idx) {\n\t\t\t\t\t// Internal data grab\n\t\t\t\t\tvar row = data[ idx ];\n\t\n\t\t\t\t\tif ( row._detailsShow ) {\n\t\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\n\t\t\t// Column visibility change - update the colspan\n\t\t\tapi.on( colvisEvent, function ( e, ctx, idx, vis ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t// Update the colspan for the details rows (note, only if it already has\n\t\t\t\t// a colspan)\n\t\t\t\tvar row, visible = _fnVisbleColumns( ctx );\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = data[i];\n\t\n\t\t\t\t\tif ( row._details ) {\n\t\t\t\t\t\trow._details.children('td[colspan]').attr('colspan', visible );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\t// Table destroyed - nuke any child rows\n\t\t\tapi.on( destroyEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( data[i]._details ) {\n\t\t\t\t\t\t__details_remove( api, i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t// Strings for the method names to help minification\n\tvar _emp = '';\n\tvar _child_obj = _emp+'row().child';\n\tvar _child_mth = _child_obj+'()';\n\t\n\t// data can be:\n\t// tr\n\t// string\n\t// jQuery or array of any of the above\n\t_api_register( _child_mth, function ( data, klass ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._details :\n\t\t\t\tundefined;\n\t\t}\n\t\telse if ( data === true ) {\n\t\t\t// show\n\t\t\tthis.child.show();\n\t\t}\n\t\telse if ( data === false ) {\n\t\t\t// remove\n\t\t\t__details_remove( this );\n\t\t}\n\t\telse if ( ctx.length && this.length ) {\n\t\t\t// set\n\t\t\t__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );\n\t\t}\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.show()',\n\t\t_child_mth+'.show()' // only when `child()` was called with parameters (without\n\t], function ( show ) { // it returns an object and this method is not executed)\n\t\t__details_display( this, true );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.hide()',\n\t\t_child_mth+'.hide()' // only when `child()` was called with parameters (without\n\t], function () { // it returns an object and this method is not executed)\n\t\t__details_display( this, false );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.remove()',\n\t\t_child_mth+'.remove()' // only when `child()` was called with parameters (without\n\t], function () { // it returns an object and this method is not executed)\n\t\t__details_remove( this );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( _child_obj+'.isShown()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length && this.length ) {\n\t\t\t// _detailsShown as false or undefined will fall through to return false\n\t\t\treturn ctx[0].aoData[ this[0] ]._detailsShow || false;\n\t\t}\n\t\treturn false;\n\t} );\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Columns\n\t *\n\t * {integer} - column index (>=0 count from left, <0 count from right)\n\t * \"{integer}:visIdx\" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)\n\t * \"{integer}:visible\" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)\n\t * \"{string}:name\" - column name\n\t * \"{string}\" - jQuery selector on column header nodes\n\t *\n\t */\n\t\n\t// can be an array of these items, comma separated list, or an array of comma\n\t// separated lists\n\t\n\tvar __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;\n\t\n\t\n\t// r1 and r2 are redundant - but it means that the parameters match for the\n\t// iterator callback in columns().data()\n\tvar __columnData = function ( settings, column, r1, r2, rows ) {\n\t\tvar a = [];\n\t\tfor ( var row=0, ien=rows.length ; row<ien ; row++ ) {\n\t\t\ta.push( _fnGetCellData( settings, rows[row], column ) );\n\t\t}\n\t\treturn a;\n\t};\n\t\n\t\n\tvar __column_selector = function ( settings, selector, opts )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tnames = _pluck( columns, 'sName' ),\n\t\t\tnodes = _pluck( columns, 'nTh' );\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar selInt = _intVal( s );\n\t\n\t\t\t// Selector - all\n\t\t\tif ( s === '' ) {\n\t\t\t\treturn _range( columns.length );\n\t\t\t}\n\t\n\t\t\t// Selector - index\n\t\t\tif ( selInt !== null ) {\n\t\t\t\treturn [ selInt >= 0 ?\n\t\t\t\t\tselInt : // Count from left\n\t\t\t\t\tcolumns.length + selInt // Count from right (+ because its a negative value)\n\t\t\t\t];\n\t\t\t}\n\t\n\t\t\t// Selector = function\n\t\t\tif ( typeof s === 'function' ) {\n\t\t\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\n\t\t\t\treturn $.map( columns, function (col, idx) {\n\t\t\t\t\treturn s(\n\t\t\t\t\t\t\tidx,\n\t\t\t\t\t\t\t__columnData( settings, idx, 0, 0, rows ),\n\t\t\t\t\t\t\tnodes[ idx ]\n\t\t\t\t\t\t) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// jQuery or string selector\n\t\t\tvar match = typeof s === 'string' ?\n\t\t\t\ts.match( __re_column_selector ) :\n\t\t\t\t'';\n\t\n\t\t\tif ( match ) {\n\t\t\t\tswitch( match[2] ) {\n\t\t\t\t\tcase 'visIdx':\n\t\t\t\t\tcase 'visible':\n\t\t\t\t\t\tvar idx = parseInt( match[1], 10 );\n\t\t\t\t\t\t// Visible index given, convert to column index\n\t\t\t\t\t\tif ( idx < 0 ) {\n\t\t\t\t\t\t\t// Counting from the right\n\t\t\t\t\t\t\tvar visColumns = $.map( columns, function (col,i) {\n\t\t\t\t\t\t\t\treturn col.bVisible ? i : null;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\treturn [ visColumns[ visColumns.length + idx ] ];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Counting from the left\n\t\t\t\t\t\treturn [ _fnVisibleToColumnIndex( settings, idx ) ];\n\t\n\t\t\t\t\tcase 'name':\n\t\t\t\t\t\t// match by name. `names` is column index complete and in order\n\t\t\t\t\t\treturn $.map( names, function (name, i) {\n\t\t\t\t\t\t\treturn name === match[1] ? i : null;\n\t\t\t\t\t\t} );\n\t\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Cell in the table body\n\t\t\tif ( s.nodeName && s._DT_CellIndex ) {\n\t\t\t\treturn [ s._DT_CellIndex.column ];\n\t\t\t}\n\t\n\t\t\t// jQuery selector on the TH elements for the columns\n\t\t\tvar jqResult = $( nodes )\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn $.inArray( this, nodes ); // `nodes` is column index complete and in order\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise a node which might have a `dt-column` data attribute, or be\n\t\t\t// a child or such an element\n\t\t\tvar host = $(s).closest('*[data-dt-column]');\n\t\t\treturn host.length ?\n\t\t\t\t[ host.data('dt-column') ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'column', selector, run, settings, opts );\n\t};\n\t\n\t\n\tvar __setColumnVis = function ( settings, column, vis ) {\n\t\tvar\n\t\t\tcols = settings.aoColumns,\n\t\t\tcol = cols[ column ],\n\t\t\tdata = settings.aoData,\n\t\t\trow, cells, i, ien, tr;\n\t\n\t\t// Get\n\t\tif ( vis === undefined ) {\n\t\t\treturn col.bVisible;\n\t\t}\n\t\n\t\t// Set\n\t\t// No change\n\t\tif ( col.bVisible === vis ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( vis ) {\n\t\t\t// Insert column\n\t\t\t// Need to decide if we should use appendChild or insertBefore\n\t\t\tvar insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );\n\t\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\ttr = data[i].nTr;\n\t\t\t\tcells = data[i].anCells;\n\t\n\t\t\t\tif ( tr ) {\n\t\t\t\t\t// insertBefore can act like appendChild if 2nd arg is null\n\t\t\t\t\ttr.insertBefore( cells[ column ], cells[ insertBefore ] || null );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Remove column\n\t\t\t$( _pluck( settings.aoData, 'anCells', column ) ).detach();\n\t\t}\n\t\n\t\t// Common actions\n\t\tcol.bVisible = vis;\n\t};\n\t\n\t\n\t_api_register( 'columns()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __column_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in _row_selector?\n\t\tinst.selector.cols = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTh;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTf;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().data()', 'column().data()', function () {\n\t\treturn this.iterator( 'column-rows', __columnData, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].mData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows,\n\t\t\t\ttype === 'search' ? '_aFilterData' : '_aSortData', column\n\t\t\t);\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, 'anCells', column ) ;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {\n\t\tvar that = this;\n\t\tvar ret = this.iterator( 'column', function ( settings, column ) {\n\t\t\tif ( vis === undefined ) {\n\t\t\t\treturn settings.aoColumns[ column ].bVisible;\n\t\t\t} // else\n\t\t\t__setColumnVis( settings, column, vis );\n\t\t} );\n\t\n\t\t// Group the column visibility changes\n\t\tif ( vis !== undefined ) {\n\t\t\tthis.iterator( 'table', function ( settings ) {\n\t\t\t\t// Redraw the header after changes\n\t\t\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\t\n\t\t\t\t// Update colspan for no records display. Child rows and extensions will use their own\n\t\t\t\t// listeners to do this - only need to update the empty table item here\n\t\t\t\tif ( ! settings.aiDisplay.length ) {\n\t\t\t\t\t$(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));\n\t\t\t\t}\n\t\t\n\t\t\t\t_fnSaveState( settings );\n\t\n\t\t\t\t// Second loop once the first is done for events\n\t\t\t\tthat.iterator( 'column', function ( settings, column ) {\n\t\t\t\t\t_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );\n\t\t\t\t} );\n\t\n\t\t\t\tif ( calc === undefined || calc ) {\n\t\t\t\t\tthat.columns.adjust();\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\n\t\treturn ret;\n\t} );\n\t\n\t_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn type === 'visible' ?\n\t\t\t\t_fnColumnIndexToVisible( settings, column ) :\n\t\t\t\tcolumn;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'columns.adjust()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'column.index()', function ( type, idx ) {\n\t\tif ( this.context.length !== 0 ) {\n\t\t\tvar ctx = this.context[0];\n\t\n\t\t\tif ( type === 'fromVisible' || type === 'toData' ) {\n\t\t\t\treturn _fnVisibleToColumnIndex( ctx, idx );\n\t\t\t}\n\t\t\telse if ( type === 'fromData' || type === 'toVisible' ) {\n\t\t\t\treturn _fnColumnIndexToVisible( ctx, idx );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t_api_register( 'column()', function ( selector, opts ) {\n\t\treturn _selector_first( this.columns( selector, opts ) );\n\t} );\n\t\n\tvar __cell_selector = function ( settings, selector, opts )\n\t{\n\t\tvar data = settings.aoData;\n\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\tvar cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );\n\t\tvar allCells = $(_flatten( [], cells ));\n\t\tvar row;\n\t\tvar columns = settings.aoColumns.length;\n\t\tvar a, i, ien, j, o, host;\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar fnSelector = typeof s === 'function';\n\t\n\t\t\tif ( s === null || s === undefined || fnSelector ) {\n\t\t\t\t// All cells and function selectors\n\t\t\t\ta = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tfor ( j=0 ; j<columns ; j++ ) {\n\t\t\t\t\t\to = {\n\t\t\t\t\t\t\trow: row,\n\t\t\t\t\t\t\tcolumn: j\n\t\t\t\t\t\t};\n\t\n\t\t\t\t\t\tif ( fnSelector ) {\n\t\t\t\t\t\t\t// Selector - function\n\t\t\t\t\t\t\thost = data[ row ];\n\t\n\t\t\t\t\t\t\tif ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {\n\t\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Selector - all\n\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn a;\n\t\t\t}\n\t\t\t\n\t\t\t// Selector - index\n\t\t\tif ( $.isPlainObject( s ) ) {\n\t\t\t\t// Valid cell index and its in the array of selectable rows\n\t\t\t\treturn s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ?\n\t\t\t\t\t[s] :\n\t\t\t\t\t[];\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery filtered cells\n\t\t\tvar jqResult = allCells\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function (i, el) {\n\t\t\t\t\treturn { // use a new object, in case someone changes the values\n\t\t\t\t\t\trow: el._DT_CellIndex.row,\n\t\t\t\t\t\tcolumn: el._DT_CellIndex.column\n\t \t\t\t\t};\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise the selector is a node, and there is one last option - the\n\t\t\t// element might be a child of an element which has dt-row and dt-column\n\t\t\t// data attributes\n\t\t\thost = $(s).closest('*[data-dt-row]');\n\t\t\treturn host.length ?\n\t\t\t\t[ {\n\t\t\t\t\trow: host.data('dt-row'),\n\t\t\t\t\tcolumn: host.data('dt-column')\n\t\t\t\t} ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'cell', selector, run, settings, opts );\n\t};\n\t\n\t\n\t\n\t\n\t_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {\n\t\t// Argument shifting\n\t\tif ( $.isPlainObject( rowSelector ) ) {\n\t\t\t// Indexes\n\t\t\tif ( rowSelector.row === undefined ) {\n\t\t\t\t// Selector options in first parameter\n\t\t\t\topts = rowSelector;\n\t\t\t\trowSelector = null;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Cell index objects in first parameter\n\t\t\t\topts = columnSelector;\n\t\t\t\tcolumnSelector = null;\n\t\t\t}\n\t\t}\n\t\tif ( $.isPlainObject( columnSelector ) ) {\n\t\t\topts = columnSelector;\n\t\t\tcolumnSelector = null;\n\t\t}\n\t\n\t\t// Cell selector\n\t\tif ( columnSelector === null || columnSelector === undefined ) {\n\t\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t\treturn __cell_selector( settings, rowSelector, _selector_opts( opts ) );\n\t\t\t} );\n\t\t}\n\t\n\t\t// The default built in options need to apply to row and columns\n\t\tvar internalOpts = opts ? {\n\t\t\tpage: opts.page,\n\t\t\torder: opts.order,\n\t\t\tsearch: opts.search\n\t\t} : {};\n\t\n\t\t// Row + column selector\n\t\tvar columns = this.columns( columnSelector, internalOpts );\n\t\tvar rows = this.rows( rowSelector, internalOpts );\n\t\tvar i, ien, j, jen;\n\t\n\t\tvar cellsNoOpts = this.iterator( 'table', function ( settings, idx ) {\n\t\t\tvar a = [];\n\t\n\t\t\tfor ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {\n\t\t\t\tfor ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {\n\t\t\t\t\ta.push( {\n\t\t\t\t\t\trow: rows[idx][i],\n\t\t\t\t\t\tcolumn: columns[idx][j]\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn a;\n\t\t}, 1 );\n\t\n\t\t// There is currently only one extension which uses a cell selector extension\n\t\t// It is a _major_ performance drag to run this if it isn't needed, so this is\n\t\t// an extension specific check at the moment\n\t\tvar cells = opts && opts.selected ?\n\t\t\tthis.cells( cellsNoOpts, opts ) :\n\t\t\tcellsNoOpts;\n\t\n\t\t$.extend( cells.selector, {\n\t\t\tcols: columnSelector,\n\t\t\trows: rowSelector,\n\t\t\topts: opts\n\t\t} );\n\t\n\t\treturn cells;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\tvar data = settings.aoData[ row ];\n\t\n\t\t\treturn data && data.anCells ?\n\t\t\t\tdata.anCells[ column ] :\n\t\t\t\tundefined;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_register( 'cells().data()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {\n\t\ttype = type === 'search' ? '_aFilterData' : '_aSortData';\n\t\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn settings.aoData[ row ][ type ][ column ];\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column, type );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn {\n\t\t\t\trow: row,\n\t\t\t\tcolumn: column,\n\t\t\t\tcolumnVisible: _fnColumnIndexToVisible( settings, column )\n\t\t\t};\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\t_fnInvalidate( settings, row, src, column );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {\n\t\treturn _selector_first( this.cells( rowSelector, columnSelector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'cell().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\tvar cell = this[0];\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && cell.length ?\n\t\t\t\t_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\t_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );\n\t\t_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get current ordering (sorting) that has been applied to the table.\n\t *\n\t * @returns {array} 2D array containing the sorting information for the first\n\t * table in the current context. Each element in the parent array represents\n\t * a column being sorted upon (i.e. multi-sorting with two columns would have\n\t * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is\n\t * the column index that the sorting condition applies to, the second is the\n\t * direction of the sort (`desc` or `asc`) and, optionally, the third is the\n\t * index of the sorting order from the `column.sorting` initialisation array.\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {integer} order Column index to sort upon.\n\t * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 1D array of sorting information to be applied.\n\t * @param {array} [...] Optional additional sorting conditions\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 2D array of sorting information to be applied.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order()', function ( order, dir ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( order === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].aaSorting :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\tif ( typeof order === 'number' ) {\n\t\t\t// Simple column / direction passed in\n\t\t\torder = [ [ order, dir ] ];\n\t\t}\n\t\telse if ( order.length && ! Array.isArray( order[0] ) ) {\n\t\t\t// Arguments passed in (list of 1D arrays)\n\t\t\torder = Array.prototype.slice.call( arguments );\n\t\t}\n\t\t// otherwise a 2D array was passed in\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSorting = order.slice();\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Attach a sort listener to an element for a given column\n\t *\n\t * @param {node|jQuery|string} node Identifier for the element(s) to attach the\n\t * listener to. This can take the form of a single DOM node, a jQuery\n\t * collection of nodes or a jQuery selector which will identify the node(s).\n\t * @param {integer} column the column that a click on this node will sort on\n\t * @param {function} [callback] callback function when sort is run\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order.listener()', function ( node, column, callback ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSortAttachListener( settings, node, column, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'order.fixed()', function ( set ) {\n\t\tif ( ! set ) {\n\t\t\tvar ctx = this.context;\n\t\t\tvar fixed = ctx.length ?\n\t\t\t\tctx[0].aaSortingFixed :\n\t\t\t\tundefined;\n\t\n\t\t\treturn Array.isArray( fixed ) ?\n\t\t\t\t{ pre: fixed } :\n\t\t\t\tfixed;\n\t\t}\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSortingFixed = $.extend( true, {}, set );\n\t\t} );\n\t} );\n\t\n\t\n\t// Order by the selected column(s)\n\t_api_register( [\n\t\t'columns().order()',\n\t\t'column().order()'\n\t], function ( dir ) {\n\t\tvar that = this;\n\t\n\t\treturn this.iterator( 'table', function ( settings, i ) {\n\t\t\tvar sort = [];\n\t\n\t\t\t$.each( that[i], function (j, col) {\n\t\t\t\tsort.push( [ col, dir ] );\n\t\t\t} );\n\t\n\t\t\tsettings.aaSorting = sort;\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'search()', function ( input, regex, smart, caseInsen ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( input === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].oPreviousSearch.sSearch :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t_fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {\n\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\"bRegex\": regex === null ? false : regex,\n\t\t\t\t\"bSmart\": smart === null ? true : smart,\n\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t} ), 1 );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural(\n\t\t'columns().search()',\n\t\t'column().search()',\n\t\tfunction ( input, regex, smart, caseInsen ) {\n\t\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\t\tvar preSearch = settings.aoPreSearchCols;\n\t\n\t\t\t\tif ( input === undefined ) {\n\t\t\t\t\t// get\n\t\t\t\t\treturn preSearch[ column ].sSearch;\n\t\t\t\t}\n\t\n\t\t\t\t// set\n\t\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t$.extend( preSearch[ column ], {\n\t\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\t\"bRegex\": regex === null ? false : regex,\n\t\t\t\t\t\"bSmart\": smart === null ? true : smart,\n\t\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t\t} );\n\t\n\t\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch, 1 );\n\t\t\t} );\n\t\t}\n\t);\n\t\n\t/*\n\t * State API methods\n\t */\n\t\n\t_api_register( 'state()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oSavedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t// Save an empty object\n\t\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, {} );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'state.loaded()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oLoadedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.save()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSaveState( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Provide a common method for plug-ins to check the version of DataTables being\n\t * used, in order to ensure compatibility.\n\t *\n\t * @param {string} version Version string to check for, in the format \"X.Y.Z\".\n\t * Note that the formats \"X\" and \"X.Y\" are also acceptable.\n\t * @returns {boolean} true if this version of DataTables is greater or equal to\n\t * the required version, or false if this version of DataTales is not\n\t * suitable\n\t * @static\n\t * @dtopt API-Static\n\t *\n\t * @example\n\t * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );\n\t */\n\tDataTable.versionCheck = DataTable.fnVersionCheck = function( version )\n\t{\n\t\tvar aThis = DataTable.version.split('.');\n\t\tvar aThat = version.split('.');\n\t\tvar iThis, iThat;\n\t\n\t\tfor ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {\n\t\t\tiThis = parseInt( aThis[i], 10 ) || 0;\n\t\t\tiThat = parseInt( aThat[i], 10 ) || 0;\n\t\n\t\t\t// Parts are the same, keep comparing\n\t\t\tif (iThis === iThat) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\t// Parts are different, return immediately\n\t\t\treturn iThis > iThat;\n\t\t}\n\t\n\t\treturn true;\n\t};\n\t\n\t\n\t/**\n\t * Check if a `<table>` node is a DataTable table already or not.\n\t *\n\t * @param {node|jquery|string} table Table node, jQuery object or jQuery\n\t * selector for the table to test. Note that if more than more than one\n\t * table is passed on, only the first will be checked\n\t * @returns {boolean} true the table given is a DataTable, or false otherwise\n\t * @static\n\t * @dtopt API-Static\n\t *\n\t * @example\n\t * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {\n\t * $('#example').dataTable();\n\t * }\n\t */\n\tDataTable.isDataTable = DataTable.fnIsDataTable = function ( table )\n\t{\n\t\tvar t = $(table).get(0);\n\t\tvar is = false;\n\t\n\t\tif ( table instanceof DataTable.Api ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\t$.each( DataTable.settings, function (i, o) {\n\t\t\tvar head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;\n\t\t\tvar foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;\n\t\n\t\t\tif ( o.nTable === t || head === t || foot === t ) {\n\t\t\t\tis = true;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn is;\n\t};\n\t\n\t\n\t/**\n\t * Get all DataTable tables that have been initialised - optionally you can\n\t * select to get only currently visible tables.\n\t *\n\t * @param {boolean} [visible=false] Flag to indicate if you want all (default)\n\t * or visible tables only.\n\t * @returns {array} Array of `table` nodes (not DataTable instances) which are\n\t * DataTables\n\t * @static\n\t * @dtopt API-Static\n\t *\n\t * @example\n\t * $.each( $.fn.dataTable.tables(true), function () {\n\t * $(table).DataTable().columns.adjust();\n\t * } );\n\t */\n\tDataTable.tables = DataTable.fnTables = function ( visible )\n\t{\n\t\tvar api = false;\n\t\n\t\tif ( $.isPlainObject( visible ) ) {\n\t\t\tapi = visible.api;\n\t\t\tvisible = visible.visible;\n\t\t}\n\t\n\t\tvar a = $.map( DataTable.settings, function (o) {\n\t\t\tif ( !visible || (visible && $(o.nTable).is(':visible')) ) {\n\t\t\t\treturn o.nTable;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn api ?\n\t\t\tnew _Api( a ) :\n\t\t\ta;\n\t};\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian notation. This is made public\n\t * for the extensions to provide the same ability as DataTables core to accept\n\t * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase\n\t * parameters.\n\t *\n\t * @param {object} src The model object which holds all parameters that can be\n\t * mapped.\n\t * @param {object} user The object to convert from camel case to Hungarian.\n\t * @param {boolean} force When set to `true`, properties which already have a\n\t * Hungarian value in the `user` object will be overwritten. Otherwise they\n\t * won't be.\n\t */\n\tDataTable.camelToHungarian = _fnCamelToHungarian;\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( '$()', function ( selector, opts ) {\n\t\tvar\n\t\t\trows = this.rows( opts ).nodes(), // Get all rows\n\t\t\tjqRows = $(rows);\n\t\n\t\treturn $( [].concat(\n\t\t\tjqRows.filter( selector ).toArray(),\n\t\t\tjqRows.find( selector ).toArray()\n\t\t) );\n\t} );\n\t\n\t\n\t// jQuery functions to operate on the tables\n\t$.each( [ 'on', 'one', 'off' ], function (i, key) {\n\t\t_api_register( key+'()', function ( /* event, handler */ ) {\n\t\t\tvar args = Array.prototype.slice.call(arguments);\n\t\n\t\t\t// Add the `dt` namespace automatically if it isn't already present\n\t\t\targs[0] = $.map( args[0].split( /\\s/ ), function ( e ) {\n\t\t\t\treturn ! e.match(/\\.dt\\b/) ?\n\t\t\t\t\te+'.dt' :\n\t\t\t\t\te;\n\t\t\t\t} ).join( ' ' );\n\t\n\t\t\tvar inst = $( this.tables().nodes() );\n\t\t\tinst[key].apply( inst, args );\n\t\t\treturn this;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnClearTable( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'settings()', function () {\n\t\treturn new _Api( this.context, this.context );\n\t} );\n\t\n\t\n\t_api_register( 'init()', function () {\n\t\tvar ctx = this.context;\n\t\treturn ctx.length ? ctx[0].oInit : null;\n\t} );\n\t\n\t\n\t_api_register( 'data()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\treturn _pluck( settings.aoData, '_aData' );\n\t\t} ).flatten();\n\t} );\n\t\n\t\n\t_api_register( 'destroy()', function ( remove ) {\n\t\tremove = remove || false;\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tvar orig = settings.nTableWrapper.parentNode;\n\t\t\tvar classes = settings.oClasses;\n\t\t\tvar table = settings.nTable;\n\t\t\tvar tbody = settings.nTBody;\n\t\t\tvar thead = settings.nTHead;\n\t\t\tvar tfoot = settings.nTFoot;\n\t\t\tvar jqTable = $(table);\n\t\t\tvar jqTbody = $(tbody);\n\t\t\tvar jqWrapper = $(settings.nTableWrapper);\n\t\t\tvar rows = $.map( settings.aoData, function (r) { return r.nTr; } );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Flag to note that the table is currently being destroyed - no action\n\t\t\t// should be taken\n\t\t\tsettings.bDestroying = true;\n\t\n\t\t\t// Fire off the destroy callbacks for plug-ins etc\n\t\t\t_fnCallbackFire( settings, \"aoDestroyCallback\", \"destroy\", [settings] );\n\t\n\t\t\t// If not being removed from the document, make all columns visible\n\t\t\tif ( ! remove ) {\n\t\t\t\tnew _Api( settings ).columns().visible( true );\n\t\t\t}\n\t\n\t\t\t// Blitz all `DT` namespaced events (these are internal events, the\n\t\t\t// lowercase, `dt` events are user subscribed and they are responsible\n\t\t\t// for removing them\n\t\t\tjqWrapper.off('.DT').find(':not(tbody *)').off('.DT');\n\t\t\t$(window).off('.DT-'+settings.sInstance);\n\t\n\t\t\t// When scrolling we had to break the table up - restore it\n\t\t\tif ( table != thead.parentNode ) {\n\t\t\t\tjqTable.children('thead').detach();\n\t\t\t\tjqTable.append( thead );\n\t\t\t}\n\t\n\t\t\tif ( tfoot && table != tfoot.parentNode ) {\n\t\t\t\tjqTable.children('tfoot').detach();\n\t\t\t\tjqTable.append( tfoot );\n\t\t\t}\n\t\n\t\t\tsettings.aaSorting = [];\n\t\t\tsettings.aaSortingFixed = [];\n\t\t\t_fnSortingClasses( settings );\n\t\n\t\t\t$( rows ).removeClass( settings.asStripeClasses.join(' ') );\n\t\n\t\t\t$('th, td', thead).removeClass( classes.sSortable+' '+\n\t\t\t\tclasses.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone\n\t\t\t);\n\t\n\t\t\t// Add the TR elements back into the table in their original order\n\t\t\tjqTbody.children().detach();\n\t\t\tjqTbody.append( rows );\n\t\n\t\t\t// Remove the DataTables generated nodes, events and classes\n\t\t\tvar removedMethod = remove ? 'remove' : 'detach';\n\t\t\tjqTable[ removedMethod ]();\n\t\t\tjqWrapper[ removedMethod ]();\n\t\n\t\t\t// If we need to reattach the table to the document\n\t\t\tif ( ! remove && orig ) {\n\t\t\t\t// insertBefore acts like appendChild if !arg[1]\n\t\t\t\torig.insertBefore( table, settings.nTableReinsertBefore );\n\t\n\t\t\t\t// Restore the width of the original table - was read from the style property,\n\t\t\t\t// so we can restore directly to that\n\t\t\t\tjqTable\n\t\t\t\t\t.css( 'width', settings.sDestroyWidth )\n\t\t\t\t\t.removeClass( classes.sTable );\n\t\n\t\t\t\t// If the were originally stripe classes - then we add them back here.\n\t\t\t\t// Note this is not fool proof (for example if not all rows had stripe\n\t\t\t\t// classes - but it's a good effort without getting carried away\n\t\t\t\tien = settings.asDestroyStripes.length;\n\t\n\t\t\t\tif ( ien ) {\n\t\t\t\t\tjqTbody.children().each( function (i) {\n\t\t\t\t\t\t$(this).addClass( settings.asDestroyStripes[i % ien] );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Remove the settings object from the settings array */\n\t\t\tvar idx = $.inArray( settings, DataTable.settings );\n\t\t\tif ( idx !== -1 ) {\n\t\t\t\tDataTable.settings.splice( idx, 1 );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t// Add the `every()` method for rows, columns and cells in a compact form\n\t$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {\n\t\t_api_register( type+'s().every()', function ( fn ) {\n\t\t\tvar opts = this.selector.opts;\n\t\t\tvar api = this;\n\t\n\t\t\treturn this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {\n\t\t\t\t// Rows and columns:\n\t\t\t\t// arg1 - index\n\t\t\t\t// arg2 - table counter\n\t\t\t\t// arg3 - loop counter\n\t\t\t\t// arg4 - undefined\n\t\t\t\t// Cells:\n\t\t\t\t// arg1 - row index\n\t\t\t\t// arg2 - column index\n\t\t\t\t// arg3 - table counter\n\t\t\t\t// arg4 - loop counter\n\t\t\t\tfn.call(\n\t\t\t\t\tapi[ type ](\n\t\t\t\t\t\targ1,\n\t\t\t\t\t\ttype==='cell' ? arg2 : opts,\n\t\t\t\t\t\ttype==='cell' ? opts : undefined\n\t\t\t\t\t),\n\t\t\t\t\targ1, arg2, arg3, arg4\n\t\t\t\t);\n\t\t\t} );\n\t\t} );\n\t} );\n\t\n\t\n\t// i18n method for extensions to be able to use the language object from the\n\t// DataTable\n\t_api_register( 'i18n()', function ( token, def, plural ) {\n\t\tvar ctx = this.context[0];\n\t\tvar resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );\n\t\n\t\tif ( resolved === undefined ) {\n\t\t\tresolved = def;\n\t\t}\n\t\n\t\tif ( plural !== undefined && $.isPlainObject( resolved ) ) {\n\t\t\tresolved = resolved[ plural ] !== undefined ?\n\t\t\t\tresolved[ plural ] :\n\t\t\t\tresolved._;\n\t\t}\n\t\n\t\treturn resolved.replace( '%d', plural ); // nb: plural might be undefined,\n\t} );\n\t/**\n\t * Version string for plug-ins to check compatibility. Allowed format is\n\t * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used\n\t * only for non-release builds. See http://semver.org/ for more information.\n\t * @member\n\t * @type string\n\t * @default Version number\n\t */\n\tDataTable.version = \"1.11.3\";\n\n\t/**\n\t * Private data store, containing all of the settings objects that are\n\t * created for the tables on a given page.\n\t *\n\t * Note that the `DataTable.settings` object is aliased to\n\t * `jQuery.fn.dataTableExt` through which it may be accessed and\n\t * manipulated, or `jQuery.fn.dataTable.settings`.\n\t * @member\n\t * @type array\n\t * @default []\n\t * @private\n\t */\n\tDataTable.settings = [];\n\n\t/**\n\t * Object models container, for the various models that DataTables has\n\t * available to it. These models define the objects that are used to hold\n\t * the active state and configuration of the table.\n\t * @namespace\n\t */\n\tDataTable.models = {};\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * search information for the global filter and individual column filters.\n\t * @namespace\n\t */\n\tDataTable.models.oSearch = {\n\t\t/**\n\t\t * Flag to indicate if the filtering should be case insensitive or not\n\t\t * @type boolean\n\t\t * @default true\n\t\t */\n\t\t\"bCaseInsensitive\": true,\n\t\n\t\t/**\n\t\t * Applied search term\n\t\t * @type string\n\t\t * @default <i>Empty string</i>\n\t\t */\n\t\t\"sSearch\": \"\",\n\t\n\t\t/**\n\t\t * Flag to indicate if the search term should be interpreted as a\n\t\t * regular expression (true) or not (false) and therefore and special\n\t\t * regex characters escaped.\n\t\t * @type boolean\n\t\t * @default false\n\t\t */\n\t\t\"bRegex\": false,\n\t\n\t\t/**\n\t\t * Flag to indicate if DataTables is to use its smart filtering or not.\n\t\t * @type boolean\n\t\t * @default true\n\t\t */\n\t\t\"bSmart\": true,\n\t\n\t\t/**\n\t\t * Flag to indicate if DataTables should only trigger a search when\n\t\t * the return key is pressed.\n\t\t * @type boolean\n\t\t * @default false\n\t\t */\n\t\t\"return\": false\n\t};\n\t\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * each individual row. This is the object format used for the settings\n\t * aoData array.\n\t * @namespace\n\t */\n\tDataTable.models.oRow = {\n\t\t/**\n\t\t * TR element for the row\n\t\t * @type node\n\t\t * @default null\n\t\t */\n\t\t\"nTr\": null,\n\t\n\t\t/**\n\t\t * Array of TD elements for each row. This is null until the row has been\n\t\t * created.\n\t\t * @type array nodes\n\t\t * @default []\n\t\t */\n\t\t\"anCells\": null,\n\t\n\t\t/**\n\t\t * Data object from the original data source for the row. This is either\n\t\t * an array if using the traditional form of DataTables, or an object if\n\t\t * using mData options. The exact type will depend on the passed in\n\t\t * data from the data source, or will be an array if using DOM a data\n\t\t * source.\n\t\t * @type array|object\n\t\t * @default []\n\t\t */\n\t\t\"_aData\": [],\n\t\n\t\t/**\n\t\t * Sorting data cache - this array is ostensibly the same length as the\n\t\t * number of columns (although each index is generated only as it is\n\t\t * needed), and holds the data that is used for sorting each column in the\n\t\t * row. We do this cache generation at the start of the sort in order that\n\t\t * the formatting of the sort data need be done only once for each cell\n\t\t * per sort. This array should not be read from or written to by anything\n\t\t * other than the master sorting methods.\n\t\t * @type array\n\t\t * @default null\n\t\t * @private\n\t\t */\n\t\t\"_aSortData\": null,\n\t\n\t\t/**\n\t\t * Per cell filtering data cache. As per the sort data cache, used to\n\t\t * increase the performance of the filtering in DataTables\n\t\t * @type array\n\t\t * @default null\n\t\t * @private\n\t\t */\n\t\t\"_aFilterData\": null,\n\t\n\t\t/**\n\t\t * Filtering data cache. This is the same as the cell filtering cache, but\n\t\t * in this case a string rather than an array. This is easily computed with\n\t\t * a join on `_aFilterData`, but is provided as a cache so the join isn't\n\t\t * needed on every search (memory traded for performance)\n\t\t * @type array\n\t\t * @default null\n\t\t * @private\n\t\t */\n\t\t\"_sFilterRow\": null,\n\t\n\t\t/**\n\t\t * Cache of the class name that DataTables has applied to the row, so we\n\t\t * can quickly look at this variable rather than needing to do a DOM check\n\t\t * on className for the nTr property.\n\t\t * @type string\n\t\t * @default <i>Empty string</i>\n\t\t * @private\n\t\t */\n\t\t\"_sRowStripe\": \"\",\n\t\n\t\t/**\n\t\t * Denote if the original data source was from the DOM, or the data source\n\t\t * object. This is used for invalidating data, so DataTables can\n\t\t * automatically read data from the original source, unless uninstructed\n\t\t * otherwise.\n\t\t * @type string\n\t\t * @default null\n\t\t * @private\n\t\t */\n\t\t\"src\": null,\n\t\n\t\t/**\n\t\t * Index in the aoData array. This saves an indexOf lookup when we have the\n\t\t * object, but want to know the index\n\t\t * @type integer\n\t\t * @default -1\n\t\t * @private\n\t\t */\n\t\t\"idx\": -1\n\t};\n\t\n\t\n\t/**\n\t * Template object for the column information object in DataTables. This object\n\t * is held in the settings aoColumns array and contains all the information that\n\t * DataTables needs about each individual column.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults.column}\n\t * but this one is the internal data store for DataTables's cache of columns.\n\t * It should NOT be manipulated outside of DataTables. Any configuration should\n\t * be done through the initialisation options.\n\t * @namespace\n\t */\n\tDataTable.models.oColumn = {\n\t\t/**\n\t\t * Column index. This could be worked out on-the-fly with $.inArray, but it\n\t\t * is faster to just hold it as a variable\n\t\t * @type integer\n\t\t * @default null\n\t\t */\n\t\t\"idx\": null,\n\t\n\t\t/**\n\t\t * A list of the columns that sorting should occur on when this column\n\t\t * is sorted. That this property is an array allows multi-column sorting\n\t\t * to be defined for a column (for example first name / last name columns\n\t\t * would benefit from this). The values are integers pointing to the\n\t\t * columns to be sorted on (typically it will be a single integer pointing\n\t\t * at itself, but that doesn't need to be the case).\n\t\t * @type array\n\t\t */\n\t\t\"aDataSort\": null,\n\t\n\t\t/**\n\t\t * Define the sorting directions that are applied to the column, in sequence\n\t\t * as the column is repeatedly sorted upon - i.e. the first value is used\n\t\t * as the sorting direction when the column if first sorted (clicked on).\n\t\t * Sort it again (click again) and it will move on to the next index.\n\t\t * Repeat until loop.\n\t\t * @type array\n\t\t */\n\t\t\"asSorting\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is searchable, and thus should be included\n\t\t * in the filtering or not.\n\t\t * @type boolean\n\t\t */\n\t\t\"bSearchable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is sortable or not.\n\t\t * @type boolean\n\t\t */\n\t\t\"bSortable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is currently visible in the table or not\n\t\t * @type boolean\n\t\t */\n\t\t\"bVisible\": null,\n\t\n\t\t/**\n\t\t * Store for manual type assignment using the `column.type` option. This\n\t\t * is held in store so we can manipulate the column's `sType` property.\n\t\t * @type string\n\t\t * @default null\n\t\t * @private\n\t\t */\n\t\t\"_sManualType\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if HTML5 data attributes should be used as the data\n\t\t * source for filtering or sorting. True is either are.\n\t\t * @type boolean\n\t\t * @default false\n\t\t * @private\n\t\t */\n\t\t\"_bAttrSrc\": false,\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t * @type function\n\t\t * @param {element} nTd The TD node that has been created\n\t\t * @param {*} sData The Data for the cell\n\t\t * @param {array|object} oData The data for the whole row\n\t\t * @param {int} iRow The row index for the aoData data store\n\t\t * @default null\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\t/**\n\t\t * Function to get data from a cell in a column. You should <b>never</b>\n\t\t * access data directly through _aData internally in DataTables - always use\n\t\t * the method attached to this property. It allows mData to function as\n\t\t * required. This function is automatically assigned by the column\n\t\t * initialisation method\n\t\t * @type function\n\t\t * @param {array|object} oData The data array/object for the array\n\t\t * (i.e. aoData[]._aData)\n\t\t * @param {string} sSpecific The specific data type you want to get -\n\t\t * 'display', 'type' 'filter' 'sort'\n\t\t * @returns {*} The data for the cell from the given row's data\n\t\t * @default null\n\t\t */\n\t\t\"fnGetData\": null,\n\t\n\t\t/**\n\t\t * Function to set data for a cell in the column. You should <b>never</b>\n\t\t * set the data directly to _aData internally in DataTables - always use\n\t\t * this method. It allows mData to function as required. This function\n\t\t * is automatically assigned by the column initialisation method\n\t\t * @type function\n\t\t * @param {array|object} oData The data array/object for the array\n\t\t * (i.e. aoData[]._aData)\n\t\t * @param {*} sValue Value to set\n\t\t * @default null\n\t\t */\n\t\t\"fnSetData\": null,\n\t\n\t\t/**\n\t\t * Property to read the value for the cells in the column from the data\n\t\t * source array / object. If null, then the default content is used, if a\n\t\t * function is given then the return from the function is used.\n\t\t * @type function|int|string|null\n\t\t * @default null\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\t/**\n\t\t * Partner property to mData which is used (only when defined) to get\n\t\t * the data - i.e. it is basically the same as mData, but without the\n\t\t * 'set' option, and also the data fed to it is the result from mData.\n\t\t * This is the rendering method to match the data method of mData.\n\t\t * @type function|int|string|null\n\t\t * @default null\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\t/**\n\t\t * Unique header TH/TD element for this column - this is what the sorting\n\t\t * listener is attached to (if sorting is enabled.)\n\t\t * @type node\n\t\t * @default null\n\t\t */\n\t\t\"nTh\": null,\n\t\n\t\t/**\n\t\t * Unique footer TH/TD element for this column (if there is one). Not used\n\t\t * in DataTables as such, but can be used for plug-ins to reference the\n\t\t * footer for each column.\n\t\t * @type node\n\t\t * @default null\n\t\t */\n\t\t\"nTf\": null,\n\t\n\t\t/**\n\t\t * The class to apply to all TD elements in the table's TBODY for the column\n\t\t * @type string\n\t\t * @default null\n\t\t */\n\t\t\"sClass\": null,\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t * @type string\n\t\t */\n\t\t\"sContentPadding\": null,\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because mData\n\t\t * is set to null, or because the data source itself is null).\n\t\t * @type string\n\t\t * @default null\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\t/**\n\t\t * Name for the column, allowing reference to the column by name as well as\n\t\t * by index (needs a lookup to work by name).\n\t\t * @type string\n\t\t */\n\t\t\"sName\": null,\n\t\n\t\t/**\n\t\t * Custom sorting data type - defines which of the available plug-ins in\n\t\t * afnSortData the custom sorting will use - if any is defined.\n\t\t * @type string\n\t\t * @default std\n\t\t */\n\t\t\"sSortDataType\": 'std',\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column\n\t\t * @type string\n\t\t * @default null\n\t\t */\n\t\t\"sSortingClass\": null,\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column -\n\t\t * when jQuery UI theming is used.\n\t\t * @type string\n\t\t * @default null\n\t\t */\n\t\t\"sSortingClassJUI\": null,\n\t\n\t\t/**\n\t\t * Title of the column - what is seen in the TH element (nTh).\n\t\t * @type string\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\t/**\n\t\t * Column sorting and filtering type\n\t\t * @type string\n\t\t * @default null\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\t/**\n\t\t * Width of the column\n\t\t * @type string\n\t\t * @default null\n\t\t */\n\t\t\"sWidth\": null,\n\t\n\t\t/**\n\t\t * Width of the column when it was first \"encountered\"\n\t\t * @type string\n\t\t * @default null\n\t\t */\n\t\t\"sWidthOrig\": null\n\t};\n\t\n\t\n\t/*\n\t * Developer note: The properties of the object below are given in Hungarian\n\t * notation, that was used as the interface for DataTables prior to v1.10, however\n\t * from v1.10 onwards the primary interface is camel case. In order to avoid\n\t * breaking backwards compatibility utterly with this change, the Hungarian\n\t * version is still, internally the primary interface, but is is not documented\n\t * - hence the @name tags in each doc comment. This allows a Javascript function\n\t * to create a map from Hungarian notation to camel case (going the other direction\n\t * would require each property to be listed, which would add around 3K to the size\n\t * of DataTables, while this method is about a 0.5K hit).\n\t *\n\t * Ultimately this does pave the way for Hungarian notation to be dropped\n\t * completely, but that is a massive amount of work and will break current\n\t * installs (therefore is on-hold until v2).\n\t */\n\t\n\t/**\n\t * Initialisation options that can be given to DataTables at initialisation\n\t * time.\n\t * @namespace\n\t */\n\tDataTable.defaults = {\n\t\t/**\n\t\t * An array of data to use for the table, passed in at initialisation which\n\t\t * will be used in preference to any data which is already in the DOM. This is\n\t\t * particularly useful for constructing tables purely in Javascript, for\n\t\t * example with a custom Ajax call.\n\t\t * @type array\n\t\t * @default null\n\t\t *\n\t\t * @dtopt Option\n\t\t * @name DataTable.defaults.data\n\t\t *\n\t\t * @example\n\t\t * // Using a 2D array data source\n\t\t * $(document).ready( function () {\n\t\t * $('#example').dataTable( {\n\t\t * \"data\": [\n\t\t * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],\n\t\t * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],\n\t\t * ],\n\t\t * \"columns\": [\n\t\t * { \"title\": \"Engine\" },\n\t\t * { \"title\": \"Browser\" },\n\t\t * { \"title\": \"Platform\" },\n\t\t * { \"title\": \"Version\" },\n\t\t * { \"title\": \"Grade\" }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using an array of objects as a data source (`data`)\n\t\t * $(document).ready( function () {\n\t\t * $('#example').dataTable( {\n\t\t * \"data\": [\n\t\t * {\n\t\t * \"engine\": \"Trident\",\n\t\t * \"browser\": \"Internet Explorer 4.0\",\n\t\t * \"platform\": \"Win 95+\",\n\t\t * \"version\": 4,\n\t\t * \"grade\": \"X\"\n\t\t * },\n\t\t * {\n\t\t * \"engine\": \"Trident\",\n\t\t * \"browser\": \"Internet Explorer 5.0\",\n\t\t * \"platform\": \"Win 95+\",\n\t\t * \"version\": 5,\n\t\t * \"grade\": \"C\"\n\t\t * }\n\t\t * ],\n\t\t * \"columns\": [\n\t\t * { \"title\": \"Engine\", \"data\": \"engine\" },\n\t\t * { \"title\": \"Browser\", \"data\": \"browser\" },\n\t\t * { \"title\": \"Platform\", \"data\": \"platform\" },\n\t\t * { \"title\": \"Version\", \"data\": \"version\" },\n\t\t * { \"title\": \"Grade\", \"data\": \"grade\" }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"aaData\": null,\n\t\n\t\n\t\t/**\n\t\t * If ordering is enabled, then DataTables will perform a first pass sort on\n\t\t * initialisation. You can define which column(s) the sort is performed\n\t\t * upon, and the sorting direction, with this variable. The `sorting` array\n\t\t * should contain an array for each column to be sorted initially containing\n\t\t * the column's index and a direction string ('asc' or 'desc').\n\t\t * @type array\n\t\t * @default [[0,'asc']]\n\t\t *\n\t\t * @dtopt Option\n\t\t * @name DataTable.defaults.order\n\t\t *\n\t\t * @example\n\t\t * // Sort by 3rd column first, and then 4th column\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"order\": [[2,'asc'], [3,'desc']]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * // No initial sorting\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"order\": []\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"aaSorting\": [[0,'asc']],\n\t\n\t\n\t\t/**\n\t\t * This parameter is basically identical to the `sorting` parameter, but\n\t\t * cannot be overridden by user interaction with the table. What this means\n\t\t * is that you could have a column (visible or hidden) which the sorting\n\t\t * will always be forced on first - any sorting after that (from the user)\n\t\t * will then be performed as required. This can be useful for grouping rows\n\t\t * together.\n\t\t * @type array\n\t\t * @default null\n\t\t *\n\t\t * @dtopt Option\n\t\t * @name DataTable.defaults.orderFixed\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"orderFixed\": [[0,'asc']]\n\t\t * } );\n\t\t * } )\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\n\t\t/**\n\t\t * DataTables can be instructed to load data to display in the table from a\n\t\t * Ajax source. This option defines how that Ajax call is made and where to.\n\t\t *\n\t\t * The `ajax` property has three different modes of operation, depending on\n\t\t * how it is defined. These are:\n\t\t *\n\t\t * * `string` - Set the URL from where the data should be loaded from.\n\t\t * * `object` - Define properties for `jQuery.ajax`.\n\t\t * * `function` - Custom data get function\n\t\t *\n\t\t * `string`\n\t\t * --------\n\t\t *\n\t\t * As a string, the `ajax` property simply defines the URL from which\n\t\t * DataTables will load data.\n\t\t *\n\t\t * `object`\n\t\t * --------\n\t\t *\n\t\t * As an object, the parameters in the object are passed to\n\t\t * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control\n\t\t * of the Ajax request. DataTables has a number of default parameters which\n\t\t * you can override using this option. Please refer to the jQuery\n\t\t * documentation for a full description of the options available, although\n\t\t * the following parameters provide additional options in DataTables or\n\t\t * require special consideration:\n\t\t *\n\t\t * * `data` - As with jQuery, `data` can be provided as an object, but it\n\t\t * can also be used as a function to manipulate the data DataTables sends\n\t\t * to the server. The function takes a single parameter, an object of\n\t\t * parameters with the values that DataTables has readied for sending. An\n\t\t * object may be returned which will be merged into the DataTables\n\t\t * defaults, or you can add the items to the object that was passed in and\n\t\t * not return anything from the function. This supersedes `fnServerParams`\n\t\t * from DataTables 1.9-.\n\t\t *\n\t\t * * `dataSrc` - By default DataTables will look for the property `data` (or\n\t\t * `aaData` for compatibility with DataTables 1.9-) when obtaining data\n\t\t * from an Ajax source or for server-side processing - this parameter\n\t\t * allows that property to be changed. You can use Javascript dotted\n\t\t * object notation to get a data source for multiple levels of nesting, or\n\t\t * it my be used as a function. As a function it takes a single parameter,\n\t\t * the JSON returned from the server, which can be manipulated as\n\t\t * required, with the returned value being that used by DataTables as the\n\t\t * data source for the table. This supersedes `sAjaxDataProp` from\n\t\t * DataTables 1.9-.\n\t\t *\n\t\t * * `success` - Should not be overridden it is used internally in\n\t\t * DataTables. To manipulate / transform the data returned by the server\n\t\t * use `ajax.dataSrc`, or use `ajax` as a function (see below).\n\t\t *\n\t\t * `function`\n\t\t * ----------\n\t\t *\n\t\t * As a function, making the Ajax call is left up to yourself allowing\n\t\t * complete control of the Ajax request. Indeed, if desired, a method other\n\t\t * than Ajax could be used to obtain the required data, such as Web storage\n\t\t * or an AIR database.\n\t\t *\n\t\t * The function is given four parameters and no return is required. The\n\t\t * parameters are:\n\t\t *\n\t\t * 1. _object_ - Data to send to the server\n\t\t * 2. _function_ - Callback function that must be executed when the required\n\t\t * data has been obtained. That data should be passed into the callback\n\t\t * as the only parameter\n\t\t * 3. _object_ - DataTables settings object for the table\n\t\t *\n\t\t * Note that this supersedes `fnServerData` from DataTables 1.9-.\n\t\t *\n\t\t * @type string|object|function\n\t\t * @default null\n\t\t *\n\t\t * @dtopt Option\n\t\t * @name DataTable.defaults.ajax\n\t\t * @since 1.10.0\n\t\t *\n\t\t * @example\n\t\t * // Get JSON data from a file via Ajax.\n\t\t * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).\n\t\t * $('#example').dataTable( {\n\t\t * \"ajax\": \"data.json\"\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Get JSON data from a file via Ajax, using `dataSrc` to change\n\t\t * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)\n\t\t * $('#example').dataTable( {\n\t\t * \"ajax\": {\n\t\t * \"url\": \"data.json\",\n\t\t * \"dataSrc\": \"tableData\"\n\t\t * }\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Get JSON data from a file via Ajax, using `dataSrc` to read data\n\t\t * // from a plain array rather than an array in an object\n\t\t * $('#example').dataTable( {\n\t\t * \"ajax\": {\n\t\t * \"url\": \"data.json\",\n\t\t * \"dataSrc\": \"\"\n\t\t * }\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Manipulate the data returned from the server - add a link to data\n\t\t * // (note this can, should, be done using `render` for the column - this\n\t\t * // is just a simple example of how the data can be manipulated).\n\t\t * $('#example').dataTable( {\n\t\t * \"ajax\": {\n\t\t * \"url\": \"data.json\",\n\t\t * \"dataSrc\": function ( json ) {\n\t\t * for ( var i=0, ien=json.length ; i<ien ; i++ ) {\n\t\t * json[i][0] = '<a href=\"/message/'+json[i][0]+'>View message</a>';\n\t\t * }\n\t\t * return json;\n\t\t * }\n\t\t * }\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Add data to the request\n\t\t * $('#example').dataTable( {\n\t\t * \"ajax\": {\n\t\t * \"url\": \"data.json\",\n\t\t * \"data\": function ( d ) {\n\t\t * return {\n\t\t * \"extra_search\": $('#extra').val()\n\t\t * };\n\t\t * }\n\t\t * }\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Send request as POST\n\t\t * $('#example').dataTable( {\n\t\t * \"ajax\": {\n\t\t * \"url\": \"data.json\",\n\t\t * \"type\": \"POST\"\n\t\t * }\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Get the data from localStorage (could interface with a form for\n\t\t * // adding, editing and removing rows).\n\t\t * $('#example').dataTable( {\n\t\t * \"ajax\": function (data, callback, settings) {\n\t\t * callback(\n\t\t * JSON.parse( localStorage.getItem('dataTablesData') )\n\t\t * );\n\t\t * }\n\t\t * } );\n\t\t */\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to readily specify the entries in the length drop\n\t\t * down menu that DataTables shows when pagination is enabled. It can be\n\t\t * either a 1D array of options which will be used for both the displayed\n\t\t * option and the value, or a 2D array which will use the array in the first\n\t\t * position as the value, and the array in the second position as the\n\t\t * displayed options (useful for language strings such as 'All').\n\t\t *\n\t\t * Note that the `pageLength` property will be automatically set to the\n\t\t * first value given in this array, unless `pageLength` is also provided.\n\t\t * @type array\n\t\t * @default [ 10, 25, 50, 100 ]\n\t\t *\n\t\t * @dtopt Option\n\t\t * @name DataTable.defaults.lengthMenu\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"lengthMenu\": [[10, 25, 50, -1], [10, 25, 50, \"All\"]]\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"aLengthMenu\": [ 10, 25, 50, 100 ],\n\t\n\t\n\t\t/**\n\t\t * The `columns` option in the initialisation parameter allows you to define\n\t\t * details about the way individual columns behave. For a full list of\n\t\t * column options that can be set, please see\n\t\t * {@link DataTable.defaults.column}. Note that if you use `columns` to\n\t\t * define your columns, you must have an entry in the array for every single\n\t\t * column that you have in your table (these can be null if you don't which\n\t\t * to specify any options).\n\t\t * @member\n\t\t *\n\t\t * @name DataTable.defaults.column\n\t\t */\n\t\t\"aoColumns\": null,\n\t\n\t\t/**\n\t\t * Very similar to `columns`, `columnDefs` allows you to target a specific\n\t\t * column, multiple columns, or all columns, using the `targets` property of\n\t\t * each object in the array. This allows great flexibility when creating\n\t\t * tables, as the `columnDefs` arrays can be of any length, targeting the\n\t\t * columns you specifically want. `columnDefs` may use any of the column\n\t\t * options available: {@link DataTable.defaults.column}, but it _must_\n\t\t * have `targets` defined in each object in the array. Values in the `targets`\n\t\t * array may be:\n\t\t * <ul>\n\t\t * <li>a string - class name will be matched on the TH for the column</li>\n\t\t * <li>0 or a positive integer - column index counting from the left</li>\n\t\t * <li>a negative integer - column index counting from the right</li>\n\t\t * <li>the string \"_all\" - all columns (i.e. assign a default)</li>\n\t\t * </ul>\n\t\t * @member\n\t\t *\n\t\t * @name DataTable.defaults.columnDefs\n\t\t */\n\t\t\"aoColumnDefs\": null,\n\t\n\t\n\t\t/**\n\t\t * Basically the same as `search`, this parameter defines the individual column\n\t\t * filtering state at initialisation time. The array must be of the same size\n\t\t * as the number of columns, and each element be an object with the parameters\n\t\t * `search` and `escapeRegex` (the latter is optional). 'null' is also\n\t\t * accepted and the default will be used.\n\t\t * @type array\n\t\t * @default []\n\t\t *\n\t\t * @dtopt Option\n\t\t * @name DataTable.defaults.searchCols\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"searchCols\": [\n\t\t * null,\n\t\t * { \"search\": \"My filter\" },\n\t\t * null,\n\t\t * { \"search\": \"^[0-9]\", \"escapeRegex\": false }\n\t\t * ]\n\t\t * } );\n\t\t * } )\n\t\t */\n\t\t\"aoSearchCols\": [],\n\t\n\t\n\t\t/**\n\t\t * An array of CSS classes that should be applied to displayed rows. This\n\t\t * array may be of any length, and DataTables will apply each class\n\t\t * sequentially, looping when required.\n\t\t * @type array\n\t\t * @default null <i>Will take the values determined by the `oClasses.stripe*`\n\t\t * options</i>\n\t\t *\n\t\t * @dtopt Option\n\t\t * @name DataTable.defaults.stripeClasses\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"stripeClasses\": [ 'strip1', 'strip2', 'strip3' ]\n\t\t * } );\n\t\t * } )\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable automatic column width calculation. This can be disabled\n\t\t * as an optimisation (it takes some time to calculate the widths) if the\n\t\t * tables widths are passed in using `columns`.\n\t\t * @type boolean\n\t\t * @default true\n\t\t *\n\t\t * @dtopt Features\n\t\t * @name DataTable.defaults.autoWidth\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function () {\n\t\t * $('#example').dataTable( {\n\t\t * \"autoWidth\": false\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"bAutoWidth\": true,\n\t\n\t\n\t\t/**\n\t\t * Deferred rendering can provide DataTables with a huge speed boost when you\n\t\t * are using an Ajax or JS data source for the table. This option, when set to\n\t\t * true, will cause DataTables to defer the creation of the table elements for\n\t\t * each row until they are needed for a draw - saving a significant amount of\n\t\t * time.\n\t\t * @type boolean\n\t\t * @default false\n\t\t *\n\t\t * @dtopt Features\n\t\t * @name DataTable.defaults.deferRender\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"ajax\": \"sources/arrays.txt\",\n\t\t * \"deferRender\": true\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"bDeferRender\": false,\n\t\n\t\n\t\t/**\n\t\t * Replace a DataTable which matches the given selector and replace it with\n\t\t * one which has the properties of the new initialisation object passed. If no\n\t\t * table matches the selector, then the new DataTable will be constructed as\n\t\t * per normal.\n\t\t * @type boolean\n\t\t * @default false\n\t\t *\n\t\t * @dtopt Options\n\t\t * @name DataTable.defaults.destroy\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"srollY\": \"200px\",\n\t\t * \"paginate\": false\n\t\t * } );\n\t\t *\n\t\t * // Some time later....\n\t\t * $('#example').dataTable( {\n\t\t * \"filter\": false,\n\t\t * \"destroy\": true\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"bDestroy\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering of data. Filtering in DataTables is \"smart\" in\n\t\t * that it allows the end user to input multiple words (space separated) and\n\t\t * will match a row containing those words, even if not in the order that was\n\t\t * specified (this allow matching across multiple columns). Note that if you\n\t\t * wish to use filtering in DataTables this must remain 'true' - to remove the\n\t\t * default filtering input box and retain filtering abilities, please use\n\t\t * {@link DataTable.defaults.dom}.\n\t\t * @type boolean\n\t\t * @default true\n\t\t *\n\t\t * @dtopt Features\n\t\t * @name DataTable.defaults.searching\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function () {\n\t\t * $('#example').dataTable( {\n\t\t * \"searching\": false\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"bFilter\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the table information display. This shows information\n\t\t * about the data that is currently visible on the page, including information\n\t\t * about filtered data if that action is being performed.\n\t\t * @type boolean\n\t\t * @default true\n\t\t *\n\t\t * @dtopt Features\n\t\t * @name DataTable.defaults.info\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function () {\n\t\t * $('#example').dataTable( {\n\t\t * \"info\": false\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"bInfo\": true,\n\t\n\t\n\t\t/**\n\t\t * Allows the end user to select the size of a formatted page from a select\n\t\t * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).\n\t\t * @type boolean\n\t\t * @default true\n\t\t *\n\t\t * @dtopt Features\n\t\t * @name DataTable.defaults.lengthChange\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function () {\n\t\t * $('#example').dataTable( {\n\t\t * \"lengthChange\": false\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"bLengthChange\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable pagination.\n\t\t * @type boolean\n\t\t * @default true\n\t\t *\n\t\t * @dtopt Features\n\t\t * @name DataTable.defaults.paging\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function () {\n\t\t * $('#example').dataTable( {\n\t\t * \"paging\": false\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"bPaginate\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of a 'processing' indicator when the table is\n\t\t * being processed (e.g. a sort). This is particularly useful for tables with\n\t\t * large amounts of data where it can take a noticeable amount of time to sort\n\t\t * the entries.\n\t\t * @type boolean\n\t\t * @default false\n\t\t *\n\t\t * @dtopt Features\n\t\t * @name DataTable.defaults.processing\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function () {\n\t\t * $('#example').dataTable( {\n\t\t * \"processing\": true\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"bProcessing\": false,\n\t\n\t\n\t\t/**\n\t\t * Retrieve the DataTables object for the given selector. Note that if the\n\t\t * table has already been initialised, this parameter will cause DataTables\n\t\t * to simply return the object that has already been set up - it will not take\n\t\t * account of any changes you might have made to the initialisation object\n\t\t * passed to DataTables (setting this parameter to true is an acknowledgement\n\t\t * that you understand this). `destroy` can be used to reinitialise a table if\n\t\t * you need.\n\t\t * @type boolean\n\t\t * @default false\n\t\t *\n\t\t * @dtopt Options\n\t\t * @name DataTable.defaults.retrieve\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * initTable();\n\t\t * tableActions();\n\t\t * } );\n\t\t *\n\t\t * function initTable ()\n\t\t * {\n\t\t * return $('#example').dataTable( {\n\t\t * \"scrollY\": \"200px\",\n\t\t * \"paginate\": false,\n\t\t * \"retrieve\": true\n\t\t * } );\n\t\t * }\n\t\t *\n\t\t * function tableActions ()\n\t\t * {\n\t\t * var table = initTable();\n\t\t * // perform API operations with oTable\n\t\t * }\n\t\t */\n\t\t\"bRetrieve\": false,\n\t\n\t\n\t\t/**\n\t\t * When vertical (y) scrolling is enabled, DataTables will force the height of\n\t\t * the table's viewport to the given height at all times (useful for layout).\n\t\t * However, this can look odd when filtering data down to a small data set,\n\t\t * and the footer is left \"floating\" further down. This parameter (when\n\t\t * enabled) will cause DataTables to collapse the table's viewport down when\n\t\t * the result set will fit within the given Y height.\n\t\t * @type boolean\n\t\t * @default false\n\t\t *\n\t\t * @dtopt Options\n\t\t * @name DataTable.defaults.scrollCollapse\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"scrollY\": \"200\",\n\t\t * \"scrollCollapse\": true\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"bScrollCollapse\": false,\n\t\n\t\n\t\t/**\n\t\t * Configure DataTables to use server-side processing. Note that the\n\t\t * `ajax` parameter must also be given in order to give DataTables a\n\t\t * source to obtain the required data for each draw.\n\t\t * @type boolean\n\t\t * @default false\n\t\t *\n\t\t * @dtopt Features\n\t\t * @dtopt Server-side\n\t\t * @name DataTable.defaults.serverSide\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function () {\n\t\t * $('#example').dataTable( {\n\t\t * \"serverSide\": true,\n\t\t * \"ajax\": \"xhr.php\"\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"bServerSide\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable sorting of columns. Sorting of individual columns can be\n\t\t * disabled by the `sortable` option for each column.\n\t\t * @type boolean\n\t\t * @default true\n\t\t *\n\t\t * @dtopt Features\n\t\t * @name DataTable.defaults.ordering\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function () {\n\t\t * $('#example').dataTable( {\n\t\t * \"ordering\": false\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"bSort\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or display DataTables' ability to sort multiple columns at the\n\t\t * same time (activated by shift-click by the user).\n\t\t * @type boolean\n\t\t * @default true\n\t\t *\n\t\t * @dtopt Options\n\t\t * @name DataTable.defaults.orderMulti\n\t\t *\n\t\t * @example\n\t\t * // Disable multiple column sorting ability\n\t\t * $(document).ready( function () {\n\t\t * $('#example').dataTable( {\n\t\t * \"orderMulti\": false\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"bSortMulti\": true,\n\t\n\t\n\t\t/**\n\t\t * Allows control over whether DataTables should use the top (true) unique\n\t\t * cell that is found for a single column, or the bottom (false - default).\n\t\t * This is useful when using complex headers.\n\t\t * @type boolean\n\t\t * @default false\n\t\t *\n\t\t * @dtopt Options\n\t\t * @name DataTable.defaults.orderCellsTop\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"orderCellsTop\": true\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"bSortCellsTop\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the addition of the classes `sorting\\_1`, `sorting\\_2` and\n\t\t * `sorting\\_3` to the columns which are currently being sorted on. This is\n\t\t * presented as a feature switch as it can increase processing time (while\n\t\t * classes are removed and added) so for large data sets you might want to\n\t\t * turn this off.\n\t\t * @type boolean\n\t\t * @default true\n\t\t *\n\t\t * @dtopt Features\n\t\t * @name DataTable.defaults.orderClasses\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function () {\n\t\t * $('#example').dataTable( {\n\t\t * \"orderClasses\": false\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"bSortClasses\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable state saving. When enabled HTML5 `localStorage` will be\n\t\t * used to save table display information such as pagination information,\n\t\t * display length, filtering and sorting. As such when the end user reloads\n\t\t * the page the display display will match what thy had previously set up.\n\t\t *\n\t\t * Due to the use of `localStorage` the default state saving is not supported\n\t\t * in IE6 or 7. If state saving is required in those browsers, use\n\t\t * `stateSaveCallback` to provide a storage solution such as cookies.\n\t\t * @type boolean\n\t\t * @default false\n\t\t *\n\t\t * @dtopt Features\n\t\t * @name DataTable.defaults.stateSave\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function () {\n\t\t * $('#example').dataTable( {\n\t\t * \"stateSave\": true\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"bStateSave\": false,\n\t\n\t\n\t\t/**\n\t\t * This function is called when a TR element is created (and all TD child\n\t\t * elements have been inserted), or registered if using a DOM source, allowing\n\t\t * manipulation of the TR element (adding classes etc).\n\t\t * @type function\n\t\t * @param {node} row \"TR\" element for the current row\n\t\t * @param {array} data Raw data array for this row\n\t\t * @param {int} dataIndex The index of this row in the internal aoData array\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @name DataTable.defaults.createdRow\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"createdRow\": function( row, data, dataIndex ) {\n\t\t * // Bold the grade for all 'A' grade browsers\n\t\t * if ( data[4] == \"A\" )\n\t\t * {\n\t\t * $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t * }\n\t\t * }\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"fnCreatedRow\": null,\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify any aspect you want about the created DOM.\n\t\t * @type function\n\t\t * @param {object} settings DataTables settings object\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @name DataTable.defaults.drawCallback\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"drawCallback\": function( settings ) {\n\t\t * alert( 'DataTables has redrawn the table' );\n\t\t * }\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"fnDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Identical to fnHeaderCallback() but for the table footer this function\n\t\t * allows you to modify the table footer on every 'draw' event.\n\t\t * @type function\n\t\t * @param {node} foot \"TR\" element for the footer\n\t\t * @param {array} data Full table data (as derived from the original HTML)\n\t\t * @param {int} start Index for the current display starting point in the\n\t\t * display array\n\t\t * @param {int} end Index for the current display ending point in the\n\t\t * display array\n\t\t * @param {array int} display Index array to translate the visual position\n\t\t * to the full data array\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @name DataTable.defaults.footerCallback\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"footerCallback\": function( tfoot, data, start, end, display ) {\n\t\t * tfoot.getElementsByTagName('th')[0].innerHTML = \"Starting index is \"+start;\n\t\t * }\n\t\t * } );\n\t\t * } )\n\t\t */\n\t\t\"fnFooterCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * When rendering large numbers in the information element for the table\n\t\t * (i.e. \"Showing 1 to 10 of 57 entries\") DataTables will render large numbers\n\t\t * to have a comma separator for the 'thousands' units (e.g. 1 million is\n\t\t * rendered as \"1,000,000\") to help readability for the end user. This\n\t\t * function will override the default method DataTables uses.\n\t\t * @type function\n\t\t * @member\n\t\t * @param {int} toFormat number to be formatted\n\t\t * @returns {string} formatted string for DataTables to show the number\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @name DataTable.defaults.formatNumber\n\t\t *\n\t\t * @example\n\t\t * // Format a number using a single quote for the separator (note that\n\t\t * // this can also be done with the language.thousands option)\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"formatNumber\": function ( toFormat ) {\n\t\t * return toFormat.toString().replace(\n\t\t * /\\B(?=(\\d{3})+(?!\\d))/g, \"'\"\n\t\t * );\n\t\t * };\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"fnFormatNumber\": function ( toFormat ) {\n\t\t\treturn toFormat.toString().replace(\n\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g,\n\t\t\t\tthis.oLanguage.sThousands\n\t\t\t);\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify the header row. This can be used to calculate and\n\t\t * display useful information about the table.\n\t\t * @type function\n\t\t * @param {node} head \"TR\" element for the header\n\t\t * @param {array} data Full table data (as derived from the original HTML)\n\t\t * @param {int} start Index for the current display starting point in the\n\t\t * display array\n\t\t * @param {int} end Index for the current display ending point in the\n\t\t * display array\n\t\t * @param {array int} display Index array to translate the visual position\n\t\t * to the full data array\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @name DataTable.defaults.headerCallback\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"fheaderCallback\": function( head, data, start, end, display ) {\n\t\t * head.getElementsByTagName('th')[0].innerHTML = \"Displaying \"+(end-start)+\" records\";\n\t\t * }\n\t\t * } );\n\t\t * } )\n\t\t */\n\t\t\"fnHeaderCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * The information element can be used to convey information about the current\n\t\t * state of the table. Although the internationalisation options presented by\n\t\t * DataTables are quite capable of dealing with most customisations, there may\n\t\t * be times where you wish to customise the string further. This callback\n\t\t * allows you to do exactly that.\n\t\t * @type function\n\t\t * @param {object} oSettings DataTables settings object\n\t\t * @param {int} start Starting position in data for the draw\n\t\t * @param {int} end End position in data for the draw\n\t\t * @param {int} max Total number of rows in the table (regardless of\n\t\t * filtering)\n\t\t * @param {int} total Total number of rows in the data set, after filtering\n\t\t * @param {string} pre The string that DataTables has formatted using it's\n\t\t * own rules\n\t\t * @returns {string} The string to be displayed in the information element.\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @name DataTable.defaults.infoCallback\n\t\t *\n\t\t * @example\n\t\t * $('#example').dataTable( {\n\t\t * \"infoCallback\": function( settings, start, end, max, total, pre ) {\n\t\t * return start +\" to \"+ end;\n\t\t * }\n\t\t * } );\n\t\t */\n\t\t\"fnInfoCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Called when the table has been initialised. Normally DataTables will\n\t\t * initialise sequentially and there will be no need for this function,\n\t\t * however, this does not hold true when using external language information\n\t\t * since that is obtained using an async XHR call.\n\t\t * @type function\n\t\t * @param {object} settings DataTables settings object\n\t\t * @param {object} json The JSON object request from the server - only\n\t\t * present if client-side Ajax sourced data is used\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @name DataTable.defaults.initComplete\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"initComplete\": function(settings, json) {\n\t\t * alert( 'DataTables has finished its initialisation.' );\n\t\t * }\n\t\t * } );\n\t\t * } )\n\t\t */\n\t\t\"fnInitComplete\": null,\n\t\n\t\n\t\t/**\n\t\t * Called at the very start of each table draw and can be used to cancel the\n\t\t * draw by returning false, any other return (including undefined) results in\n\t\t * the full draw occurring).\n\t\t * @type function\n\t\t * @param {object} settings DataTables settings object\n\t\t * @returns {boolean} False will cancel the draw, anything else (including no\n\t\t * return) will allow it to complete.\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @name DataTable.defaults.preDrawCallback\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"preDrawCallback\": function( settings ) {\n\t\t * if ( $('#test').val() == 1 ) {\n\t\t * return false;\n\t\t * }\n\t\t * }\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"fnPreDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * This function allows you to 'post process' each row after it have been\n\t\t * generated for each table draw, but before it is rendered on screen. This\n\t\t * function might be used for setting the row class name etc.\n\t\t * @type function\n\t\t * @param {node} row \"TR\" element for the current row\n\t\t * @param {array} data Raw data array for this row\n\t\t * @param {int} displayIndex The display index for the current table draw\n\t\t * @param {int} displayIndexFull The index of the data in the full list of\n\t\t * rows (after filtering)\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @name DataTable.defaults.rowCallback\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"rowCallback\": function( row, data, displayIndex, displayIndexFull ) {\n\t\t * // Bold the grade for all 'A' grade browsers\n\t\t * if ( data[4] == \"A\" ) {\n\t\t * $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t * }\n\t\t * }\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"fnRowCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * This parameter allows you to override the default function which obtains\n\t\t * the data from the server so something more suitable for your application.\n\t\t * For example you could use POST data, or pull information from a Gears or\n\t\t * AIR database.\n\t\t * @type function\n\t\t * @member\n\t\t * @param {string} source HTTP source to obtain the data from (`ajax`)\n\t\t * @param {array} data A key/value pair object containing the data to send\n\t\t * to the server\n\t\t * @param {function} callback to be called on completion of the data get\n\t\t * process that will draw the data on the page.\n\t\t * @param {object} settings DataTables settings object\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @dtopt Server-side\n\t\t * @name DataTable.defaults.serverData\n\t\t *\n\t\t * @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * It is often useful to send extra data to the server when making an Ajax\n\t\t * request - for example custom filtering information, and this callback\n\t\t * function makes it trivial to send extra information to the server. The\n\t\t * passed in parameter is the data set that has been constructed by\n\t\t * DataTables, and you can add to this or modify it as you require.\n\t\t * @type function\n\t\t * @param {array} data Data array (array of objects which are name/value\n\t\t * pairs) that has been constructed by DataTables and will be sent to the\n\t\t * server. In the case of Ajax sourced data with server-side processing\n\t\t * this will be an empty array, for server-side processing there will be a\n\t\t * significant number of parameters!\n\t\t * @returns {undefined} Ensure that you modify the data array passed in,\n\t\t * as this is passed by reference.\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @dtopt Server-side\n\t\t * @name DataTable.defaults.serverParams\n\t\t *\n\t\t * @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Load the table state. With this function you can define from where, and how, the\n\t\t * state of a table is loaded. By default DataTables will load from `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t * @type function\n\t\t * @member\n\t\t * @param {object} settings DataTables settings object\n\t\t * @param {object} callback Callback that can be executed when done. It\n\t\t * should be passed the loaded state object.\n\t\t * @return {object} The DataTables state object to be loaded\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @name DataTable.defaults.stateLoadCallback\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"stateSave\": true,\n\t\t * \"stateLoadCallback\": function (settings, callback) {\n\t\t * $.ajax( {\n\t\t * \"url\": \"/state_load\",\n\t\t * \"dataType\": \"json\",\n\t\t * \"success\": function (json) {\n\t\t * callback( json );\n\t\t * }\n\t\t * } );\n\t\t * }\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"fnStateLoadCallback\": function ( settings ) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(\n\t\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(\n\t\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t} catch (e) {\n\t\t\t\treturn {};\n\t\t\t}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the saved state prior to loading that state.\n\t\t * This callback is called when the table is loading state from the stored data, but\n\t\t * prior to the settings object being modified by the saved state. Note that for\n\t\t * plug-in authors, you should use the `stateLoadParams` event to load parameters for\n\t\t * a plug-in.\n\t\t * @type function\n\t\t * @param {object} settings DataTables settings object\n\t\t * @param {object} data The state object that is to be loaded\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @name DataTable.defaults.stateLoadParams\n\t\t *\n\t\t * @example\n\t\t * // Remove a saved filter, so filtering is never loaded\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"stateSave\": true,\n\t\t * \"stateLoadParams\": function (settings, data) {\n\t\t * data.oSearch.sSearch = \"\";\n\t\t * }\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Disallow state loading by returning false\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"stateSave\": true,\n\t\t * \"stateLoadParams\": function (settings, data) {\n\t\t * return false;\n\t\t * }\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"fnStateLoadParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Callback that is called when the state has been loaded from the state saving method\n\t\t * and the DataTables settings object has been modified as a result of the loaded state.\n\t\t * @type function\n\t\t * @param {object} settings DataTables settings object\n\t\t * @param {object} data The state object that was loaded\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @name DataTable.defaults.stateLoaded\n\t\t *\n\t\t * @example\n\t\t * // Show an alert with the filtering value that was saved\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"stateSave\": true,\n\t\t * \"stateLoaded\": function (settings, data) {\n\t\t * alert( 'Saved filter was: '+data.oSearch.sSearch );\n\t\t * }\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"fnStateLoaded\": null,\n\t\n\t\n\t\t/**\n\t\t * Save the table state. This function allows you to define where and how the state\n\t\t * information for the table is stored By default DataTables will use `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t * @type function\n\t\t * @member\n\t\t * @param {object} settings DataTables settings object\n\t\t * @param {object} data The state object to be saved\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @name DataTable.defaults.stateSaveCallback\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"stateSave\": true,\n\t\t * \"stateSaveCallback\": function (settings, data) {\n\t\t * // Send an Ajax request to the server with the state object\n\t\t * $.ajax( {\n\t\t * \"url\": \"/state_save\",\n\t\t * \"data\": data,\n\t\t * \"dataType\": \"json\",\n\t\t * \"method\": \"POST\"\n\t\t * \"success\": function () {}\n\t\t * } );\n\t\t * }\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"fnStateSaveCallback\": function ( settings, data ) {\n\t\t\ttry {\n\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(\n\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname,\n\t\t\t\t\tJSON.stringify( data )\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the state to be saved. Called when the table\n\t\t * has changed state a new state save is required. This method allows modification of\n\t\t * the state saving object prior to actually doing the save, including addition or\n\t\t * other state properties or modification. Note that for plug-in authors, you should\n\t\t * use the `stateSaveParams` event to save parameters for a plug-in.\n\t\t * @type function\n\t\t * @param {object} settings DataTables settings object\n\t\t * @param {object} data The state object to be saved\n\t\t *\n\t\t * @dtopt Callbacks\n\t\t * @name DataTable.defaults.stateSaveParams\n\t\t *\n\t\t * @example\n\t\t * // Remove a saved filter, so filtering is never saved\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"stateSave\": true,\n\t\t * \"stateSaveParams\": function (settings, data) {\n\t\t * data.oSearch.sSearch = \"\";\n\t\t * }\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"fnStateSaveParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Duration for which the saved state information is considered valid. After this period\n\t\t * has elapsed the state will be returned to the default.\n\t\t * Value is given in seconds.\n\t\t * @type int\n\t\t * @default 7200 <i>(2 hours)</i>\n\t\t *\n\t\t * @dtopt Options\n\t\t * @name DataTable.defaults.stateDuration\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"stateDuration\": 60*60*24; // 1 day\n\t\t * } );\n\t\t * } )\n\t\t */\n\t\t\"iStateDuration\": 7200,\n\t\n\t\n\t\t/**\n\t\t * When enabled DataTables will not make a request to the server for the first\n\t\t * page draw - rather it will use the data already on the page (no sorting etc\n\t\t * will be applied to it), thus saving on an XHR at load time. `deferLoading`\n\t\t * is used to indicate that deferred loading is required, but it is also used\n\t\t * to tell DataTables how many records there are in the full table (allowing\n\t\t * the information element and pagination to be displayed correctly). In the case\n\t\t * where a filtering is applied to the table on initial load, this can be\n\t\t * indicated by giving the parameter as an array, where the first element is\n\t\t * the number of records available after filtering and the second element is the\n\t\t * number of records without filtering (allowing the table information element\n\t\t * to be shown correctly).\n\t\t * @type int | array\n\t\t * @default null\n\t\t *\n\t\t * @dtopt Options\n\t\t * @name DataTable.defaults.deferLoading\n\t\t *\n\t\t * @example\n\t\t * // 57 records available in the table, no filtering applied\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"serverSide\": true,\n\t\t * \"ajax\": \"scripts/server_processing.php\",\n\t\t * \"deferLoading\": 57\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // 57 records after filtering, 100 without filtering (an initial filter applied)\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"serverSide\": true,\n\t\t * \"ajax\": \"scripts/server_processing.php\",\n\t\t * \"deferLoading\": [ 57, 100 ],\n\t\t * \"search\": {\n\t\t * \"search\": \"my_filter\"\n\t\t * }\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"iDeferLoading\": null,\n\t\n\t\n\t\t/**\n\t\t * Number of rows to display on a single page when using pagination. If\n\t\t * feature enabled (`lengthChange`) then the end user will be able to override\n\t\t * this to a custom setting using a pop-up menu.\n\t\t * @type int\n\t\t * @default 10\n\t\t *\n\t\t * @dtopt Options\n\t\t * @name DataTable.defaults.pageLength\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"pageLength\": 50\n\t\t * } );\n\t\t * } )\n\t\t */\n\t\t\"iDisplayLength\": 10,\n\t\n\t\n\t\t/**\n\t\t * Define the starting point for data display when using DataTables with\n\t\t * pagination. Note that this parameter is the number of records, rather than\n\t\t * the page number, so if you have 10 records per page and want to start on\n\t\t * the third page, it should be \"20\".\n\t\t * @type int\n\t\t * @default 0\n\t\t *\n\t\t * @dtopt Options\n\t\t * @name DataTable.defaults.displayStart\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"displayStart\": 20\n\t\t * } );\n\t\t * } )\n\t\t */\n\t\t\"iDisplayStart\": 0,\n\t\n\t\n\t\t/**\n\t\t * By default DataTables allows keyboard navigation of the table (sorting, paging,\n\t\t * and filtering) by adding a `tabindex` attribute to the required elements. This\n\t\t * allows you to tab through the controls and press the enter key to activate them.\n\t\t * The tabindex is default 0, meaning that the tab follows the flow of the document.\n\t\t * You can overrule this using this parameter if you wish. Use a value of -1 to\n\t\t * disable built-in keyboard navigation.\n\t\t * @type int\n\t\t * @default 0\n\t\t *\n\t\t * @dtopt Options\n\t\t * @name DataTable.defaults.tabIndex\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"tabIndex\": 1\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\n\t\t/**\n\t\t * Classes that DataTables assigns to the various components and features\n\t\t * that it adds to the HTML table. This allows classes to be configured\n\t\t * during initialisation in addition to through the static\n\t\t * {@link DataTable.ext.oStdClasses} object).\n\t\t * @namespace\n\t\t * @name DataTable.defaults.classes\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\n\t\t/**\n\t\t * All strings that DataTables uses in the user interface that it creates\n\t\t * are defined in this object, allowing you to modified them individually or\n\t\t * completely replace them all as required.\n\t\t * @namespace\n\t\t * @name DataTable.defaults.language\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Strings that are used for WAI-ARIA labels and controls only (these are not\n\t\t\t * actually visible on the page, but will be read by screenreaders, and thus\n\t\t\t * must be internationalised as well).\n\t\t\t * @namespace\n\t\t\t * @name DataTable.defaults.language.aria\n\t\t\t */\n\t\t\t\"oAria\": {\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted ascending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t * @type string\n\t\t\t\t * @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t * @dtopt Language\n\t\t\t\t * @name DataTable.defaults.language.aria.sortAscending\n\t\t\t\t *\n\t\t\t\t * @example\n\t\t\t\t * $(document).ready( function() {\n\t\t\t\t * $('#example').dataTable( {\n\t\t\t\t * \"language\": {\n\t\t\t\t * \"aria\": {\n\t\t\t\t * \"sortAscending\": \" - click/return to sort ascending\"\n\t\t\t\t * }\n\t\t\t\t * }\n\t\t\t\t * } );\n\t\t\t\t * } );\n\t\t\t\t */\n\t\t\t\t\"sSortAscending\": \": activate to sort column ascending\",\n\t\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted descending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t * @type string\n\t\t\t\t * @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t * @dtopt Language\n\t\t\t\t * @name DataTable.defaults.language.aria.sortDescending\n\t\t\t\t *\n\t\t\t\t * @example\n\t\t\t\t * $(document).ready( function() {\n\t\t\t\t * $('#example').dataTable( {\n\t\t\t\t * \"language\": {\n\t\t\t\t * \"aria\": {\n\t\t\t\t * \"sortDescending\": \" - click/return to sort descending\"\n\t\t\t\t * }\n\t\t\t\t * }\n\t\t\t\t * } );\n\t\t\t\t * } );\n\t\t\t\t */\n\t\t\t\t\"sSortDescending\": \": activate to sort column descending\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * Pagination string used by DataTables for the built-in pagination\n\t\t\t * control types.\n\t\t\t * @namespace\n\t\t\t * @name DataTable.defaults.language.paginate\n\t\t\t */\n\t\t\t\"oPaginate\": {\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the first page.\n\t\t\t\t * @type string\n\t\t\t\t * @default First\n\t\t\t\t *\n\t\t\t\t * @dtopt Language\n\t\t\t\t * @name DataTable.defaults.language.paginate.first\n\t\t\t\t *\n\t\t\t\t * @example\n\t\t\t\t * $(document).ready( function() {\n\t\t\t\t * $('#example').dataTable( {\n\t\t\t\t * \"language\": {\n\t\t\t\t * \"paginate\": {\n\t\t\t\t * \"first\": \"First page\"\n\t\t\t\t * }\n\t\t\t\t * }\n\t\t\t\t * } );\n\t\t\t\t * } );\n\t\t\t\t */\n\t\t\t\t\"sFirst\": \"First\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the last page.\n\t\t\t\t * @type string\n\t\t\t\t * @default Last\n\t\t\t\t *\n\t\t\t\t * @dtopt Language\n\t\t\t\t * @name DataTable.defaults.language.paginate.last\n\t\t\t\t *\n\t\t\t\t * @example\n\t\t\t\t * $(document).ready( function() {\n\t\t\t\t * $('#example').dataTable( {\n\t\t\t\t * \"language\": {\n\t\t\t\t * \"paginate\": {\n\t\t\t\t * \"last\": \"Last page\"\n\t\t\t\t * }\n\t\t\t\t * }\n\t\t\t\t * } );\n\t\t\t\t * } );\n\t\t\t\t */\n\t\t\t\t\"sLast\": \"Last\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'next' pagination button (to take the user to the\n\t\t\t\t * next page).\n\t\t\t\t * @type string\n\t\t\t\t * @default Next\n\t\t\t\t *\n\t\t\t\t * @dtopt Language\n\t\t\t\t * @name DataTable.defaults.language.paginate.next\n\t\t\t\t *\n\t\t\t\t * @example\n\t\t\t\t * $(document).ready( function() {\n\t\t\t\t * $('#example').dataTable( {\n\t\t\t\t * \"language\": {\n\t\t\t\t * \"paginate\": {\n\t\t\t\t * \"next\": \"Next page\"\n\t\t\t\t * }\n\t\t\t\t * }\n\t\t\t\t * } );\n\t\t\t\t * } );\n\t\t\t\t */\n\t\t\t\t\"sNext\": \"Next\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'previous' pagination button (to take the user to\n\t\t\t\t * the previous page).\n\t\t\t\t * @type string\n\t\t\t\t * @default Previous\n\t\t\t\t *\n\t\t\t\t * @dtopt Language\n\t\t\t\t * @name DataTable.defaults.language.paginate.previous\n\t\t\t\t *\n\t\t\t\t * @example\n\t\t\t\t * $(document).ready( function() {\n\t\t\t\t * $('#example').dataTable( {\n\t\t\t\t * \"language\": {\n\t\t\t\t * \"paginate\": {\n\t\t\t\t * \"previous\": \"Previous page\"\n\t\t\t\t * }\n\t\t\t\t * }\n\t\t\t\t * } );\n\t\t\t\t * } );\n\t\t\t\t */\n\t\t\t\t\"sPrevious\": \"Previous\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * This string is shown in preference to `zeroRecords` when the table is\n\t\t\t * empty of data (regardless of filtering). Note that this is an optional\n\t\t\t * parameter - if it is not given, the value of `zeroRecords` will be used\n\t\t\t * instead (either the default or given value).\n\t\t\t * @type string\n\t\t\t * @default No data available in table\n\t\t\t *\n\t\t\t * @dtopt Language\n\t\t\t * @name DataTable.defaults.language.emptyTable\n\t\t\t *\n\t\t\t * @example\n\t\t\t * $(document).ready( function() {\n\t\t\t * $('#example').dataTable( {\n\t\t\t * \"language\": {\n\t\t\t * \"emptyTable\": \"No data available in table\"\n\t\t\t * }\n\t\t\t * } );\n\t\t\t * } );\n\t\t\t */\n\t\t\t\"sEmptyTable\": \"No data available in table\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This string gives information to the end user about the information\n\t\t\t * that is current on display on the page. The following tokens can be\n\t\t\t * used in the string and will be dynamically replaced as the table\n\t\t\t * display updates. This tokens can be placed anywhere in the string, or\n\t\t\t * removed as needed by the language requires:\n\t\t\t *\n\t\t\t * * `\\_START\\_` - Display index of the first record on the current page\n\t\t\t * * `\\_END\\_` - Display index of the last record on the current page\n\t\t\t * * `\\_TOTAL\\_` - Number of records in the table after filtering\n\t\t\t * * `\\_MAX\\_` - Number of records in the table without filtering\n\t\t\t * * `\\_PAGE\\_` - Current page number\n\t\t\t * * `\\_PAGES\\_` - Total number of pages of data in the table\n\t\t\t *\n\t\t\t * @type string\n\t\t\t * @default Showing _START_ to _END_ of _TOTAL_ entries\n\t\t\t *\n\t\t\t * @dtopt Language\n\t\t\t * @name DataTable.defaults.language.info\n\t\t\t *\n\t\t\t * @example\n\t\t\t * $(document).ready( function() {\n\t\t\t * $('#example').dataTable( {\n\t\t\t * \"language\": {\n\t\t\t * \"info\": \"Showing page _PAGE_ of _PAGES_\"\n\t\t\t * }\n\t\t\t * } );\n\t\t\t * } );\n\t\t\t */\n\t\t\t\"sInfo\": \"Showing _START_ to _END_ of _TOTAL_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Display information string for when the table is empty. Typically the\n\t\t\t * format of this string should match `info`.\n\t\t\t * @type string\n\t\t\t * @default Showing 0 to 0 of 0 entries\n\t\t\t *\n\t\t\t * @dtopt Language\n\t\t\t * @name DataTable.defaults.language.infoEmpty\n\t\t\t *\n\t\t\t * @example\n\t\t\t * $(document).ready( function() {\n\t\t\t * $('#example').dataTable( {\n\t\t\t * \"language\": {\n\t\t\t * \"infoEmpty\": \"No entries to show\"\n\t\t\t * }\n\t\t\t * } );\n\t\t\t * } );\n\t\t\t */\n\t\t\t\"sInfoEmpty\": \"Showing 0 to 0 of 0 entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When a user filters the information in a table, this string is appended\n\t\t\t * to the information (`info`) to give an idea of how strong the filtering\n\t\t\t * is. The variable _MAX_ is dynamically updated.\n\t\t\t * @type string\n\t\t\t * @default (filtered from _MAX_ total entries)\n\t\t\t *\n\t\t\t * @dtopt Language\n\t\t\t * @name DataTable.defaults.language.infoFiltered\n\t\t\t *\n\t\t\t * @example\n\t\t\t * $(document).ready( function() {\n\t\t\t * $('#example').dataTable( {\n\t\t\t * \"language\": {\n\t\t\t * \"infoFiltered\": \" - filtering from _MAX_ records\"\n\t\t\t * }\n\t\t\t * } );\n\t\t\t * } );\n\t\t\t */\n\t\t\t\"sInfoFiltered\": \"(filtered from _MAX_ total entries)\",\n\t\n\t\n\t\t\t/**\n\t\t\t * If can be useful to append extra information to the info string at times,\n\t\t\t * and this variable does exactly that. This information will be appended to\n\t\t\t * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are\n\t\t\t * being used) at all times.\n\t\t\t * @type string\n\t\t\t * @default <i>Empty string</i>\n\t\t\t *\n\t\t\t * @dtopt Language\n\t\t\t * @name DataTable.defaults.language.infoPostFix\n\t\t\t *\n\t\t\t * @example\n\t\t\t * $(document).ready( function() {\n\t\t\t * $('#example').dataTable( {\n\t\t\t * \"language\": {\n\t\t\t * \"infoPostFix\": \"All records shown are derived from real information.\"\n\t\t\t * }\n\t\t\t * } );\n\t\t\t * } );\n\t\t\t */\n\t\t\t\"sInfoPostFix\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This decimal place operator is a little different from the other\n\t\t\t * language options since DataTables doesn't output floating point\n\t\t\t * numbers, so it won't ever use this for display of a number. Rather,\n\t\t\t * what this parameter does is modify the sort methods of the table so\n\t\t\t * that numbers which are in a format which has a character other than\n\t\t\t * a period (`.`) as a decimal place will be sorted numerically.\n\t\t\t *\n\t\t\t * Note that numbers with different decimal places cannot be shown in\n\t\t\t * the same table and still be sortable, the table must be consistent.\n\t\t\t * However, multiple different tables on the page can use different\n\t\t\t * decimal place characters.\n\t\t\t * @type string\n\t\t\t * @default \n\t\t\t *\n\t\t\t * @dtopt Language\n\t\t\t * @name DataTable.defaults.language.decimal\n\t\t\t *\n\t\t\t * @example\n\t\t\t * $(document).ready( function() {\n\t\t\t * $('#example').dataTable( {\n\t\t\t * \"language\": {\n\t\t\t * \"decimal\": \",\"\n\t\t\t * \"thousands\": \".\"\n\t\t\t * }\n\t\t\t * } );\n\t\t\t * } );\n\t\t\t */\n\t\t\t\"sDecimal\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * DataTables has a build in number formatter (`formatNumber`) which is\n\t\t\t * used to format large numbers that are used in the table information.\n\t\t\t * By default a comma is used, but this can be trivially changed to any\n\t\t\t * character you wish with this parameter.\n\t\t\t * @type string\n\t\t\t * @default ,\n\t\t\t *\n\t\t\t * @dtopt Language\n\t\t\t * @name DataTable.defaults.language.thousands\n\t\t\t *\n\t\t\t * @example\n\t\t\t * $(document).ready( function() {\n\t\t\t * $('#example').dataTable( {\n\t\t\t * \"language\": {\n\t\t\t * \"thousands\": \"'\"\n\t\t\t * }\n\t\t\t * } );\n\t\t\t * } );\n\t\t\t */\n\t\t\t\"sThousands\": \",\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Detail the action that will be taken when the drop down menu for the\n\t\t\t * pagination length option is changed. The '_MENU_' variable is replaced\n\t\t\t * with a default select list of 10, 25, 50 and 100, and can be replaced\n\t\t\t * with a custom select box if required.\n\t\t\t * @type string\n\t\t\t * @default Show _MENU_ entries\n\t\t\t *\n\t\t\t * @dtopt Language\n\t\t\t * @name DataTable.defaults.language.lengthMenu\n\t\t\t *\n\t\t\t * @example\n\t\t\t * // Language change only\n\t\t\t * $(document).ready( function() {\n\t\t\t * $('#example').dataTable( {\n\t\t\t * \"language\": {\n\t\t\t * \"lengthMenu\": \"Display _MENU_ records\"\n\t\t\t * }\n\t\t\t * } );\n\t\t\t * } );\n\t\t\t *\n\t\t\t * @example\n\t\t\t * // Language and options change\n\t\t\t * $(document).ready( function() {\n\t\t\t * $('#example').dataTable( {\n\t\t\t * \"language\": {\n\t\t\t * \"lengthMenu\": 'Display <select>'+\n\t\t\t * '<option value=\"10\">10</option>'+\n\t\t\t * '<option value=\"20\">20</option>'+\n\t\t\t * '<option value=\"30\">30</option>'+\n\t\t\t * '<option value=\"40\">40</option>'+\n\t\t\t * '<option value=\"50\">50</option>'+\n\t\t\t * '<option value=\"-1\">All</option>'+\n\t\t\t * '</select> records'\n\t\t\t * }\n\t\t\t * } );\n\t\t\t * } );\n\t\t\t */\n\t\t\t\"sLengthMenu\": \"Show _MENU_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When using Ajax sourced data and during the first draw when DataTables is\n\t\t\t * gathering the data, this message is shown in an empty row in the table to\n\t\t\t * indicate to the end user the the data is being loaded. Note that this\n\t\t\t * parameter is not used when loading data by server-side processing, just\n\t\t\t * Ajax sourced data with client-side processing.\n\t\t\t * @type string\n\t\t\t * @default Loading...\n\t\t\t *\n\t\t\t * @dtopt Language\n\t\t\t * @name DataTable.defaults.language.loadingRecords\n\t\t\t *\n\t\t\t * @example\n\t\t\t * $(document).ready( function() {\n\t\t\t * $('#example').dataTable( {\n\t\t\t * \"language\": {\n\t\t\t * \"loadingRecords\": \"Please wait - loading...\"\n\t\t\t * }\n\t\t\t * } );\n\t\t\t * } );\n\t\t\t */\n\t\t\t\"sLoadingRecords\": \"Loading...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text which is displayed when the table is processing a user action\n\t\t\t * (usually a sort command or similar).\n\t\t\t * @type string\n\t\t\t * @default Processing...\n\t\t\t *\n\t\t\t * @dtopt Language\n\t\t\t * @name DataTable.defaults.language.processing\n\t\t\t *\n\t\t\t * @example\n\t\t\t * $(document).ready( function() {\n\t\t\t * $('#example').dataTable( {\n\t\t\t * \"language\": {\n\t\t\t * \"processing\": \"DataTables is currently busy\"\n\t\t\t * }\n\t\t\t * } );\n\t\t\t * } );\n\t\t\t */\n\t\t\t\"sProcessing\": \"Processing...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Details the actions that will be taken when the user types into the\n\t\t\t * filtering input text box. The variable \"_INPUT_\", if used in the string,\n\t\t\t * is replaced with the HTML text box for the filtering input allowing\n\t\t\t * control over where it appears in the string. If \"_INPUT_\" is not given\n\t\t\t * then the input box is appended to the string automatically.\n\t\t\t * @type string\n\t\t\t * @default Search:\n\t\t\t *\n\t\t\t * @dtopt Language\n\t\t\t * @name DataTable.defaults.language.search\n\t\t\t *\n\t\t\t * @example\n\t\t\t * // Input text box will be appended at the end automatically\n\t\t\t * $(document).ready( function() {\n\t\t\t * $('#example').dataTable( {\n\t\t\t * \"language\": {\n\t\t\t * \"search\": \"Filter records:\"\n\t\t\t * }\n\t\t\t * } );\n\t\t\t * } );\n\t\t\t *\n\t\t\t * @example\n\t\t\t * // Specify where the filter should appear\n\t\t\t * $(document).ready( function() {\n\t\t\t * $('#example').dataTable( {\n\t\t\t * \"language\": {\n\t\t\t * \"search\": \"Apply filter _INPUT_ to table\"\n\t\t\t * }\n\t\t\t * } );\n\t\t\t * } );\n\t\t\t */\n\t\t\t\"sSearch\": \"Search:\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Assign a `placeholder` attribute to the search `input` element\n\t\t\t * @type string\n\t\t\t * @default \n\t\t\t *\n\t\t\t * @dtopt Language\n\t\t\t * @name DataTable.defaults.language.searchPlaceholder\n\t\t\t */\n\t\t\t\"sSearchPlaceholder\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * All of the language information can be stored in a file on the\n\t\t\t * server-side, which DataTables will look up if this parameter is passed.\n\t\t\t * It must store the URL of the language file, which is in a JSON format,\n\t\t\t * and the object has the same properties as the oLanguage object in the\n\t\t\t * initialiser object (i.e. the above parameters). Please refer to one of\n\t\t\t * the example language files to see how this works in action.\n\t\t\t * @type string\n\t\t\t * @default <i>Empty string - i.e. disabled</i>\n\t\t\t *\n\t\t\t * @dtopt Language\n\t\t\t * @name DataTable.defaults.language.url\n\t\t\t *\n\t\t\t * @example\n\t\t\t * $(document).ready( function() {\n\t\t\t * $('#example').dataTable( {\n\t\t\t * \"language\": {\n\t\t\t * \"url\": \"http://www.sprymedia.co.uk/dataTables/lang.txt\"\n\t\t\t * }\n\t\t\t * } );\n\t\t\t * } );\n\t\t\t */\n\t\t\t\"sUrl\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text shown inside the table records when the is no information to be\n\t\t\t * displayed after filtering. `emptyTable` is shown when there is simply no\n\t\t\t * information in the table at all (regardless of filtering).\n\t\t\t * @type string\n\t\t\t * @default No matching records found\n\t\t\t *\n\t\t\t * @dtopt Language\n\t\t\t * @name DataTable.defaults.language.zeroRecords\n\t\t\t *\n\t\t\t * @example\n\t\t\t * $(document).ready( function() {\n\t\t\t * $('#example').dataTable( {\n\t\t\t * \"language\": {\n\t\t\t * \"zeroRecords\": \"No records to display\"\n\t\t\t * }\n\t\t\t * } );\n\t\t\t * } );\n\t\t\t */\n\t\t\t\"sZeroRecords\": \"No matching records found\"\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to have define the global filtering state at\n\t\t * initialisation time. As an object the `search` parameter must be\n\t\t * defined, but all other parameters are optional. When `regex` is true,\n\t\t * the search string will be treated as a regular expression, when false\n\t\t * (default) it will be treated as a straight string. When `smart`\n\t\t * DataTables will use it's smart filtering methods (to word match at\n\t\t * any point in the data), when false this will not be done.\n\t\t * @namespace\n\t\t * @extends DataTable.models.oSearch\n\t\t *\n\t\t * @dtopt Options\n\t\t * @name DataTable.defaults.search\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"search\": {\"search\": \"Initial search\"}\n\t\t * } );\n\t\t * } )\n\t\t */\n\t\t\"oSearch\": $.extend( {}, DataTable.models.oSearch ),\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * By default DataTables will look for the property `data` (or `aaData` for\n\t\t * compatibility with DataTables 1.9-) when obtaining data from an Ajax\n\t\t * source or for server-side processing - this parameter allows that\n\t\t * property to be changed. You can use Javascript dotted object notation to\n\t\t * get a data source for multiple levels of nesting.\n\t\t * @type string\n\t\t * @default data\n\t\t *\n\t\t * @dtopt Options\n\t\t * @dtopt Server-side\n\t\t * @name DataTable.defaults.ajaxDataProp\n\t\t *\n\t\t * @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxDataProp\": \"data\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * You can instruct DataTables to load data from an external\n\t\t * source using this parameter (use aData if you want to pass data in you\n\t\t * already have). Simply provide a url a JSON object can be obtained from.\n\t\t * @type string\n\t\t * @default null\n\t\t *\n\t\t * @dtopt Options\n\t\t * @dtopt Server-side\n\t\t * @name DataTable.defaults.ajaxSource\n\t\t *\n\t\t * @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\n\t\t/**\n\t\t * This initialisation variable allows you to specify exactly where in the\n\t\t * DOM you want DataTables to inject the various controls it adds to the page\n\t\t * (for example you might want the pagination controls at the top of the\n\t\t * table). DIV elements (with or without a custom class) can also be added to\n\t\t * aid styling. The follow syntax is used:\n\t\t * <ul>\n\t\t * <li>The following options are allowed:\n\t\t * <ul>\n\t\t * <li>'l' - Length changing</li>\n\t\t * <li>'f' - Filtering input</li>\n\t\t * <li>'t' - The table!</li>\n\t\t * <li>'i' - Information</li>\n\t\t * <li>'p' - Pagination</li>\n\t\t * <li>'r' - pRocessing</li>\n\t\t * </ul>\n\t\t * </li>\n\t\t * <li>The following constants are allowed:\n\t\t * <ul>\n\t\t * <li>'H' - jQueryUI theme \"header\" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>\n\t\t * <li>'F' - jQueryUI theme \"footer\" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>\n\t\t * </ul>\n\t\t * </li>\n\t\t * <li>The following syntax is expected:\n\t\t * <ul>\n\t\t * <li>'<' and '>' - div elements</li>\n\t\t * <li>'<\"class\" and '>' - div with a class</li>\n\t\t * <li>'<\"#id\" and '>' - div with an ID</li>\n\t\t * </ul>\n\t\t * </li>\n\t\t * <li>Examples:\n\t\t * <ul>\n\t\t * <li>'<\"wrapper\"flipt>'</li>\n\t\t * <li>'<lf<t>ip>'</li>\n\t\t * </ul>\n\t\t * </li>\n\t\t * </ul>\n\t\t * @type string\n\t\t * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>\n\t\t * <\"H\"lfr>t<\"F\"ip> <i>(when `jQueryUI` is true)</i>\n\t\t *\n\t\t * @dtopt Options\n\t\t * @name DataTable.defaults.dom\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"dom\": '<\"top\"i>rt<\"bottom\"flp><\"clear\">'\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"sDom\": \"lfrtip\",\n\t\n\t\n\t\t/**\n\t\t * Search delay option. This will throttle full table searches that use the\n\t\t * DataTables provided search input element (it does not effect calls to\n\t\t * `dt-api search()`, providing a delay before the search is made.\n\t\t * @type integer\n\t\t * @default 0\n\t\t *\n\t\t * @dtopt Options\n\t\t * @name DataTable.defaults.searchDelay\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"searchDelay\": 200\n\t\t * } );\n\t\t * } )\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\n\t\t/**\n\t\t * DataTables features six different built-in options for the buttons to\n\t\t * display for pagination control:\n\t\t *\n\t\t * * `numbers` - Page number buttons only\n\t\t * * `simple` - 'Previous' and 'Next' buttons only\n\t\t * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers\n\t\t * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons\n\t\t * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers\n\t\t * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers\n\t\t * \n\t\t * Further methods can be added using {@link DataTable.ext.oPagination}.\n\t\t * @type string\n\t\t * @default simple_numbers\n\t\t *\n\t\t * @dtopt Options\n\t\t * @name DataTable.defaults.pagingType\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"pagingType\": \"full_numbers\"\n\t\t * } );\n\t\t * } )\n\t\t */\n\t\t\"sPaginationType\": \"simple_numbers\",\n\t\n\t\n\t\t/**\n\t\t * Enable horizontal scrolling. When a table is too wide to fit into a\n\t\t * certain layout, or you have a large number of columns in the table, you\n\t\t * can enable x-scrolling to show the table in a viewport, which can be\n\t\t * scrolled. This property can be `true` which will allow the table to\n\t\t * scroll horizontally when needed, or any CSS unit, or a number (in which\n\t\t * case it will be treated as a pixel measurement). Setting as simply `true`\n\t\t * is recommended.\n\t\t * @type boolean|string\n\t\t * @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t * @dtopt Features\n\t\t * @name DataTable.defaults.scrollX\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"scrollX\": true,\n\t\t * \"scrollCollapse\": true\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"sScrollX\": \"\",\n\t\n\t\n\t\t/**\n\t\t * This property can be used to force a DataTable to use more width than it\n\t\t * might otherwise do when x-scrolling is enabled. For example if you have a\n\t\t * table which requires to be well spaced, this parameter is useful for\n\t\t * \"over-sizing\" the table, and thus forcing scrolling. This property can by\n\t\t * any CSS unit, or a number (in which case it will be treated as a pixel\n\t\t * measurement).\n\t\t * @type string\n\t\t * @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t * @dtopt Options\n\t\t * @name DataTable.defaults.scrollXInner\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"scrollX\": \"100%\",\n\t\t * \"scrollXInner\": \"110%\"\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"sScrollXInner\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Enable vertical scrolling. Vertical scrolling will constrain the DataTable\n\t\t * to the given height, and enable scrolling for any data which overflows the\n\t\t * current viewport. This can be used as an alternative to paging to display\n\t\t * a lot of data in a small area (although paging and scrolling can both be\n\t\t * enabled at the same time). This property can be any CSS unit, or a number\n\t\t * (in which case it will be treated as a pixel measurement).\n\t\t * @type string\n\t\t * @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t * @dtopt Features\n\t\t * @name DataTable.defaults.scrollY\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"scrollY\": \"200px\",\n\t\t * \"paginate\": false\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"sScrollY\": \"\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * Set the HTTP method that is used to make the Ajax call for server-side\n\t\t * processing or Ajax sourced data.\n\t\t * @type string\n\t\t * @default GET\n\t\t *\n\t\t * @dtopt Options\n\t\t * @dtopt Server-side\n\t\t * @name DataTable.defaults.serverMethod\n\t\t *\n\t\t * @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sServerMethod\": \"GET\",\n\t\n\t\n\t\t/**\n\t\t * DataTables makes use of renderers when displaying HTML elements for\n\t\t * a table. These renderers can be added or modified by plug-ins to\n\t\t * generate suitable mark-up for a site. For example the Bootstrap\n\t\t * integration plug-in for DataTables uses a paging button renderer to\n\t\t * display pagination buttons in the mark-up required by Bootstrap.\n\t\t *\n\t\t * For further information about the renderers available see\n\t\t * DataTable.ext.renderer\n\t\t * @type string|object\n\t\t * @default null\n\t\t *\n\t\t * @name DataTable.defaults.renderer\n\t\t *\n\t\t */\n\t\t\"renderer\": null,\n\t\n\t\n\t\t/**\n\t\t * Set the data property name that DataTables should use to get a row's id\n\t\t * to set as the `id` property in the node.\n\t\t * @type string\n\t\t * @default DT_RowId\n\t\t *\n\t\t * @name DataTable.defaults.rowId\n\t\t */\n\t\t\"rowId\": \"DT_RowId\"\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults );\n\t\n\t\n\t\n\t/*\n\t * Developer note - See note in model.defaults.js about the use of Hungarian\n\t * notation and camel case.\n\t */\n\t\n\t/**\n\t * Column options that can be given to DataTables at initialisation time.\n\t * @namespace\n\t */\n\tDataTable.defaults.column = {\n\t\t/**\n\t\t * Define which column(s) an order will occur on for this column. This\n\t\t * allows a column's ordering to take multiple columns into account when\n\t\t * doing a sort or use the data from a different column. For example first\n\t\t * name / last name columns make sense to do a multi-column sort over the\n\t\t * two columns.\n\t\t * @type array|int\n\t\t * @default null <i>Takes the value of the column index automatically</i>\n\t\t *\n\t\t * @name DataTable.defaults.column.orderData\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Using `columnDefs`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [\n\t\t * { \"orderData\": [ 0, 1 ], \"targets\": [ 0 ] },\n\t\t * { \"orderData\": [ 1, 0 ], \"targets\": [ 1 ] },\n\t\t * { \"orderData\": 2, \"targets\": [ 2 ] }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using `columns`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columns\": [\n\t\t * { \"orderData\": [ 0, 1 ] },\n\t\t * { \"orderData\": [ 1, 0 ] },\n\t\t * { \"orderData\": 2 },\n\t\t * null,\n\t\t * null\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"aDataSort\": null,\n\t\t\"iDataSort\": -1,\n\t\n\t\n\t\t/**\n\t\t * You can control the default ordering direction, and even alter the\n\t\t * behaviour of the sort handler (i.e. only allow ascending ordering etc)\n\t\t * using this parameter.\n\t\t * @type array\n\t\t * @default [ 'asc', 'desc' ]\n\t\t *\n\t\t * @name DataTable.defaults.column.orderSequence\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Using `columnDefs`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [\n\t\t * { \"orderSequence\": [ \"asc\" ], \"targets\": [ 1 ] },\n\t\t * { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ], \"targets\": [ 2 ] },\n\t\t * { \"orderSequence\": [ \"desc\" ], \"targets\": [ 3 ] }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using `columns`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columns\": [\n\t\t * null,\n\t\t * { \"orderSequence\": [ \"asc\" ] },\n\t\t * { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ] },\n\t\t * { \"orderSequence\": [ \"desc\" ] },\n\t\t * null\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"asSorting\": [ 'asc', 'desc' ],\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering on the data in this column.\n\t\t * @type boolean\n\t\t * @default true\n\t\t *\n\t\t * @name DataTable.defaults.column.searchable\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Using `columnDefs`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [\n\t\t * { \"searchable\": false, \"targets\": [ 0 ] }\n\t\t * ] } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using `columns`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columns\": [\n\t\t * { \"searchable\": false },\n\t\t * null,\n\t\t * null,\n\t\t * null,\n\t\t * null\n\t\t * ] } );\n\t\t * } );\n\t\t */\n\t\t\"bSearchable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable ordering on this column.\n\t\t * @type boolean\n\t\t * @default true\n\t\t *\n\t\t * @name DataTable.defaults.column.orderable\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Using `columnDefs`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [\n\t\t * { \"orderable\": false, \"targets\": [ 0 ] }\n\t\t * ] } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using `columns`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columns\": [\n\t\t * { \"orderable\": false },\n\t\t * null,\n\t\t * null,\n\t\t * null,\n\t\t * null\n\t\t * ] } );\n\t\t * } );\n\t\t */\n\t\t\"bSortable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of this column.\n\t\t * @type boolean\n\t\t * @default true\n\t\t *\n\t\t * @name DataTable.defaults.column.visible\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Using `columnDefs`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [\n\t\t * { \"visible\": false, \"targets\": [ 0 ] }\n\t\t * ] } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using `columns`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columns\": [\n\t\t * { \"visible\": false },\n\t\t * null,\n\t\t * null,\n\t\t * null,\n\t\t * null\n\t\t * ] } );\n\t\t * } );\n\t\t */\n\t\t\"bVisible\": true,\n\t\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t * @type function\n\t\t * @param {element} td The TD node that has been created\n\t\t * @param {*} cellData The Data for the cell\n\t\t * @param {array|object} rowData The data for the whole row\n\t\t * @param {int} row The row index for the aoData data store\n\t\t * @param {int} col The column index for aoColumns\n\t\t *\n\t\t * @name DataTable.defaults.column.createdCell\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [ {\n\t\t * \"targets\": [3],\n\t\t * \"createdCell\": function (td, cellData, rowData, row, col) {\n\t\t * if ( cellData == \"1.7\" ) {\n\t\t * $(td).css('color', 'blue')\n\t\t * }\n\t\t * }\n\t\t * } ]\n\t\t * });\n\t\t * } );\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter has been replaced by `data` in DataTables to ensure naming\n\t\t * consistency. `dataProp` can still be used, as there is backwards\n\t\t * compatibility in DataTables for this option, but it is strongly\n\t\t * recommended that you use `data` in preference to `dataProp`.\n\t\t * @name DataTable.defaults.column.dataProp\n\t\t */\n\t\n\t\n\t\t/**\n\t\t * This property can be used to read data from any data source property,\n\t\t * including deeply nested objects / properties. `data` can be given in a\n\t\t * number of different ways which effect its behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t * default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t * three 'special' options that can be used in the string to alter how\n\t\t * DataTables reads the data from the source object:\n\t\t * * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t * Javascript to read from nested objects, so to can the options\n\t\t * specified in `data`. For example: `browser.version` or\n\t\t * `browser.name`. If your object parameter name contains a period, use\n\t\t * `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t * * `[]` - Array notation. DataTables can automatically combine data\n\t\t * from and array source, joining the data with the characters provided\n\t\t * between the two brackets. For example: `name[, ]` would provide a\n\t\t * comma-space separated list from the source array. If no characters\n\t\t * are provided between the brackets, the original array source is\n\t\t * returned.\n\t\t * * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t * execute a function of the name given. For example: `browser()` for a\n\t\t * simple function on the data source, `browser.version()` for a\n\t\t * function in a nested property or even `browser().version` to get an\n\t\t * object property if the function called returns an object. Note that\n\t\t * function notation is recommended for use in `render` rather than\n\t\t * `data` as it is much simpler to use as a renderer.\n\t\t * * `null` - use the original data source for the row rather than plucking\n\t\t * data directly from it. This action has effects on two other\n\t\t * initialisation options:\n\t\t * * `defaultContent` - When null is given as the `data` option and\n\t\t * `defaultContent` is specified for the column, the value defined by\n\t\t * `defaultContent` will be used for the cell.\n\t\t * * `render` - When null is used for the `data` option and the `render`\n\t\t * option is specified for the column, the whole data source for the\n\t\t * row is used for the renderer.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t * needs to set or get the data for a cell in the column. The function\n\t\t * takes three parameters:\n\t\t * * Parameters:\n\t\t * * `{array|object}` The data source for the row\n\t\t * * `{string}` The type call data requested - this will be 'set' when\n\t\t * setting data or 'filter', 'display', 'type', 'sort' or undefined\n\t\t * when gathering data. Note that when `undefined` is given for the\n\t\t * type DataTables expects to get the raw data for the object back<\n\t\t * * `{*}` Data to set when the second parameter is 'set'.\n\t\t * * Return:\n\t\t * * The return value from the function is not required when 'set' is\n\t\t * the type of call, but otherwise the return is what will be used\n\t\t * for the data requested.\n\t\t *\n\t\t * Note that `data` is a getter and setter option. If you just require\n\t\t * formatting of data for output, you will likely want to use `render` which\n\t\t * is simply a getter and thus simpler to use.\n\t\t *\n\t\t * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The\n\t\t * name change reflects the flexibility of this property and is consistent\n\t\t * with the naming of mRender. If 'mDataProp' is given, then it will still\n\t\t * be used by DataTables, as it automatically maps the old name to the new\n\t\t * if required.\n\t\t *\n\t\t * @type string|int|function|null\n\t\t * @default null <i>Use automatically calculated column index</i>\n\t\t *\n\t\t * @name DataTable.defaults.column.data\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Read table data from objects\n\t\t * // JSON structure for each row:\n\t\t * // {\n\t\t * // \"engine\": {value},\n\t\t * // \"browser\": {value},\n\t\t * // \"platform\": {value},\n\t\t * // \"version\": {value},\n\t\t * // \"grade\": {value}\n\t\t * // }\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"ajaxSource\": \"sources/objects.txt\",\n\t\t * \"columns\": [\n\t\t * { \"data\": \"engine\" },\n\t\t * { \"data\": \"browser\" },\n\t\t * { \"data\": \"platform\" },\n\t\t * { \"data\": \"version\" },\n\t\t * { \"data\": \"grade\" }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Read information from deeply nested objects\n\t\t * // JSON structure for each row:\n\t\t * // {\n\t\t * // \"engine\": {value},\n\t\t * // \"browser\": {value},\n\t\t * // \"platform\": {\n\t\t * // \"inner\": {value}\n\t\t * // },\n\t\t * // \"details\": [\n\t\t * // {value}, {value}\n\t\t * // ]\n\t\t * // }\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"ajaxSource\": \"sources/deep.txt\",\n\t\t * \"columns\": [\n\t\t * { \"data\": \"engine\" },\n\t\t * { \"data\": \"browser\" },\n\t\t * { \"data\": \"platform.inner\" },\n\t\t * { \"data\": \"details.0\" },\n\t\t * { \"data\": \"details.1\" }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using `data` as a function to provide different information for\n\t\t * // sorting, filtering and display. In this case, currency (price)\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [ {\n\t\t * \"targets\": [ 0 ],\n\t\t * \"data\": function ( source, type, val ) {\n\t\t * if (type === 'set') {\n\t\t * source.price = val;\n\t\t * // Store the computed display and filter values for efficiency\n\t\t * source.price_display = val==\"\" ? \"\" : \"$\"+numberFormat(val);\n\t\t * source.price_filter = val==\"\" ? \"\" : \"$\"+numberFormat(val)+\" \"+val;\n\t\t * return;\n\t\t * }\n\t\t * else if (type === 'display') {\n\t\t * return source.price_display;\n\t\t * }\n\t\t * else if (type === 'filter') {\n\t\t * return source.price_filter;\n\t\t * }\n\t\t * // 'sort', 'type' and undefined all just use the integer\n\t\t * return source.price;\n\t\t * }\n\t\t * } ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using default content\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [ {\n\t\t * \"targets\": [ 0 ],\n\t\t * \"data\": null,\n\t\t * \"defaultContent\": \"Click to edit\"\n\t\t * } ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using array notation - outputting a list from an array\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [ {\n\t\t * \"targets\": [ 0 ],\n\t\t * \"data\": \"name[, ]\"\n\t\t * } ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\n\t\t/**\n\t\t * This property is the rendering partner to `data` and it is suggested that\n\t\t * when you want to manipulate data for display (including filtering,\n\t\t * sorting etc) without altering the underlying data for the table, use this\n\t\t * property. `render` can be considered to be the the read only companion to\n\t\t * `data` which is read / write (then as such more complex). Like `data`\n\t\t * this option can be given in a number of different ways to effect its\n\t\t * behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t * default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t * three 'special' options that can be used in the string to alter how\n\t\t * DataTables reads the data from the source object:\n\t\t * * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t * Javascript to read from nested objects, so to can the options\n\t\t * specified in `data`. For example: `browser.version` or\n\t\t * `browser.name`. If your object parameter name contains a period, use\n\t\t * `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t * * `[]` - Array notation. DataTables can automatically combine data\n\t\t * from and array source, joining the data with the characters provided\n\t\t * between the two brackets. For example: `name[, ]` would provide a\n\t\t * comma-space separated list from the source array. If no characters\n\t\t * are provided between the brackets, the original array source is\n\t\t * returned.\n\t\t * * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t * execute a function of the name given. For example: `browser()` for a\n\t\t * simple function on the data source, `browser.version()` for a\n\t\t * function in a nested property or even `browser().version` to get an\n\t\t * object property if the function called returns an object.\n\t\t * * `object` - use different data for the different data types requested by\n\t\t * DataTables ('filter', 'display', 'type' or 'sort'). The property names\n\t\t * of the object is the data type the property refers to and the value can\n\t\t * defined using an integer, string or function using the same rules as\n\t\t * `render` normally does. Note that an `_` option _must_ be specified.\n\t\t * This is the default value to use if you haven't specified a value for\n\t\t * the data type requested by DataTables.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t * needs to set or get the data for a cell in the column. The function\n\t\t * takes three parameters:\n\t\t * * Parameters:\n\t\t * * {array|object} The data source for the row (based on `data`)\n\t\t * * {string} The type call data requested - this will be 'filter',\n\t\t * 'display', 'type' or 'sort'.\n\t\t * * {array|object} The full data source for the row (not based on\n\t\t * `data`)\n\t\t * * Return:\n\t\t * * The return value from the function is what will be used for the\n\t\t * data requested.\n\t\t *\n\t\t * @type string|int|function|object|null\n\t\t * @default null Use the data source value.\n\t\t *\n\t\t * @name DataTable.defaults.column.render\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Create a comma separated list from an array of objects\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"ajaxSource\": \"sources/deep.txt\",\n\t\t * \"columns\": [\n\t\t * { \"data\": \"engine\" },\n\t\t * { \"data\": \"browser\" },\n\t\t * {\n\t\t * \"data\": \"platform\",\n\t\t * \"render\": \"[, ].name\"\n\t\t * }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Execute a function to obtain data\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [ {\n\t\t * \"targets\": [ 0 ],\n\t\t * \"data\": null, // Use the full data source object for the renderer's source\n\t\t * \"render\": \"browserName()\"\n\t\t * } ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // As an object, extracting different data for the different types\n\t\t * // This would be used with a data source such as:\n\t\t * // { \"phone\": 5552368, \"phone_filter\": \"5552368 555-2368\", \"phone_display\": \"555-2368\" }\n\t\t * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`\n\t\t * // (which has both forms) is used for filtering for if a user inputs either format, while\n\t\t * // the formatted phone number is the one that is shown in the table.\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [ {\n\t\t * \"targets\": [ 0 ],\n\t\t * \"data\": null, // Use the full data source object for the renderer's source\n\t\t * \"render\": {\n\t\t * \"_\": \"phone\",\n\t\t * \"filter\": \"phone_filter\",\n\t\t * \"display\": \"phone_display\"\n\t\t * }\n\t\t * } ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Use as a function to create a link from the data source\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [ {\n\t\t * \"targets\": [ 0 ],\n\t\t * \"data\": \"download_link\",\n\t\t * \"render\": function ( data, type, full ) {\n\t\t * return '<a href=\"'+data+'\">Download</a>';\n\t\t * }\n\t\t * } ]\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\n\t\t/**\n\t\t * Change the cell type created for the column - either TD cells or TH cells. This\n\t\t * can be useful as TH cells have semantic meaning in the table body, allowing them\n\t\t * to act as a header for a row (you may wish to add scope='row' to the TH elements).\n\t\t * @type string\n\t\t * @default td\n\t\t *\n\t\t * @name DataTable.defaults.column.cellType\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Make the first column use TH cells\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [ {\n\t\t * \"targets\": [ 0 ],\n\t\t * \"cellType\": \"th\"\n\t\t * } ]\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"sCellType\": \"td\",\n\t\n\t\n\t\t/**\n\t\t * Class to give to each cell in this column.\n\t\t * @type string\n\t\t * @default <i>Empty string</i>\n\t\t *\n\t\t * @name DataTable.defaults.column.class\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Using `columnDefs`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [\n\t\t * { \"class\": \"my_class\", \"targets\": [ 0 ] }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using `columns`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columns\": [\n\t\t * { \"class\": \"my_class\" },\n\t\t * null,\n\t\t * null,\n\t\t * null,\n\t\t * null\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"sClass\": \"\",\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t * Generally you shouldn't need this!\n\t\t * @type string\n\t\t * @default <i>Empty string<i>\n\t\t *\n\t\t * @name DataTable.defaults.column.contentPadding\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Using `columns`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columns\": [\n\t\t * null,\n\t\t * null,\n\t\t * null,\n\t\t * {\n\t\t * \"contentPadding\": \"mmm\"\n\t\t * }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"sContentPadding\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because `data`\n\t\t * is set to null, or because the data source itself is null).\n\t\t * @type string\n\t\t * @default null\n\t\t *\n\t\t * @name DataTable.defaults.column.defaultContent\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Using `columnDefs`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [\n\t\t * {\n\t\t * \"data\": null,\n\t\t * \"defaultContent\": \"Edit\",\n\t\t * \"targets\": [ -1 ]\n\t\t * }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using `columns`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columns\": [\n\t\t * null,\n\t\t * null,\n\t\t * null,\n\t\t * {\n\t\t * \"data\": null,\n\t\t * \"defaultContent\": \"Edit\"\n\t\t * }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter is only used in DataTables' server-side processing. It can\n\t\t * be exceptionally useful to know what columns are being displayed on the\n\t\t * client side, and to map these to database fields. When defined, the names\n\t\t * also allow DataTables to reorder information from the server if it comes\n\t\t * back in an unexpected order (i.e. if you switch your columns around on the\n\t\t * client-side, your server-side code does not also need updating).\n\t\t * @type string\n\t\t * @default <i>Empty string</i>\n\t\t *\n\t\t * @name DataTable.defaults.column.name\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Using `columnDefs`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [\n\t\t * { \"name\": \"engine\", \"targets\": [ 0 ] },\n\t\t * { \"name\": \"browser\", \"targets\": [ 1 ] },\n\t\t * { \"name\": \"platform\", \"targets\": [ 2 ] },\n\t\t * { \"name\": \"version\", \"targets\": [ 3 ] },\n\t\t * { \"name\": \"grade\", \"targets\": [ 4 ] }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using `columns`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columns\": [\n\t\t * { \"name\": \"engine\" },\n\t\t * { \"name\": \"browser\" },\n\t\t * { \"name\": \"platform\" },\n\t\t * { \"name\": \"version\" },\n\t\t * { \"name\": \"grade\" }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"sName\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Defines a data source type for the ordering which can be used to read\n\t\t * real-time information from the table (updating the internally cached\n\t\t * version) prior to ordering. This allows ordering to occur on user\n\t\t * editable elements such as form inputs.\n\t\t * @type string\n\t\t * @default std\n\t\t *\n\t\t * @name DataTable.defaults.column.orderDataType\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Using `columnDefs`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [\n\t\t * { \"orderDataType\": \"dom-text\", \"targets\": [ 2, 3 ] },\n\t\t * { \"type\": \"numeric\", \"targets\": [ 3 ] },\n\t\t * { \"orderDataType\": \"dom-select\", \"targets\": [ 4 ] },\n\t\t * { \"orderDataType\": \"dom-checkbox\", \"targets\": [ 5 ] }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using `columns`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columns\": [\n\t\t * null,\n\t\t * null,\n\t\t * { \"orderDataType\": \"dom-text\" },\n\t\t * { \"orderDataType\": \"dom-text\", \"type\": \"numeric\" },\n\t\t * { \"orderDataType\": \"dom-select\" },\n\t\t * { \"orderDataType\": \"dom-checkbox\" }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"sSortDataType\": \"std\",\n\t\n\t\n\t\t/**\n\t\t * The title of this column.\n\t\t * @type string\n\t\t * @default null <i>Derived from the 'TH' value for this column in the\n\t\t * original HTML table.</i>\n\t\t *\n\t\t * @name DataTable.defaults.column.title\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Using `columnDefs`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [\n\t\t * { \"title\": \"My column title\", \"targets\": [ 0 ] }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using `columns`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columns\": [\n\t\t * { \"title\": \"My column title\" },\n\t\t * null,\n\t\t * null,\n\t\t * null,\n\t\t * null\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\n\t\t/**\n\t\t * The type allows you to specify how the data for this column will be\n\t\t * ordered. Four types (string, numeric, date and html (which will strip\n\t\t * HTML tags before ordering)) are currently available. Note that only date\n\t\t * formats understood by Javascript's Date() object will be accepted as type\n\t\t * date. For example: \"Mar 26, 2008 5:03 PM\". May take the values: 'string',\n\t\t * 'numeric', 'date' or 'html' (by default). Further types can be adding\n\t\t * through plug-ins.\n\t\t * @type string\n\t\t * @default null <i>Auto-detected from raw data</i>\n\t\t *\n\t\t * @name DataTable.defaults.column.type\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Using `columnDefs`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [\n\t\t * { \"type\": \"html\", \"targets\": [ 0 ] }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using `columns`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columns\": [\n\t\t * { \"type\": \"html\" },\n\t\t * null,\n\t\t * null,\n\t\t * null,\n\t\t * null\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\n\t\t/**\n\t\t * Defining the width of the column, this parameter may take any CSS value\n\t\t * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not\n\t\t * been given a specific width through this interface ensuring that the table\n\t\t * remains readable.\n\t\t * @type string\n\t\t * @default null <i>Automatic</i>\n\t\t *\n\t\t * @name DataTable.defaults.column.width\n\t\t * @dtopt Columns\n\t\t *\n\t\t * @example\n\t\t * // Using `columnDefs`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columnDefs\": [\n\t\t * { \"width\": \"20%\", \"targets\": [ 0 ] }\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t *\n\t\t * @example\n\t\t * // Using `columns`\n\t\t * $(document).ready( function() {\n\t\t * $('#example').dataTable( {\n\t\t * \"columns\": [\n\t\t * { \"width\": \"20%\" },\n\t\t * null,\n\t\t * null,\n\t\t * null,\n\t\t * null\n\t\t * ]\n\t\t * } );\n\t\t * } );\n\t\t */\n\t\t\"sWidth\": null\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults.column );\n\t\n\t\n\t\n\t/**\n\t * DataTables settings object - this holds all the information needed for a\n\t * given table, including configuration, data and current application of the\n\t * table options. DataTables does not have a single instance for each DataTable\n\t * with the settings attached to that instance, but rather instances of the\n\t * DataTable \"class\" are created on-the-fly as needed (typically by a\n\t * $().dataTable() call) and the settings object is then applied to that\n\t * instance.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults} but this\n\t * one is the internal data store for DataTables's cache of columns. It should\n\t * NOT be manipulated outside of DataTables. Any configuration should be done\n\t * through the initialisation options.\n\t * @namespace\n\t * @todo Really should attach the settings object to individual instances so we\n\t * don't need to create new instances on each $().dataTable() call (if the\n\t * table already exists). It would also save passing oSettings around and\n\t * into every single function. However, this is a very significant\n\t * architecture change for DataTables and will almost certainly break\n\t * backwards compatibility with older installations. This is something that\n\t * will be done in 2.0.\n\t */\n\tDataTable.models.oSettings = {\n\t\t/**\n\t\t * Primary features of DataTables and their enablement state.\n\t\t * @namespace\n\t\t */\n\t\t\"oFeatures\": {\n\t\n\t\t\t/**\n\t\t\t * Flag to say if DataTables should automatically try to calculate the\n\t\t\t * optimum table and columns widths (true) or not (false).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type boolean\n\t\t\t */\n\t\t\t\"bAutoWidth\": null,\n\t\n\t\t\t/**\n\t\t\t * Delay the creation of TR and TD elements until they are actually\n\t\t\t * needed by a driven page draw. This can give a significant speed\n\t\t\t * increase for Ajax source and Javascript source data, but makes no\n\t\t\t * difference at all for DOM and server-side processing tables.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type boolean\n\t\t\t */\n\t\t\t\"bDeferRender\": null,\n\t\n\t\t\t/**\n\t\t\t * Enable filtering on the table or not. Note that if this is disabled\n\t\t\t * then there is no filtering at all on the table, including fnFilter.\n\t\t\t * To just remove the filtering input use sDom and remove the 'f' option.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type boolean\n\t\t\t */\n\t\t\t\"bFilter\": null,\n\t\n\t\t\t/**\n\t\t\t * Table information element (the 'Showing x of y records' div) enable\n\t\t\t * flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type boolean\n\t\t\t */\n\t\t\t\"bInfo\": null,\n\t\n\t\t\t/**\n\t\t\t * Present a user control allowing the end user to change the page size\n\t\t\t * when pagination is enabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type boolean\n\t\t\t */\n\t\t\t\"bLengthChange\": null,\n\t\n\t\t\t/**\n\t\t\t * Pagination enabled or not. Note that if this is disabled then length\n\t\t\t * changing must also be disabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type boolean\n\t\t\t */\n\t\t\t\"bPaginate\": null,\n\t\n\t\t\t/**\n\t\t\t * Processing indicator enable flag whenever DataTables is enacting a\n\t\t\t * user request - typically an Ajax request for server-side processing.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type boolean\n\t\t\t */\n\t\t\t\"bProcessing\": null,\n\t\n\t\t\t/**\n\t\t\t * Server-side processing enabled flag - when enabled DataTables will\n\t\t\t * get all data from the server for every draw - there is no filtering,\n\t\t\t * sorting or paging done on the client-side.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type boolean\n\t\t\t */\n\t\t\t\"bServerSide\": null,\n\t\n\t\t\t/**\n\t\t\t * Sorting enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type boolean\n\t\t\t */\n\t\t\t\"bSort\": null,\n\t\n\t\t\t/**\n\t\t\t * Multi-column sorting\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type boolean\n\t\t\t */\n\t\t\t\"bSortMulti\": null,\n\t\n\t\t\t/**\n\t\t\t * Apply a class to the columns which are being sorted to provide a\n\t\t\t * visual highlight or not. This can slow things down when enabled since\n\t\t\t * there is a lot of DOM interaction.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type boolean\n\t\t\t */\n\t\t\t\"bSortClasses\": null,\n\t\n\t\t\t/**\n\t\t\t * State saving enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type boolean\n\t\t\t */\n\t\t\t\"bStateSave\": null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Scrolling settings for a table.\n\t\t * @namespace\n\t\t */\n\t\t\"oScroll\": {\n\t\t\t/**\n\t\t\t * When the table is shorter in height than sScrollY, collapse the\n\t\t\t * table container down to the height of the table (when true).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type boolean\n\t\t\t */\n\t\t\t\"bCollapse\": null,\n\t\n\t\t\t/**\n\t\t\t * Width of the scrollbar for the web-browser's platform. Calculated\n\t\t\t * during table initialisation.\n\t\t\t * @type int\n\t\t\t * @default 0\n\t\t\t */\n\t\t\t\"iBarWidth\": 0,\n\t\n\t\t\t/**\n\t\t\t * Viewport width for horizontal scrolling. Horizontal scrolling is\n\t\t\t * disabled if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type string\n\t\t\t */\n\t\t\t\"sX\": null,\n\t\n\t\t\t/**\n\t\t\t * Width to expand the table to when using x-scrolling. Typically you\n\t\t\t * should not need to use this.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type string\n\t\t\t * @deprecated\n\t\t\t */\n\t\t\t\"sXInner\": null,\n\t\n\t\t\t/**\n\t\t\t * Viewport height for vertical scrolling. Vertical scrolling is disabled\n\t\t\t * if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t * @type string\n\t\t\t */\n\t\t\t\"sY\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Language information for the table.\n\t\t * @namespace\n\t\t * @extends DataTable.defaults.oLanguage\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Information callback function. See\n\t\t\t * {@link DataTable.defaults.fnInfoCallback}\n\t\t\t * @type function\n\t\t\t * @default null\n\t\t\t */\n\t\t\t\"fnInfoCallback\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Browser support parameters\n\t\t * @namespace\n\t\t */\n\t\t\"oBrowser\": {\n\t\t\t/**\n\t\t\t * Indicate if the browser incorrectly calculates width:100% inside a\n\t\t\t * scrolling element (IE6/7)\n\t\t\t * @type boolean\n\t\t\t * @default false\n\t\t\t */\n\t\t\t\"bScrollOversize\": false,\n\t\n\t\t\t/**\n\t\t\t * Determine if the vertical scrollbar is on the right or left of the\n\t\t\t * scrolling container - needed for rtl language layout, although not\n\t\t\t * all browsers move the scrollbar (Safari).\n\t\t\t * @type boolean\n\t\t\t * @default false\n\t\t\t */\n\t\t\t\"bScrollbarLeft\": false,\n\t\n\t\t\t/**\n\t\t\t * Flag for if `getBoundingClientRect` is fully supported or not\n\t\t\t * @type boolean\n\t\t\t * @default false\n\t\t\t */\n\t\t\t\"bBounding\": false,\n\t\n\t\t\t/**\n\t\t\t * Browser scrollbar width\n\t\t\t * @type integer\n\t\t\t * @default 0\n\t\t\t */\n\t\t\t\"barWidth\": 0\n\t\t},\n\t\n\t\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * Array referencing the nodes which are used for the features. The\n\t\t * parameters of this object match what is allowed by sDom - i.e.\n\t\t * <ul>\n\t\t * <li>'l' - Length changing</li>\n\t\t * <li>'f' - Filtering input</li>\n\t\t * <li>'t' - The table!</li>\n\t\t * <li>'i' - Information</li>\n\t\t * <li>'p' - Pagination</li>\n\t\t * <li>'r' - pRocessing</li>\n\t\t * </ul>\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aanFeatures\": [],\n\t\n\t\t/**\n\t\t * Store data information - see {@link DataTable.models.oRow} for detailed\n\t\t * information.\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoData\": [],\n\t\n\t\t/**\n\t\t * Array of indexes which are in the current display (after filtering etc)\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aiDisplay\": [],\n\t\n\t\t/**\n\t\t * Array of indexes for display - no filtering\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aiDisplayMaster\": [],\n\t\n\t\t/**\n\t\t * Map of row ids to data indexes\n\t\t * @type object\n\t\t * @default {}\n\t\t */\n\t\t\"aIds\": {},\n\t\n\t\t/**\n\t\t * Store information about each column that is in use\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoColumns\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's header\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoHeader\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's footer\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoFooter\": [],\n\t\n\t\t/**\n\t\t * Store the applied global search information in case we want to force a\n\t\t * research or compare the old search to a new one.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t * @namespace\n\t\t * @extends DataTable.models.oSearch\n\t\t */\n\t\t\"oPreviousSearch\": {},\n\t\n\t\t/**\n\t\t * Store the applied search for each column - see\n\t\t * {@link DataTable.models.oSearch} for the format that is used for the\n\t\t * filtering information for each column.\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoPreSearchCols\": [],\n\t\n\t\t/**\n\t\t * Sorting that is applied to the table. Note that the inner arrays are\n\t\t * used in the following manner:\n\t\t * <ul>\n\t\t * <li>Index 0 - column number</li>\n\t\t * <li>Index 1 - current sorting direction</li>\n\t\t * </ul>\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t * @type array\n\t\t * @todo These inner arrays should really be objects\n\t\t */\n\t\t\"aaSorting\": null,\n\t\n\t\t/**\n\t\t * Sorting that is always applied to the table (i.e. prefixed in front of\n\t\t * aaSorting).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\t/**\n\t\t * Classes to use for the striping of a table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its striping classes as well\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"asDestroyStripes\": [],\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its width\n\t\t * @type int\n\t\t * @default 0\n\t\t */\n\t\t\"sDestroyWidth\": 0,\n\t\n\t\t/**\n\t\t * Callback functions array for every time a row is inserted (i.e. on a draw).\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoRowCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for the header on each draw.\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoHeaderCallback\": [],\n\t\n\t\t/**\n\t\t * Callback function for the footer on each draw.\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoFooterCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for draw callback functions\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for row created function\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoRowCreatedCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for just before the table is redrawn. A return of\n\t\t * false will be used to cancel the draw.\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoPreDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for when the table has been initialised.\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoInitComplete\": [],\n\t\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings to be stored for state saving, prior to\n\t\t * saving state.\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoStateSaveParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings that have been stored for state saving\n\t\t * prior to using the stored values to restore the state.\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoStateLoadParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for operating on the settings object once the saved state has been\n\t\t * loaded\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoStateLoaded\": [],\n\t\n\t\t/**\n\t\t * Cache the table ID for quick access\n\t\t * @type string\n\t\t * @default <i>Empty string</i>\n\t\t */\n\t\t\"sTableId\": \"\",\n\t\n\t\t/**\n\t\t * The TABLE node for the main table\n\t\t * @type node\n\t\t * @default null\n\t\t */\n\t\t\"nTable\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the thead element\n\t\t * @type node\n\t\t * @default null\n\t\t */\n\t\t\"nTHead\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tfoot element - if it exists\n\t\t * @type node\n\t\t * @default null\n\t\t */\n\t\t\"nTFoot\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tbody element\n\t\t * @type node\n\t\t * @default null\n\t\t */\n\t\t\"nTBody\": null,\n\t\n\t\t/**\n\t\t * Cache the wrapper node (contains all DataTables controlled elements)\n\t\t * @type node\n\t\t * @default null\n\t\t */\n\t\t\"nTableWrapper\": null,\n\t\n\t\t/**\n\t\t * Indicate if when using server-side processing the loading of data\n\t\t * should be deferred until the second draw.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t * @type boolean\n\t\t * @default false\n\t\t */\n\t\t\"bDeferLoading\": false,\n\t\n\t\t/**\n\t\t * Indicate if all required information has been read in\n\t\t * @type boolean\n\t\t * @default false\n\t\t */\n\t\t\"bInitialised\": false,\n\t\n\t\t/**\n\t\t * Information about open rows. Each object in the array has the parameters\n\t\t * 'nTr' and 'nParent'\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoOpenRows\": [],\n\t\n\t\t/**\n\t\t * Dictate the positioning of DataTables' control elements - see\n\t\t * {@link DataTable.model.oInit.sDom}.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t * @type string\n\t\t * @default null\n\t\t */\n\t\t\"sDom\": null,\n\t\n\t\t/**\n\t\t * Search delay (in mS)\n\t\t * @type integer\n\t\t * @default null\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\t/**\n\t\t * Which type of pagination should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t * @type string\n\t\t * @default two_button\n\t\t */\n\t\t\"sPaginationType\": \"two_button\",\n\t\n\t\t/**\n\t\t * The state duration (for `stateSave`) in seconds.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t * @type int\n\t\t * @default 0\n\t\t */\n\t\t\"iStateDuration\": 0,\n\t\n\t\t/**\n\t\t * Array of callback functions for state saving. Each array element is an\n\t\t * object with the following parameters:\n\t\t * <ul>\n\t\t * <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t * and the JSON string to save that has been thus far created. Returns\n\t\t * a JSON string to be inserted into a json object\n\t\t * (i.e. '\"param\": [ 0, 1, 2]')</li>\n\t\t * <li>string:sName - name of callback</li>\n\t\t * </ul>\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoStateSave\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for state loading. Each array element is an\n\t\t * object with the following parameters:\n\t\t * <ul>\n\t\t * <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t * and the object stored. May return false to cancel state loading</li>\n\t\t * <li>string:sName - name of callback</li>\n\t\t * </ul>\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoStateLoad\": [],\n\t\n\t\t/**\n\t\t * State that was saved. Useful for back reference\n\t\t * @type object\n\t\t * @default null\n\t\t */\n\t\t\"oSavedState\": null,\n\t\n\t\t/**\n\t\t * State that was loaded. Useful for back reference\n\t\t * @type object\n\t\t * @default null\n\t\t */\n\t\t\"oLoadedState\": null,\n\t\n\t\t/**\n\t\t * Source url for AJAX data for the table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t * @type string\n\t\t * @default null\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\t/**\n\t\t * Property from a given object from which to read the table data from. This\n\t\t * can be an empty string (when not server-side processing), in which case\n\t\t * it is assumed an an array is given directly.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t * @type string\n\t\t */\n\t\t\"sAjaxDataProp\": null,\n\t\n\t\t/**\n\t\t * The last jQuery XHR object that was used for server-side data gathering.\n\t\t * This can be used for working with the XHR information in one of the\n\t\t * callbacks\n\t\t * @type object\n\t\t * @default null\n\t\t */\n\t\t\"jqXHR\": null,\n\t\n\t\t/**\n\t\t * JSON returned from the server in the last Ajax request\n\t\t * @type object\n\t\t * @default undefined\n\t\t */\n\t\t\"json\": undefined,\n\t\n\t\t/**\n\t\t * Data submitted as part of the last Ajax request\n\t\t * @type object\n\t\t * @default undefined\n\t\t */\n\t\t\"oAjaxData\": undefined,\n\t\n\t\t/**\n\t\t * Function to get the server-side data.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t * @type function\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\t/**\n\t\t * Functions which are called prior to sending an Ajax request so extra\n\t\t * parameters can easily be sent to the server\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoServerParams\": [],\n\t\n\t\t/**\n\t\t * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if\n\t\t * required).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t * @type string\n\t\t */\n\t\t\"sServerMethod\": null,\n\t\n\t\t/**\n\t\t * Format numbers for display.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t * @type function\n\t\t */\n\t\t\"fnFormatNumber\": null,\n\t\n\t\t/**\n\t\t * List of options that can be used for the user selectable length menu.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aLengthMenu\": null,\n\t\n\t\t/**\n\t\t * Counter for the draws that the table does. Also used as a tracker for\n\t\t * server-side processing\n\t\t * @type int\n\t\t * @default 0\n\t\t */\n\t\t\"iDraw\": 0,\n\t\n\t\t/**\n\t\t * Indicate if a redraw is being done - useful for Ajax\n\t\t * @type boolean\n\t\t * @default false\n\t\t */\n\t\t\"bDrawing\": false,\n\t\n\t\t/**\n\t\t * Draw index (iDraw) of the last error when parsing the returned data\n\t\t * @type int\n\t\t * @default -1\n\t\t */\n\t\t\"iDrawError\": -1,\n\t\n\t\t/**\n\t\t * Paging display length\n\t\t * @type int\n\t\t * @default 10\n\t\t */\n\t\t\"_iDisplayLength\": 10,\n\t\n\t\t/**\n\t\t * Paging start point - aiDisplay index\n\t\t * @type int\n\t\t * @default 0\n\t\t */\n\t\t\"_iDisplayStart\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the result set\n\t\t * (i.e. before filtering), Use fnRecordsTotal rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t * @type int\n\t\t * @default 0\n\t\t * @private\n\t\t */\n\t\t\"_iRecordsTotal\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the current display set\n\t\t * (i.e. after filtering). Use fnRecordsDisplay rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t * @type boolean\n\t\t * @default 0\n\t\t * @private\n\t\t */\n\t\t\"_iRecordsDisplay\": 0,\n\t\n\t\t/**\n\t\t * The classes to use for the table\n\t\t * @type object\n\t\t * @default {}\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if filtering has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t * @type boolean\n\t\t * @default false\n\t\t * @deprecated\n\t\t */\n\t\t\"bFiltered\": false,\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if sorting has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t * @type boolean\n\t\t * @default false\n\t\t * @deprecated\n\t\t */\n\t\t\"bSorted\": false,\n\t\n\t\t/**\n\t\t * Indicate that if multiple rows are in the header and there is more than\n\t\t * one unique cell per column, if the top one (true) or bottom one (false)\n\t\t * should be used for sorting / title by DataTables.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t * @type boolean\n\t\t */\n\t\t\"bSortCellsTop\": null,\n\t\n\t\t/**\n\t\t * Initialisation object that is used for the table\n\t\t * @type object\n\t\t * @default null\n\t\t */\n\t\t\"oInit\": null,\n\t\n\t\t/**\n\t\t * Destroy callback functions - for plug-ins to attach themselves to the\n\t\t * destroy so they can clean up markup and events.\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aoDestroyCallback\": [],\n\t\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, before filtering\n\t\t * @type function\n\t\t */\n\t\t\"fnRecordsTotal\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsTotal * 1 :\n\t\t\t\tthis.aiDisplayMaster.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, after filtering\n\t\t * @type function\n\t\t */\n\t\t\"fnRecordsDisplay\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsDisplay * 1 :\n\t\t\t\tthis.aiDisplay.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the display end point - aiDisplay index\n\t\t * @type function\n\t\t */\n\t\t\"fnDisplayEnd\": function ()\n\t\t{\n\t\t\tvar\n\t\t\t\tlen = this._iDisplayLength,\n\t\t\t\tstart = this._iDisplayStart,\n\t\t\t\tcalc = start + len,\n\t\t\t\trecords = this.aiDisplay.length,\n\t\t\t\tfeatures = this.oFeatures,\n\t\t\t\tpaginate = features.bPaginate;\n\t\n\t\t\tif ( features.bServerSide ) {\n\t\t\t\treturn paginate === false || len === -1 ?\n\t\t\t\t\tstart + records :\n\t\t\t\t\tMath.min( start+len, this._iRecordsDisplay );\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn ! paginate || calc>records || len===-1 ?\n\t\t\t\t\trecords :\n\t\t\t\t\tcalc;\n\t\t\t}\n\t\t},\n\t\n\t\t/**\n\t\t * The DataTables object for this table\n\t\t * @type object\n\t\t * @default null\n\t\t */\n\t\t\"oInstance\": null,\n\t\n\t\t/**\n\t\t * Unique identifier for each instance of the DataTables object. If there\n\t\t * is an ID on the table node, then it takes that value, otherwise an\n\t\t * incrementing internal counter is used.\n\t\t * @type string\n\t\t * @default null\n\t\t */\n\t\t\"sInstance\": null,\n\t\n\t\t/**\n\t\t * tabindex attribute value that is added to DataTables control elements, allowing\n\t\t * keyboard navigation of the table and its controls.\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollHead\": null,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollFoot\": null,\n\t\n\t\t/**\n\t\t * Last applied sort\n\t\t * @type array\n\t\t * @default []\n\t\t */\n\t\t\"aLastSort\": [],\n\t\n\t\t/**\n\t\t * Stored plug-in instances\n\t\t * @type object\n\t\t * @default {}\n\t\t */\n\t\t\"oPlugins\": {},\n\t\n\t\t/**\n\t\t * Function used to get a row's id from the row's data\n\t\t * @type function\n\t\t * @default null\n\t\t */\n\t\t\"rowIdFn\": null,\n\t\n\t\t/**\n\t\t * Data location where to store a row's id\n\t\t * @type string\n\t\t * @default null\n\t\t */\n\t\t\"rowId\": null\n\t};\n\n\t/**\n\t * Extension object for DataTables that is used to provide all extension\n\t * options.\n\t *\n\t * Note that the `DataTable.ext` object is available through\n\t * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is\n\t * also aliased to `jQuery.fn.dataTableExt` for historic reasons.\n\t * @namespace\n\t * @extends DataTable.models.ext\n\t */\n\t\n\t\n\t/**\n\t * DataTables extensions\n\t * \n\t * This namespace acts as a collection area for plug-ins that can be used to\n\t * extend DataTables capabilities. Indeed many of the build in methods\n\t * use this method to provide their own capabilities (sorting methods for\n\t * example).\n\t *\n\t * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy\n\t * reasons\n\t *\n\t * @namespace\n\t */\n\tDataTable.ext = _ext = {\n\t\t/**\n\t\t * Buttons. For use with the Buttons extension for DataTables. This is\n\t\t * defined here so other extensions can define buttons regardless of load\n\t\t * order. It is _not_ used by DataTables core.\n\t\t *\n\t\t * @type object\n\t\t * @default {}\n\t\t */\n\t\tbuttons: {},\n\t\n\t\n\t\t/**\n\t\t * Element class names\n\t\t *\n\t\t * @type object\n\t\t * @default {}\n\t\t */\n\t\tclasses: {},\n\t\n\t\n\t\t/**\n\t\t * DataTables build type (expanded by the download builder)\n\t\t *\n\t\t * @type string\n\t\t */\n\t\tbuilder: \"-source-\",\n\t\n\t\n\t\t/**\n\t\t * Error reporting.\n\t\t * \n\t\t * How should DataTables report an error. Can take the value 'alert',\n\t\t * 'throw', 'none' or a function.\n\t\t *\n\t\t * @type string|function\n\t\t * @default alert\n\t\t */\n\t\terrMode: \"alert\",\n\t\n\t\n\t\t/**\n\t\t * Feature plug-ins.\n\t\t * \n\t\t * This is an array of objects which describe the feature plug-ins that are\n\t\t * available to DataTables. These feature plug-ins are then available for\n\t\t * use through the `dom` initialisation option.\n\t\t * \n\t\t * Each feature plug-in is described by an object which must have the\n\t\t * following properties:\n\t\t * \n\t\t * * `fnInit` - function that is used to initialise the plug-in,\n\t\t * * `cFeature` - a character so the feature can be enabled by the `dom`\n\t\t * instillation option. This is case sensitive.\n\t\t *\n\t\t * The `fnInit` function has the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t * {@link DataTable.models.oSettings}\n\t\t *\n\t\t * And the following return is expected:\n\t\t * \n\t\t * * {node|null} The element which contains your feature. Note that the\n\t\t * return may also be void if your plug-in does not require to inject any\n\t\t * DOM elements into DataTables control (`dom`) - for example this might\n\t\t * be useful when developing a plug-in which allows table control via\n\t\t * keyboard entry\n\t\t *\n\t\t * @type array\n\t\t *\n\t\t * @example\n\t\t * $.fn.dataTable.ext.features.push( {\n\t\t * \"fnInit\": function( oSettings ) {\n\t\t * return new TableTools( { \"oDTSettings\": oSettings } );\n\t\t * },\n\t\t * \"cFeature\": \"T\"\n\t\t * } );\n\t\t */\n\t\tfeature: [],\n\t\n\t\n\t\t/**\n\t\t * Row searching.\n\t\t * \n\t\t * This method of searching is complimentary to the default type based\n\t\t * searching, and a lot more comprehensive as it allows you complete control\n\t\t * over the searching logic. Each element in this array is a function\n\t\t * (parameters described below) that is called for every row in the table,\n\t\t * and your logic decides if it should be included in the searching data set\n\t\t * or not.\n\t\t *\n\t\t * Searching functions have the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t * {@link DataTable.models.oSettings}\n\t\t * 2. `{array|object}` Data for the row to be processed (same as the\n\t\t * original format that was passed in as the data source, or an array\n\t\t * from a DOM data source\n\t\t * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which\n\t\t * can be useful to retrieve the `TR` element if you need DOM interaction.\n\t\t *\n\t\t * And the following return is expected:\n\t\t *\n\t\t * * {boolean} Include the row in the searched result set (true) or not\n\t\t * (false)\n\t\t *\n\t\t * Note that as with the main search ability in DataTables, technically this\n\t\t * is \"filtering\", since it is subtractive. However, for consistency in\n\t\t * naming we call it searching here.\n\t\t *\n\t\t * @type array\n\t\t * @default []\n\t\t *\n\t\t * @example\n\t\t * // The following example shows custom search being applied to the\n\t\t * // fourth column (i.e. the data[3] index) based on two input values\n\t\t * // from the end-user, matching the data in a certain range.\n\t\t * $.fn.dataTable.ext.search.push(\n\t\t * function( settings, data, dataIndex ) {\n\t\t * var min = document.getElementById('min').value * 1;\n\t\t * var max = document.getElementById('max').value * 1;\n\t\t * var version = data[3] == \"-\" ? 0 : data[3]*1;\n\t\t *\n\t\t * if ( min == \"\" && max == \"\" ) {\n\t\t * return true;\n\t\t * }\n\t\t * else if ( min == \"\" && version < max ) {\n\t\t * return true;\n\t\t * }\n\t\t * else if ( min < version && \"\" == max ) {\n\t\t * return true;\n\t\t * }\n\t\t * else if ( min < version && version < max ) {\n\t\t * return true;\n\t\t * }\n\t\t * return false;\n\t\t * }\n\t\t * );\n\t\t */\n\t\tsearch: [],\n\t\n\t\n\t\t/**\n\t\t * Selector extensions\n\t\t *\n\t\t * The `selector` option can be used to extend the options available for the\n\t\t * selector modifier options (`selector-modifier` object data type) that\n\t\t * each of the three built in selector types offer (row, column and cell +\n\t\t * their plural counterparts). For example the Select extension uses this\n\t\t * mechanism to provide an option to select only rows, columns and cells\n\t\t * that have been marked as selected by the end user (`{selected: true}`),\n\t\t * which can be used in conjunction with the existing built in selector\n\t\t * options.\n\t\t *\n\t\t * Each property is an array to which functions can be pushed. The functions\n\t\t * take three attributes:\n\t\t *\n\t\t * * Settings object for the host table\n\t\t * * Options object (`selector-modifier` object type)\n\t\t * * Array of selected item indexes\n\t\t *\n\t\t * The return is an array of the resulting item indexes after the custom\n\t\t * selector has been applied.\n\t\t *\n\t\t * @type object\n\t\t */\n\t\tselector: {\n\t\t\tcell: [],\n\t\t\tcolumn: [],\n\t\t\trow: []\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Internal functions, exposed for used in plug-ins.\n\t\t * \n\t\t * Please note that you should not need to use the internal methods for\n\t\t * anything other than a plug-in (and even then, try to avoid if possible).\n\t\t * The internal function may change between releases.\n\t\t *\n\t\t * @type object\n\t\t * @default {}\n\t\t */\n\t\tinternal: {},\n\t\n\t\n\t\t/**\n\t\t * Legacy configuration options. Enable and disable legacy options that\n\t\t * are available in DataTables.\n\t\t *\n\t\t * @type object\n\t\t */\n\t\tlegacy: {\n\t\t\t/**\n\t\t\t * Enable / disable DataTables 1.9 compatible server-side processing\n\t\t\t * requests\n\t\t\t *\n\t\t\t * @type boolean\n\t\t\t * @default null\n\t\t\t */\n\t\t\tajax: null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Pagination plug-in methods.\n\t\t * \n\t\t * Each entry in this object is a function and defines which buttons should\n\t\t * be shown by the pagination rendering method that is used for the table:\n\t\t * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the\n\t\t * buttons are displayed in the document, while the functions here tell it\n\t\t * what buttons to display. This is done by returning an array of button\n\t\t * descriptions (what each button will do).\n\t\t *\n\t\t * Pagination types (the four built in options and any additional plug-in\n\t\t * options defined here) can be used through the `paginationType`\n\t\t * initialisation parameter.\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{int} page` The current page index\n\t\t * 2. `{int} pages` The number of pages in the table\n\t\t *\n\t\t * Each function is expected to return an array where each element of the\n\t\t * array can be one of:\n\t\t *\n\t\t * * `first` - Jump to first page when activated\n\t\t * * `last` - Jump to last page when activated\n\t\t * * `previous` - Show previous page when activated\n\t\t * * `next` - Show next page when activated\n\t\t * * `{int}` - Show page of the index given\n\t\t * * `{array}` - A nested array containing the above elements to add a\n\t\t * containing 'DIV' element (might be useful for styling).\n\t\t *\n\t\t * Note that DataTables v1.9- used this object slightly differently whereby\n\t\t * an object with two functions would be defined for each plug-in. That\n\t\t * ability is still supported by DataTables 1.10+ to provide backwards\n\t\t * compatibility, but this option of use is now decremented and no longer\n\t\t * documented in DataTables 1.10+.\n\t\t *\n\t\t * @type object\n\t\t * @default {}\n\t\t *\n\t\t * @example\n\t\t * // Show previous, next and current page buttons only\n\t\t * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {\n\t\t * return [ 'previous', page, 'next' ];\n\t\t * };\n\t\t */\n\t\tpager: {},\n\t\n\t\n\t\trenderer: {\n\t\t\tpageButton: {},\n\t\t\theader: {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Ordering plug-ins - custom data source\n\t\t * \n\t\t * The extension options for ordering of data available here is complimentary\n\t\t * to the default type based ordering that DataTables typically uses. It\n\t\t * allows much greater control over the the data that is being used to\n\t\t * order a column, but is necessarily therefore more complex.\n\t\t * \n\t\t * This type of ordering is useful if you want to do ordering based on data\n\t\t * live from the DOM (for example the contents of an 'input' element) rather\n\t\t * than just the static string that DataTables knows of.\n\t\t * \n\t\t * The way these plug-ins work is that you create an array of the values you\n\t\t * wish to be ordering for the column in question and then return that\n\t\t * array. The data in the array much be in the index order of the rows in\n\t\t * the table (not the currently ordering order!). Which order data gathering\n\t\t * function is run here depends on the `dt-init columns.orderDataType`\n\t\t * parameter that is used for the column (if any).\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t * {@link DataTable.models.oSettings}\n\t\t * 2. `{int}` Target column index\n\t\t *\n\t\t * Each function is expected to return an array:\n\t\t *\n\t\t * * `{array}` Data for the column to be ordering upon\n\t\t *\n\t\t * @type array\n\t\t *\n\t\t * @example\n\t\t * // Ordering using `input` node values\n\t\t * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )\n\t\t * {\n\t\t * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {\n\t\t * return $('input', td).val();\n\t\t * } );\n\t\t * }\n\t\t */\n\t\torder: {},\n\t\n\t\n\t\t/**\n\t\t * Type based plug-ins.\n\t\t *\n\t\t * Each column in DataTables has a type assigned to it, either by automatic\n\t\t * detection or by direct assignment using the `type` option for the column.\n\t\t * The type of a column will effect how it is ordering and search (plug-ins\n\t\t * can also make use of the column type if required).\n\t\t *\n\t\t * @namespace\n\t\t */\n\t\ttype: {\n\t\t\t/**\n\t\t\t * Type detection functions.\n\t\t\t *\n\t\t\t * The functions defined in this object are used to automatically detect\n\t\t\t * a column's type, making initialisation of DataTables super easy, even\n\t\t\t * when complex data is in the table.\n\t\t\t *\n\t\t\t * The functions defined take two parameters:\n\t\t\t *\n\t\t * 1. `{*}` Data from the column cell to be analysed\n\t\t * 2. `{settings}` DataTables settings object. This can be used to\n\t\t * perform context specific type detection - for example detection\n\t\t * based on language settings such as using a comma for a decimal\n\t\t * place. Generally speaking the options from the settings will not\n\t\t * be required\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Data type detected, or null if unknown (and thus\n\t\t\t * pass it on to the other type detection functions.\n\t\t\t *\n\t\t\t * @type array\n\t\t\t *\n\t\t\t * @example\n\t\t\t * // Currency type detection plug-in:\n\t\t\t * $.fn.dataTable.ext.type.detect.push(\n\t\t\t * function ( data, settings ) {\n\t\t\t * // Check the numeric part\n\t\t\t * if ( ! data.substring(1).match(/[0-9]/) ) {\n\t\t\t * return null;\n\t\t\t * }\n\t\t\t *\n\t\t\t * // Check prefixed by currency\n\t\t\t * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) {\n\t\t\t * return 'currency';\n\t\t\t * }\n\t\t\t * return null;\n\t\t\t * }\n\t\t\t * );\n\t\t\t */\n\t\t\tdetect: [],\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based search formatting.\n\t\t\t *\n\t\t\t * The type based searching functions can be used to pre-format the\n\t\t\t * data to be search on. For example, it can be used to strip HTML\n\t\t\t * tags or to de-format telephone numbers for numeric only searching.\n\t\t\t *\n\t\t\t * Note that is a search is not defined for a column of a given type,\n\t\t\t * no search formatting will be performed.\n\t\t\t * \n\t\t\t * Pre-processing of searching data plug-ins - When you assign the sType\n\t\t\t * for a column (or have it automatically detected for you by DataTables\n\t\t\t * or a type detection plug-in), you will typically be using this for\n\t\t\t * custom sorting, but it can also be used to provide custom searching\n\t\t\t * by allowing you to pre-processing the data and returning the data in\n\t\t\t * the format that should be searched upon. This is done by adding\n\t\t\t * functions this object with a parameter name which matches the sType\n\t\t\t * for that target column. This is the corollary of <i>afnSortData</i>\n\t\t\t * for searching data.\n\t\t\t *\n\t\t\t * The functions defined take a single parameter:\n\t\t\t *\n\t\t * 1. `{*}` Data from the column cell to be prepared for searching\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Formatted string that will be used for the searching.\n\t\t\t *\n\t\t\t * @type object\n\t\t\t * @default {}\n\t\t\t *\n\t\t\t * @example\n\t\t\t * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {\n\t\t\t * return d.replace(/\\n/g,\" \").replace( /<.*?>/g, \"\" );\n\t\t\t * }\n\t\t\t */\n\t\t\tsearch: {},\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based ordering.\n\t\t\t *\n\t\t\t * The column type tells DataTables what ordering to apply to the table\n\t\t\t * when a column is sorted upon. The order for each type that is defined,\n\t\t\t * is defined by the functions available in this object.\n\t\t\t *\n\t\t\t * Each ordering option can be described by three properties added to\n\t\t\t * this object:\n\t\t\t *\n\t\t\t * * `{type}-pre` - Pre-formatting function\n\t\t\t * * `{type}-asc` - Ascending order function\n\t\t\t * * `{type}-desc` - Descending order function\n\t\t\t *\n\t\t\t * All three can be used together, only `{type}-pre` or only\n\t\t\t * `{type}-asc` and `{type}-desc` together. It is generally recommended\n\t\t\t * that only `{type}-pre` is used, as this provides the optimal\n\t\t\t * implementation in terms of speed, although the others are provided\n\t\t\t * for compatibility with existing Javascript sort functions.\n\t\t\t *\n\t\t\t * `{type}-pre`: Functions defined take a single parameter:\n\t\t\t *\n\t\t * 1. `{*}` Data from the column cell to be prepared for ordering\n\t\t\t *\n\t\t\t * And return:\n\t\t\t *\n\t\t\t * * `{*}` Data to be sorted upon\n\t\t\t *\n\t\t\t * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort\n\t\t\t * functions, taking two parameters:\n\t\t\t *\n\t\t * 1. `{*}` Data to compare to the second parameter\n\t\t * 2. `{*}` Data to compare to the first parameter\n\t\t\t *\n\t\t\t * And returning:\n\t\t\t *\n\t\t\t * * `{*}` Ordering match: <0 if first parameter should be sorted lower\n\t\t\t * than the second parameter, ===0 if the two parameters are equal and\n\t\t\t * >0 if the first parameter should be sorted height than the second\n\t\t\t * parameter.\n\t\t\t * \n\t\t\t * @type object\n\t\t\t * @default {}\n\t\t\t *\n\t\t\t * @example\n\t\t\t * // Numeric ordering of formatted numbers with a pre-formatter\n\t\t\t * $.extend( $.fn.dataTable.ext.type.order, {\n\t\t\t * \"string-pre\": function(x) {\n\t\t\t * a = (a === \"-\" || a === \"\") ? 0 : a.replace( /[^\\d\\-\\.]/g, \"\" );\n\t\t\t * return parseFloat( a );\n\t\t\t * }\n\t\t\t * } );\n\t\t\t *\n\t\t\t * @example\n\t\t\t * // Case-sensitive string ordering, with no pre-formatting method\n\t\t\t * $.extend( $.fn.dataTable.ext.order, {\n\t\t\t * \"string-case-asc\": function(x,y) {\n\t\t\t * return ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t\t * },\n\t\t\t * \"string-case-desc\": function(x,y) {\n\t\t\t * return ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t\t * }\n\t\t\t * } );\n\t\t\t */\n\t\t\torder: {}\n\t\t},\n\t\n\t\t/**\n\t\t * Unique DataTables instance counter\n\t\t *\n\t\t * @type int\n\t\t * @private\n\t\t */\n\t\t_unique: 0,\n\t\n\t\n\t\t//\n\t\t// Depreciated\n\t\t// The following properties are retained for backwards compatibility only.\n\t\t// The should not be used in new projects and will be removed in a future\n\t\t// version\n\t\t//\n\t\n\t\t/**\n\t\t * Version check function.\n\t\t * @type function\n\t\t * @depreciated Since 1.10\n\t\t */\n\t\tfnVersionCheck: DataTable.fnVersionCheck,\n\t\n\t\n\t\t/**\n\t\t * Index for what 'this' index API functions should use\n\t\t * @type int\n\t\t * @deprecated Since v1.10\n\t\t */\n\t\tiApiIndex: 0,\n\t\n\t\n\t\t/**\n\t\t * jQuery UI class container\n\t\t * @type object\n\t\t * @deprecated Since v1.10\n\t\t */\n\t\toJUIClasses: {},\n\t\n\t\n\t\t/**\n\t\t * Software version\n\t\t * @type string\n\t\t * @deprecated Since v1.10\n\t\t */\n\t\tsVersion: DataTable.version\n\t};\n\t\n\t\n\t//\n\t// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts\n\t//\n\t$.extend( _ext, {\n\t\tafnFiltering: _ext.search,\n\t\taTypes: _ext.type.detect,\n\t\tofnSearch: _ext.type.search,\n\t\toSort: _ext.type.order,\n\t\tafnSortData: _ext.order,\n\t\taoFeatures: _ext.feature,\n\t\toApi: _ext.internal,\n\t\toStdClasses: _ext.classes,\n\t\toPagination: _ext.pager\n\t} );\n\t\n\t\n\t$.extend( DataTable.ext.classes, {\n\t\t\"sTable\": \"dataTable\",\n\t\t\"sNoFooter\": \"no-footer\",\n\t\n\t\t/* Paging buttons */\n\t\t\"sPageButton\": \"paginate_button\",\n\t\t\"sPageButtonActive\": \"current\",\n\t\t\"sPageButtonDisabled\": \"disabled\",\n\t\n\t\t/* Striping classes */\n\t\t\"sStripeOdd\": \"odd\",\n\t\t\"sStripeEven\": \"even\",\n\t\n\t\t/* Empty row */\n\t\t\"sRowEmpty\": \"dataTables_empty\",\n\t\n\t\t/* Features */\n\t\t\"sWrapper\": \"dataTables_wrapper\",\n\t\t\"sFilter\": \"dataTables_filter\",\n\t\t\"sInfo\": \"dataTables_info\",\n\t\t\"sPaging\": \"dataTables_paginate paging_\", /* Note that the type is postfixed */\n\t\t\"sLength\": \"dataTables_length\",\n\t\t\"sProcessing\": \"dataTables_processing\",\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\": \"sorting_asc\",\n\t\t\"sSortDesc\": \"sorting_desc\",\n\t\t\"sSortable\": \"sorting\", /* Sortable in both directions */\n\t\t\"sSortableAsc\": \"sorting_desc_disabled\",\n\t\t\"sSortableDesc\": \"sorting_asc_disabled\",\n\t\t\"sSortableNone\": \"sorting_disabled\",\n\t\t\"sSortColumn\": \"sorting_\", /* Note that an int is postfixed for the sorting order */\n\t\n\t\t/* Filtering */\n\t\t\"sFilterInput\": \"\",\n\t\n\t\t/* Page length */\n\t\t\"sLengthSelect\": \"\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollWrapper\": \"dataTables_scroll\",\n\t\t\"sScrollHead\": \"dataTables_scrollHead\",\n\t\t\"sScrollHeadInner\": \"dataTables_scrollHeadInner\",\n\t\t\"sScrollBody\": \"dataTables_scrollBody\",\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot\",\n\t\t\"sScrollFootInner\": \"dataTables_scrollFootInner\",\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\": \"\",\n\t\t\"sFooterTH\": \"\",\n\t\n\t\t// Deprecated\n\t\t\"sSortJUIAsc\": \"\",\n\t\t\"sSortJUIDesc\": \"\",\n\t\t\"sSortJUI\": \"\",\n\t\t\"sSortJUIAscAllowed\": \"\",\n\t\t\"sSortJUIDescAllowed\": \"\",\n\t\t\"sSortJUIWrapper\": \"\",\n\t\t\"sSortIcon\": \"\",\n\t\t\"sJUIHeader\": \"\",\n\t\t\"sJUIFooter\": \"\"\n\t} );\n\t\n\t\n\tvar extPagination = DataTable.ext.pager;\n\t\n\tfunction _numbers ( page, pages ) {\n\t\tvar\n\t\t\tnumbers = [],\n\t\t\tbuttons = extPagination.numbers_length,\n\t\t\thalf = Math.floor( buttons / 2 ),\n\t\t\ti = 1;\n\t\n\t\tif ( pages <= buttons ) {\n\t\t\tnumbers = _range( 0, pages );\n\t\t}\n\t\telse if ( page <= half ) {\n\t\t\tnumbers = _range( 0, buttons-2 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t}\n\t\telse if ( page >= pages - 1 - half ) {\n\t\t\tnumbers = _range( pages-(buttons-2), pages );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\telse {\n\t\t\tnumbers = _range( page-half+2, page+half-1 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' );\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\n\t\tnumbers.DT_el = 'span';\n\t\treturn numbers;\n\t}\n\t\n\t\n\t$.extend( extPagination, {\n\t\tsimple: function ( page, pages ) {\n\t\t\treturn [ 'previous', 'next' ];\n\t\t},\n\t\n\t\tfull: function ( page, pages ) {\n\t\t\treturn [ 'first', 'previous', 'next', 'last' ];\n\t\t},\n\t\n\t\tnumbers: function ( page, pages ) {\n\t\t\treturn [ _numbers(page, pages) ];\n\t\t},\n\t\n\t\tsimple_numbers: function ( page, pages ) {\n\t\t\treturn [ 'previous', _numbers(page, pages), 'next' ];\n\t\t},\n\t\n\t\tfull_numbers: function ( page, pages ) {\n\t\t\treturn [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];\n\t\t},\n\t\t\n\t\tfirst_last_numbers: function (page, pages) {\n\t \t\treturn ['first', _numbers(page, pages), 'last'];\n\t \t},\n\t\n\t\t// For testing and plug-ins to use\n\t\t_numbers: _numbers,\n\t\n\t\t// Number of number buttons (including ellipsis) to show. _Must be odd!_\n\t\tnumbers_length: 7\n\t} );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\tpageButton: {\n\t\t\t_: function ( settings, host, idx, buttons, page, pages ) {\n\t\t\t\tvar classes = settings.oClasses;\n\t\t\t\tvar lang = settings.oLanguage.oPaginate;\n\t\t\t\tvar aria = settings.oLanguage.oAria.paginate || {};\n\t\t\t\tvar btnDisplay, btnClass, counter=0;\n\t\n\t\t\t\tvar attach = function( container, buttons ) {\n\t\t\t\t\tvar i, ien, node, button, tabIndex;\n\t\t\t\t\tvar disabledClass = classes.sPageButtonDisabled;\n\t\t\t\t\tvar clickHandler = function ( e ) {\n\t\t\t\t\t\t_fnPageChange( settings, e.data.action, true );\n\t\t\t\t\t};\n\t\n\t\t\t\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tbutton = buttons[i];\n\t\n\t\t\t\t\t\tif ( Array.isArray( button ) ) {\n\t\t\t\t\t\t\tvar inner = $( '<'+(button.DT_el || 'div')+'/>' )\n\t\t\t\t\t\t\t\t.appendTo( container );\n\t\t\t\t\t\t\tattach( inner, button );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tbtnDisplay = null;\n\t\t\t\t\t\t\tbtnClass = button;\n\t\t\t\t\t\t\ttabIndex = settings.iTabIndex;\n\t\n\t\t\t\t\t\t\tswitch ( button ) {\n\t\t\t\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\t\t\t\tcontainer.append('<span class=\"ellipsis\">…</span>');\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'first':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\n\t\t\t\t\t\t\t\t\tif ( page === 0 ) {\n\t\t\t\t\t\t\t\t\t\ttabIndex = -1;\n\t\t\t\t\t\t\t\t\t\tbtnClass += ' ' + disabledClass;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\n\t\t\t\t\t\t\t\t\tif ( page === 0 ) {\n\t\t\t\t\t\t\t\t\t\ttabIndex = -1;\n\t\t\t\t\t\t\t\t\t\tbtnClass += ' ' + disabledClass;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'next':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\n\t\t\t\t\t\t\t\t\tif ( pages === 0 || page === pages-1 ) {\n\t\t\t\t\t\t\t\t\t\ttabIndex = -1;\n\t\t\t\t\t\t\t\t\t\tbtnClass += ' ' + disabledClass;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'last':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\n\t\t\t\t\t\t\t\t\tif ( pages === 0 || page === pages-1 ) {\n\t\t\t\t\t\t\t\t\t\ttabIndex = -1;\n\t\t\t\t\t\t\t\t\t\tbtnClass += ' ' + disabledClass;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tbtnDisplay = settings.fnFormatNumber( button + 1 );\n\t\t\t\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t\t\t\tclasses.sPageButtonActive : '';\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\tif ( btnDisplay !== null ) {\n\t\t\t\t\t\t\t\tnode = $('<a>', {\n\t\t\t\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t\t\t\t'tabindex': tabIndex,\n\t\t\t\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t\t\t\t.appendTo( container );\n\t\n\t\t\t\t\t\t\t\t_fnBindAction(\n\t\t\t\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t\t\t\t);\n\t\n\t\t\t\t\t\t\t\tcounter++;\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\t\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame. Try / catch the error. Not good for\n\t\t\t\t// accessibility, but neither are frames.\n\t\t\t\tvar activeEl;\n\t\n\t\t\t\ttry {\n\t\t\t\t\t// Because this approach is destroying and recreating the paging\n\t\t\t\t\t// elements, focus is lost on the select button which is bad for\n\t\t\t\t\t// accessibility. So we want to restore focus once the draw has\n\t\t\t\t\t// completed\n\t\t\t\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t\t\t\t}\n\t\t\t\tcatch (e) {}\n\t\n\t\t\t\tattach( $(host).empty(), buttons );\n\t\n\t\t\t\tif ( activeEl !== undefined ) {\n\t\t\t\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t\n\t\n\t// Built in type detection. See model.ext.aTypes for information about\n\t// what is required from this methods.\n\t$.extend( DataTable.ext.type.detect, [\n\t\t// Plain numbers - first since V8 detects some plain numbers as dates\n\t\t// e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal ) ? 'num'+decimal : null;\n\t\t},\n\t\n\t\t// Dates (only those recognised by the browser's Date.parse)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\t// V8 tries _very_ hard to make a string passed into `Date.parse()`\n\t\t\t// valid, so we need to use a regex to restrict date formats. Use a\n\t\t\t// plug-in for anything other than ISO8601 style strings\n\t\t\tif ( d && !(d instanceof Date) && ! _re_date.test(d) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tvar parsed = Date.parse(d);\n\t\t\treturn (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;\n\t\t},\n\t\n\t\t// Formatted numbers\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric, formatted\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML (this is strict checking - there must be html)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\treturn _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?\n\t\t\t\t'html' : null;\n\t\t}\n\t] );\n\t\n\t\n\t\n\t// Filter formatting functions. See model.ext.ofnSearch for information about\n\t// what is required from these methods.\n\t// \n\t// Note that additional search methods are added for the html numbers and\n\t// html formatted numbers by `_addNumericSort()` when we know what the decimal\n\t// place is\n\t\n\t\n\t$.extend( DataTable.ext.type.search, {\n\t\thtml: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata\n\t\t\t\t\t\t.replace( _re_new_lines, \" \" )\n\t\t\t\t\t\t.replace( _re_html, \"\" ) :\n\t\t\t\t\t'';\n\t\t},\n\t\n\t\tstring: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata.replace( _re_new_lines, \" \" ) :\n\t\t\t\t\tdata;\n\t\t}\n\t} );\n\t\n\t\n\t\n\tvar __numericReplace = function ( d, decimalPlace, re1, re2 ) {\n\t\tif ( d !== 0 && (!d || d === '-') ) {\n\t\t\treturn -Infinity;\n\t\t}\n\t\n\t\t// If a decimal place other than `.` is used, it needs to be given to the\n\t\t// function so we can detect it and replace with a `.` which is the only\n\t\t// decimal place Javascript recognises - it is not locale aware.\n\t\tif ( decimalPlace ) {\n\t\t\td = _numToDecimal( d, decimalPlace );\n\t\t}\n\t\n\t\tif ( d.replace ) {\n\t\t\tif ( re1 ) {\n\t\t\t\td = d.replace( re1, '' );\n\t\t\t}\n\t\n\t\t\tif ( re2 ) {\n\t\t\t\td = d.replace( re2, '' );\n\t\t\t}\n\t\t}\n\t\n\t\treturn d * 1;\n\t};\n\t\n\t\n\t// Add the numeric 'deformatting' functions for sorting and search. This is done\n\t// in a function to provide an easy ability for the language options to add\n\t// additional methods if a non-period decimal place is used.\n\tfunction _addNumericSort ( decimalPlace ) {\n\t\t$.each(\n\t\t\t{\n\t\t\t\t// Plain numbers\n\t\t\t\t\"num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace );\n\t\t\t\t},\n\t\n\t\t\t\t// Formatted numbers\n\t\t\t\t\"num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_formatted_numeric );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric\n\t\t\t\t\"html-num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric, formatted\n\t\t\t\t\"html-num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );\n\t\t\t\t}\n\t\t\t},\n\t\t\tfunction ( key, fn ) {\n\t\t\t\t// Add the ordering method\n\t\t\t\t_ext.type.order[ key+decimalPlace+'-pre' ] = fn;\n\t\n\t\t\t\t// For HTML types add a search formatter that will strip the HTML\n\t\t\t\tif ( key.match(/^html\\-/) ) {\n\t\t\t\t\t_ext.type.search[ key+decimalPlace ] = _ext.type.search.html;\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\t\n\t\n\t// Default sort methods\n\t$.extend( _ext.type.order, {\n\t\t// Dates\n\t\t\"date-pre\": function ( d ) {\n\t\t\tvar ts = Date.parse( d );\n\t\t\treturn isNaN(ts) ? -Infinity : ts;\n\t\t},\n\t\n\t\t// html\n\t\t\"html-pre\": function ( a ) {\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ta.replace ?\n\t\t\t\t\ta.replace( /<.*?>/g, \"\" ).toLowerCase() :\n\t\t\t\t\ta+'';\n\t\t},\n\t\n\t\t// string\n\t\t\"string-pre\": function ( a ) {\n\t\t\t// This is a little complex, but faster than always calling toString,\n\t\t\t// http://jsperf.com/tostring-v-check\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ttypeof a === 'string' ?\n\t\t\t\t\ta.toLowerCase() :\n\t\t\t\t\t! a.toString ?\n\t\t\t\t\t\t'' :\n\t\t\t\t\t\ta.toString();\n\t\t},\n\t\n\t\t// string-asc and -desc are retained only for compatibility with the old\n\t\t// sort methods\n\t\t\"string-asc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t},\n\t\n\t\t\"string-desc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t}\n\t} );\n\t\n\t\n\t// Numeric sorting types - order doesn't matter here\n\t_addNumericSort( '' );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\theader: {\n\t\t\t_: function ( settings, cell, column, classes ) {\n\t\t\t\t// No additional mark-up required\n\t\t\t\t// Attach a sort listener to update on sort - note that using the\n\t\t\t\t// `DT` namespace will allow the event to be removed automatically\n\t\t\t\t// on destroy, while the `dt` namespaced event is the one we are\n\t\t\t\t// listening for\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) { // need to check this this is the host\n\t\t\t\t\t\treturn; // table, not a nested one\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tclasses.sSortAsc +' '+\n\t\t\t\t\t\t\tclasses.sSortDesc\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t},\n\t\n\t\t\tjqueryui: function ( settings, cell, column, classes ) {\n\t\t\t\t$('<div/>')\n\t\t\t\t\t.addClass( classes.sSortJUIWrapper )\n\t\t\t\t\t.append( cell.contents() )\n\t\t\t\t\t.append( $('<span/>')\n\t\t\t\t\t\t.addClass( classes.sSortIcon+' '+column.sSortingClassJUI )\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo( cell );\n\t\n\t\t\t\t// Attach a sort listener to update on sort\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass( classes.sSortAsc +\" \"+classes.sSortDesc )\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.find( 'span.'+classes.sSortIcon )\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tclasses.sSortJUIAsc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDesc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUI +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIAscAllowed +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDescAllowed\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortJUIAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortJUIDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClassJUI\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t/*\n\t * Public helper functions. These aren't used internally by DataTables, or\n\t * called by any of the options passed into DataTables, but they can be used\n\t * externally by developers working with DataTables. They are helper functions\n\t * to make working with DataTables a little bit easier.\n\t */\n\t\n\tvar __htmlEscapeEntities = function ( d ) {\n\t\tif (Array.isArray(d)) {\n\t\t\td = d.join(',');\n\t\t}\n\t\n\t\treturn typeof d === 'string' ?\n\t\t\td\n\t\t\t\t.replace(/&/g, '&')\n\t\t\t\t.replace(/</g, '<')\n\t\t\t\t.replace(/>/g, '>')\n\t\t\t\t.replace(/\"/g, '"') :\n\t\t\td;\n\t};\n\t\n\t/**\n\t * Helpers for `columns.render`.\n\t *\n\t * The options defined here can be used with the `columns.render` initialisation\n\t * option to provide a display renderer. The following functions are defined:\n\t *\n\t * * `number` - Will format numeric data (defined by `columns.data`) for\n\t * display, retaining the original unformatted data for sorting and filtering.\n\t * It takes 5 parameters:\n\t * * `string` - Thousands grouping separator\n\t * * `string` - Decimal point indicator\n\t * * `integer` - Number of decimal points to show\n\t * * `string` (optional) - Prefix.\n\t * * `string` (optional) - Postfix (/suffix).\n\t * * `text` - Escape HTML to help prevent XSS attacks. It has no optional\n\t * parameters.\n\t *\n\t * @example\n\t * // Column definition using the number renderer\n\t * {\n\t * data: \"salary\",\n\t * render: $.fn.dataTable.render.number( '\\'', '.', 0, '$' )\n\t * }\n\t *\n\t * @namespace\n\t */\n\tDataTable.render = {\n\t\tnumber: function ( thousands, decimal, precision, prefix, postfix ) {\n\t\t\treturn {\n\t\t\t\tdisplay: function ( d ) {\n\t\t\t\t\tif ( typeof d !== 'number' && typeof d !== 'string' ) {\n\t\t\t\t\t\treturn d;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar negative = d < 0 ? '-' : '';\n\t\t\t\t\tvar flo = parseFloat( d );\n\t\n\t\t\t\t\t// If NaN then there isn't much formatting that we can do - just\n\t\t\t\t\t// return immediately, escaping any HTML (this was supposed to\n\t\t\t\t\t// be a number after all)\n\t\t\t\t\tif ( isNaN( flo ) ) {\n\t\t\t\t\t\treturn __htmlEscapeEntities( d );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tflo = flo.toFixed( precision );\n\t\t\t\t\td = Math.abs( flo );\n\t\n\t\t\t\t\tvar intPart = parseInt( d, 10 );\n\t\t\t\t\tvar floatPart = precision ?\n\t\t\t\t\t\tdecimal+(d - intPart).toFixed( precision ).substring( 2 ):\n\t\t\t\t\t\t'';\n\t\n\t\t\t\t\t// If zero, then can't have a negative prefix\n\t\t\t\t\tif (intPart === 0 && parseFloat(floatPart) === 0) {\n\t\t\t\t\t\tnegative = '';\n\t\t\t\t\t}\n\t\n\t\t\t\t\treturn negative + (prefix||'') +\n\t\t\t\t\t\tintPart.toString().replace(\n\t\t\t\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g, thousands\n\t\t\t\t\t\t) +\n\t\t\t\t\t\tfloatPart +\n\t\t\t\t\t\t(postfix||'');\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\ttext: function () {\n\t\t\treturn {\n\t\t\t\tdisplay: __htmlEscapeEntities,\n\t\t\t\tfilter: __htmlEscapeEntities\n\t\t\t};\n\t\t}\n\t};\n\t\n\t\n\t/*\n\t * This is really a good bit rubbish this method of exposing the internal methods\n\t * publicly... - To be fixed in 2.0 using methods on the prototype\n\t */\n\t\n\t\n\t/**\n\t * Create a wrapper function for exporting an internal functions to an external API.\n\t * @param {string} fn API function name\n\t * @returns {function} wrapped function\n\t * @memberof DataTable#internal\n\t */\n\tfunction _fnExternApiFunc (fn)\n\t{\n\t\treturn function() {\n\t\t\tvar args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(\n\t\t\t\tArray.prototype.slice.call(arguments)\n\t\t\t);\n\t\t\treturn DataTable.ext.internal[fn].apply( this, args );\n\t\t};\n\t}\n\t\n\t\n\t/**\n\t * Reference to internal functions for use by plug-in developers. Note that\n\t * these methods are references to internal functions and are considered to be\n\t * private. If you use these methods, be aware that they are liable to change\n\t * between versions.\n\t * @namespace\n\t */\n\t$.extend( DataTable.ext.internal, {\n\t\t_fnExternApiFunc: _fnExternApiFunc,\n\t\t_fnBuildAjax: _fnBuildAjax,\n\t\t_fnAjaxUpdate: _fnAjaxUpdate,\n\t\t_fnAjaxParameters: _fnAjaxParameters,\n\t\t_fnAjaxUpdateDraw: _fnAjaxUpdateDraw,\n\t\t_fnAjaxDataSrc: _fnAjaxDataSrc,\n\t\t_fnAddColumn: _fnAddColumn,\n\t\t_fnColumnOptions: _fnColumnOptions,\n\t\t_fnAdjustColumnSizing: _fnAdjustColumnSizing,\n\t\t_fnVisibleToColumnIndex: _fnVisibleToColumnIndex,\n\t\t_fnColumnIndexToVisible: _fnColumnIndexToVisible,\n\t\t_fnVisbleColumns: _fnVisbleColumns,\n\t\t_fnGetColumns: _fnGetColumns,\n\t\t_fnColumnTypes: _fnColumnTypes,\n\t\t_fnApplyColumnDefs: _fnApplyColumnDefs,\n\t\t_fnHungarianMap: _fnHungarianMap,\n\t\t_fnCamelToHungarian: _fnCamelToHungarian,\n\t\t_fnLanguageCompat: _fnLanguageCompat,\n\t\t_fnBrowserDetect: _fnBrowserDetect,\n\t\t_fnAddData: _fnAddData,\n\t\t_fnAddTr: _fnAddTr,\n\t\t_fnNodeToDataIndex: _fnNodeToDataIndex,\n\t\t_fnNodeToColumnIndex: _fnNodeToColumnIndex,\n\t\t_fnGetCellData: _fnGetCellData,\n\t\t_fnSetCellData: _fnSetCellData,\n\t\t_fnSplitObjNotation: _fnSplitObjNotation,\n\t\t_fnGetObjectDataFn: _fnGetObjectDataFn,\n\t\t_fnSetObjectDataFn: _fnSetObjectDataFn,\n\t\t_fnGetDataMaster: _fnGetDataMaster,\n\t\t_fnClearTable: _fnClearTable,\n\t\t_fnDeleteIndex: _fnDeleteIndex,\n\t\t_fnInvalidate: _fnInvalidate,\n\t\t_fnGetRowElements: _fnGetRowElements,\n\t\t_fnCreateTr: _fnCreateTr,\n\t\t_fnBuildHead: _fnBuildHead,\n\t\t_fnDrawHead: _fnDrawHead,\n\t\t_fnDraw: _fnDraw,\n\t\t_fnReDraw: _fnReDraw,\n\t\t_fnAddOptionsHtml: _fnAddOptionsHtml,\n\t\t_fnDetectHeader: _fnDetectHeader,\n\t\t_fnGetUniqueThs: _fnGetUniqueThs,\n\t\t_fnFeatureHtmlFilter: _fnFeatureHtmlFilter,\n\t\t_fnFilterComplete: _fnFilterComplete,\n\t\t_fnFilterCustom: _fnFilterCustom,\n\t\t_fnFilterColumn: _fnFilterColumn,\n\t\t_fnFilter: _fnFilter,\n\t\t_fnFilterCreateSearch: _fnFilterCreateSearch,\n\t\t_fnEscapeRegex: _fnEscapeRegex,\n\t\t_fnFilterData: _fnFilterData,\n\t\t_fnFeatureHtmlInfo: _fnFeatureHtmlInfo,\n\t\t_fnUpdateInfo: _fnUpdateInfo,\n\t\t_fnInfoMacros: _fnInfoMacros,\n\t\t_fnInitialise: _fnInitialise,\n\t\t_fnInitComplete: _fnInitComplete,\n\t\t_fnLengthChange: _fnLengthChange,\n\t\t_fnFeatureHtmlLength: _fnFeatureHtmlLength,\n\t\t_fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,\n\t\t_fnPageChange: _fnPageChange,\n\t\t_fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,\n\t\t_fnProcessingDisplay: _fnProcessingDisplay,\n\t\t_fnFeatureHtmlTable: _fnFeatureHtmlTable,\n\t\t_fnScrollDraw: _fnScrollDraw,\n\t\t_fnApplyToChildren: _fnApplyToChildren,\n\t\t_fnCalculateColumnWidths: _fnCalculateColumnWidths,\n\t\t_fnThrottle: _fnThrottle,\n\t\t_fnConvertToWidth: _fnConvertToWidth,\n\t\t_fnGetWidestNode: _fnGetWidestNode,\n\t\t_fnGetMaxLenString: _fnGetMaxLenString,\n\t\t_fnStringToCss: _fnStringToCss,\n\t\t_fnSortFlatten: _fnSortFlatten,\n\t\t_fnSort: _fnSort,\n\t\t_fnSortAria: _fnSortAria,\n\t\t_fnSortListener: _fnSortListener,\n\t\t_fnSortAttachListener: _fnSortAttachListener,\n\t\t_fnSortingClasses: _fnSortingClasses,\n\t\t_fnSortData: _fnSortData,\n\t\t_fnSaveState: _fnSaveState,\n\t\t_fnLoadState: _fnLoadState,\n\t\t_fnImplementState: _fnImplementState,\n\t\t_fnSettingsFromNode: _fnSettingsFromNode,\n\t\t_fnLog: _fnLog,\n\t\t_fnMap: _fnMap,\n\t\t_fnBindAction: _fnBindAction,\n\t\t_fnCallbackReg: _fnCallbackReg,\n\t\t_fnCallbackFire: _fnCallbackFire,\n\t\t_fnLengthOverflow: _fnLengthOverflow,\n\t\t_fnRenderer: _fnRenderer,\n\t\t_fnDataSource: _fnDataSource,\n\t\t_fnRowAttributes: _fnRowAttributes,\n\t\t_fnExtend: _fnExtend,\n\t\t_fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant\n\t\t // in 1.10, so this dead-end function is\n\t\t // added to prevent errors\n\t} );\n\t\n\n\t// jQuery access\n\t$.fn.dataTable = DataTable;\n\n\t// Provide access to the host jQuery object (circular reference)\n\tDataTable.$ = $;\n\n\t// Legacy aliases\n\t$.fn.dataTableSettings = DataTable.settings;\n\t$.fn.dataTableExt = DataTable.ext;\n\n\t// With a capital `D` we return a DataTables API instance rather than a\n\t// jQuery object\n\t$.fn.DataTable = function ( opts ) {\n\t\treturn $(this).dataTable( opts ).api();\n\t};\n\n\t// All properties that are available to $.fn.dataTable should also be\n\t// available on $.fn.DataTable\n\t$.each( DataTable, function ( prop, val ) {\n\t\t$.fn.DataTable[ prop ] = val;\n\t} );\n\n\treturn DataTable;\n}));\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvZGF0YXRhYmxlcy5uZXQvanMvanF1ZXJ5LmRhdGFUYWJsZXMuanMuanMiLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxNQUFNLElBQTBDO0FBQ2hEO0FBQ0EsRUFBRSxpQ0FBUSxDQUFDLHlFQUFRLENBQUMsbUNBQUU7QUFDdEI7QUFDQSxHQUFHO0FBQUEsa0dBQUU7QUFDTDtBQUNBLE1BQU0sRUFxQko7QUFDRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRLFFBQVE7QUFDN0IsdUJBQXVCO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsb0JBQW9CO0FBQ2xDLGNBQWMsUUFBUTtBQUN0QixjQUFjLFFBQVE7QUFDdEI7QUFDQSxjQUFjLFFBQVE7QUFDdEI7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QjtBQUNBO0FBQ0EsZ0JBQWdCLFFBQVE7QUFDeEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQkFBMEIsb0JBQW9CO0FBQzlDO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxvQkFBb0I7QUFDbEMsY0FBYyxRQUFRO0FBQ3RCLGNBQWMsUUFBUTtBQUN0QjtBQUNBLGNBQWMsUUFBUTtBQUN0QjtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCO0FBQ0E7QUFDQSxnQkFBZ0IsT0FBTztBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLG9CQUFvQjtBQUN6RDtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFNBQVM7QUFDdEI7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxjQUFjO0FBQzVCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsTUFBTTtBQUNwQixnQkFBZ0IsT0FBTztBQUN2Qix3QkFBd0IsaUNBQWlDO0FBQ3pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsTUFBTTtBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsTUFBTTtBQUNwQixnQkFBZ0IsS0FBSztBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLE9BQU87QUFDckI7QUFDQSxjQUFjLGVBQWU7QUFDN0IsY0FBYyxNQUFNO0FBQ3BCLGdCQUFnQixPQUFPO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsTUFBTTtBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixjQUFjLFVBQVU7QUFDeEIsY0FBYyxNQUFNO0FBQ3BCLGNBQWMsTUFBTTtBQUNwQixjQUFjLE1BQU07QUFDcEIsY0FBYyxNQUFNO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsVUFBVTtBQUN4QjtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsS0FBSztBQUNuQixnQkFBZ0IscUJBQXFCO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsS0FBSztBQUNuQixnQkFBZ0IsWUFBWTtBQUM1QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxNQUFNO0FBQ3BCLGdCQUFnQixLQUFLO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsTUFBTTtBQUNwQixnQkFBZ0IsU0FBUztBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLE1BQU07QUFDcEIsY0FBYyxvQkFBb0I7QUFDbEMsY0FBYyxRQUFRO0FBQ3RCLGdCQUFnQixNQUFNO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFlBQVk7QUFDMUI7QUFDQSxjQUFjLE1BQU07QUFDcEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLEtBQUs7QUFDbkIsY0FBYyxNQUFNO0FBQ3BCLGNBQWMsTUFBTTtBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsUUFBUTtBQUN4QixTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxLQUFLO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsTUFBTTtBQUNwQixjQUFjLEtBQUs7QUFDbkIsY0FBYyxVQUFVO0FBQ3hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLHFCQUFxQjtBQUNuQyxjQUFjLFVBQVU7QUFDeEIsY0FBYyxLQUFLO0FBQ25CO0FBQ0EsY0FBYyxNQUFNO0FBQ3BCLGNBQWMsTUFBTTtBQUNwQixnQkFBZ0IsS0FBSztBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxREFBcUQ7QUFDckQsMEVBQTBFO0FBQzFFLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCO0FBQ0EsZ0JBQWdCLFNBQVM7QUFDekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3Q0FBd0MsU0FBUztBQUNqRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQ0FBcUM7QUFDckM7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3Q0FBd0M7QUFDeEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DLFNBQVM7QUFDNUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQ0FBMEMsU0FBUztBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQ0FBc0MsU0FBUztBQUMvQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUIsd0JBQXdCO0FBQ3pDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYLFdBQVc7QUFDWCxvQkFBb0I7QUFDcEIsMEJBQTBCO0FBQzFCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCLElBQUksV0FBVyxJQUFJLFdBQVcsSUFBSSxNQUFNLEVBQUUsR0FBRyxJQUFJLFFBQVEsRUFBRSxTQUFTLEVBQUU7QUFDM0Y7QUFDQTtBQUNBLGtHQUFrRyxLQUFLO0FBQ3ZHO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxRQUFRO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsUUFBUTtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxRQUFRO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsUUFBUTtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNCQUFzQixRQUFRO0FBQzlCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0MsUUFBUTtBQUN4QyxpQkFBaUI7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxPQUFPO0FBQ3BCLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFDQUFxQyxRQUFRO0FBQzdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLE9BQU87QUFDcEIsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQixRQUFRO0FBQzdCO0FBQ0E7QUFDQSxlQUFlLE1BQU07QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQkFBa0IsZUFBZTtBQUNqQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFVBQVU7QUFDdkIsYUFBYSxTQUFTO0FBQ3RCLGNBQWMsVUFBVTtBQUN4QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixnQkFBZ0IsUUFBUTtBQUN4QjtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsYUFBYSxHQUFHO0FBQ2hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQ0FBc0MsU0FBUztBQUMvQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUNBQXlDLFNBQVM7QUFDbEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0NBQWtDO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQ0FBa0M7QUFDbEM7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLGFBQWEsR0FBRztBQUNoQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDZCQUE2QjtBQUM3QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLFNBQVM7QUFDOUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQyxTQUFTO0FBQ3BEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DO0FBQ25DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUM7QUFDbkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQjtBQUNBLGFBQWEsUUFBUTtBQUNyQixhQUFhLFNBQVM7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGFBQWEsR0FBRztBQUNoQixhQUFhLEdBQUc7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBDQUEwQyxRQUFRO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixhQUFhLE1BQU07QUFDbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUI7QUFDekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUM7QUFDbkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixhQUFhLEtBQUs7QUFDbEIsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQ0FBMEM7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5Q0FBeUMsU0FBUztBQUNsRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxLQUFLO0FBQ2xCLGVBQWUsS0FBSztBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLEtBQUs7QUFDbEIsYUFBYSxRQUFRO0FBQ3JCLGVBQWUsS0FBSztBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixlQUFlLEtBQUs7QUFDcEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixhQUFhLFFBQVE7QUFDckI7QUFDQSxlQUFlLE9BQU87QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtDQUFrQyxRQUFRO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0NBQWtDLFFBQVE7QUFDMUMsa0NBQWtDLFFBQVE7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxPQUFPO0FBQ3BCLGFBQWEsT0FBTztBQUNwQixhQUFhLFVBQVU7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0NBQWdDLE9BQU87QUFDdkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQ0FBc0MsU0FBUztBQUMvQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUNBQXVDLFNBQVM7QUFDaEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DLFNBQVM7QUFDNUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxPQUFPO0FBQ3BCLGFBQWEsTUFBTTtBQUNuQjtBQUNBLGFBQWEsT0FBTztBQUNwQjtBQUNBLGVBQWUsS0FBSztBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0M7QUFDaEM7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUMsU0FBUztBQUNoRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxtQkFBbUI7QUFDaEMsZUFBZSxPQUFPO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixhQUFhLE1BQU07QUFDbkIsZUFBZSxLQUFLO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGFBQWEsS0FBSztBQUNsQixhQUFhLE1BQU07QUFDbkIsZUFBZSxLQUFLO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGFBQWEsS0FBSztBQUNsQixhQUFhLEtBQUs7QUFDbEIsYUFBYSxRQUFRO0FBQ3JCLGVBQWUsR0FBRztBQUNsQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1QyxTQUFTO0FBQ2hEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxLQUFLO0FBQ2xCLGFBQWEsS0FBSztBQUNsQixhQUFhLEdBQUc7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxxQkFBcUI7QUFDbEMsZUFBZSxVQUFVO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLHFCQUFxQjtBQUNsQyxlQUFlLFVBQVU7QUFDekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIscUJBQXFCLE9BQU87QUFDNUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsT0FBTztBQUNwQixhQUFhLEtBQUs7QUFDbEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUNBQWlDLFNBQVM7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFFBQVE7QUFDcEIsWUFBWSxRQUFRO0FBQ3BCLFlBQVksUUFBUTtBQUNwQjtBQUNBLFlBQVksUUFBUTtBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUMsUUFBUTtBQUMzQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0MsUUFBUTtBQUN4QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksUUFBUTtBQUNwQixZQUFZLGFBQWE7QUFDekI7QUFDQSxZQUFZLEtBQUs7QUFDakIsWUFBWSxjQUFjO0FBQzFCO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DLFFBQVE7QUFDM0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxLQUFLO0FBQ2xCLGFBQWEsTUFBTTtBQUNuQjtBQUNBLGFBQWEsT0FBTztBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdEQUFnRCxTQUFTO0FBQ3pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtDQUFrQyxRQUFRO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQ0FBaUMsUUFBUTtBQUN6QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixtQkFBbUIsU0FBUztBQUM1QixhQUFhLFNBQVM7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0NBQW9DLFNBQVM7QUFDN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3QixPQUFPO0FBQy9CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUMsU0FBUztBQUM1QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUMsU0FBUztBQUNoRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQixhQUFhO0FBQy9CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IsU0FBUztBQUNqQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0JBQStCLDhDQUE4QztBQUM3RTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1EQUFtRDtBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQixnQkFBZ0I7QUFDbEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNENBQTRDLFNBQVM7QUFDckQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQixRQUFRO0FBQzNCLGFBQWEsTUFBTTtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdDQUFnQyxTQUFTO0FBQ3pDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0MsU0FBUztBQUN6QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQixhQUFhO0FBQzlCO0FBQ0Esa0JBQWtCLGFBQWE7QUFDL0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixhQUFhLE1BQU07QUFDbkIsYUFBYSxPQUFPO0FBQ3BCLHFCQUFxQixNQUFNO0FBQzNCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1QyxTQUFTO0FBQ2hEO0FBQ0EsMkNBQTJDLFNBQVM7QUFDcEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFFBQVE7QUFDcEIsWUFBWSxPQUFPO0FBQ25CO0FBQ0EsWUFBWSxVQUFVO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUM7QUFDbkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1QztBQUN2QyxjQUFjO0FBQ2QsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixlQUFlLFNBQVM7QUFDeEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGVBQWUsTUFBTTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsK0JBQStCO0FBQy9DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxnQkFBZ0I7QUFDOUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CLGdDQUFnQztBQUNwRDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxRQUFRO0FBQ3JCLGFBQWEsUUFBUTtBQUNyQixhQUFhLEtBQUs7QUFDbEIsYUFBYSxLQUFLO0FBQ2xCLGFBQWEsT0FBTztBQUNwQixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1DQUFtQyxRQUFRO0FBQzNDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixjQUFjLFFBQVE7QUFDdEIsY0FBYyxPQUFPO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0QkFBNEI7QUFDNUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLE1BQU07QUFDckIsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0Q0FBNEM7QUFDNUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGFBQWEsUUFBUTtBQUNyQixhQUFhLEtBQUs7QUFDbEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQkFBbUIsd0JBQXdCO0FBQzNDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0NBQXNDLFFBQVE7QUFDOUM7QUFDQTtBQUNBO0FBQ0EsMkNBQTJDLFFBQVE7QUFDbkQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGFBQWEsUUFBUTtBQUNyQixhQUFhLEtBQUs7QUFDbEIsYUFBYSxNQUFNO0FBQ25CLGFBQWEsTUFBTTtBQUNuQixhQUFhLE1BQU07QUFDbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQkFBa0IsbUJBQW1CO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGFBQWEsUUFBUTtBQUNyQixhQUFhLEtBQUs7QUFDbEIsYUFBYSxNQUFNO0FBQ25CLGFBQWEsTUFBTTtBQUNuQixhQUFhLE1BQU07QUFDbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWUsbUJBQW1CO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixhQUFhLE1BQU07QUFDbkIsYUFBYSxNQUFNO0FBQ25CLGFBQWEsTUFBTTtBQUNuQixlQUFlLFFBQVE7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixlQUFlLFFBQVE7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMENBQTBDLFFBQVE7QUFDbEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9DQUFvQyxRQUFRO0FBQzVDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsZUFBZSxRQUFRO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsZUFBZSxRQUFRO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsZUFBZSxNQUFNO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw2Q0FBNkM7QUFDN0M7QUFDQTtBQUNBO0FBQ0EsMkJBQTJCLDRCQUE0QjtBQUN2RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1DQUFtQyxTQUFTO0FBQzVDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQixpQkFBaUI7QUFDbEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsZUFBZSxNQUFNO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0Esc0NBQXNDLFFBQVE7QUFDOUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixlQUFlLE1BQU07QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5Q0FBeUMsUUFBUTtBQUNqRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxZQUFZO0FBQ3pCO0FBQ0E7QUFDQSxlQUFlLE1BQU07QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixlQUFlLE1BQU07QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxNQUFNO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGVBQWUsTUFBTTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDRCQUE0QixrQ0FBa0M7QUFDOUQ7QUFDQSxjQUFjLCtCQUErQjtBQUM3QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0EsZ0JBQWdCLG9DQUFvQztBQUNwRDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYywrQkFBK0I7QUFDN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsK0JBQStCO0FBQzdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0EsZ0JBQWdCLG9DQUFvQztBQUNwRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFDQUFxQztBQUNyQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0NBQW9DO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFVBQVU7QUFDdkIsbUJBQW1CLE9BQU87QUFDMUIsbUJBQW1CLE9BQU87QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLDBCQUEwQjtBQUN4QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLGdCQUFnQjtBQUMvQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZSwwQkFBMEI7QUFDekM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQiwwQkFBMEI7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLDBCQUEwQjtBQUN6QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxVQUFVO0FBQ3ZCLGFBQWEsS0FBSztBQUNsQixlQUFlLFVBQVU7QUFDekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxNQUFNO0FBQ25CLGVBQWUsS0FBSztBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxLQUFLO0FBQ2xCLGVBQWUsTUFBTTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxLQUFLO0FBQ2xCLGVBQWUsUUFBUTtBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsUUFBUTtBQUN0RDtBQUNBO0FBQ0EseUJBQXlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGVBQWUsUUFBUTtBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLHNCQUFzQjtBQUNwQztBQUNBO0FBQ0E7QUFDQTtBQUNBLHNDQUFzQyxTQUFTO0FBQy9DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0NBQWdDLFFBQVE7QUFDeEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQ0FBMEMsU0FBUztBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUIsUUFBUTtBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQixRQUFRO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUMsU0FBUztBQUNoRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxNQUFNO0FBQ25CLGFBQWEsS0FBSztBQUNsQixhQUFhLFNBQVM7QUFDdEI7QUFDQSxhQUFhLFVBQVU7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0JBQXNCO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGFBQWEsTUFBTTtBQUNuQixhQUFhLEtBQUs7QUFDbEIsYUFBYSxVQUFVO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDZCQUE2QjtBQUM3QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1DQUFtQyxRQUFRO0FBQzNDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0MsUUFBUTtBQUN4QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsUUFBUTtBQUN0RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxRQUFRO0FBQ3JCLGFBQWEsVUFBVTtBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0Q0FBNEM7QUFDNUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFDQUFxQyxRQUFRO0FBQzdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxNQUFNO0FBQ25CLGVBQWUsUUFBUTtBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxLQUFLO0FBQ2xCLGFBQWEsUUFBUTtBQUNyQixhQUFhLEtBQUs7QUFDbEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGFBQWEsUUFBUTtBQUNyQixhQUFhLFFBQVE7QUFDckIsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixhQUFhLFFBQVE7QUFDckI7QUFDQSxhQUFhLFNBQVM7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLFFBQVE7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFNBQVM7QUFDdEIsYUFBYSxRQUFRO0FBQ3JCLGFBQWEsVUFBVTtBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwyQkFBMkI7QUFDM0I7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGFBQWEsUUFBUTtBQUNyQixhQUFhLFVBQVU7QUFDdkIsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsYUFBYSxRQUFRO0FBQ3JCO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCO0FBQ0EsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGVBQWUsUUFBUTtBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQ0FBcUM7QUFDckM7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0EseUJBQXlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUNBQXlDO0FBQ3pDO0FBQ0E7QUFDQSxlQUFlO0FBQ2Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLDJCQUEyQjtBQUN4QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxZQUFZO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0JBQXNCLEtBQUs7QUFDM0I7QUFDQTtBQUNBO0FBQ0Esc0JBQXNCLEtBQUs7QUFDM0I7QUFDQTtBQUNBLFlBQVksNEJBQTRCO0FBQ3hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLE9BQU87QUFDbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUMsUUFBUTtBQUMvQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9DQUFvQyxPQUFPO0FBQzNDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLFFBQVE7QUFDN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0NBQStDLFFBQVE7QUFDdkQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DLFFBQVE7QUFDM0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1DQUFtQyxRQUFRO0FBQzNDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLFFBQVE7QUFDN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOEJBQThCLFFBQVE7QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQ0FBcUM7QUFDckM7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0EseUJBQXlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUNBQXlDO0FBQ3pDO0FBQ0E7QUFDQSxlQUFlO0FBQ2Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9DQUFvQyxRQUFRO0FBQzVDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1DQUFtQyxRQUFRO0FBQzNDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0JBQStCLFFBQVE7QUFDdkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0JBQWtCO0FBQ2xCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksZ0JBQWdCO0FBQzVCLGFBQWEsT0FBTztBQUNwQixhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLGdCQUFnQjtBQUM1QjtBQUNBO0FBQ0E7QUFDQSxjQUFjLGVBQWU7QUFDN0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLGdCQUFnQjtBQUM1QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLGdCQUFnQjtBQUM5QjtBQUNBO0FBQ0E7QUFDQSxpQ0FBaUM7QUFDakM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSixHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksU0FBUztBQUNyQixjQUFjLGdCQUFnQjtBQUM5QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFDQUFxQyxRQUFRO0FBQzdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFNBQVM7QUFDckI7QUFDQTtBQUNBLGNBQWMsZ0JBQWdCO0FBQzlCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFFBQVE7QUFDcEIsY0FBYyxnQkFBZ0I7QUFDOUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSixHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxnQkFBZ0I7QUFDOUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DLFFBQVE7QUFDM0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDZCQUE2QixRQUFRO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQkFBK0IsUUFBUTtBQUN2QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DLFFBQVE7QUFDM0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQkFBMEI7QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtFQUFrRSxRQUFRO0FBQzFFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnREFBZ0QsUUFBUTtBQUN4RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQSwyQ0FBMkMsUUFBUTtBQUNuRDtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCO0FBQ2hCLEtBQUssV0FBVztBQUNoQixLQUFLLFdBQVc7QUFDaEIsS0FBSyxXQUFXO0FBQ2hCLEtBQUssV0FBVztBQUNoQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0NBQW9DO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0NBQXNDLFFBQVE7QUFDOUMsdUNBQXVDLFFBQVE7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0NBQWdDLFFBQVE7QUFDeEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUMsUUFBUTtBQUMvQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0RBQWtEO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLCtDQUErQyxRQUFRO0FBQ3ZEO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlDQUFpQyxRQUFRO0FBQ3pDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0NBQWtDLFFBQVE7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWUsZ0JBQWdCO0FBQy9CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTixLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFDQUFxQyxRQUFRO0FBQzdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFDQUFxQyxRQUFRO0FBQzdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQjtBQUMxQjtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQkFBMEI7QUFDMUI7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCO0FBQzVCO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSyxtQkFBbUI7QUFDeEIsTUFBTSxRQUFRO0FBQ2QsTUFBTSxRQUFRLHVCQUF1QixRQUFRO0FBQzdDLE1BQU0sT0FBTztBQUNiLE1BQU0sT0FBTztBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLFVBQVU7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNDQUFzQztBQUN0QyxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdDQUFnQyxRQUFRO0FBQ3hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQ0FBaUMsUUFBUTtBQUN6QztBQUNBO0FBQ0EsaUJBQWlCLFlBQVk7QUFDN0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLFFBQVE7QUFDN0MseUNBQXlDLFFBQVE7QUFDakQ7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSixHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxPQUFPO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksU0FBUztBQUNyQixZQUFZLFFBQVE7QUFDcEIsY0FBYyxnQkFBZ0I7QUFDOUI7QUFDQTtBQUNBO0FBQ0EsWUFBWSxPQUFPO0FBQ25CLFlBQVksT0FBTztBQUNuQixjQUFjLGdCQUFnQjtBQUM5QjtBQUNBO0FBQ0E7QUFDQSxZQUFZLE9BQU87QUFDbkIsY0FBYyxnQkFBZ0I7QUFDOUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxvQkFBb0I7QUFDaEM7QUFDQTtBQUNBLFlBQVksU0FBUztBQUNyQixZQUFZLFVBQVU7QUFDdEIsY0FBYyxnQkFBZ0I7QUFDOUI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTSxhQUFhO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0NBQStDO0FBQy9DLElBQUk7QUFDSixHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsSUFBSTtBQUNKLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDRDQUE0QztBQUM1QztBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxJQUFJO0FBQ0osR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVFQUF1RTtBQUN2RSxJQUFJO0FBQ0osR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQjtBQUNBLGVBQWUsU0FBUztBQUN4QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLFNBQVM7QUFDOUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLG9CQUFvQjtBQUNqQztBQUNBO0FBQ0EsZUFBZSxTQUFTO0FBQ3hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFNBQVM7QUFDdEI7QUFDQSxlQUFlLE9BQU87QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQjtBQUNBLGFBQWEsUUFBUTtBQUNyQixhQUFhLFNBQVM7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBEQUEwRCxnQkFBZ0I7QUFDMUU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxJQUFJO0FBQ0osR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQztBQUMzQyxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlDQUF5QztBQUN6QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkIsY0FBYyxHQUFHO0FBQ2pCLGNBQWMsY0FBYztBQUM1QixjQUFjLEtBQUs7QUFDbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsY0FBYztBQUM1QjtBQUNBLGNBQWMsUUFBUTtBQUN0QjtBQUNBLGdCQUFnQixHQUFHO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxjQUFjO0FBQzVCO0FBQ0EsY0FBYyxHQUFHO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsbUJBQW1CO0FBQ25DLGdCQUFnQixvQkFBb0I7QUFDcEMsZ0JBQWdCLHFCQUFxQjtBQUNyQyxnQkFBZ0Isb0JBQW9CO0FBQ3BDLGdCQUFnQjtBQUNoQjtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZTtBQUNmO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQix1Q0FBdUM7QUFDdkQsZ0JBQWdCLHdDQUF3QztBQUN4RCxnQkFBZ0IseUNBQXlDO0FBQ3pELGdCQUFnQix3Q0FBd0M7QUFDeEQsZ0JBQWdCO0FBQ2hCO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0RBQXNELHNCQUFzQjtBQUM1RTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLHlDQUF5QywyQkFBMkI7QUFDcEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOENBQThDLFFBQVE7QUFDdEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNLGdDQUFnQztBQUN0QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUIsZ0NBQWdDO0FBQ3pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsdUJBQXVCO0FBQ3ZDO0FBQ0EsZ0JBQWdCO0FBQ2hCO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU0sNkJBQTZCO0FBQ25DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsTUFBTTtBQUNwQixjQUFjLE9BQU87QUFDckIsY0FBYyxLQUFLO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLE1BQU07QUFDcEIsY0FBYyxPQUFPO0FBQ3JCLGNBQWMsS0FBSztBQUNuQjtBQUNBLGNBQWMsS0FBSztBQUNuQjtBQUNBLGNBQWMsV0FBVztBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLEtBQUs7QUFDbkIsZ0JBQWdCLFFBQVE7QUFDeEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQixFQUFFO0FBQzVCO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBLGNBQWMsRUFBRTtBQUNoQjtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxNQUFNO0FBQ3BCLGNBQWMsT0FBTztBQUNyQixjQUFjLEtBQUs7QUFDbkI7QUFDQSxjQUFjLEtBQUs7QUFDbkI7QUFDQSxjQUFjLFdBQVc7QUFDekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixjQUFjLEtBQUs7QUFDbkIsY0FBYyxLQUFLO0FBQ25CLGNBQWMsS0FBSztBQUNuQjtBQUNBLGNBQWMsS0FBSztBQUNuQixjQUFjLFFBQVE7QUFDdEI7QUFDQSxnQkFBZ0IsUUFBUTtBQUN4QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEIsY0FBYyxRQUFRO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixnQkFBZ0IsU0FBUztBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxNQUFNO0FBQ3BCLGNBQWMsT0FBTztBQUNyQixjQUFjLEtBQUs7QUFDbkIsY0FBYyxLQUFLO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEIsY0FBYyxPQUFPO0FBQ3JCO0FBQ0EsY0FBYyxVQUFVO0FBQ3hCO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLE9BQU87QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsV0FBVztBQUMzQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCLGNBQWMsUUFBUTtBQUN0QjtBQUNBLGVBQWUsUUFBUTtBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEIsY0FBYyxRQUFRO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCLGNBQWMsUUFBUTtBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCLGNBQWMsUUFBUTtBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixjQUFjLFFBQVE7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUNBQXVDO0FBQ3ZDLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTSxpQ0FBaUM7QUFDdkM7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCO0FBQ2hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWM7QUFDZCxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkLFlBQVk7QUFDWjtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjO0FBQ2QsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWM7QUFDZCxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkLFlBQVk7QUFDWjtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYixXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYixXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYixXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2IsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2IsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYixXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYixXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYixXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2IsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2IsV0FBVztBQUNYO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1QkFBdUI7QUFDdkIsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBLHlCQUF5QjtBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNCQUFzQixXQUFXO0FBQ2pDLHNCQUFzQixpQkFBaUI7QUFDdkMsc0JBQXNCLGVBQWU7QUFDckM7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0Isa0JBQWtCO0FBQ3hDLHNCQUFzQixNQUFNLEtBQUssTUFBTTtBQUN2QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3QixVQUFVLE1BQU0sZUFBZSxJQUFJLFdBQVc7QUFDdEUsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlDQUF5QyxnQ0FBZ0M7QUFDekU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IseUNBQXlDO0FBQ3pELGdCQUFnQix5Q0FBeUM7QUFDekQsZ0JBQWdCO0FBQ2hCO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsdUJBQXVCO0FBQ3ZDLGdCQUFnQix1QkFBdUI7QUFDdkMsZ0JBQWdCLGdCQUFnQjtBQUNoQztBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsOENBQThDO0FBQzlELGdCQUFnQiw2REFBNkQ7QUFDN0UsZ0JBQWdCO0FBQ2hCO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQiw0QkFBNEI7QUFDNUMsZ0JBQWdCLDJDQUEyQztBQUMzRCxnQkFBZ0IsNkJBQTZCO0FBQzdDO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEIsZ0JBQWdCO0FBQ2hCLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IscUJBQXFCO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCO0FBQ2hCLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCO0FBQ2hCLGdCQUFnQjtBQUNoQixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLG9CQUFvQjtBQUNwQztBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQixnQkFBZ0I7QUFDaEIsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixrQkFBa0I7QUFDbEM7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEIsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCLGNBQWMsR0FBRztBQUNqQixjQUFjLGNBQWM7QUFDNUIsY0FBYyxLQUFLO0FBQ25CLGNBQWMsS0FBSztBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkLFdBQVc7QUFDWCxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxhQUFhO0FBQzNCLGNBQWMsT0FBTztBQUNyQjtBQUNBO0FBQ0E7QUFDQSxjQUFjLEVBQUU7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwyQkFBMkIsTUFBTTtBQUNqQyw0QkFBNEIsTUFBTTtBQUNsQyw2QkFBNkIsTUFBTTtBQUNuQyw0QkFBNEIsTUFBTTtBQUNsQywwQkFBMEI7QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixrQkFBa0I7QUFDbEMsZ0JBQWdCLG1CQUFtQjtBQUNuQyxnQkFBZ0Isb0JBQW9CO0FBQ3BDLGdCQUFnQixtQkFBbUI7QUFDbkMsZ0JBQWdCO0FBQ2hCO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMkJBQTJCLE1BQU07QUFDakMsNEJBQTRCLE1BQU07QUFDbEM7QUFDQSw2QkFBNkI7QUFDN0IsaUJBQWlCO0FBQ2pCO0FBQ0Esb0JBQW9CLE1BQU0sR0FBRztBQUM3QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0Isa0JBQWtCO0FBQ2xDLGdCQUFnQixtQkFBbUI7QUFDbkMsZ0JBQWdCLDBCQUEwQjtBQUMxQyxnQkFBZ0IscUJBQXFCO0FBQ3JDLGdCQUFnQjtBQUNoQjtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjO0FBQ2QsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjO0FBQ2QsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLGNBQWM7QUFDM0IsYUFBYSxRQUFRO0FBQ3JCO0FBQ0EsYUFBYSxjQUFjO0FBQzNCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0Isa0JBQWtCO0FBQ2xDLGdCQUFnQixtQkFBbUI7QUFDbkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlO0FBQ2Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjO0FBQ2QsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLHFCQUFxQjtBQUNyQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLG9DQUFvQztBQUNwRCxnQkFBZ0IscUNBQXFDO0FBQ3JELGdCQUFnQixzQ0FBc0M7QUFDdEQsZ0JBQWdCLHFDQUFxQztBQUNyRCxnQkFBZ0I7QUFDaEI7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixrQkFBa0I7QUFDbEMsZ0JBQWdCLG1CQUFtQjtBQUNuQyxnQkFBZ0Isb0JBQW9CO0FBQ3BDLGdCQUFnQixtQkFBbUI7QUFDbkMsZ0JBQWdCO0FBQ2hCO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLGtEQUFrRDtBQUNsRSxnQkFBZ0IscUNBQXFDO0FBQ3JELGdCQUFnQixpREFBaUQ7QUFDakUsZ0JBQWdCO0FBQ2hCO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLDZCQUE2QjtBQUM3QyxnQkFBZ0IsZ0RBQWdEO0FBQ2hFLGdCQUFnQiwrQkFBK0I7QUFDL0MsZ0JBQWdCO0FBQ2hCO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQiw0QkFBNEI7QUFDNUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBLFlBQVk7QUFDWixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLGdCQUFnQjtBQUNoQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCO0FBQ2hCO0FBQ0EsWUFBWTtBQUNaLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsZ0JBQWdCO0FBQ2hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5Q0FBeUMsMEJBQTBCO0FBQ25FO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUIseUJBQXlCO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLHlCQUF5QjtBQUNsRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUIseUJBQXlCO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUIseUJBQXlCO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUIseUJBQXlCO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUIseUJBQXlCO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUIseUJBQXlCO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlCQUF5Qix5QkFBeUI7QUFDbEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUIseUJBQXlCO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLHlCQUF5QjtBQUNsRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUIseUJBQXlCO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLHlCQUF5QjtBQUNsRDtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlCQUF5Qix5QkFBeUI7QUFDbEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUIseUJBQXlCO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUIseUJBQXlCO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlCQUF5Qix5QkFBeUI7QUFDbEQ7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUMsNkJBQTZCO0FBQ2hFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IseUJBQXlCO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBLHVCQUF1QjtBQUN2QjtBQUNBO0FBQ0E7QUFDQSxNQUFNLGdDQUFnQztBQUN0QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLHlCQUF5QjtBQUNqRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IseUJBQXlCO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IseUJBQXlCO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IseUJBQXlCO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTSxpQ0FBaUM7QUFDdkM7QUFDQSx3QkFBd0IseUJBQXlCO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3Qix5QkFBeUI7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3Qix5QkFBeUI7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3Qix5QkFBeUI7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IseUJBQXlCO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3Qix5QkFBeUI7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IseUJBQXlCO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLHlCQUF5QjtBQUNqRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3Qix5QkFBeUI7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLHlCQUF5QjtBQUNqRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSxPQUFPO0FBQ2pCLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxRQUFRLFdBQVc7QUFDbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQ0FBcUMsMkJBQTJCO0FBQ2hFLFdBQVc7QUFDWDtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsT0FBTztBQUNqQixTQUFTO0FBQ1QsVUFBVSxhQUFhO0FBQ3ZCO0FBQ0E7QUFDQSxVQUFVLElBQUksY0FBYyx3Q0FBd0M7QUFDcEU7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRLFNBQVM7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwREFBMEQsZUFBZTtBQUN6RTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU0sd0NBQXdDO0FBQzlDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSxLQUFLO0FBQ2YsVUFBVSxLQUFLO0FBQ2Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVMsSUFBSTtBQUNiLFNBQVMsTUFBTTtBQUNmO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLE9BQU87QUFDakIsU0FBUztBQUNULFVBQVUsSUFBSTtBQUNkO0FBQ0E7QUFDQTtBQUNBLFNBQVMsTUFBTTtBQUNmO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMENBQTBDLGVBQWU7QUFDekQ7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWUsRUFBRTtBQUNqQixlQUFlLFNBQVM7QUFDeEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLFlBQVk7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFFQUFxRTtBQUNyRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWUsRUFBRTtBQUNqQjtBQUNBO0FBQ0E7QUFDQSxVQUFVLFlBQVk7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsS0FBSztBQUNmLFVBQVUsS0FBSztBQUNmLFVBQVUsS0FBSztBQUNmO0FBQ0EsNkNBQTZDLEtBQUs7QUFDbEQsUUFBUSxLQUFLLFlBQVksS0FBSztBQUM5QixrQkFBa0IsS0FBSztBQUN2QjtBQUNBO0FBQ0E7QUFDQSxRQUFRLEtBQUs7QUFDYjtBQUNBLGVBQWUsRUFBRTtBQUNqQjtBQUNBO0FBQ0E7QUFDQSxVQUFVLEVBQUU7QUFDWjtBQUNBLFFBQVEsS0FBSyxZQUFZLEtBQUs7QUFDOUI7QUFDQTtBQUNBLGVBQWUsRUFBRTtBQUNqQixlQUFlLEVBQUU7QUFDakI7QUFDQTtBQUNBO0FBQ0EsVUFBVSxFQUFFO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1QztBQUN2QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFDQUFxQyxRQUFRO0FBQzdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwREFBMEQ7QUFDMUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsZUFBZTtBQUMvQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQkFBK0I7QUFDL0IsNEJBQTRCO0FBQzVCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ04sSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCO0FBQ3pCLHdCQUF3QjtBQUN4Qix3QkFBd0I7QUFDeEIsMEJBQTBCO0FBQzFCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUIsRUFBRTtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQixlQUFlLFVBQVU7QUFDekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0NBQWtDO0FBQ2xDO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBLENBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvZGF0YXRhYmxlcy5uZXQvanMvanF1ZXJ5LmRhdGFUYWJsZXMuanM/MTNiMiJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiEgRGF0YVRhYmxlcyAxLjExLjNcbiAqIMKpMjAwOC0yMDIxIFNwcnlNZWRpYSBMdGQgLSBkYXRhdGFibGVzLm5ldC9saWNlbnNlXG4gKi9cblxuLyoqXG4gKiBAc3VtbWFyeSAgICAgRGF0YVRhYmxlc1xuICogQGRlc2NyaXB0aW9uIFBhZ2luYXRlLCBzZWFyY2ggYW5kIG9yZGVyIEhUTUwgdGFibGVzXG4gKiBAdmVyc2lvbiAgICAgMS4xMS4zXG4gKiBAZmlsZSAgICAgICAganF1ZXJ5LmRhdGFUYWJsZXMuanNcbiAqIEBhdXRob3IgICAgICBTcHJ5TWVkaWEgTHRkXG4gKiBAY29udGFjdCAgICAgd3d3LmRhdGF0YWJsZXMubmV0XG4gKiBAY29weXJpZ2h0ICAgQ29weXJpZ2h0IDIwMDgtMjAyMSBTcHJ5TWVkaWEgTHRkLlxuICpcbiAqIFRoaXMgc291cmNlIGZpbGUgaXMgZnJlZSBzb2Z0d2FyZSwgYXZhaWxhYmxlIHVuZGVyIHRoZSBmb2xsb3dpbmcgbGljZW5zZTpcbiAqICAgTUlUIGxpY2Vuc2UgLSBodHRwOi8vZGF0YXRhYmxlcy5uZXQvbGljZW5zZVxuICpcbiAqIFRoaXMgc291cmNlIGZpbGUgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0XG4gKiBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICogb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgbGljZW5zZSBmaWxlcyBmb3IgZGV0YWlscy5cbiAqXG4gKiBGb3IgZGV0YWlscyBwbGVhc2UgcmVmZXIgdG86IGh0dHA6Ly93d3cuZGF0YXRhYmxlcy5uZXRcbiAqL1xuXG4vKmpzbGludCBldmlsOiB0cnVlLCB1bmRlZjogdHJ1ZSwgYnJvd3NlcjogdHJ1ZSAqL1xuLypnbG9iYWxzICQscmVxdWlyZSxqUXVlcnksZGVmaW5lLF9zZWxlY3Rvcl9ydW4sX3NlbGVjdG9yX29wdHMsX3NlbGVjdG9yX2ZpcnN0LF9zZWxlY3Rvcl9yb3dfaW5kZXhlcyxfZXh0LF9BcGksX2FwaV9yZWdpc3RlcixfYXBpX3JlZ2lzdGVyUGx1cmFsLF9yZV9uZXdfbGluZXMsX3JlX2h0bWwsX3JlX2Zvcm1hdHRlZF9udW1lcmljLF9yZV9lc2NhcGVfcmVnZXgsX2VtcHR5LF9pbnRWYWwsX251bVRvRGVjaW1hbCxfaXNOdW1iZXIsX2lzSHRtbCxfaHRtbE51bWVyaWMsX3BsdWNrLF9wbHVja19vcmRlcixfcmFuZ2UsX3N0cmlwSHRtbCxfdW5pcXVlLF9mbkJ1aWxkQWpheCxfZm5BamF4VXBkYXRlLF9mbkFqYXhQYXJhbWV0ZXJzLF9mbkFqYXhVcGRhdGVEcmF3LF9mbkFqYXhEYXRhU3JjLF9mbkFkZENvbHVtbixfZm5Db2x1bW5PcHRpb25zLF9mbkFkanVzdENvbHVtblNpemluZyxfZm5WaXNpYmxlVG9Db2x1bW5JbmRleCxfZm5Db2x1bW5JbmRleFRvVmlzaWJsZSxfZm5WaXNibGVDb2x1bW5zLF9mbkdldENvbHVtbnMsX2ZuQ29sdW1uVHlwZXMsX2ZuQXBwbHlDb2x1bW5EZWZzLF9mbkh1bmdhcmlhbk1hcCxfZm5DYW1lbFRvSHVuZ2FyaWFuLF9mbkxhbmd1YWdlQ29tcGF0LF9mbkJyb3dzZXJEZXRlY3QsX2ZuQWRkRGF0YSxfZm5BZGRUcixfZm5Ob2RlVG9EYXRhSW5kZXgsX2ZuTm9kZVRvQ29sdW1uSW5kZXgsX2ZuR2V0Q2VsbERhdGEsX2ZuU2V0Q2VsbERhdGEsX2ZuU3BsaXRPYmpOb3RhdGlvbixfZm5HZXRPYmplY3REYXRhRm4sX2ZuU2V0T2JqZWN0RGF0YUZuLF9mbkdldERhdGFNYXN0ZXIsX2ZuQ2xlYXJUYWJsZSxfZm5EZWxldGVJbmRleCxfZm5JbnZhbGlkYXRlLF9mbkdldFJvd0VsZW1lbnRzLF9mbkNyZWF0ZVRyLF9mbkJ1aWxkSGVhZCxfZm5EcmF3SGVhZCxfZm5EcmF3LF9mblJlRHJhdyxfZm5BZGRPcHRpb25zSHRtbCxfZm5EZXRlY3RIZWFkZXIsX2ZuR2V0VW5pcXVlVGhzLF9mbkZlYXR1cmVIdG1sRmlsdGVyLF9mbkZpbHRlckNvbXBsZXRlLF9mbkZpbHRlckN1c3RvbSxfZm5GaWx0ZXJDb2x1bW4sX2ZuRmlsdGVyLF9mbkZpbHRlckNyZWF0ZVNlYXJjaCxfZm5Fc2NhcGVSZWdleCxfZm5GaWx0ZXJEYXRhLF9mbkZlYXR1cmVIdG1sSW5mbyxfZm5VcGRhdGVJbmZvLF9mbkluZm9NYWNyb3MsX2ZuSW5pdGlhbGlzZSxfZm5Jbml0Q29tcGxldGUsX2ZuTGVuZ3RoQ2hhbmdlLF9mbkZlYXR1cmVIdG1sTGVuZ3RoLF9mbkZlYXR1cmVIdG1sUGFnaW5hdGUsX2ZuUGFnZUNoYW5nZSxfZm5GZWF0dXJlSHRtbFByb2Nlc3NpbmcsX2ZuUHJvY2Vzc2luZ0Rpc3BsYXksX2ZuRmVhdHVyZUh0bWxUYWJsZSxfZm5TY3JvbGxEcmF3LF9mbkFwcGx5VG9DaGlsZHJlbixfZm5DYWxjdWxhdGVDb2x1bW5XaWR0aHMsX2ZuVGhyb3R0bGUsX2ZuQ29udmVydFRvV2lkdGgsX2ZuR2V0V2lkZXN0Tm9kZSxfZm5HZXRNYXhMZW5TdHJpbmcsX2ZuU3RyaW5nVG9Dc3MsX2ZuU29ydEZsYXR0ZW4sX2ZuU29ydCxfZm5Tb3J0QXJpYSxfZm5Tb3J0TGlzdGVuZXIsX2ZuU29ydEF0dGFjaExpc3RlbmVyLF9mblNvcnRpbmdDbGFzc2VzLF9mblNvcnREYXRhLF9mblNhdmVTdGF0ZSxfZm5Mb2FkU3RhdGUsX2ZuU2V0dGluZ3NGcm9tTm9kZSxfZm5Mb2csX2ZuTWFwLF9mbkJpbmRBY3Rpb24sX2ZuQ2FsbGJhY2tSZWcsX2ZuQ2FsbGJhY2tGaXJlLF9mbkxlbmd0aE92ZXJmbG93LF9mblJlbmRlcmVyLF9mbkRhdGFTb3VyY2UsX2ZuUm93QXR0cmlidXRlcyovXG5cbihmdW5jdGlvbiggZmFjdG9yeSApIHtcblx0XCJ1c2Ugc3RyaWN0XCI7XG5cblx0aWYgKCB0eXBlb2YgZGVmaW5lID09PSAnZnVuY3Rpb24nICYmIGRlZmluZS5hbWQgKSB7XG5cdFx0Ly8gQU1EXG5cdFx0ZGVmaW5lKCBbJ2pxdWVyeSddLCBmdW5jdGlvbiAoICQgKSB7XG5cdFx0XHRyZXR1cm4gZmFjdG9yeSggJCwgd2luZG93LCBkb2N1bWVudCApO1xuXHRcdH0gKTtcblx0fVxuXHRlbHNlIGlmICggdHlwZW9mIGV4cG9ydHMgPT09ICdvYmplY3QnICkge1xuXHRcdC8vIENvbW1vbkpTXG5cdFx0bW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAocm9vdCwgJCkge1xuXHRcdFx0aWYgKCAhIHJvb3QgKSB7XG5cdFx0XHRcdC8vIENvbW1vbkpTIGVudmlyb25tZW50cyB3aXRob3V0IGEgd2luZG93IGdsb2JhbCBtdXN0IHBhc3MgYVxuXHRcdFx0XHQvLyByb290LiBUaGlzIHdpbGwgZ2l2ZSBhbiBlcnJvciBvdGhlcndpc2Vcblx0XHRcdFx0cm9vdCA9IHdpbmRvdztcblx0XHRcdH1cblxuXHRcdFx0aWYgKCAhICQgKSB7XG5cdFx0XHRcdCQgPSB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyA/IC8vIGpRdWVyeSdzIGZhY3RvcnkgY2hlY2tzIGZvciBhIGdsb2JhbCB3aW5kb3dcblx0XHRcdFx0XHRyZXF1aXJlKCdqcXVlcnknKSA6XG5cdFx0XHRcdFx0cmVxdWlyZSgnanF1ZXJ5JykoIHJvb3QgKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGZhY3RvcnkoICQsIHJvb3QsIHJvb3QuZG9jdW1lbnQgKTtcblx0XHR9O1xuXHR9XG5cdGVsc2Uge1xuXHRcdC8vIEJyb3dzZXJcblx0XHR3aW5kb3cuRGF0YVRhYmxlID0gZmFjdG9yeSggalF1ZXJ5LCB3aW5kb3csIGRvY3VtZW50ICk7XG5cdH1cbn1cbihmdW5jdGlvbiggJCwgd2luZG93LCBkb2N1bWVudCwgdW5kZWZpbmVkICkge1xuXHRcInVzZSBzdHJpY3RcIjtcblxuXHQvKipcblx0ICogRGF0YVRhYmxlcyBpcyBhIHBsdWctaW4gZm9yIHRoZSBqUXVlcnkgSmF2YXNjcmlwdCBsaWJyYXJ5LiBJdCBpcyBhIGhpZ2hseVxuXHQgKiBmbGV4aWJsZSB0b29sLCBiYXNlZCB1cG9uIHRoZSBmb3VuZGF0aW9ucyBvZiBwcm9ncmVzc2l2ZSBlbmhhbmNlbWVudCxcblx0ICogd2hpY2ggd2lsbCBhZGQgYWR2YW5jZWQgaW50ZXJhY3Rpb24gY29udHJvbHMgdG8gYW55IEhUTUwgdGFibGUuIEZvciBhXG5cdCAqIGZ1bGwgbGlzdCBvZiBmZWF0dXJlcyBwbGVhc2UgcmVmZXIgdG9cblx0ICogW0RhdGFUYWJsZXMubmV0XShocmVmPVwiaHR0cDovL2RhdGF0YWJsZXMubmV0KS5cblx0ICpcblx0ICogTm90ZSB0aGF0IHRoZSBgRGF0YVRhYmxlYCBvYmplY3QgaXMgbm90IGEgZ2xvYmFsIHZhcmlhYmxlIGJ1dCBpcyBhbGlhc2VkXG5cdCAqIHRvIGBqUXVlcnkuZm4uRGF0YVRhYmxlYCBhbmQgYGpRdWVyeS5mbi5kYXRhVGFibGVgIHRocm91Z2ggd2hpY2ggaXQgbWF5XG5cdCAqIGJlICBhY2Nlc3NlZC5cblx0ICpcblx0ICogIEBjbGFzc1xuXHQgKiAgQHBhcmFtIHtvYmplY3R9IFtpbml0PXt9XSBDb25maWd1cmF0aW9uIG9iamVjdCBmb3IgRGF0YVRhYmxlcy4gT3B0aW9uc1xuXHQgKiAgICBhcmUgZGVmaW5lZCBieSB7QGxpbmsgRGF0YVRhYmxlLmRlZmF1bHRzfVxuXHQgKiAgQHJlcXVpcmVzIGpRdWVyeSAxLjcrXG5cdCAqXG5cdCAqICBAZXhhbXBsZVxuXHQgKiAgICAvLyBCYXNpYyBpbml0aWFsaXNhdGlvblxuXHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24ge1xuXHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCk7XG5cdCAqICAgIH0gKTtcblx0ICpcblx0ICogIEBleGFtcGxlXG5cdCAqICAgIC8vIEluaXRpYWxpc2F0aW9uIHdpdGggY29uZmlndXJhdGlvbiBvcHRpb25zIC0gaW4gdGhpcyBjYXNlLCBkaXNhYmxlXG5cdCAqICAgIC8vIHBhZ2luYXRpb24gYW5kIHNvcnRpbmcuXG5cdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbiB7XG5cdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0ICogICAgICAgIFwicGFnaW5hdGVcIjogZmFsc2UsXG5cdCAqICAgICAgICBcInNvcnRcIjogZmFsc2Vcblx0ICogICAgICB9ICk7XG5cdCAqICAgIH0gKTtcblx0ICovXG5cdHZhciBEYXRhVGFibGUgPSBmdW5jdGlvbiAoIHNlbGVjdG9yLCBvcHRpb25zIClcblx0e1xuXHRcdC8vIFdoZW4gY3JlYXRpbmcgd2l0aCBgbmV3YCwgY3JlYXRlIGEgbmV3IERhdGFUYWJsZSwgcmV0dXJuaW5nIHRoZSBBUEkgaW5zdGFuY2Vcblx0XHRpZiAodGhpcyBpbnN0YW5jZW9mIERhdGFUYWJsZSkge1xuXHRcdFx0cmV0dXJuICQoc2VsZWN0b3IpLkRhdGFUYWJsZShvcHRpb25zKTtcblx0XHR9XG5cdFx0ZWxzZSB7XG5cdFx0XHQvLyBBcmd1bWVudCBzd2l0Y2hpbmdcblx0XHRcdG9wdGlvbnMgPSBzZWxlY3Rvcjtcblx0XHR9XG5cblx0XHQvKipcblx0XHQgKiBQZXJmb3JtIGEgalF1ZXJ5IHNlbGVjdG9yIGFjdGlvbiBvbiB0aGUgdGFibGUncyBUUiBlbGVtZW50cyAoZnJvbSB0aGUgdGJvZHkpIGFuZFxuXHRcdCAqIHJldHVybiB0aGUgcmVzdWx0aW5nIGpRdWVyeSBvYmplY3QuXG5cdFx0ICogIEBwYXJhbSB7c3RyaW5nfG5vZGV8alF1ZXJ5fSBzU2VsZWN0b3IgalF1ZXJ5IHNlbGVjdG9yIG9yIG5vZGUgY29sbGVjdGlvbiB0byBhY3Qgb25cblx0XHQgKiAgQHBhcmFtIHtvYmplY3R9IFtvT3B0c10gT3B0aW9uYWwgcGFyYW1ldGVycyBmb3IgbW9kaWZ5aW5nIHRoZSByb3dzIHRvIGJlIGluY2x1ZGVkXG5cdFx0ICogIEBwYXJhbSB7c3RyaW5nfSBbb09wdHMuZmlsdGVyPW5vbmVdIFNlbGVjdCBUUiBlbGVtZW50cyB0aGF0IG1lZXQgdGhlIGN1cnJlbnQgZmlsdGVyXG5cdFx0ICogICAgY3JpdGVyaW9uIChcImFwcGxpZWRcIikgb3IgYWxsIFRSIGVsZW1lbnRzIChpLmUuIG5vIGZpbHRlcikuXG5cdFx0ICogIEBwYXJhbSB7c3RyaW5nfSBbb09wdHMub3JkZXI9Y3VycmVudF0gT3JkZXIgb2YgdGhlIFRSIGVsZW1lbnRzIGluIHRoZSBwcm9jZXNzZWQgYXJyYXkuXG5cdFx0ICogICAgQ2FuIGJlIGVpdGhlciAnY3VycmVudCcsIHdoZXJlYnkgdGhlIGN1cnJlbnQgc29ydGluZyBvZiB0aGUgdGFibGUgaXMgdXNlZCwgb3Jcblx0XHQgKiAgICAnb3JpZ2luYWwnIHdoZXJlYnkgdGhlIG9yaWdpbmFsIG9yZGVyIHRoZSBkYXRhIHdhcyByZWFkIGludG8gdGhlIHRhYmxlIGlzIHVzZWQuXG5cdFx0ICogIEBwYXJhbSB7c3RyaW5nfSBbb09wdHMucGFnZT1hbGxdIExpbWl0IHRoZSBzZWxlY3Rpb24gdG8gdGhlIGN1cnJlbnRseSBkaXNwbGF5ZWQgcGFnZVxuXHRcdCAqICAgIChcImN1cnJlbnRcIikgb3Igbm90IChcImFsbFwiKS4gSWYgJ2N1cnJlbnQnIGlzIGdpdmVuLCB0aGVuIG9yZGVyIGlzIGFzc3VtZWQgdG8gYmVcblx0XHQgKiAgICAnY3VycmVudCcgYW5kIGZpbHRlciBpcyAnYXBwbGllZCcsIHJlZ2FyZGxlc3Mgb2Ygd2hhdCB0aGV5IG1pZ2h0IGJlIGdpdmVuIGFzLlxuXHRcdCAqICBAcmV0dXJucyB7b2JqZWN0fSBqUXVlcnkgb2JqZWN0LCBmaWx0ZXJlZCBieSB0aGUgZ2l2ZW4gc2VsZWN0b3IuXG5cdFx0ICogIEBkdG9wdCBBUElcblx0XHQgKiAgQGRlcHJlY2F0ZWQgU2luY2UgdjEuMTBcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgdmFyIG9UYWJsZSA9ICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCk7XG5cdFx0ICpcblx0XHQgKiAgICAgIC8vIEhpZ2hsaWdodCBldmVyeSBzZWNvbmQgcm93XG5cdFx0ICogICAgICBvVGFibGUuJCgndHI6b2RkJykuY3NzKCdiYWNrZ3JvdW5kQ29sb3InLCAnYmx1ZScpO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgdmFyIG9UYWJsZSA9ICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCk7XG5cdFx0ICpcblx0XHQgKiAgICAgIC8vIEZpbHRlciB0byByb3dzIHdpdGggJ1dlYmtpdCcgaW4gdGhlbSwgYWRkIGEgYmFja2dyb3VuZCBjb2xvdXIgYW5kIHRoZW5cblx0XHQgKiAgICAgIC8vIHJlbW92ZSB0aGUgZmlsdGVyLCB0aHVzIGhpZ2hsaWdodGluZyB0aGUgJ1dlYmtpdCcgcm93cyBvbmx5LlxuXHRcdCAqICAgICAgb1RhYmxlLmZuRmlsdGVyKCdXZWJraXQnKTtcblx0XHQgKiAgICAgIG9UYWJsZS4kKCd0cicsIHtcInNlYXJjaFwiOiBcImFwcGxpZWRcIn0pLmNzcygnYmFja2dyb3VuZENvbG9yJywgJ2JsdWUnKTtcblx0XHQgKiAgICAgIG9UYWJsZS5mbkZpbHRlcignJyk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdHRoaXMuJCA9IGZ1bmN0aW9uICggc1NlbGVjdG9yLCBvT3B0cyApXG5cdFx0e1xuXHRcdFx0cmV0dXJuIHRoaXMuYXBpKHRydWUpLiQoIHNTZWxlY3Rvciwgb09wdHMgKTtcblx0XHR9O1xuXHRcdFxuXHRcdFxuXHRcdC8qKlxuXHRcdCAqIEFsbW9zdCBpZGVudGljYWwgdG8gJCBpbiBvcGVyYXRpb24sIGJ1dCBpbiB0aGlzIGNhc2UgcmV0dXJucyB0aGUgZGF0YSBmb3IgdGhlIG1hdGNoZWRcblx0XHQgKiByb3dzIC0gYXMgc3VjaCwgdGhlIGpRdWVyeSBzZWxlY3RvciB1c2VkIHNob3VsZCBtYXRjaCBUUiByb3cgbm9kZXMgb3IgVEQvVEggY2VsbCBub2Rlc1xuXHRcdCAqIHJhdGhlciB0aGFuIGFueSBkZXNjZW5kYW50cywgc28gdGhlIGRhdGEgY2FuIGJlIG9idGFpbmVkIGZvciB0aGUgcm93L2NlbGwuIElmIG1hdGNoaW5nXG5cdFx0ICogcm93cyBhcmUgZm91bmQsIHRoZSBkYXRhIHJldHVybmVkIGlzIHRoZSBvcmlnaW5hbCBkYXRhIGFycmF5L29iamVjdCB0aGF0IHdhcyB1c2VkIHRvXG5cdFx0ICogY3JlYXRlIHRoZSByb3cgKG9yIGEgZ2VuZXJhdGVkIGFycmF5IGlmIGZyb20gYSBET00gc291cmNlKS5cblx0XHQgKlxuXHRcdCAqIFRoaXMgbWV0aG9kIGlzIG9mdGVuIHVzZWZ1bCBpbi1jb21iaW5hdGlvbiB3aXRoICQgd2hlcmUgYm90aCBmdW5jdGlvbnMgYXJlIGdpdmVuIHRoZVxuXHRcdCAqIHNhbWUgcGFyYW1ldGVycyBhbmQgdGhlIGFycmF5IGluZGV4ZXMgd2lsbCBtYXRjaCBpZGVudGljYWxseS5cblx0XHQgKiAgQHBhcmFtIHtzdHJpbmd8bm9kZXxqUXVlcnl9IHNTZWxlY3RvciBqUXVlcnkgc2VsZWN0b3Igb3Igbm9kZSBjb2xsZWN0aW9uIHRvIGFjdCBvblxuXHRcdCAqICBAcGFyYW0ge29iamVjdH0gW29PcHRzXSBPcHRpb25hbCBwYXJhbWV0ZXJzIGZvciBtb2RpZnlpbmcgdGhlIHJvd3MgdG8gYmUgaW5jbHVkZWRcblx0XHQgKiAgQHBhcmFtIHtzdHJpbmd9IFtvT3B0cy5maWx0ZXI9bm9uZV0gU2VsZWN0IGVsZW1lbnRzIHRoYXQgbWVldCB0aGUgY3VycmVudCBmaWx0ZXJcblx0XHQgKiAgICBjcml0ZXJpb24gKFwiYXBwbGllZFwiKSBvciBhbGwgZWxlbWVudHMgKGkuZS4gbm8gZmlsdGVyKS5cblx0XHQgKiAgQHBhcmFtIHtzdHJpbmd9IFtvT3B0cy5vcmRlcj1jdXJyZW50XSBPcmRlciBvZiB0aGUgZGF0YSBpbiB0aGUgcHJvY2Vzc2VkIGFycmF5LlxuXHRcdCAqICAgIENhbiBiZSBlaXRoZXIgJ2N1cnJlbnQnLCB3aGVyZWJ5IHRoZSBjdXJyZW50IHNvcnRpbmcgb2YgdGhlIHRhYmxlIGlzIHVzZWQsIG9yXG5cdFx0ICogICAgJ29yaWdpbmFsJyB3aGVyZWJ5IHRoZSBvcmlnaW5hbCBvcmRlciB0aGUgZGF0YSB3YXMgcmVhZCBpbnRvIHRoZSB0YWJsZSBpcyB1c2VkLlxuXHRcdCAqICBAcGFyYW0ge3N0cmluZ30gW29PcHRzLnBhZ2U9YWxsXSBMaW1pdCB0aGUgc2VsZWN0aW9uIHRvIHRoZSBjdXJyZW50bHkgZGlzcGxheWVkIHBhZ2Vcblx0XHQgKiAgICAoXCJjdXJyZW50XCIpIG9yIG5vdCAoXCJhbGxcIikuIElmICdjdXJyZW50JyBpcyBnaXZlbiwgdGhlbiBvcmRlciBpcyBhc3N1bWVkIHRvIGJlXG5cdFx0ICogICAgJ2N1cnJlbnQnIGFuZCBmaWx0ZXIgaXMgJ2FwcGxpZWQnLCByZWdhcmRsZXNzIG9mIHdoYXQgdGhleSBtaWdodCBiZSBnaXZlbiBhcy5cblx0XHQgKiAgQHJldHVybnMge2FycmF5fSBEYXRhIGZvciB0aGUgbWF0Y2hlZCBlbGVtZW50cy4gSWYgYW55IGVsZW1lbnRzLCBhcyBhIHJlc3VsdCBvZiB0aGVcblx0XHQgKiAgICBzZWxlY3Rvciwgd2VyZSBub3QgVFIsIFREIG9yIFRIIGVsZW1lbnRzIGluIHRoZSBEYXRhVGFibGUsIHRoZXkgd2lsbCBoYXZlIGEgbnVsbFxuXHRcdCAqICAgIGVudHJ5IGluIHRoZSBhcnJheS5cblx0XHQgKiAgQGR0b3B0IEFQSVxuXHRcdCAqICBAZGVwcmVjYXRlZCBTaW5jZSB2MS4xMFxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICB2YXIgb1RhYmxlID0gJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoKTtcblx0XHQgKlxuXHRcdCAqICAgICAgLy8gR2V0IHRoZSBkYXRhIGZyb20gdGhlIGZpcnN0IHJvdyBpbiB0aGUgdGFibGVcblx0XHQgKiAgICAgIHZhciBkYXRhID0gb1RhYmxlLl8oJ3RyOmZpcnN0Jyk7XG5cdFx0ICpcblx0XHQgKiAgICAgIC8vIERvIHNvbWV0aGluZyB1c2VmdWwgd2l0aCB0aGUgZGF0YVxuXHRcdCAqICAgICAgYWxlcnQoIFwiRmlyc3QgY2VsbCBpczogXCIrZGF0YVswXSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgdmFyIG9UYWJsZSA9ICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCk7XG5cdFx0ICpcblx0XHQgKiAgICAgIC8vIEZpbHRlciB0byAnV2Via2l0JyBhbmQgZ2V0IGFsbCBkYXRhIGZvclxuXHRcdCAqICAgICAgb1RhYmxlLmZuRmlsdGVyKCdXZWJraXQnKTtcblx0XHQgKiAgICAgIHZhciBkYXRhID0gb1RhYmxlLl8oJ3RyJywge1wic2VhcmNoXCI6IFwiYXBwbGllZFwifSk7XG5cdFx0ICpcblx0XHQgKiAgICAgIC8vIERvIHNvbWV0aGluZyB3aXRoIHRoZSBkYXRhXG5cdFx0ICogICAgICBhbGVydCggZGF0YS5sZW5ndGgrXCIgcm93cyBtYXRjaGVkIHRoZSBzZWFyY2hcIiApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHR0aGlzLl8gPSBmdW5jdGlvbiAoIHNTZWxlY3Rvciwgb09wdHMgKVxuXHRcdHtcblx0XHRcdHJldHVybiB0aGlzLmFwaSh0cnVlKS5yb3dzKCBzU2VsZWN0b3IsIG9PcHRzICkuZGF0YSgpO1xuXHRcdH07XG5cdFx0XG5cdFx0XG5cdFx0LyoqXG5cdFx0ICogQ3JlYXRlIGEgRGF0YVRhYmxlcyBBcGkgaW5zdGFuY2UsIHdpdGggdGhlIGN1cnJlbnRseSBzZWxlY3RlZCB0YWJsZXMgZm9yXG5cdFx0ICogdGhlIEFwaSdzIGNvbnRleHQuXG5cdFx0ICogQHBhcmFtIHtib29sZWFufSBbdHJhZGl0aW9uYWw9ZmFsc2VdIFNldCB0aGUgQVBJIGluc3RhbmNlJ3MgY29udGV4dCB0byBiZVxuXHRcdCAqICAgb25seSB0aGUgdGFibGUgcmVmZXJyZWQgdG8gYnkgdGhlIGBEYXRhVGFibGUuZXh0LmlBcGlJbmRleGAgb3B0aW9uLCBhcyB3YXNcblx0XHQgKiAgIHVzZWQgaW4gdGhlIEFQSSBwcmVzZW50ZWQgYnkgRGF0YVRhYmxlcyAxLjktIChpLmUuIHRoZSB0cmFkaXRpb25hbCBtb2RlKSxcblx0XHQgKiAgIG9yIGlmIGFsbCB0YWJsZXMgY2FwdHVyZWQgaW4gdGhlIGpRdWVyeSBvYmplY3Qgc2hvdWxkIGJlIHVzZWQuXG5cdFx0ICogQHJldHVybiB7RGF0YVRhYmxlcy5BcGl9XG5cdFx0ICovXG5cdFx0dGhpcy5hcGkgPSBmdW5jdGlvbiAoIHRyYWRpdGlvbmFsIClcblx0XHR7XG5cdFx0XHRyZXR1cm4gdHJhZGl0aW9uYWwgP1xuXHRcdFx0XHRuZXcgX0FwaShcblx0XHRcdFx0XHRfZm5TZXR0aW5nc0Zyb21Ob2RlKCB0aGlzWyBfZXh0LmlBcGlJbmRleCBdIClcblx0XHRcdFx0KSA6XG5cdFx0XHRcdG5ldyBfQXBpKCB0aGlzICk7XG5cdFx0fTtcblx0XHRcblx0XHRcblx0XHQvKipcblx0XHQgKiBBZGQgYSBzaW5nbGUgbmV3IHJvdyBvciBtdWx0aXBsZSByb3dzIG9mIGRhdGEgdG8gdGhlIHRhYmxlLiBQbGVhc2Ugbm90ZVxuXHRcdCAqIHRoYXQgdGhpcyBpcyBzdWl0YWJsZSBmb3IgY2xpZW50LXNpZGUgcHJvY2Vzc2luZyBvbmx5IC0gaWYgeW91IGFyZSB1c2luZ1xuXHRcdCAqIHNlcnZlci1zaWRlIHByb2Nlc3NpbmcgKGkuZS4gXCJiU2VydmVyU2lkZVwiOiB0cnVlKSwgdGhlbiB0byBhZGQgZGF0YSwgeW91XG5cdFx0ICogbXVzdCBhZGQgaXQgdG8gdGhlIGRhdGEgc291cmNlLCBpLmUuIHRoZSBzZXJ2ZXItc2lkZSwgdGhyb3VnaCBhbiBBamF4IGNhbGwuXG5cdFx0ICogIEBwYXJhbSB7YXJyYXl8b2JqZWN0fSBkYXRhIFRoZSBkYXRhIHRvIGJlIGFkZGVkIHRvIHRoZSB0YWJsZS4gVGhpcyBjYW4gYmU6XG5cdFx0ICogICAgPHVsPlxuXHRcdCAqICAgICAgPGxpPjFEIGFycmF5IG9mIGRhdGEgLSBhZGQgYSBzaW5nbGUgcm93IHdpdGggdGhlIGRhdGEgcHJvdmlkZWQ8L2xpPlxuXHRcdCAqICAgICAgPGxpPjJEIGFycmF5IG9mIGFycmF5cyAtIGFkZCBtdWx0aXBsZSByb3dzIGluIGEgc2luZ2xlIGNhbGw8L2xpPlxuXHRcdCAqICAgICAgPGxpPm9iamVjdCAtIGRhdGEgb2JqZWN0IHdoZW4gdXNpbmcgPGk+bURhdGE8L2k+PC9saT5cblx0XHQgKiAgICAgIDxsaT5hcnJheSBvZiBvYmplY3RzIC0gbXVsdGlwbGUgZGF0YSBvYmplY3RzIHdoZW4gdXNpbmcgPGk+bURhdGE8L2k+PC9saT5cblx0XHQgKiAgICA8L3VsPlxuXHRcdCAqICBAcGFyYW0ge2Jvb2x9IFtyZWRyYXc9dHJ1ZV0gcmVkcmF3IHRoZSB0YWJsZSBvciBub3Rcblx0XHQgKiAgQHJldHVybnMge2FycmF5fSBBbiBhcnJheSBvZiBpbnRlZ2VycywgcmVwcmVzZW50aW5nIHRoZSBsaXN0IG9mIGluZGV4ZXMgaW5cblx0XHQgKiAgICA8aT5hb0RhdGE8L2k+ICh7QGxpbmsgRGF0YVRhYmxlLm1vZGVscy5vU2V0dGluZ3N9KSB0aGF0IGhhdmUgYmVlbiBhZGRlZCB0b1xuXHRcdCAqICAgIHRoZSB0YWJsZS5cblx0XHQgKiAgQGR0b3B0IEFQSVxuXHRcdCAqICBAZGVwcmVjYXRlZCBTaW5jZSB2MS4xMFxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgLy8gR2xvYmFsIHZhciBmb3IgY291bnRlclxuXHRcdCAqICAgIHZhciBnaUNvdW50ID0gMjtcblx0XHQgKlxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICpcblx0XHQgKiAgICBmdW5jdGlvbiBmbkNsaWNrQWRkUm93KCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoKS5mbkFkZERhdGEoIFtcblx0XHQgKiAgICAgICAgZ2lDb3VudCtcIi4xXCIsXG5cdFx0ICogICAgICAgIGdpQ291bnQrXCIuMlwiLFxuXHRcdCAqICAgICAgICBnaUNvdW50K1wiLjNcIixcblx0XHQgKiAgICAgICAgZ2lDb3VudCtcIi40XCIgXVxuXHRcdCAqICAgICAgKTtcblx0XHQgKlxuXHRcdCAqICAgICAgZ2lDb3VudCsrO1xuXHRcdCAqICAgIH1cblx0XHQgKi9cblx0XHR0aGlzLmZuQWRkRGF0YSA9IGZ1bmN0aW9uKCBkYXRhLCByZWRyYXcgKVxuXHRcdHtcblx0XHRcdHZhciBhcGkgPSB0aGlzLmFwaSggdHJ1ZSApO1xuXHRcdFxuXHRcdFx0LyogQ2hlY2sgaWYgd2Ugd2FudCB0byBhZGQgbXVsdGlwbGUgcm93cyBvciBub3QgKi9cblx0XHRcdHZhciByb3dzID0gQXJyYXkuaXNBcnJheShkYXRhKSAmJiAoIEFycmF5LmlzQXJyYXkoZGF0YVswXSkgfHwgJC5pc1BsYWluT2JqZWN0KGRhdGFbMF0pICkgP1xuXHRcdFx0XHRhcGkucm93cy5hZGQoIGRhdGEgKSA6XG5cdFx0XHRcdGFwaS5yb3cuYWRkKCBkYXRhICk7XG5cdFx0XG5cdFx0XHRpZiAoIHJlZHJhdyA9PT0gdW5kZWZpbmVkIHx8IHJlZHJhdyApIHtcblx0XHRcdFx0YXBpLmRyYXcoKTtcblx0XHRcdH1cblx0XHRcblx0XHRcdHJldHVybiByb3dzLmZsYXR0ZW4oKS50b0FycmF5KCk7XG5cdFx0fTtcblx0XHRcblx0XHRcblx0XHQvKipcblx0XHQgKiBUaGlzIGZ1bmN0aW9uIHdpbGwgbWFrZSBEYXRhVGFibGVzIHJlY2FsY3VsYXRlIHRoZSBjb2x1bW4gc2l6ZXMsIGJhc2VkIG9uIHRoZSBkYXRhXG5cdFx0ICogY29udGFpbmVkIGluIHRoZSB0YWJsZSBhbmQgdGhlIHNpemVzIGFwcGxpZWQgdG8gdGhlIGNvbHVtbnMgKGluIHRoZSBET00sIENTUyBvclxuXHRcdCAqIHRocm91Z2ggdGhlIHNXaWR0aCBwYXJhbWV0ZXIpLiBUaGlzIGNhbiBiZSB1c2VmdWwgd2hlbiB0aGUgd2lkdGggb2YgdGhlIHRhYmxlJ3Ncblx0XHQgKiBwYXJlbnQgZWxlbWVudCBjaGFuZ2VzIChmb3IgZXhhbXBsZSBhIHdpbmRvdyByZXNpemUpLlxuXHRcdCAqICBAcGFyYW0ge2Jvb2xlYW59IFtiUmVkcmF3PXRydWVdIFJlZHJhdyB0aGUgdGFibGUgb3Igbm90LCB5b3Ugd2lsbCB0eXBpY2FsbHkgd2FudCB0b1xuXHRcdCAqICBAZHRvcHQgQVBJXG5cdFx0ICogIEBkZXByZWNhdGVkIFNpbmNlIHYxLjEwXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgIHZhciBvVGFibGUgPSAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcInNTY3JvbGxZXCI6IFwiMjAwcHhcIixcblx0XHQgKiAgICAgICAgXCJiUGFnaW5hdGVcIjogZmFsc2Vcblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKlxuXHRcdCAqICAgICAgJCh3aW5kb3cpLm9uKCdyZXNpemUnLCBmdW5jdGlvbiAoKSB7XG5cdFx0ICogICAgICAgIG9UYWJsZS5mbkFkanVzdENvbHVtblNpemluZygpO1xuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHR0aGlzLmZuQWRqdXN0Q29sdW1uU2l6aW5nID0gZnVuY3Rpb24gKCBiUmVkcmF3IClcblx0XHR7XG5cdFx0XHR2YXIgYXBpID0gdGhpcy5hcGkoIHRydWUgKS5jb2x1bW5zLmFkanVzdCgpO1xuXHRcdFx0dmFyIHNldHRpbmdzID0gYXBpLnNldHRpbmdzKClbMF07XG5cdFx0XHR2YXIgc2Nyb2xsID0gc2V0dGluZ3Mub1Njcm9sbDtcblx0XHRcblx0XHRcdGlmICggYlJlZHJhdyA9PT0gdW5kZWZpbmVkIHx8IGJSZWRyYXcgKSB7XG5cdFx0XHRcdGFwaS5kcmF3KCBmYWxzZSApO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSBpZiAoIHNjcm9sbC5zWCAhPT0gXCJcIiB8fCBzY3JvbGwuc1kgIT09IFwiXCIgKSB7XG5cdFx0XHRcdC8qIElmIG5vdCByZWRyYXdpbmcsIGJ1dCBzY3JvbGxpbmcsIHdlIHdhbnQgdG8gYXBwbHkgdGhlIG5ldyBjb2x1bW4gc2l6ZXMgYW55d2F5ICovXG5cdFx0XHRcdF9mblNjcm9sbERyYXcoIHNldHRpbmdzICk7XG5cdFx0XHR9XG5cdFx0fTtcblx0XHRcblx0XHRcblx0XHQvKipcblx0XHQgKiBRdWlja2x5IGFuZCBzaW1wbHkgY2xlYXIgYSB0YWJsZVxuXHRcdCAqICBAcGFyYW0ge2Jvb2x9IFtiUmVkcmF3PXRydWVdIHJlZHJhdyB0aGUgdGFibGUgb3Igbm90XG5cdFx0ICogIEBkdG9wdCBBUElcblx0XHQgKiAgQGRlcHJlY2F0ZWQgU2luY2UgdjEuMTBcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgdmFyIG9UYWJsZSA9ICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCk7XG5cdFx0ICpcblx0XHQgKiAgICAgIC8vIEltbWVkaWF0ZWx5ICdudWtlJyB0aGUgY3VycmVudCByb3dzIChwZXJoYXBzIHdhaXRpbmcgZm9yIGFuIEFqYXggY2FsbGJhY2suLi4pXG5cdFx0ICogICAgICBvVGFibGUuZm5DbGVhclRhYmxlKCk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdHRoaXMuZm5DbGVhclRhYmxlID0gZnVuY3Rpb24oIGJSZWRyYXcgKVxuXHRcdHtcblx0XHRcdHZhciBhcGkgPSB0aGlzLmFwaSggdHJ1ZSApLmNsZWFyKCk7XG5cdFx0XG5cdFx0XHRpZiAoIGJSZWRyYXcgPT09IHVuZGVmaW5lZCB8fCBiUmVkcmF3ICkge1xuXHRcdFx0XHRhcGkuZHJhdygpO1xuXHRcdFx0fVxuXHRcdH07XG5cdFx0XG5cdFx0XG5cdFx0LyoqXG5cdFx0ICogVGhlIGV4YWN0IG9wcG9zaXRlIG9mICdvcGVuaW5nJyBhIHJvdywgdGhpcyBmdW5jdGlvbiB3aWxsIGNsb3NlIGFueSByb3dzIHdoaWNoXG5cdFx0ICogYXJlIGN1cnJlbnRseSAnb3BlbicuXG5cdFx0ICogIEBwYXJhbSB7bm9kZX0gblRyIHRoZSB0YWJsZSByb3cgdG8gJ2Nsb3NlJ1xuXHRcdCAqICBAcmV0dXJucyB7aW50fSAwIG9uIHN1Y2Nlc3MsIG9yIDEgaWYgZmFpbGVkIChjYW4ndCBmaW5kIHRoZSByb3cpXG5cdFx0ICogIEBkdG9wdCBBUElcblx0XHQgKiAgQGRlcHJlY2F0ZWQgU2luY2UgdjEuMTBcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgdmFyIG9UYWJsZTtcblx0XHQgKlxuXHRcdCAqICAgICAgLy8gJ29wZW4nIGFuIGluZm9ybWF0aW9uIHJvdyB3aGVuIGEgcm93IGlzIGNsaWNrZWQgb25cblx0XHQgKiAgICAgICQoJyNleGFtcGxlIHRib2R5IHRyJykuY2xpY2soIGZ1bmN0aW9uICgpIHtcblx0XHQgKiAgICAgICAgaWYgKCBvVGFibGUuZm5Jc09wZW4odGhpcykgKSB7XG5cdFx0ICogICAgICAgICAgb1RhYmxlLmZuQ2xvc2UoIHRoaXMgKTtcblx0XHQgKiAgICAgICAgfSBlbHNlIHtcblx0XHQgKiAgICAgICAgICBvVGFibGUuZm5PcGVuKCB0aGlzLCBcIlRlbXBvcmFyeSByb3cgb3BlbmVkXCIsIFwiaW5mb19yb3dcIiApO1xuXHRcdCAqICAgICAgICB9XG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICpcblx0XHQgKiAgICAgIG9UYWJsZSA9ICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdHRoaXMuZm5DbG9zZSA9IGZ1bmN0aW9uKCBuVHIgKVxuXHRcdHtcblx0XHRcdHRoaXMuYXBpKCB0cnVlICkucm93KCBuVHIgKS5jaGlsZC5oaWRlKCk7XG5cdFx0fTtcblx0XHRcblx0XHRcblx0XHQvKipcblx0XHQgKiBSZW1vdmUgYSByb3cgZm9yIHRoZSB0YWJsZVxuXHRcdCAqICBAcGFyYW0ge21peGVkfSB0YXJnZXQgVGhlIGluZGV4IG9mIHRoZSByb3cgZnJvbSBhb0RhdGEgdG8gYmUgZGVsZXRlZCwgb3Jcblx0XHQgKiAgICB0aGUgVFIgZWxlbWVudCB5b3Ugd2FudCB0byBkZWxldGVcblx0XHQgKiAgQHBhcmFtIHtmdW5jdGlvbnxudWxsfSBbY2FsbEJhY2tdIENhbGxiYWNrIGZ1bmN0aW9uXG5cdFx0ICogIEBwYXJhbSB7Ym9vbH0gW3JlZHJhdz10cnVlXSBSZWRyYXcgdGhlIHRhYmxlIG9yIG5vdFxuXHRcdCAqICBAcmV0dXJucyB7YXJyYXl9IFRoZSByb3cgdGhhdCB3YXMgZGVsZXRlZFxuXHRcdCAqICBAZHRvcHQgQVBJXG5cdFx0ICogIEBkZXByZWNhdGVkIFNpbmNlIHYxLjEwXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgIHZhciBvVGFibGUgPSAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgpO1xuXHRcdCAqXG5cdFx0ICogICAgICAvLyBJbW1lZGlhdGVseSByZW1vdmUgdGhlIGZpcnN0IHJvd1xuXHRcdCAqICAgICAgb1RhYmxlLmZuRGVsZXRlUm93KCAwICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdHRoaXMuZm5EZWxldGVSb3cgPSBmdW5jdGlvbiggdGFyZ2V0LCBjYWxsYmFjaywgcmVkcmF3IClcblx0XHR7XG5cdFx0XHR2YXIgYXBpID0gdGhpcy5hcGkoIHRydWUgKTtcblx0XHRcdHZhciByb3dzID0gYXBpLnJvd3MoIHRhcmdldCApO1xuXHRcdFx0dmFyIHNldHRpbmdzID0gcm93cy5zZXR0aW5ncygpWzBdO1xuXHRcdFx0dmFyIGRhdGEgPSBzZXR0aW5ncy5hb0RhdGFbIHJvd3NbMF1bMF0gXTtcblx0XHRcblx0XHRcdHJvd3MucmVtb3ZlKCk7XG5cdFx0XG5cdFx0XHRpZiAoIGNhbGxiYWNrICkge1xuXHRcdFx0XHRjYWxsYmFjay5jYWxsKCB0aGlzLCBzZXR0aW5ncywgZGF0YSApO1xuXHRcdFx0fVxuXHRcdFxuXHRcdFx0aWYgKCByZWRyYXcgPT09IHVuZGVmaW5lZCB8fCByZWRyYXcgKSB7XG5cdFx0XHRcdGFwaS5kcmF3KCk7XG5cdFx0XHR9XG5cdFx0XG5cdFx0XHRyZXR1cm4gZGF0YTtcblx0XHR9O1xuXHRcdFxuXHRcdFxuXHRcdC8qKlxuXHRcdCAqIFJlc3RvcmUgdGhlIHRhYmxlIHRvIGl0J3Mgb3JpZ2luYWwgc3RhdGUgaW4gdGhlIERPTSBieSByZW1vdmluZyBhbGwgb2YgRGF0YVRhYmxlc1xuXHRcdCAqIGVuaGFuY2VtZW50cywgYWx0ZXJhdGlvbnMgdG8gdGhlIERPTSBzdHJ1Y3R1cmUgb2YgdGhlIHRhYmxlIGFuZCBldmVudCBsaXN0ZW5lcnMuXG5cdFx0ICogIEBwYXJhbSB7Ym9vbGVhbn0gW3JlbW92ZT1mYWxzZV0gQ29tcGxldGVseSByZW1vdmUgdGhlIHRhYmxlIGZyb20gdGhlIERPTVxuXHRcdCAqICBAZHRvcHQgQVBJXG5cdFx0ICogIEBkZXByZWNhdGVkIFNpbmNlIHYxLjEwXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgIC8vIFRoaXMgZXhhbXBsZSBpcyBmYWlybHkgcG9pbnRsZXNzIGluIHJlYWxpdHksIGJ1dCBzaG93cyBob3cgZm5EZXN0cm95IGNhbiBiZSB1c2VkXG5cdFx0ICogICAgICB2YXIgb1RhYmxlID0gJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoKTtcblx0XHQgKiAgICAgIG9UYWJsZS5mbkRlc3Ryb3koKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0dGhpcy5mbkRlc3Ryb3kgPSBmdW5jdGlvbiAoIHJlbW92ZSApXG5cdFx0e1xuXHRcdFx0dGhpcy5hcGkoIHRydWUgKS5kZXN0cm95KCByZW1vdmUgKTtcblx0XHR9O1xuXHRcdFxuXHRcdFxuXHRcdC8qKlxuXHRcdCAqIFJlZHJhdyB0aGUgdGFibGVcblx0XHQgKiAgQHBhcmFtIHtib29sfSBbY29tcGxldGU9dHJ1ZV0gUmUtZmlsdGVyIGFuZCByZXNvcnQgKGlmIGVuYWJsZWQpIHRoZSB0YWJsZSBiZWZvcmUgdGhlIGRyYXcuXG5cdFx0ICogIEBkdG9wdCBBUElcblx0XHQgKiAgQGRlcHJlY2F0ZWQgU2luY2UgdjEuMTBcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgdmFyIG9UYWJsZSA9ICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCk7XG5cdFx0ICpcblx0XHQgKiAgICAgIC8vIFJlLWRyYXcgdGhlIHRhYmxlIC0geW91IHdvdWxkbid0IHdhbnQgdG8gZG8gaXQgaGVyZSwgYnV0IGl0J3MgYW4gZXhhbXBsZSA6LSlcblx0XHQgKiAgICAgIG9UYWJsZS5mbkRyYXcoKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0dGhpcy5mbkRyYXcgPSBmdW5jdGlvbiggY29tcGxldGUgKVxuXHRcdHtcblx0XHRcdC8vIE5vdGUgdGhhdCB0aGlzIGlzbid0IGFuIGV4YWN0IG1hdGNoIHRvIHRoZSBvbGQgY2FsbCB0byBfZm5EcmF3IC0gaXQgdGFrZXNcblx0XHRcdC8vIGludG8gYWNjb3VudCB0aGUgbmV3IGRhdGEsIGJ1dCBjYW4gaG9sZCBwb3NpdGlvbi5cblx0XHRcdHRoaXMuYXBpKCB0cnVlICkuZHJhdyggY29tcGxldGUgKTtcblx0XHR9O1xuXHRcdFxuXHRcdFxuXHRcdC8qKlxuXHRcdCAqIEZpbHRlciB0aGUgaW5wdXQgYmFzZWQgb24gZGF0YVxuXHRcdCAqICBAcGFyYW0ge3N0cmluZ30gc0lucHV0IFN0cmluZyB0byBmaWx0ZXIgdGhlIHRhYmxlIG9uXG5cdFx0ICogIEBwYXJhbSB7aW50fG51bGx9IFtpQ29sdW1uXSBDb2x1bW4gdG8gbGltaXQgZmlsdGVyaW5nIHRvXG5cdFx0ICogIEBwYXJhbSB7Ym9vbH0gW2JSZWdleD1mYWxzZV0gVHJlYXQgYXMgcmVndWxhciBleHByZXNzaW9uIG9yIG5vdFxuXHRcdCAqICBAcGFyYW0ge2Jvb2x9IFtiU21hcnQ9dHJ1ZV0gUGVyZm9ybSBzbWFydCBmaWx0ZXJpbmcgb3Igbm90XG5cdFx0ICogIEBwYXJhbSB7Ym9vbH0gW2JTaG93R2xvYmFsPXRydWVdIFNob3cgdGhlIGlucHV0IGdsb2JhbCBmaWx0ZXIgaW4gaXQncyBpbnB1dCBib3goZXMpXG5cdFx0ICogIEBwYXJhbSB7Ym9vbH0gW2JDYXNlSW5zZW5zaXRpdmU9dHJ1ZV0gRG8gY2FzZS1pbnNlbnNpdGl2ZSBtYXRjaGluZyAodHJ1ZSkgb3Igbm90IChmYWxzZSlcblx0XHQgKiAgQGR0b3B0IEFQSVxuXHRcdCAqICBAZGVwcmVjYXRlZCBTaW5jZSB2MS4xMFxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICB2YXIgb1RhYmxlID0gJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoKTtcblx0XHQgKlxuXHRcdCAqICAgICAgLy8gU29tZXRpbWUgbGF0ZXIgLSBmaWx0ZXIuLi5cblx0XHQgKiAgICAgIG9UYWJsZS5mbkZpbHRlciggJ3Rlc3Qgc3RyaW5nJyApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHR0aGlzLmZuRmlsdGVyID0gZnVuY3Rpb24oIHNJbnB1dCwgaUNvbHVtbiwgYlJlZ2V4LCBiU21hcnQsIGJTaG93R2xvYmFsLCBiQ2FzZUluc2Vuc2l0aXZlIClcblx0XHR7XG5cdFx0XHR2YXIgYXBpID0gdGhpcy5hcGkoIHRydWUgKTtcblx0XHRcblx0XHRcdGlmICggaUNvbHVtbiA9PT0gbnVsbCB8fCBpQ29sdW1uID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdGFwaS5zZWFyY2goIHNJbnB1dCwgYlJlZ2V4LCBiU21hcnQsIGJDYXNlSW5zZW5zaXRpdmUgKTtcblx0XHRcdH1cblx0XHRcdGVsc2Uge1xuXHRcdFx0XHRhcGkuY29sdW1uKCBpQ29sdW1uICkuc2VhcmNoKCBzSW5wdXQsIGJSZWdleCwgYlNtYXJ0LCBiQ2FzZUluc2Vuc2l0aXZlICk7XG5cdFx0XHR9XG5cdFx0XG5cdFx0XHRhcGkuZHJhdygpO1xuXHRcdH07XG5cdFx0XG5cdFx0XG5cdFx0LyoqXG5cdFx0ICogR2V0IHRoZSBkYXRhIGZvciB0aGUgd2hvbGUgdGFibGUsIGFuIGluZGl2aWR1YWwgcm93IG9yIGFuIGluZGl2aWR1YWwgY2VsbCBiYXNlZCBvbiB0aGVcblx0XHQgKiBwcm92aWRlZCBwYXJhbWV0ZXJzLlxuXHRcdCAqICBAcGFyYW0ge2ludHxub2RlfSBbc3JjXSBBIFRSIHJvdyBub2RlLCBURC9USCBjZWxsIG5vZGUgb3IgYW4gaW50ZWdlci4gSWYgZ2l2ZW4gYXNcblx0XHQgKiAgICBhIFRSIG5vZGUgdGhlbiB0aGUgZGF0YSBzb3VyY2UgZm9yIHRoZSB3aG9sZSByb3cgd2lsbCBiZSByZXR1cm5lZC4gSWYgZ2l2ZW4gYXMgYVxuXHRcdCAqICAgIFREL1RIIGNlbGwgbm9kZSB0aGVuIGlDb2wgd2lsbCBiZSBhdXRvbWF0aWNhbGx5IGNhbGN1bGF0ZWQgYW5kIHRoZSBkYXRhIGZvciB0aGVcblx0XHQgKiAgICBjZWxsIHJldHVybmVkLiBJZiBnaXZlbiBhcyBhbiBpbnRlZ2VyLCB0aGVuIHRoaXMgaXMgdHJlYXRlZCBhcyB0aGUgYW9EYXRhIGludGVybmFsXG5cdFx0ICogICAgZGF0YSBpbmRleCBmb3IgdGhlIHJvdyAoc2VlIGZuR2V0UG9zaXRpb24pIGFuZCB0aGUgZGF0YSBmb3IgdGhhdCByb3cgdXNlZC5cblx0XHQgKiAgQHBhcmFtIHtpbnR9IFtjb2xdIE9wdGlvbmFsIGNvbHVtbiBpbmRleCB0aGF0IHlvdSB3YW50IHRoZSBkYXRhIG9mLlxuXHRcdCAqICBAcmV0dXJucyB7YXJyYXl8b2JqZWN0fHN0cmluZ30gSWYgbVJvdyBpcyB1bmRlZmluZWQsIHRoZW4gdGhlIGRhdGEgZm9yIGFsbCByb3dzIGlzXG5cdFx0ICogICAgcmV0dXJuZWQuIElmIG1Sb3cgaXMgZGVmaW5lZCwganVzdCBkYXRhIGZvciB0aGF0IHJvdywgYW5kIGlzIGlDb2wgaXNcblx0XHQgKiAgICBkZWZpbmVkLCBvbmx5IGRhdGEgZm9yIHRoZSBkZXNpZ25hdGVkIGNlbGwgaXMgcmV0dXJuZWQuXG5cdFx0ICogIEBkdG9wdCBBUElcblx0XHQgKiAgQGRlcHJlY2F0ZWQgU2luY2UgdjEuMTBcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgIC8vIFJvdyBkYXRhXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICBvVGFibGUgPSAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgpO1xuXHRcdCAqXG5cdFx0ICogICAgICBvVGFibGUuJCgndHInKS5jbGljayggZnVuY3Rpb24gKCkge1xuXHRcdCAqICAgICAgICB2YXIgZGF0YSA9IG9UYWJsZS5mbkdldERhdGEoIHRoaXMgKTtcblx0XHQgKiAgICAgICAgLy8gLi4uIGRvIHNvbWV0aGluZyB3aXRoIHRoZSBhcnJheSAvIG9iamVjdCBvZiBkYXRhIGZvciB0aGUgcm93XG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgLy8gSW5kaXZpZHVhbCBjZWxsIGRhdGFcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgIG9UYWJsZSA9ICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCk7XG5cdFx0ICpcblx0XHQgKiAgICAgIG9UYWJsZS4kKCd0ZCcpLmNsaWNrKCBmdW5jdGlvbiAoKSB7XG5cdFx0ICogICAgICAgIHZhciBzRGF0YSA9IG9UYWJsZS5mbkdldERhdGEoIHRoaXMgKTtcblx0XHQgKiAgICAgICAgYWxlcnQoICdUaGUgY2VsbCBjbGlja2VkIG9uIGhhZCB0aGUgdmFsdWUgb2YgJytzRGF0YSApO1xuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHR0aGlzLmZuR2V0RGF0YSA9IGZ1bmN0aW9uKCBzcmMsIGNvbCApXG5cdFx0e1xuXHRcdFx0dmFyIGFwaSA9IHRoaXMuYXBpKCB0cnVlICk7XG5cdFx0XG5cdFx0XHRpZiAoIHNyYyAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHR2YXIgdHlwZSA9IHNyYy5ub2RlTmFtZSA/IHNyYy5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpIDogJyc7XG5cdFx0XG5cdFx0XHRcdHJldHVybiBjb2wgIT09IHVuZGVmaW5lZCB8fCB0eXBlID09ICd0ZCcgfHwgdHlwZSA9PSAndGgnID9cblx0XHRcdFx0XHRhcGkuY2VsbCggc3JjLCBjb2wgKS5kYXRhKCkgOlxuXHRcdFx0XHRcdGFwaS5yb3coIHNyYyApLmRhdGEoKSB8fCBudWxsO1xuXHRcdFx0fVxuXHRcdFxuXHRcdFx0cmV0dXJuIGFwaS5kYXRhKCkudG9BcnJheSgpO1xuXHRcdH07XG5cdFx0XG5cdFx0XG5cdFx0LyoqXG5cdFx0ICogR2V0IGFuIGFycmF5IG9mIHRoZSBUUiBub2RlcyB0aGF0IGFyZSB1c2VkIGluIHRoZSB0YWJsZSdzIGJvZHkuIE5vdGUgdGhhdCB5b3Ugd2lsbFxuXHRcdCAqIHR5cGljYWxseSB3YW50IHRvIHVzZSB0aGUgJyQnIEFQSSBtZXRob2QgaW4gcHJlZmVyZW5jZSB0byB0aGlzIGFzIGl0IGlzIG1vcmVcblx0XHQgKiBmbGV4aWJsZS5cblx0XHQgKiAgQHBhcmFtIHtpbnR9IFtpUm93XSBPcHRpb25hbCByb3cgaW5kZXggZm9yIHRoZSBUUiBlbGVtZW50IHlvdSB3YW50XG5cdFx0ICogIEByZXR1cm5zIHthcnJheXxub2RlfSBJZiBpUm93IGlzIHVuZGVmaW5lZCwgcmV0dXJucyBhbiBhcnJheSBvZiBhbGwgVFIgZWxlbWVudHNcblx0XHQgKiAgICBpbiB0aGUgdGFibGUncyBib2R5LCBvciBpUm93IGlzIGRlZmluZWQsIGp1c3QgdGhlIFRSIGVsZW1lbnQgcmVxdWVzdGVkLlxuXHRcdCAqICBAZHRvcHQgQVBJXG5cdFx0ICogIEBkZXByZWNhdGVkIFNpbmNlIHYxLjEwXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgIHZhciBvVGFibGUgPSAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgpO1xuXHRcdCAqXG5cdFx0ICogICAgICAvLyBHZXQgdGhlIG5vZGVzIGZyb20gdGhlIHRhYmxlXG5cdFx0ICogICAgICB2YXIgbk5vZGVzID0gb1RhYmxlLmZuR2V0Tm9kZXMoICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdHRoaXMuZm5HZXROb2RlcyA9IGZ1bmN0aW9uKCBpUm93IClcblx0XHR7XG5cdFx0XHR2YXIgYXBpID0gdGhpcy5hcGkoIHRydWUgKTtcblx0XHRcblx0XHRcdHJldHVybiBpUm93ICE9PSB1bmRlZmluZWQgP1xuXHRcdFx0XHRhcGkucm93KCBpUm93ICkubm9kZSgpIDpcblx0XHRcdFx0YXBpLnJvd3MoKS5ub2RlcygpLmZsYXR0ZW4oKS50b0FycmF5KCk7XG5cdFx0fTtcblx0XHRcblx0XHRcblx0XHQvKipcblx0XHQgKiBHZXQgdGhlIGFycmF5IGluZGV4ZXMgb2YgYSBwYXJ0aWN1bGFyIGNlbGwgZnJvbSBpdCdzIERPTSBlbGVtZW50XG5cdFx0ICogYW5kIGNvbHVtbiBpbmRleCBpbmNsdWRpbmcgaGlkZGVuIGNvbHVtbnNcblx0XHQgKiAgQHBhcmFtIHtub2RlfSBub2RlIHRoaXMgY2FuIGVpdGhlciBiZSBhIFRSLCBURCBvciBUSCBpbiB0aGUgdGFibGUncyBib2R5XG5cdFx0ICogIEByZXR1cm5zIHtpbnR9IElmIG5Ob2RlIGlzIGdpdmVuIGFzIGEgVFIsIHRoZW4gYSBzaW5nbGUgaW5kZXggaXMgcmV0dXJuZWQsIG9yXG5cdFx0ICogICAgaWYgZ2l2ZW4gYXMgYSBjZWxsLCBhbiBhcnJheSBvZiBbcm93IGluZGV4LCBjb2x1bW4gaW5kZXggKHZpc2libGUpLFxuXHRcdCAqICAgIGNvbHVtbiBpbmRleCAoYWxsKV0gaXMgZ2l2ZW4uXG5cdFx0ICogIEBkdG9wdCBBUElcblx0XHQgKiAgQGRlcHJlY2F0ZWQgU2luY2UgdjEuMTBcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUgdGJvZHkgdGQnKS5jbGljayggZnVuY3Rpb24gKCkge1xuXHRcdCAqICAgICAgICAvLyBHZXQgdGhlIHBvc2l0aW9uIG9mIHRoZSBjdXJyZW50IGRhdGEgZnJvbSB0aGUgbm9kZVxuXHRcdCAqICAgICAgICB2YXIgYVBvcyA9IG9UYWJsZS5mbkdldFBvc2l0aW9uKCB0aGlzICk7XG5cdFx0ICpcblx0XHQgKiAgICAgICAgLy8gR2V0IHRoZSBkYXRhIGFycmF5IGZvciB0aGlzIHJvd1xuXHRcdCAqICAgICAgICB2YXIgYURhdGEgPSBvVGFibGUuZm5HZXREYXRhKCBhUG9zWzBdICk7XG5cdFx0ICpcblx0XHQgKiAgICAgICAgLy8gVXBkYXRlIHRoZSBkYXRhIGFycmF5IGFuZCByZXR1cm4gdGhlIHZhbHVlXG5cdFx0ICogICAgICAgIGFEYXRhWyBhUG9zWzFdIF0gPSAnY2xpY2tlZCc7XG5cdFx0ICogICAgICAgIHRoaXMuaW5uZXJIVE1MID0gJ2NsaWNrZWQnO1xuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqXG5cdFx0ICogICAgICAvLyBJbml0IERhdGFUYWJsZXNcblx0XHQgKiAgICAgIG9UYWJsZSA9ICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdHRoaXMuZm5HZXRQb3NpdGlvbiA9IGZ1bmN0aW9uKCBub2RlIClcblx0XHR7XG5cdFx0XHR2YXIgYXBpID0gdGhpcy5hcGkoIHRydWUgKTtcblx0XHRcdHZhciBub2RlTmFtZSA9IG5vZGUubm9kZU5hbWUudG9VcHBlckNhc2UoKTtcblx0XHRcblx0XHRcdGlmICggbm9kZU5hbWUgPT0gJ1RSJyApIHtcblx0XHRcdFx0cmV0dXJuIGFwaS5yb3coIG5vZGUgKS5pbmRleCgpO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSBpZiAoIG5vZGVOYW1lID09ICdURCcgfHwgbm9kZU5hbWUgPT0gJ1RIJyApIHtcblx0XHRcdFx0dmFyIGNlbGwgPSBhcGkuY2VsbCggbm9kZSApLmluZGV4KCk7XG5cdFx0XG5cdFx0XHRcdHJldHVybiBbXG5cdFx0XHRcdFx0Y2VsbC5yb3csXG5cdFx0XHRcdFx0Y2VsbC5jb2x1bW5WaXNpYmxlLFxuXHRcdFx0XHRcdGNlbGwuY29sdW1uXG5cdFx0XHRcdF07XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gbnVsbDtcblx0XHR9O1xuXHRcdFxuXHRcdFxuXHRcdC8qKlxuXHRcdCAqIENoZWNrIHRvIHNlZSBpZiBhIHJvdyBpcyAnb3Blbicgb3Igbm90LlxuXHRcdCAqICBAcGFyYW0ge25vZGV9IG5UciB0aGUgdGFibGUgcm93IHRvIGNoZWNrXG5cdFx0ICogIEByZXR1cm5zIHtib29sZWFufSB0cnVlIGlmIHRoZSByb3cgaXMgY3VycmVudGx5IG9wZW4sIGZhbHNlIG90aGVyd2lzZVxuXHRcdCAqICBAZHRvcHQgQVBJXG5cdFx0ICogIEBkZXByZWNhdGVkIFNpbmNlIHYxLjEwXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgIHZhciBvVGFibGU7XG5cdFx0ICpcblx0XHQgKiAgICAgIC8vICdvcGVuJyBhbiBpbmZvcm1hdGlvbiByb3cgd2hlbiBhIHJvdyBpcyBjbGlja2VkIG9uXG5cdFx0ICogICAgICAkKCcjZXhhbXBsZSB0Ym9keSB0cicpLmNsaWNrKCBmdW5jdGlvbiAoKSB7XG5cdFx0ICogICAgICAgIGlmICggb1RhYmxlLmZuSXNPcGVuKHRoaXMpICkge1xuXHRcdCAqICAgICAgICAgIG9UYWJsZS5mbkNsb3NlKCB0aGlzICk7XG5cdFx0ICogICAgICAgIH0gZWxzZSB7XG5cdFx0ICogICAgICAgICAgb1RhYmxlLmZuT3BlbiggdGhpcywgXCJUZW1wb3Jhcnkgcm93IG9wZW5lZFwiLCBcImluZm9fcm93XCIgKTtcblx0XHQgKiAgICAgICAgfVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqXG5cdFx0ICogICAgICBvVGFibGUgPSAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgpO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHR0aGlzLmZuSXNPcGVuID0gZnVuY3Rpb24oIG5UciApXG5cdFx0e1xuXHRcdFx0cmV0dXJuIHRoaXMuYXBpKCB0cnVlICkucm93KCBuVHIgKS5jaGlsZC5pc1Nob3duKCk7XG5cdFx0fTtcblx0XHRcblx0XHRcblx0XHQvKipcblx0XHQgKiBUaGlzIGZ1bmN0aW9uIHdpbGwgcGxhY2UgYSBuZXcgcm93IGRpcmVjdGx5IGFmdGVyIGEgcm93IHdoaWNoIGlzIGN1cnJlbnRseVxuXHRcdCAqIG9uIGRpc3BsYXkgb24gdGhlIHBhZ2UsIHdpdGggdGhlIEhUTUwgY29udGVudHMgdGhhdCBpcyBwYXNzZWQgaW50byB0aGVcblx0XHQgKiBmdW5jdGlvbi4gVGhpcyBjYW4gYmUgdXNlZCwgZm9yIGV4YW1wbGUsIHRvIGFzayBmb3IgY29uZmlybWF0aW9uIHRoYXQgYVxuXHRcdCAqIHBhcnRpY3VsYXIgcmVjb3JkIHNob3VsZCBiZSBkZWxldGVkLlxuXHRcdCAqICBAcGFyYW0ge25vZGV9IG5UciBUaGUgdGFibGUgcm93IHRvICdvcGVuJ1xuXHRcdCAqICBAcGFyYW0ge3N0cmluZ3xub2RlfGpRdWVyeX0gbUh0bWwgVGhlIEhUTUwgdG8gcHV0IGludG8gdGhlIHJvd1xuXHRcdCAqICBAcGFyYW0ge3N0cmluZ30gc0NsYXNzIENsYXNzIHRvIGdpdmUgdGhlIG5ldyBURCBjZWxsXG5cdFx0ICogIEByZXR1cm5zIHtub2RlfSBUaGUgcm93IG9wZW5lZC4gTm90ZSB0aGF0IGlmIHRoZSB0YWJsZSByb3cgcGFzc2VkIGluIGFzIHRoZVxuXHRcdCAqICAgIGZpcnN0IHBhcmFtZXRlciwgaXMgbm90IGZvdW5kIGluIHRoZSB0YWJsZSwgdGhpcyBtZXRob2Qgd2lsbCBzaWxlbnRseVxuXHRcdCAqICAgIHJldHVybi5cblx0XHQgKiAgQGR0b3B0IEFQSVxuXHRcdCAqICBAZGVwcmVjYXRlZCBTaW5jZSB2MS4xMFxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICB2YXIgb1RhYmxlO1xuXHRcdCAqXG5cdFx0ICogICAgICAvLyAnb3BlbicgYW4gaW5mb3JtYXRpb24gcm93IHdoZW4gYSByb3cgaXMgY2xpY2tlZCBvblxuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUgdGJvZHkgdHInKS5jbGljayggZnVuY3Rpb24gKCkge1xuXHRcdCAqICAgICAgICBpZiAoIG9UYWJsZS5mbklzT3Blbih0aGlzKSApIHtcblx0XHQgKiAgICAgICAgICBvVGFibGUuZm5DbG9zZSggdGhpcyApO1xuXHRcdCAqICAgICAgICB9IGVsc2Uge1xuXHRcdCAqICAgICAgICAgIG9UYWJsZS5mbk9wZW4oIHRoaXMsIFwiVGVtcG9yYXJ5IHJvdyBvcGVuZWRcIiwgXCJpbmZvX3Jvd1wiICk7XG5cdFx0ICogICAgICAgIH1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKlxuXHRcdCAqICAgICAgb1RhYmxlID0gJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0dGhpcy5mbk9wZW4gPSBmdW5jdGlvbiggblRyLCBtSHRtbCwgc0NsYXNzIClcblx0XHR7XG5cdFx0XHRyZXR1cm4gdGhpcy5hcGkoIHRydWUgKVxuXHRcdFx0XHQucm93KCBuVHIgKVxuXHRcdFx0XHQuY2hpbGQoIG1IdG1sLCBzQ2xhc3MgKVxuXHRcdFx0XHQuc2hvdygpXG5cdFx0XHRcdC5jaGlsZCgpWzBdO1xuXHRcdH07XG5cdFx0XG5cdFx0XG5cdFx0LyoqXG5cdFx0ICogQ2hhbmdlIHRoZSBwYWdpbmF0aW9uIC0gcHJvdmlkZXMgdGhlIGludGVybmFsIGxvZ2ljIGZvciBwYWdpbmF0aW9uIGluIGEgc2ltcGxlIEFQSVxuXHRcdCAqIGZ1bmN0aW9uLiBXaXRoIHRoaXMgZnVuY3Rpb24geW91IGNhbiBoYXZlIGEgRGF0YVRhYmxlcyB0YWJsZSBnbyB0byB0aGUgbmV4dCxcblx0XHQgKiBwcmV2aW91cywgZmlyc3Qgb3IgbGFzdCBwYWdlcy5cblx0XHQgKiAgQHBhcmFtIHtzdHJpbmd8aW50fSBtQWN0aW9uIFBhZ2luZyBhY3Rpb24gdG8gdGFrZTogXCJmaXJzdFwiLCBcInByZXZpb3VzXCIsIFwibmV4dFwiIG9yIFwibGFzdFwiXG5cdFx0ICogICAgb3IgcGFnZSBudW1iZXIgdG8ganVtcCB0byAoaW50ZWdlciksIG5vdGUgdGhhdCBwYWdlIDAgaXMgdGhlIGZpcnN0IHBhZ2UuXG5cdFx0ICogIEBwYXJhbSB7Ym9vbH0gW2JSZWRyYXc9dHJ1ZV0gUmVkcmF3IHRoZSB0YWJsZSBvciBub3Rcblx0XHQgKiAgQGR0b3B0IEFQSVxuXHRcdCAqICBAZGVwcmVjYXRlZCBTaW5jZSB2MS4xMFxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICB2YXIgb1RhYmxlID0gJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoKTtcblx0XHQgKiAgICAgIG9UYWJsZS5mblBhZ2VDaGFuZ2UoICduZXh0JyApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHR0aGlzLmZuUGFnZUNoYW5nZSA9IGZ1bmN0aW9uICggbUFjdGlvbiwgYlJlZHJhdyApXG5cdFx0e1xuXHRcdFx0dmFyIGFwaSA9IHRoaXMuYXBpKCB0cnVlICkucGFnZSggbUFjdGlvbiApO1xuXHRcdFxuXHRcdFx0aWYgKCBiUmVkcmF3ID09PSB1bmRlZmluZWQgfHwgYlJlZHJhdyApIHtcblx0XHRcdFx0YXBpLmRyYXcoZmFsc2UpO1xuXHRcdFx0fVxuXHRcdH07XG5cdFx0XG5cdFx0XG5cdFx0LyoqXG5cdFx0ICogU2hvdyBhIHBhcnRpY3VsYXIgY29sdW1uXG5cdFx0ICogIEBwYXJhbSB7aW50fSBpQ29sIFRoZSBjb2x1bW4gd2hvc2UgZGlzcGxheSBzaG91bGQgYmUgY2hhbmdlZFxuXHRcdCAqICBAcGFyYW0ge2Jvb2x9IGJTaG93IFNob3cgKHRydWUpIG9yIGhpZGUgKGZhbHNlKSB0aGUgY29sdW1uXG5cdFx0ICogIEBwYXJhbSB7Ym9vbH0gW2JSZWRyYXc9dHJ1ZV0gUmVkcmF3IHRoZSB0YWJsZSBvciBub3Rcblx0XHQgKiAgQGR0b3B0IEFQSVxuXHRcdCAqICBAZGVwcmVjYXRlZCBTaW5jZSB2MS4xMFxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICB2YXIgb1RhYmxlID0gJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoKTtcblx0XHQgKlxuXHRcdCAqICAgICAgLy8gSGlkZSB0aGUgc2Vjb25kIGNvbHVtbiBhZnRlciBpbml0aWFsaXNhdGlvblxuXHRcdCAqICAgICAgb1RhYmxlLmZuU2V0Q29sdW1uVmlzKCAxLCBmYWxzZSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHR0aGlzLmZuU2V0Q29sdW1uVmlzID0gZnVuY3Rpb24gKCBpQ29sLCBiU2hvdywgYlJlZHJhdyApXG5cdFx0e1xuXHRcdFx0dmFyIGFwaSA9IHRoaXMuYXBpKCB0cnVlICkuY29sdW1uKCBpQ29sICkudmlzaWJsZSggYlNob3cgKTtcblx0XHRcblx0XHRcdGlmICggYlJlZHJhdyA9PT0gdW5kZWZpbmVkIHx8IGJSZWRyYXcgKSB7XG5cdFx0XHRcdGFwaS5jb2x1bW5zLmFkanVzdCgpLmRyYXcoKTtcblx0XHRcdH1cblx0XHR9O1xuXHRcdFxuXHRcdFxuXHRcdC8qKlxuXHRcdCAqIEdldCB0aGUgc2V0dGluZ3MgZm9yIGEgcGFydGljdWxhciB0YWJsZSBmb3IgZXh0ZXJuYWwgbWFuaXB1bGF0aW9uXG5cdFx0ICogIEByZXR1cm5zIHtvYmplY3R9IERhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0LiBTZWVcblx0XHQgKiAgICB7QGxpbmsgRGF0YVRhYmxlLm1vZGVscy5vU2V0dGluZ3N9XG5cdFx0ICogIEBkdG9wdCBBUElcblx0XHQgKiAgQGRlcHJlY2F0ZWQgU2luY2UgdjEuMTBcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgdmFyIG9UYWJsZSA9ICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCk7XG5cdFx0ICogICAgICB2YXIgb1NldHRpbmdzID0gb1RhYmxlLmZuU2V0dGluZ3MoKTtcblx0XHQgKlxuXHRcdCAqICAgICAgLy8gU2hvdyBhbiBleGFtcGxlIHBhcmFtZXRlciBmcm9tIHRoZSBzZXR0aW5nc1xuXHRcdCAqICAgICAgYWxlcnQoIG9TZXR0aW5ncy5faURpc3BsYXlTdGFydCApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHR0aGlzLmZuU2V0dGluZ3MgPSBmdW5jdGlvbigpXG5cdFx0e1xuXHRcdFx0cmV0dXJuIF9mblNldHRpbmdzRnJvbU5vZGUoIHRoaXNbX2V4dC5pQXBpSW5kZXhdICk7XG5cdFx0fTtcblx0XHRcblx0XHRcblx0XHQvKipcblx0XHQgKiBTb3J0IHRoZSB0YWJsZSBieSBhIHBhcnRpY3VsYXIgY29sdW1uXG5cdFx0ICogIEBwYXJhbSB7aW50fSBpQ29sIHRoZSBkYXRhIGluZGV4IHRvIHNvcnQgb24uIE5vdGUgdGhhdCB0aGlzIHdpbGwgbm90IG1hdGNoIHRoZVxuXHRcdCAqICAgICdkaXNwbGF5IGluZGV4JyBpZiB5b3UgaGF2ZSBoaWRkZW4gZGF0YSBlbnRyaWVzXG5cdFx0ICogIEBkdG9wdCBBUElcblx0XHQgKiAgQGRlcHJlY2F0ZWQgU2luY2UgdjEuMTBcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgdmFyIG9UYWJsZSA9ICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCk7XG5cdFx0ICpcblx0XHQgKiAgICAgIC8vIFNvcnQgaW1tZWRpYXRlbHkgd2l0aCBjb2x1bW5zIDAgYW5kIDFcblx0XHQgKiAgICAgIG9UYWJsZS5mblNvcnQoIFsgWzAsJ2FzYyddLCBbMSwnYXNjJ10gXSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHR0aGlzLmZuU29ydCA9IGZ1bmN0aW9uKCBhYVNvcnQgKVxuXHRcdHtcblx0XHRcdHRoaXMuYXBpKCB0cnVlICkub3JkZXIoIGFhU29ydCApLmRyYXcoKTtcblx0XHR9O1xuXHRcdFxuXHRcdFxuXHRcdC8qKlxuXHRcdCAqIEF0dGFjaCBhIHNvcnQgbGlzdGVuZXIgdG8gYW4gZWxlbWVudCBmb3IgYSBnaXZlbiBjb2x1bW5cblx0XHQgKiAgQHBhcmFtIHtub2RlfSBuTm9kZSB0aGUgZWxlbWVudCB0byBhdHRhY2ggdGhlIHNvcnQgbGlzdGVuZXIgdG9cblx0XHQgKiAgQHBhcmFtIHtpbnR9IGlDb2x1bW4gdGhlIGNvbHVtbiB0aGF0IGEgY2xpY2sgb24gdGhpcyBub2RlIHdpbGwgc29ydCBvblxuXHRcdCAqICBAcGFyYW0ge2Z1bmN0aW9ufSBbZm5DYWxsYmFja10gY2FsbGJhY2sgZnVuY3Rpb24gd2hlbiBzb3J0IGlzIHJ1blxuXHRcdCAqICBAZHRvcHQgQVBJXG5cdFx0ICogIEBkZXByZWNhdGVkIFNpbmNlIHYxLjEwXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgIHZhciBvVGFibGUgPSAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgpO1xuXHRcdCAqXG5cdFx0ICogICAgICAvLyBTb3J0IG9uIGNvbHVtbiAxLCB3aGVuICdzb3J0ZXInIGlzIGNsaWNrZWQgb25cblx0XHQgKiAgICAgIG9UYWJsZS5mblNvcnRMaXN0ZW5lciggZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3NvcnRlcicpLCAxICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdHRoaXMuZm5Tb3J0TGlzdGVuZXIgPSBmdW5jdGlvbiggbk5vZGUsIGlDb2x1bW4sIGZuQ2FsbGJhY2sgKVxuXHRcdHtcblx0XHRcdHRoaXMuYXBpKCB0cnVlICkub3JkZXIubGlzdGVuZXIoIG5Ob2RlLCBpQ29sdW1uLCBmbkNhbGxiYWNrICk7XG5cdFx0fTtcblx0XHRcblx0XHRcblx0XHQvKipcblx0XHQgKiBVcGRhdGUgYSB0YWJsZSBjZWxsIG9yIHJvdyAtIHRoaXMgbWV0aG9kIHdpbGwgYWNjZXB0IGVpdGhlciBhIHNpbmdsZSB2YWx1ZSB0b1xuXHRcdCAqIHVwZGF0ZSB0aGUgY2VsbCB3aXRoLCBhbiBhcnJheSBvZiB2YWx1ZXMgd2l0aCBvbmUgZWxlbWVudCBmb3IgZWFjaCBjb2x1bW4gb3Jcblx0XHQgKiBhbiBvYmplY3QgaW4gdGhlIHNhbWUgZm9ybWF0IGFzIHRoZSBvcmlnaW5hbCBkYXRhIHNvdXJjZS4gVGhlIGZ1bmN0aW9uIGlzXG5cdFx0ICogc2VsZi1yZWZlcmVuY2luZyBpbiBvcmRlciB0byBtYWtlIHRoZSBtdWx0aSBjb2x1bW4gdXBkYXRlcyBlYXNpZXIuXG5cdFx0ICogIEBwYXJhbSB7b2JqZWN0fGFycmF5fHN0cmluZ30gbURhdGEgRGF0YSB0byB1cGRhdGUgdGhlIGNlbGwvcm93IHdpdGhcblx0XHQgKiAgQHBhcmFtIHtub2RlfGludH0gbVJvdyBUUiBlbGVtZW50IHlvdSB3YW50IHRvIHVwZGF0ZSBvciB0aGUgYW9EYXRhIGluZGV4XG5cdFx0ICogIEBwYXJhbSB7aW50fSBbaUNvbHVtbl0gVGhlIGNvbHVtbiB0byB1cGRhdGUsIGdpdmUgYXMgbnVsbCBvciB1bmRlZmluZWQgdG9cblx0XHQgKiAgICB1cGRhdGUgYSB3aG9sZSByb3cuXG5cdFx0ICogIEBwYXJhbSB7Ym9vbH0gW2JSZWRyYXc9dHJ1ZV0gUmVkcmF3IHRoZSB0YWJsZSBvciBub3Rcblx0XHQgKiAgQHBhcmFtIHtib29sfSBbYkFjdGlvbj10cnVlXSBQZXJmb3JtIHByZS1kcmF3IGFjdGlvbnMgb3Igbm90XG5cdFx0ICogIEByZXR1cm5zIHtpbnR9IDAgb24gc3VjY2VzcywgMSBvbiBlcnJvclxuXHRcdCAqICBAZHRvcHQgQVBJXG5cdFx0ICogIEBkZXByZWNhdGVkIFNpbmNlIHYxLjEwXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgIHZhciBvVGFibGUgPSAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgpO1xuXHRcdCAqICAgICAgb1RhYmxlLmZuVXBkYXRlKCAnRXhhbXBsZSB1cGRhdGUnLCAwLCAwICk7IC8vIFNpbmdsZSBjZWxsXG5cdFx0ICogICAgICBvVGFibGUuZm5VcGRhdGUoIFsnYScsICdiJywgJ2MnLCAnZCcsICdlJ10sICQoJ3Rib2R5IHRyJylbMF0gKTsgLy8gUm93XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdHRoaXMuZm5VcGRhdGUgPSBmdW5jdGlvbiggbURhdGEsIG1Sb3csIGlDb2x1bW4sIGJSZWRyYXcsIGJBY3Rpb24gKVxuXHRcdHtcblx0XHRcdHZhciBhcGkgPSB0aGlzLmFwaSggdHJ1ZSApO1xuXHRcdFxuXHRcdFx0aWYgKCBpQ29sdW1uID09PSB1bmRlZmluZWQgfHwgaUNvbHVtbiA9PT0gbnVsbCApIHtcblx0XHRcdFx0YXBpLnJvdyggbVJvdyApLmRhdGEoIG1EYXRhICk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0YXBpLmNlbGwoIG1Sb3csIGlDb2x1bW4gKS5kYXRhKCBtRGF0YSApO1xuXHRcdFx0fVxuXHRcdFxuXHRcdFx0aWYgKCBiQWN0aW9uID09PSB1bmRlZmluZWQgfHwgYkFjdGlvbiApIHtcblx0XHRcdFx0YXBpLmNvbHVtbnMuYWRqdXN0KCk7XG5cdFx0XHR9XG5cdFx0XG5cdFx0XHRpZiAoIGJSZWRyYXcgPT09IHVuZGVmaW5lZCB8fCBiUmVkcmF3ICkge1xuXHRcdFx0XHRhcGkuZHJhdygpO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIDA7XG5cdFx0fTtcblx0XHRcblx0XHRcblx0XHQvKipcblx0XHQgKiBQcm92aWRlIGEgY29tbW9uIG1ldGhvZCBmb3IgcGx1Zy1pbnMgdG8gY2hlY2sgdGhlIHZlcnNpb24gb2YgRGF0YVRhYmxlcyBiZWluZyB1c2VkLCBpbiBvcmRlclxuXHRcdCAqIHRvIGVuc3VyZSBjb21wYXRpYmlsaXR5LlxuXHRcdCAqICBAcGFyYW0ge3N0cmluZ30gc1ZlcnNpb24gVmVyc2lvbiBzdHJpbmcgdG8gY2hlY2sgZm9yLCBpbiB0aGUgZm9ybWF0IFwiWC5ZLlpcIi4gTm90ZSB0aGF0IHRoZVxuXHRcdCAqICAgIGZvcm1hdHMgXCJYXCIgYW5kIFwiWC5ZXCIgYXJlIGFsc28gYWNjZXB0YWJsZS5cblx0XHQgKiAgQHJldHVybnMge2Jvb2xlYW59IHRydWUgaWYgdGhpcyB2ZXJzaW9uIG9mIERhdGFUYWJsZXMgaXMgZ3JlYXRlciBvciBlcXVhbCB0byB0aGUgcmVxdWlyZWRcblx0XHQgKiAgICB2ZXJzaW9uLCBvciBmYWxzZSBpZiB0aGlzIHZlcnNpb24gb2YgRGF0YVRhbGVzIGlzIG5vdCBzdWl0YWJsZVxuXHRcdCAqICBAbWV0aG9kXG5cdFx0ICogIEBkdG9wdCBBUElcblx0XHQgKiAgQGRlcHJlY2F0ZWQgU2luY2UgdjEuMTBcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgdmFyIG9UYWJsZSA9ICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCk7XG5cdFx0ICogICAgICBhbGVydCggb1RhYmxlLmZuVmVyc2lvbkNoZWNrKCAnMS45LjAnICkgKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0dGhpcy5mblZlcnNpb25DaGVjayA9IF9leHQuZm5WZXJzaW9uQ2hlY2s7XG5cdFx0XG5cblx0XHR2YXIgX3RoYXQgPSB0aGlzO1xuXHRcdHZhciBlbXB0eUluaXQgPSBvcHRpb25zID09PSB1bmRlZmluZWQ7XG5cdFx0dmFyIGxlbiA9IHRoaXMubGVuZ3RoO1xuXG5cdFx0aWYgKCBlbXB0eUluaXQgKSB7XG5cdFx0XHRvcHRpb25zID0ge307XG5cdFx0fVxuXG5cdFx0dGhpcy5vQXBpID0gdGhpcy5pbnRlcm5hbCA9IF9leHQuaW50ZXJuYWw7XG5cblx0XHQvLyBFeHRlbmQgd2l0aCBvbGQgc3R5bGUgcGx1Zy1pbiBBUEkgbWV0aG9kc1xuXHRcdGZvciAoIHZhciBmbiBpbiBEYXRhVGFibGUuZXh0LmludGVybmFsICkge1xuXHRcdFx0aWYgKCBmbiApIHtcblx0XHRcdFx0dGhpc1tmbl0gPSBfZm5FeHRlcm5BcGlGdW5jKGZuKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aGlzLmVhY2goZnVuY3Rpb24oKSB7XG5cdFx0XHQvLyBGb3IgZWFjaCBpbml0aWFsaXNhdGlvbiB3ZSB3YW50IHRvIGdpdmUgaXQgYSBjbGVhbiBpbml0aWFsaXNhdGlvblxuXHRcdFx0Ly8gb2JqZWN0IHRoYXQgY2FuIGJlIGJhc2hlZCBhcm91bmRcblx0XHRcdHZhciBvID0ge307XG5cdFx0XHR2YXIgb0luaXQgPSBsZW4gPiAxID8gLy8gb3B0aW1pc2F0aW9uIGZvciBzaW5nbGUgdGFibGUgY2FzZVxuXHRcdFx0XHRfZm5FeHRlbmQoIG8sIG9wdGlvbnMsIHRydWUgKSA6XG5cdFx0XHRcdG9wdGlvbnM7XG5cblx0XHRcdC8qZ2xvYmFsIG9Jbml0LF90aGF0LGVtcHR5SW5pdCovXG5cdFx0XHR2YXIgaT0wLCBpTGVuLCBqLCBqTGVuLCBrLCBrTGVuO1xuXHRcdFx0dmFyIHNJZCA9IHRoaXMuZ2V0QXR0cmlidXRlKCAnaWQnICk7XG5cdFx0XHR2YXIgYkluaXRIYW5kZWRPZmYgPSBmYWxzZTtcblx0XHRcdHZhciBkZWZhdWx0cyA9IERhdGFUYWJsZS5kZWZhdWx0cztcblx0XHRcdHZhciAkdGhpcyA9ICQodGhpcyk7XG5cdFx0XHRcblx0XHRcdFxuXHRcdFx0LyogU2FuaXR5IGNoZWNrICovXG5cdFx0XHRpZiAoIHRoaXMubm9kZU5hbWUudG9Mb3dlckNhc2UoKSAhPSAndGFibGUnIClcblx0XHRcdHtcblx0XHRcdFx0X2ZuTG9nKCBudWxsLCAwLCAnTm9uLXRhYmxlIG5vZGUgaW5pdGlhbGlzYXRpb24gKCcrdGhpcy5ub2RlTmFtZSsnKScsIDIgKTtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXHRcdFx0XG5cdFx0XHQvKiBCYWNrd2FyZHMgY29tcGF0aWJpbGl0eSBmb3IgdGhlIGRlZmF1bHRzICovXG5cdFx0XHRfZm5Db21wYXRPcHRzKCBkZWZhdWx0cyApO1xuXHRcdFx0X2ZuQ29tcGF0Q29scyggZGVmYXVsdHMuY29sdW1uICk7XG5cdFx0XHRcblx0XHRcdC8qIENvbnZlcnQgdGhlIGNhbWVsLWNhc2UgZGVmYXVsdHMgdG8gSHVuZ2FyaWFuICovXG5cdFx0XHRfZm5DYW1lbFRvSHVuZ2FyaWFuKCBkZWZhdWx0cywgZGVmYXVsdHMsIHRydWUgKTtcblx0XHRcdF9mbkNhbWVsVG9IdW5nYXJpYW4oIGRlZmF1bHRzLmNvbHVtbiwgZGVmYXVsdHMuY29sdW1uLCB0cnVlICk7XG5cdFx0XHRcblx0XHRcdC8qIFNldHRpbmcgdXAgdGhlIGluaXRpYWxpc2F0aW9uIG9iamVjdCAqL1xuXHRcdFx0X2ZuQ2FtZWxUb0h1bmdhcmlhbiggZGVmYXVsdHMsICQuZXh0ZW5kKCBvSW5pdCwgJHRoaXMuZGF0YSgpICksIHRydWUgKTtcblx0XHRcdFxuXHRcdFx0XG5cdFx0XHRcblx0XHRcdC8qIENoZWNrIHRvIHNlZSBpZiB3ZSBhcmUgcmUtaW5pdGlhbGlzaW5nIGEgdGFibGUgKi9cblx0XHRcdHZhciBhbGxTZXR0aW5ncyA9IERhdGFUYWJsZS5zZXR0aW5ncztcblx0XHRcdGZvciAoIGk9MCwgaUxlbj1hbGxTZXR0aW5ncy5sZW5ndGggOyBpPGlMZW4gOyBpKysgKVxuXHRcdFx0e1xuXHRcdFx0XHR2YXIgcyA9IGFsbFNldHRpbmdzW2ldO1xuXHRcdFx0XG5cdFx0XHRcdC8qIEJhc2UgY2hlY2sgb24gdGFibGUgbm9kZSAqL1xuXHRcdFx0XHRpZiAoXG5cdFx0XHRcdFx0cy5uVGFibGUgPT0gdGhpcyB8fFxuXHRcdFx0XHRcdChzLm5USGVhZCAmJiBzLm5USGVhZC5wYXJlbnROb2RlID09IHRoaXMpIHx8XG5cdFx0XHRcdFx0KHMublRGb290ICYmIHMublRGb290LnBhcmVudE5vZGUgPT0gdGhpcylcblx0XHRcdFx0KSB7XG5cdFx0XHRcdFx0dmFyIGJSZXRyaWV2ZSA9IG9Jbml0LmJSZXRyaWV2ZSAhPT0gdW5kZWZpbmVkID8gb0luaXQuYlJldHJpZXZlIDogZGVmYXVsdHMuYlJldHJpZXZlO1xuXHRcdFx0XHRcdHZhciBiRGVzdHJveSA9IG9Jbml0LmJEZXN0cm95ICE9PSB1bmRlZmluZWQgPyBvSW5pdC5iRGVzdHJveSA6IGRlZmF1bHRzLmJEZXN0cm95O1xuXHRcdFx0XG5cdFx0XHRcdFx0aWYgKCBlbXB0eUluaXQgfHwgYlJldHJpZXZlIClcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRyZXR1cm4gcy5vSW5zdGFuY2U7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGVsc2UgaWYgKCBiRGVzdHJveSApXG5cdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0cy5vSW5zdGFuY2UuZm5EZXN0cm95KCk7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZVxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdF9mbkxvZyggcywgMCwgJ0Nhbm5vdCByZWluaXRpYWxpc2UgRGF0YVRhYmxlJywgMyApO1xuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XG5cdFx0XHRcdC8qIElmIHRoZSBlbGVtZW50IHdlIGFyZSBpbml0aWFsaXNpbmcgaGFzIHRoZSBzYW1lIElEIGFzIGEgdGFibGUgd2hpY2ggd2FzIHByZXZpb3VzbHlcblx0XHRcdFx0ICogaW5pdGlhbGlzZWQsIGJ1dCB0aGUgdGFibGUgbm9kZXMgZG9uJ3QgbWF0Y2ggKGZyb20gYmVmb3JlKSB0aGVuIHdlIGRlc3Ryb3kgdGhlIG9sZFxuXHRcdFx0XHQgKiBpbnN0YW5jZSBieSBzaW1wbHkgZGVsZXRpbmcgaXQuIFRoaXMgaXMgdW5kZXIgdGhlIGFzc3VtcHRpb24gdGhhdCB0aGUgdGFibGUgaGFzIGJlZW5cblx0XHRcdFx0ICogZGVzdHJveWVkIGJ5IG90aGVyIG1ldGhvZHMuIEFueW9uZSB1c2luZyBub24taWQgc2VsZWN0b3JzIHdpbGwgbmVlZCB0byBkbyB0aGlzIG1hbnVhbGx5XG5cdFx0XHRcdCAqL1xuXHRcdFx0XHRpZiAoIHMuc1RhYmxlSWQgPT0gdGhpcy5pZCApXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRhbGxTZXR0aW5ncy5zcGxpY2UoIGksIDEgKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0XG5cdFx0XHQvKiBFbnN1cmUgdGhlIHRhYmxlIGhhcyBhbiBJRCAtIHJlcXVpcmVkIGZvciBhY2Nlc3NpYmlsaXR5ICovXG5cdFx0XHRpZiAoIHNJZCA9PT0gbnVsbCB8fCBzSWQgPT09IFwiXCIgKVxuXHRcdFx0e1xuXHRcdFx0XHRzSWQgPSBcIkRhdGFUYWJsZXNfVGFibGVfXCIrKERhdGFUYWJsZS5leHQuX3VuaXF1ZSsrKTtcblx0XHRcdFx0dGhpcy5pZCA9IHNJZDtcblx0XHRcdH1cblx0XHRcdFxuXHRcdFx0LyogQ3JlYXRlIHRoZSBzZXR0aW5ncyBvYmplY3QgZm9yIHRoaXMgdGFibGUgYW5kIHNldCBzb21lIG9mIHRoZSBkZWZhdWx0IHBhcmFtZXRlcnMgKi9cblx0XHRcdHZhciBvU2V0dGluZ3MgPSAkLmV4dGVuZCggdHJ1ZSwge30sIERhdGFUYWJsZS5tb2RlbHMub1NldHRpbmdzLCB7XG5cdFx0XHRcdFwic0Rlc3Ryb3lXaWR0aFwiOiAkdGhpc1swXS5zdHlsZS53aWR0aCxcblx0XHRcdFx0XCJzSW5zdGFuY2VcIjogICAgIHNJZCxcblx0XHRcdFx0XCJzVGFibGVJZFwiOiAgICAgIHNJZFxuXHRcdFx0fSApO1xuXHRcdFx0b1NldHRpbmdzLm5UYWJsZSA9IHRoaXM7XG5cdFx0XHRvU2V0dGluZ3Mub0FwaSAgID0gX3RoYXQuaW50ZXJuYWw7XG5cdFx0XHRvU2V0dGluZ3Mub0luaXQgID0gb0luaXQ7XG5cdFx0XHRcblx0XHRcdGFsbFNldHRpbmdzLnB1c2goIG9TZXR0aW5ncyApO1xuXHRcdFx0XG5cdFx0XHQvLyBOZWVkIHRvIGFkZCB0aGUgaW5zdGFuY2UgYWZ0ZXIgdGhlIGluc3RhbmNlIGFmdGVyIHRoZSBzZXR0aW5ncyBvYmplY3QgaGFzIGJlZW4gYWRkZWRcblx0XHRcdC8vIHRvIHRoZSBzZXR0aW5ncyBhcnJheSwgc28gd2UgY2FuIHNlbGYgcmVmZXJlbmNlIHRoZSB0YWJsZSBpbnN0YW5jZSBpZiBtb3JlIHRoYW4gb25lXG5cdFx0XHRvU2V0dGluZ3Mub0luc3RhbmNlID0gKF90aGF0Lmxlbmd0aD09PTEpID8gX3RoYXQgOiAkdGhpcy5kYXRhVGFibGUoKTtcblx0XHRcdFxuXHRcdFx0Ly8gQmFja3dhcmRzIGNvbXBhdGliaWxpdHksIGJlZm9yZSB3ZSBhcHBseSBhbGwgdGhlIGRlZmF1bHRzXG5cdFx0XHRfZm5Db21wYXRPcHRzKCBvSW5pdCApO1xuXHRcdFx0X2ZuTGFuZ3VhZ2VDb21wYXQoIG9Jbml0Lm9MYW5ndWFnZSApO1xuXHRcdFx0XG5cdFx0XHQvLyBJZiB0aGUgbGVuZ3RoIG1lbnUgaXMgZ2l2ZW4sIGJ1dCB0aGUgaW5pdCBkaXNwbGF5IGxlbmd0aCBpcyBub3QsIHVzZSB0aGUgbGVuZ3RoIG1lbnVcblx0XHRcdGlmICggb0luaXQuYUxlbmd0aE1lbnUgJiYgISBvSW5pdC5pRGlzcGxheUxlbmd0aCApXG5cdFx0XHR7XG5cdFx0XHRcdG9Jbml0LmlEaXNwbGF5TGVuZ3RoID0gQXJyYXkuaXNBcnJheSggb0luaXQuYUxlbmd0aE1lbnVbMF0gKSA/XG5cdFx0XHRcdFx0b0luaXQuYUxlbmd0aE1lbnVbMF1bMF0gOiBvSW5pdC5hTGVuZ3RoTWVudVswXTtcblx0XHRcdH1cblx0XHRcdFxuXHRcdFx0Ly8gQXBwbHkgdGhlIGRlZmF1bHRzIGFuZCBpbml0IG9wdGlvbnMgdG8gbWFrZSBhIHNpbmdsZSBpbml0IG9iamVjdCB3aWxsIGFsbFxuXHRcdFx0Ly8gb3B0aW9ucyBkZWZpbmVkIGZyb20gZGVmYXVsdHMgYW5kIGluc3RhbmNlIG9wdGlvbnMuXG5cdFx0XHRvSW5pdCA9IF9mbkV4dGVuZCggJC5leHRlbmQoIHRydWUsIHt9LCBkZWZhdWx0cyApLCBvSW5pdCApO1xuXHRcdFx0XG5cdFx0XHRcblx0XHRcdC8vIE1hcCB0aGUgaW5pdGlhbGlzYXRpb24gb3B0aW9ucyBvbnRvIHRoZSBzZXR0aW5ncyBvYmplY3Rcblx0XHRcdF9mbk1hcCggb1NldHRpbmdzLm9GZWF0dXJlcywgb0luaXQsIFtcblx0XHRcdFx0XCJiUGFnaW5hdGVcIixcblx0XHRcdFx0XCJiTGVuZ3RoQ2hhbmdlXCIsXG5cdFx0XHRcdFwiYkZpbHRlclwiLFxuXHRcdFx0XHRcImJTb3J0XCIsXG5cdFx0XHRcdFwiYlNvcnRNdWx0aVwiLFxuXHRcdFx0XHRcImJJbmZvXCIsXG5cdFx0XHRcdFwiYlByb2Nlc3NpbmdcIixcblx0XHRcdFx0XCJiQXV0b1dpZHRoXCIsXG5cdFx0XHRcdFwiYlNvcnRDbGFzc2VzXCIsXG5cdFx0XHRcdFwiYlNlcnZlclNpZGVcIixcblx0XHRcdFx0XCJiRGVmZXJSZW5kZXJcIlxuXHRcdFx0XSApO1xuXHRcdFx0X2ZuTWFwKCBvU2V0dGluZ3MsIG9Jbml0LCBbXG5cdFx0XHRcdFwiYXNTdHJpcGVDbGFzc2VzXCIsXG5cdFx0XHRcdFwiYWpheFwiLFxuXHRcdFx0XHRcImZuU2VydmVyRGF0YVwiLFxuXHRcdFx0XHRcImZuRm9ybWF0TnVtYmVyXCIsXG5cdFx0XHRcdFwic1NlcnZlck1ldGhvZFwiLFxuXHRcdFx0XHRcImFhU29ydGluZ1wiLFxuXHRcdFx0XHRcImFhU29ydGluZ0ZpeGVkXCIsXG5cdFx0XHRcdFwiYUxlbmd0aE1lbnVcIixcblx0XHRcdFx0XCJzUGFnaW5hdGlvblR5cGVcIixcblx0XHRcdFx0XCJzQWpheFNvdXJjZVwiLFxuXHRcdFx0XHRcInNBamF4RGF0YVByb3BcIixcblx0XHRcdFx0XCJpU3RhdGVEdXJhdGlvblwiLFxuXHRcdFx0XHRcInNEb21cIixcblx0XHRcdFx0XCJiU29ydENlbGxzVG9wXCIsXG5cdFx0XHRcdFwiaVRhYkluZGV4XCIsXG5cdFx0XHRcdFwiZm5TdGF0ZUxvYWRDYWxsYmFja1wiLFxuXHRcdFx0XHRcImZuU3RhdGVTYXZlQ2FsbGJhY2tcIixcblx0XHRcdFx0XCJyZW5kZXJlclwiLFxuXHRcdFx0XHRcInNlYXJjaERlbGF5XCIsXG5cdFx0XHRcdFwicm93SWRcIixcblx0XHRcdFx0WyBcImlDb29raWVEdXJhdGlvblwiLCBcImlTdGF0ZUR1cmF0aW9uXCIgXSwgLy8gYmFja3dhcmRzIGNvbXBhdFxuXHRcdFx0XHRbIFwib1NlYXJjaFwiLCBcIm9QcmV2aW91c1NlYXJjaFwiIF0sXG5cdFx0XHRcdFsgXCJhb1NlYXJjaENvbHNcIiwgXCJhb1ByZVNlYXJjaENvbHNcIiBdLFxuXHRcdFx0XHRbIFwiaURpc3BsYXlMZW5ndGhcIiwgXCJfaURpc3BsYXlMZW5ndGhcIiBdXG5cdFx0XHRdICk7XG5cdFx0XHRfZm5NYXAoIG9TZXR0aW5ncy5vU2Nyb2xsLCBvSW5pdCwgW1xuXHRcdFx0XHRbIFwic1Njcm9sbFhcIiwgXCJzWFwiIF0sXG5cdFx0XHRcdFsgXCJzU2Nyb2xsWElubmVyXCIsIFwic1hJbm5lclwiIF0sXG5cdFx0XHRcdFsgXCJzU2Nyb2xsWVwiLCBcInNZXCIgXSxcblx0XHRcdFx0WyBcImJTY3JvbGxDb2xsYXBzZVwiLCBcImJDb2xsYXBzZVwiIF1cblx0XHRcdF0gKTtcblx0XHRcdF9mbk1hcCggb1NldHRpbmdzLm9MYW5ndWFnZSwgb0luaXQsIFwiZm5JbmZvQ2FsbGJhY2tcIiApO1xuXHRcdFx0XG5cdFx0XHQvKiBDYWxsYmFjayBmdW5jdGlvbnMgd2hpY2ggYXJlIGFycmF5IGRyaXZlbiAqL1xuXHRcdFx0X2ZuQ2FsbGJhY2tSZWcoIG9TZXR0aW5ncywgJ2FvRHJhd0NhbGxiYWNrJywgICAgICAgb0luaXQuZm5EcmF3Q2FsbGJhY2ssICAgICAgJ3VzZXInICk7XG5cdFx0XHRfZm5DYWxsYmFja1JlZyggb1NldHRpbmdzLCAnYW9TZXJ2ZXJQYXJhbXMnLCAgICAgICBvSW5pdC5mblNlcnZlclBhcmFtcywgICAgICAndXNlcicgKTtcblx0XHRcdF9mbkNhbGxiYWNrUmVnKCBvU2V0dGluZ3MsICdhb1N0YXRlU2F2ZVBhcmFtcycsICAgIG9Jbml0LmZuU3RhdGVTYXZlUGFyYW1zLCAgICd1c2VyJyApO1xuXHRcdFx0X2ZuQ2FsbGJhY2tSZWcoIG9TZXR0aW5ncywgJ2FvU3RhdGVMb2FkUGFyYW1zJywgICAgb0luaXQuZm5TdGF0ZUxvYWRQYXJhbXMsICAgJ3VzZXInICk7XG5cdFx0XHRfZm5DYWxsYmFja1JlZyggb1NldHRpbmdzLCAnYW9TdGF0ZUxvYWRlZCcsICAgICAgICBvSW5pdC5mblN0YXRlTG9hZGVkLCAgICAgICAndXNlcicgKTtcblx0XHRcdF9mbkNhbGxiYWNrUmVnKCBvU2V0dGluZ3MsICdhb1Jvd0NhbGxiYWNrJywgICAgICAgIG9Jbml0LmZuUm93Q2FsbGJhY2ssICAgICAgICd1c2VyJyApO1xuXHRcdFx0X2ZuQ2FsbGJhY2tSZWcoIG9TZXR0aW5ncywgJ2FvUm93Q3JlYXRlZENhbGxiYWNrJywgb0luaXQuZm5DcmVhdGVkUm93LCAgICAgICAgJ3VzZXInICk7XG5cdFx0XHRfZm5DYWxsYmFja1JlZyggb1NldHRpbmdzLCAnYW9IZWFkZXJDYWxsYmFjaycsICAgICBvSW5pdC5mbkhlYWRlckNhbGxiYWNrLCAgICAndXNlcicgKTtcblx0XHRcdF9mbkNhbGxiYWNrUmVnKCBvU2V0dGluZ3MsICdhb0Zvb3RlckNhbGxiYWNrJywgICAgIG9Jbml0LmZuRm9vdGVyQ2FsbGJhY2ssICAgICd1c2VyJyApO1xuXHRcdFx0X2ZuQ2FsbGJhY2tSZWcoIG9TZXR0aW5ncywgJ2FvSW5pdENvbXBsZXRlJywgICAgICAgb0luaXQuZm5Jbml0Q29tcGxldGUsICAgICAgJ3VzZXInICk7XG5cdFx0XHRfZm5DYWxsYmFja1JlZyggb1NldHRpbmdzLCAnYW9QcmVEcmF3Q2FsbGJhY2snLCAgICBvSW5pdC5mblByZURyYXdDYWxsYmFjaywgICAndXNlcicgKTtcblx0XHRcdFxuXHRcdFx0b1NldHRpbmdzLnJvd0lkRm4gPSBfZm5HZXRPYmplY3REYXRhRm4oIG9Jbml0LnJvd0lkICk7XG5cdFx0XHRcblx0XHRcdC8qIEJyb3dzZXIgc3VwcG9ydCBkZXRlY3Rpb24gKi9cblx0XHRcdF9mbkJyb3dzZXJEZXRlY3QoIG9TZXR0aW5ncyApO1xuXHRcdFx0XG5cdFx0XHR2YXIgb0NsYXNzZXMgPSBvU2V0dGluZ3Mub0NsYXNzZXM7XG5cdFx0XHRcblx0XHRcdCQuZXh0ZW5kKCBvQ2xhc3NlcywgRGF0YVRhYmxlLmV4dC5jbGFzc2VzLCBvSW5pdC5vQ2xhc3NlcyApO1xuXHRcdFx0JHRoaXMuYWRkQ2xhc3MoIG9DbGFzc2VzLnNUYWJsZSApO1xuXHRcdFx0XG5cdFx0XHRcblx0XHRcdGlmICggb1NldHRpbmdzLmlJbml0RGlzcGxheVN0YXJ0ID09PSB1bmRlZmluZWQgKVxuXHRcdFx0e1xuXHRcdFx0XHQvKiBEaXNwbGF5IHN0YXJ0IHBvaW50LCB0YWtpbmcgaW50byBhY2NvdW50IHRoZSBzYXZlIHNhdmluZyAqL1xuXHRcdFx0XHRvU2V0dGluZ3MuaUluaXREaXNwbGF5U3RhcnQgPSBvSW5pdC5pRGlzcGxheVN0YXJ0O1xuXHRcdFx0XHRvU2V0dGluZ3MuX2lEaXNwbGF5U3RhcnQgPSBvSW5pdC5pRGlzcGxheVN0YXJ0O1xuXHRcdFx0fVxuXHRcdFx0XG5cdFx0XHRpZiAoIG9Jbml0LmlEZWZlckxvYWRpbmcgIT09IG51bGwgKVxuXHRcdFx0e1xuXHRcdFx0XHRvU2V0dGluZ3MuYkRlZmVyTG9hZGluZyA9IHRydWU7XG5cdFx0XHRcdHZhciB0bXAgPSBBcnJheS5pc0FycmF5KCBvSW5pdC5pRGVmZXJMb2FkaW5nICk7XG5cdFx0XHRcdG9TZXR0aW5ncy5faVJlY29yZHNEaXNwbGF5ID0gdG1wID8gb0luaXQuaURlZmVyTG9hZGluZ1swXSA6IG9Jbml0LmlEZWZlckxvYWRpbmc7XG5cdFx0XHRcdG9TZXR0aW5ncy5faVJlY29yZHNUb3RhbCA9IHRtcCA/IG9Jbml0LmlEZWZlckxvYWRpbmdbMV0gOiBvSW5pdC5pRGVmZXJMb2FkaW5nO1xuXHRcdFx0fVxuXHRcdFx0XG5cdFx0XHQvKiBMYW5ndWFnZSBkZWZpbml0aW9ucyAqL1xuXHRcdFx0dmFyIG9MYW5ndWFnZSA9IG9TZXR0aW5ncy5vTGFuZ3VhZ2U7XG5cdFx0XHQkLmV4dGVuZCggdHJ1ZSwgb0xhbmd1YWdlLCBvSW5pdC5vTGFuZ3VhZ2UgKTtcblx0XHRcdFxuXHRcdFx0aWYgKCBvTGFuZ3VhZ2Uuc1VybCApXG5cdFx0XHR7XG5cdFx0XHRcdC8qIEdldCB0aGUgbGFuZ3VhZ2UgZGVmaW5pdGlvbnMgZnJvbSBhIGZpbGUgLSBiZWNhdXNlIHRoaXMgQWpheCBjYWxsIG1ha2VzIHRoZSBsYW5ndWFnZVxuXHRcdFx0XHQgKiBnZXQgYXN5bmMgdG8gdGhlIHJlbWFpbmRlciBvZiB0aGlzIGZ1bmN0aW9uIHdlIHVzZSBiSW5pdEhhbmRlZE9mZiB0byBpbmRpY2F0ZSB0aGF0XG5cdFx0XHRcdCAqIF9mbkluaXRpYWxpc2Ugd2lsbCBiZSBmaXJlZCBieSB0aGUgcmV0dXJuZWQgQWpheCBoYW5kbGVyLCByYXRoZXIgdGhhbiB0aGUgY29uc3RydWN0b3Jcblx0XHRcdFx0ICovXG5cdFx0XHRcdCQuYWpheCgge1xuXHRcdFx0XHRcdGRhdGFUeXBlOiAnanNvbicsXG5cdFx0XHRcdFx0dXJsOiBvTGFuZ3VhZ2Uuc1VybCxcblx0XHRcdFx0XHRzdWNjZXNzOiBmdW5jdGlvbiAoIGpzb24gKSB7XG5cdFx0XHRcdFx0XHRfZm5DYW1lbFRvSHVuZ2FyaWFuKCBkZWZhdWx0cy5vTGFuZ3VhZ2UsIGpzb24gKTtcblx0XHRcdFx0XHRcdF9mbkxhbmd1YWdlQ29tcGF0KCBqc29uICk7XG5cdFx0XHRcdFx0XHQkLmV4dGVuZCggdHJ1ZSwgb0xhbmd1YWdlLCBqc29uICk7XG5cdFx0XHRcblx0XHRcdFx0XHRcdF9mbkNhbGxiYWNrRmlyZSggb1NldHRpbmdzLCBudWxsLCAnaTE4bicsIFtvU2V0dGluZ3NdKTtcblx0XHRcdFx0XHRcdF9mbkluaXRpYWxpc2UoIG9TZXR0aW5ncyApO1xuXHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0ZXJyb3I6IGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRcdC8vIEVycm9yIG9jY3VycmVkIGxvYWRpbmcgbGFuZ3VhZ2UgZmlsZSwgY29udGludWUgb24gYXMgYmVzdCB3ZSBjYW5cblx0XHRcdFx0XHRcdF9mbkluaXRpYWxpc2UoIG9TZXR0aW5ncyApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHRcdFx0XHRiSW5pdEhhbmRlZE9mZiA9IHRydWU7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0X2ZuQ2FsbGJhY2tGaXJlKCBvU2V0dGluZ3MsIG51bGwsICdpMThuJywgW29TZXR0aW5nc10pO1xuXHRcdFx0fVxuXHRcdFx0XG5cdFx0XHQvKlxuXHRcdFx0ICogU3RyaXBlc1xuXHRcdFx0ICovXG5cdFx0XHRpZiAoIG9Jbml0LmFzU3RyaXBlQ2xhc3NlcyA9PT0gbnVsbCApXG5cdFx0XHR7XG5cdFx0XHRcdG9TZXR0aW5ncy5hc1N0cmlwZUNsYXNzZXMgPVtcblx0XHRcdFx0XHRvQ2xhc3Nlcy5zU3RyaXBlT2RkLFxuXHRcdFx0XHRcdG9DbGFzc2VzLnNTdHJpcGVFdmVuXG5cdFx0XHRcdF07XG5cdFx0XHR9XG5cdFx0XHRcblx0XHRcdC8qIFJlbW92ZSByb3cgc3RyaXBlIGNsYXNzZXMgaWYgdGhleSBhcmUgYWxyZWFkeSBvbiB0aGUgdGFibGUgcm93ICovXG5cdFx0XHR2YXIgc3RyaXBlQ2xhc3NlcyA9IG9TZXR0aW5ncy5hc1N0cmlwZUNsYXNzZXM7XG5cdFx0XHR2YXIgcm93T25lID0gJHRoaXMuY2hpbGRyZW4oJ3Rib2R5JykuZmluZCgndHInKS5lcSgwKTtcblx0XHRcdGlmICggJC5pbkFycmF5KCB0cnVlLCAkLm1hcCggc3RyaXBlQ2xhc3NlcywgZnVuY3Rpb24oZWwsIGkpIHtcblx0XHRcdFx0cmV0dXJuIHJvd09uZS5oYXNDbGFzcyhlbCk7XG5cdFx0XHR9ICkgKSAhPT0gLTEgKSB7XG5cdFx0XHRcdCQoJ3Rib2R5IHRyJywgdGhpcykucmVtb3ZlQ2xhc3MoIHN0cmlwZUNsYXNzZXMuam9pbignICcpICk7XG5cdFx0XHRcdG9TZXR0aW5ncy5hc0Rlc3Ryb3lTdHJpcGVzID0gc3RyaXBlQ2xhc3Nlcy5zbGljZSgpO1xuXHRcdFx0fVxuXHRcdFx0XG5cdFx0XHQvKlxuXHRcdFx0ICogQ29sdW1uc1xuXHRcdFx0ICogU2VlIGlmIHdlIHNob3VsZCBsb2FkIGNvbHVtbnMgYXV0b21hdGljYWxseSBvciB1c2UgZGVmaW5lZCBvbmVzXG5cdFx0XHQgKi9cblx0XHRcdHZhciBhblRocyA9IFtdO1xuXHRcdFx0dmFyIGFvQ29sdW1uc0luaXQ7XG5cdFx0XHR2YXIgblRoZWFkID0gdGhpcy5nZXRFbGVtZW50c0J5VGFnTmFtZSgndGhlYWQnKTtcblx0XHRcdGlmICggblRoZWFkLmxlbmd0aCAhPT0gMCApXG5cdFx0XHR7XG5cdFx0XHRcdF9mbkRldGVjdEhlYWRlciggb1NldHRpbmdzLmFvSGVhZGVyLCBuVGhlYWRbMF0gKTtcblx0XHRcdFx0YW5UaHMgPSBfZm5HZXRVbmlxdWVUaHMoIG9TZXR0aW5ncyApO1xuXHRcdFx0fVxuXHRcdFx0XG5cdFx0XHQvKiBJZiBub3QgZ2l2ZW4gYSBjb2x1bW4gYXJyYXksIGdlbmVyYXRlIG9uZSB3aXRoIG51bGxzICovXG5cdFx0XHRpZiAoIG9Jbml0LmFvQ29sdW1ucyA9PT0gbnVsbCApXG5cdFx0XHR7XG5cdFx0XHRcdGFvQ29sdW1uc0luaXQgPSBbXTtcblx0XHRcdFx0Zm9yICggaT0wLCBpTGVuPWFuVGhzLmxlbmd0aCA7IGk8aUxlbiA7IGkrKyApXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRhb0NvbHVtbnNJbml0LnB1c2goIG51bGwgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0ZWxzZVxuXHRcdFx0e1xuXHRcdFx0XHRhb0NvbHVtbnNJbml0ID0gb0luaXQuYW9Db2x1bW5zO1xuXHRcdFx0fVxuXHRcdFx0XG5cdFx0XHQvKiBBZGQgdGhlIGNvbHVtbnMgKi9cblx0XHRcdGZvciAoIGk9MCwgaUxlbj1hb0NvbHVtbnNJbml0Lmxlbmd0aCA7IGk8aUxlbiA7IGkrKyApXG5cdFx0XHR7XG5cdFx0XHRcdF9mbkFkZENvbHVtbiggb1NldHRpbmdzLCBhblRocyA/IGFuVGhzW2ldIDogbnVsbCApO1xuXHRcdFx0fVxuXHRcdFx0XG5cdFx0XHQvKiBBcHBseSB0aGUgY29sdW1uIGRlZmluaXRpb25zICovXG5cdFx0XHRfZm5BcHBseUNvbHVtbkRlZnMoIG9TZXR0aW5ncywgb0luaXQuYW9Db2x1bW5EZWZzLCBhb0NvbHVtbnNJbml0LCBmdW5jdGlvbiAoaUNvbCwgb0RlZikge1xuXHRcdFx0XHRfZm5Db2x1bW5PcHRpb25zKCBvU2V0dGluZ3MsIGlDb2wsIG9EZWYgKTtcblx0XHRcdH0gKTtcblx0XHRcdFxuXHRcdFx0LyogSFRNTDUgYXR0cmlidXRlIGRldGVjdGlvbiAtIGJ1aWxkIGFuIG1EYXRhIG9iamVjdCBhdXRvbWF0aWNhbGx5IGlmIHRoZVxuXHRcdFx0ICogYXR0cmlidXRlcyBhcmUgZm91bmRcblx0XHRcdCAqL1xuXHRcdFx0aWYgKCByb3dPbmUubGVuZ3RoICkge1xuXHRcdFx0XHR2YXIgYSA9IGZ1bmN0aW9uICggY2VsbCwgbmFtZSApIHtcblx0XHRcdFx0XHRyZXR1cm4gY2VsbC5nZXRBdHRyaWJ1dGUoICdkYXRhLScrbmFtZSApICE9PSBudWxsID8gbmFtZSA6IG51bGw7XG5cdFx0XHRcdH07XG5cdFx0XHRcblx0XHRcdFx0JCggcm93T25lWzBdICkuY2hpbGRyZW4oJ3RoLCB0ZCcpLmVhY2goIGZ1bmN0aW9uIChpLCBjZWxsKSB7XG5cdFx0XHRcdFx0dmFyIGNvbCA9IG9TZXR0aW5ncy5hb0NvbHVtbnNbaV07XG5cdFx0XHRcblx0XHRcdFx0XHRpZiAoIGNvbC5tRGF0YSA9PT0gaSApIHtcblx0XHRcdFx0XHRcdHZhciBzb3J0ID0gYSggY2VsbCwgJ3NvcnQnICkgfHwgYSggY2VsbCwgJ29yZGVyJyApO1xuXHRcdFx0XHRcdFx0dmFyIGZpbHRlciA9IGEoIGNlbGwsICdmaWx0ZXInICkgfHwgYSggY2VsbCwgJ3NlYXJjaCcgKTtcblx0XHRcdFxuXHRcdFx0XHRcdFx0aWYgKCBzb3J0ICE9PSBudWxsIHx8IGZpbHRlciAhPT0gbnVsbCApIHtcblx0XHRcdFx0XHRcdFx0Y29sLm1EYXRhID0ge1xuXHRcdFx0XHRcdFx0XHRcdF86ICAgICAgaSsnLmRpc3BsYXknLFxuXHRcdFx0XHRcdFx0XHRcdHNvcnQ6ICAgc29ydCAhPT0gbnVsbCAgID8gaSsnLkBkYXRhLScrc29ydCAgIDogdW5kZWZpbmVkLFxuXHRcdFx0XHRcdFx0XHRcdHR5cGU6ICAgc29ydCAhPT0gbnVsbCAgID8gaSsnLkBkYXRhLScrc29ydCAgIDogdW5kZWZpbmVkLFxuXHRcdFx0XHRcdFx0XHRcdGZpbHRlcjogZmlsdGVyICE9PSBudWxsID8gaSsnLkBkYXRhLScrZmlsdGVyIDogdW5kZWZpbmVkXG5cdFx0XHRcdFx0XHRcdH07XG5cdFx0XHRcblx0XHRcdFx0XHRcdFx0X2ZuQ29sdW1uT3B0aW9ucyggb1NldHRpbmdzLCBpICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cdFx0XHRcblx0XHRcdHZhciBmZWF0dXJlcyA9IG9TZXR0aW5ncy5vRmVhdHVyZXM7XG5cdFx0XHR2YXIgbG9hZGVkSW5pdCA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0Lypcblx0XHRcdFx0ICogU29ydGluZ1xuXHRcdFx0XHQgKiBAdG9kbyBGb3IgbW9kdWxhcmlzYXRpb24gKDEuMTEpIHRoaXMgbmVlZHMgdG8gZG8gaW50byBhIHNvcnQgc3RhcnQgdXAgaGFuZGxlclxuXHRcdFx0XHQgKi9cblx0XHRcdFxuXHRcdFx0XHQvLyBJZiBhYVNvcnRpbmcgaXMgbm90IGRlZmluZWQsIHRoZW4gd2UgdXNlIHRoZSBmaXJzdCBpbmRpY2F0b3IgaW4gYXNTb3J0aW5nXG5cdFx0XHRcdC8vIGluIGNhc2UgdGhhdCBoYXMgYmVlbiBhbHRlcmVkLCBzbyB0aGUgZGVmYXVsdCBzb3J0IHJlZmxlY3RzIHRoYXQgb3B0aW9uXG5cdFx0XHRcdGlmICggb0luaXQuYWFTb3J0aW5nID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0dmFyIHNvcnRpbmcgPSBvU2V0dGluZ3MuYWFTb3J0aW5nO1xuXHRcdFx0XHRcdGZvciAoIGk9MCwgaUxlbj1zb3J0aW5nLmxlbmd0aCA7IGk8aUxlbiA7IGkrKyApIHtcblx0XHRcdFx0XHRcdHNvcnRpbmdbaV1bMV0gPSBvU2V0dGluZ3MuYW9Db2x1bW5zWyBpIF0uYXNTb3J0aW5nWzBdO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XG5cdFx0XHRcdC8qIERvIGEgZmlyc3QgcGFzcyBvbiB0aGUgc29ydGluZyBjbGFzc2VzIChhbGxvd3MgYW55IHNpemUgY2hhbmdlcyB0byBiZSB0YWtlbiBpbnRvXG5cdFx0XHRcdCAqIGFjY291bnQsIGFuZCBhbHNvIHdpbGwgYXBwbHkgc29ydGluZyBkaXNhYmxlZCBjbGFzc2VzIGlmIGRpc2FibGVkXG5cdFx0XHRcdCAqL1xuXHRcdFx0XHRfZm5Tb3J0aW5nQ2xhc3Nlcyggb1NldHRpbmdzICk7XG5cdFx0XHRcblx0XHRcdFx0aWYgKCBmZWF0dXJlcy5iU29ydCApIHtcblx0XHRcdFx0XHRfZm5DYWxsYmFja1JlZyggb1NldHRpbmdzLCAnYW9EcmF3Q2FsbGJhY2snLCBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0XHRpZiAoIG9TZXR0aW5ncy5iU29ydGVkICkge1xuXHRcdFx0XHRcdFx0XHR2YXIgYVNvcnQgPSBfZm5Tb3J0RmxhdHRlbiggb1NldHRpbmdzICk7XG5cdFx0XHRcdFx0XHRcdHZhciBzb3J0ZWRDb2x1bW5zID0ge307XG5cdFx0XHRcblx0XHRcdFx0XHRcdFx0JC5lYWNoKCBhU29ydCwgZnVuY3Rpb24gKGksIHZhbCkge1xuXHRcdFx0XHRcdFx0XHRcdHNvcnRlZENvbHVtbnNbIHZhbC5zcmMgXSA9IHZhbC5kaXI7XG5cdFx0XHRcdFx0XHRcdH0gKTtcblx0XHRcdFxuXHRcdFx0XHRcdFx0XHRfZm5DYWxsYmFja0ZpcmUoIG9TZXR0aW5ncywgbnVsbCwgJ29yZGVyJywgW29TZXR0aW5ncywgYVNvcnQsIHNvcnRlZENvbHVtbnNdICk7XG5cdFx0XHRcdFx0XHRcdF9mblNvcnRBcmlhKCBvU2V0dGluZ3MgKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdH1cblx0XHRcdFxuXHRcdFx0XHRfZm5DYWxsYmFja1JlZyggb1NldHRpbmdzLCAnYW9EcmF3Q2FsbGJhY2snLCBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0aWYgKCBvU2V0dGluZ3MuYlNvcnRlZCB8fCBfZm5EYXRhU291cmNlKCBvU2V0dGluZ3MgKSA9PT0gJ3NzcCcgfHwgZmVhdHVyZXMuYkRlZmVyUmVuZGVyICkge1xuXHRcdFx0XHRcdFx0X2ZuU29ydGluZ0NsYXNzZXMoIG9TZXR0aW5ncyApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSwgJ3NjJyApO1xuXHRcdFx0XG5cdFx0XHRcblx0XHRcdFx0Lypcblx0XHRcdFx0ICogRmluYWwgaW5pdFxuXHRcdFx0XHQgKiBDYWNoZSB0aGUgaGVhZGVyLCBib2R5IGFuZCBmb290ZXIgYXMgcmVxdWlyZWQsIGNyZWF0aW5nIHRoZW0gaWYgbmVlZGVkXG5cdFx0XHRcdCAqL1xuXHRcdFx0XG5cdFx0XHRcdC8vIFdvcmsgYXJvdW5kIGZvciBXZWJraXQgYnVnIDgzODY3IC0gc3RvcmUgdGhlIGNhcHRpb24tc2lkZSBiZWZvcmUgcmVtb3ZpbmcgZnJvbSBkb2Ncblx0XHRcdFx0dmFyIGNhcHRpb25zID0gJHRoaXMuY2hpbGRyZW4oJ2NhcHRpb24nKS5lYWNoKCBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0dGhpcy5fY2FwdGlvblNpZGUgPSAkKHRoaXMpLmNzcygnY2FwdGlvbi1zaWRlJyk7XG5cdFx0XHRcdH0gKTtcblx0XHRcdFxuXHRcdFx0XHR2YXIgdGhlYWQgPSAkdGhpcy5jaGlsZHJlbigndGhlYWQnKTtcblx0XHRcdFx0aWYgKCB0aGVhZC5sZW5ndGggPT09IDAgKSB7XG5cdFx0XHRcdFx0dGhlYWQgPSAkKCc8dGhlYWQvPicpLmFwcGVuZFRvKCR0aGlzKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRvU2V0dGluZ3MublRIZWFkID0gdGhlYWRbMF07XG5cdFx0XHRcblx0XHRcdFx0dmFyIHRib2R5ID0gJHRoaXMuY2hpbGRyZW4oJ3Rib2R5Jyk7XG5cdFx0XHRcdGlmICggdGJvZHkubGVuZ3RoID09PSAwICkge1xuXHRcdFx0XHRcdHRib2R5ID0gJCgnPHRib2R5Lz4nKS5pbnNlcnRBZnRlcih0aGVhZCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0b1NldHRpbmdzLm5UQm9keSA9IHRib2R5WzBdO1xuXHRcdFx0XG5cdFx0XHRcdHZhciB0Zm9vdCA9ICR0aGlzLmNoaWxkcmVuKCd0Zm9vdCcpO1xuXHRcdFx0XHRpZiAoIHRmb290Lmxlbmd0aCA9PT0gMCAmJiBjYXB0aW9ucy5sZW5ndGggPiAwICYmIChvU2V0dGluZ3Mub1Njcm9sbC5zWCAhPT0gXCJcIiB8fCBvU2V0dGluZ3Mub1Njcm9sbC5zWSAhPT0gXCJcIikgKSB7XG5cdFx0XHRcdFx0Ly8gSWYgd2UgYXJlIGEgc2Nyb2xsaW5nIHRhYmxlLCBhbmQgbm8gZm9vdGVyIGhhcyBiZWVuIGdpdmVuLCB0aGVuIHdlIG5lZWQgdG8gY3JlYXRlXG5cdFx0XHRcdFx0Ly8gYSB0Zm9vdCBlbGVtZW50IGZvciB0aGUgY2FwdGlvbiBlbGVtZW50IHRvIGJlIGFwcGVuZGVkIHRvXG5cdFx0XHRcdFx0dGZvb3QgPSAkKCc8dGZvb3QvPicpLmFwcGVuZFRvKCR0aGlzKTtcblx0XHRcdFx0fVxuXHRcdFx0XG5cdFx0XHRcdGlmICggdGZvb3QubGVuZ3RoID09PSAwIHx8IHRmb290LmNoaWxkcmVuKCkubGVuZ3RoID09PSAwICkge1xuXHRcdFx0XHRcdCR0aGlzLmFkZENsYXNzKCBvQ2xhc3Nlcy5zTm9Gb290ZXIgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIGlmICggdGZvb3QubGVuZ3RoID4gMCApIHtcblx0XHRcdFx0XHRvU2V0dGluZ3MublRGb290ID0gdGZvb3RbMF07XG5cdFx0XHRcdFx0X2ZuRGV0ZWN0SGVhZGVyKCBvU2V0dGluZ3MuYW9Gb290ZXIsIG9TZXR0aW5ncy5uVEZvb3QgKTtcblx0XHRcdFx0fVxuXHRcdFx0XG5cdFx0XHRcdC8qIENoZWNrIGlmIHRoZXJlIGlzIGRhdGEgcGFzc2luZyBpbnRvIHRoZSBjb25zdHJ1Y3RvciAqL1xuXHRcdFx0XHRpZiAoIG9Jbml0LmFhRGF0YSApIHtcblx0XHRcdFx0XHRmb3IgKCBpPTAgOyBpPG9Jbml0LmFhRGF0YS5sZW5ndGggOyBpKysgKSB7XG5cdFx0XHRcdFx0XHRfZm5BZGREYXRhKCBvU2V0dGluZ3MsIG9Jbml0LmFhRGF0YVsgaSBdICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdGVsc2UgaWYgKCBvU2V0dGluZ3MuYkRlZmVyTG9hZGluZyB8fCBfZm5EYXRhU291cmNlKCBvU2V0dGluZ3MgKSA9PSAnZG9tJyApIHtcblx0XHRcdFx0XHQvKiBHcmFiIHRoZSBkYXRhIGZyb20gdGhlIHBhZ2UgLSBvbmx5IGRvIHRoaXMgd2hlbiBkZWZlcnJlZCBsb2FkaW5nIG9yIG5vIEFqYXhcblx0XHRcdFx0XHQgKiBzb3VyY2Ugc2luY2UgdGhlcmUgaXMgbm8gcG9pbnQgaW4gcmVhZGluZyB0aGUgRE9NIGRhdGEgaWYgd2UgYXJlIHRoZW4gZ29pbmdcblx0XHRcdFx0XHQgKiB0byByZXBsYWNlIGl0IHdpdGggQWpheCBkYXRhXG5cdFx0XHRcdFx0ICovXG5cdFx0XHRcdFx0X2ZuQWRkVHIoIG9TZXR0aW5ncywgJChvU2V0dGluZ3MublRCb2R5KS5jaGlsZHJlbigndHInKSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcblx0XHRcdFx0LyogQ29weSB0aGUgZGF0YSBpbmRleCBhcnJheSAqL1xuXHRcdFx0XHRvU2V0dGluZ3MuYWlEaXNwbGF5ID0gb1NldHRpbmdzLmFpRGlzcGxheU1hc3Rlci5zbGljZSgpO1xuXHRcdFx0XG5cdFx0XHRcdC8qIEluaXRpYWxpc2F0aW9uIGNvbXBsZXRlIC0gdGFibGUgY2FuIGJlIGRyYXduICovXG5cdFx0XHRcdG9TZXR0aW5ncy5iSW5pdGlhbGlzZWQgPSB0cnVlO1xuXHRcdFx0XG5cdFx0XHRcdC8qIENoZWNrIGlmIHdlIG5lZWQgdG8gaW5pdGlhbGlzZSB0aGUgdGFibGUgKGl0IG1pZ2h0IG5vdCBoYXZlIGJlZW4gaGFuZGVkIG9mZiB0byB0aGVcblx0XHRcdFx0ICogbGFuZ3VhZ2UgcHJvY2Vzc29yKVxuXHRcdFx0XHQgKi9cblx0XHRcdFx0aWYgKCBiSW5pdEhhbmRlZE9mZiA9PT0gZmFsc2UgKSB7XG5cdFx0XHRcdFx0X2ZuSW5pdGlhbGlzZSggb1NldHRpbmdzICk7XG5cdFx0XHRcdH1cblx0XHRcdH07XG5cdFx0XHRcblx0XHRcdC8qIE11c3QgYmUgZG9uZSBhZnRlciBldmVyeXRoaW5nIHdoaWNoIGNhbiBiZSBvdmVycmlkZGVuIGJ5IHRoZSBzdGF0ZSBzYXZpbmchICovXG5cdFx0XHRfZm5DYWxsYmFja1JlZyggb1NldHRpbmdzLCAnYW9EcmF3Q2FsbGJhY2snLCBfZm5TYXZlU3RhdGUsICdzdGF0ZV9zYXZlJyApO1xuXHRcdFx0XG5cdFx0XHRpZiAoIG9Jbml0LmJTdGF0ZVNhdmUgKVxuXHRcdFx0e1xuXHRcdFx0XHRmZWF0dXJlcy5iU3RhdGVTYXZlID0gdHJ1ZTtcblx0XHRcdFx0X2ZuTG9hZFN0YXRlKCBvU2V0dGluZ3MsIG9Jbml0LCBsb2FkZWRJbml0ICk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0bG9hZGVkSW5pdCgpO1xuXHRcdFx0fVxuXHRcdFx0XG5cdFx0fSApO1xuXHRcdF90aGF0ID0gbnVsbDtcblx0XHRyZXR1cm4gdGhpcztcblx0fTtcblxuXHRcblx0Lypcblx0ICogSXQgaXMgdXNlZnVsIHRvIGhhdmUgdmFyaWFibGVzIHdoaWNoIGFyZSBzY29wZWQgbG9jYWxseSBzbyBvbmx5IHRoZVxuXHQgKiBEYXRhVGFibGVzIGZ1bmN0aW9ucyBjYW4gYWNjZXNzIHRoZW0gYW5kIHRoZXkgZG9uJ3QgbGVhayBpbnRvIGdsb2JhbCBzcGFjZS5cblx0ICogQXQgdGhlIHNhbWUgdGltZSB0aGVzZSBmdW5jdGlvbnMgYXJlIG9mdGVuIHVzZWZ1bCBvdmVyIG11bHRpcGxlIGZpbGVzIGluIHRoZVxuXHQgKiBjb3JlIGFuZCBBUEksIHNvIHdlIGxpc3QsIG9yIGF0IGxlYXN0IGRvY3VtZW50LCBhbGwgdmFyaWFibGVzIHdoaWNoIGFyZSB1c2VkXG5cdCAqIGJ5IERhdGFUYWJsZXMgYXMgcHJpdmF0ZSB2YXJpYWJsZXMgaGVyZS4gVGhpcyBhbHNvIGVuc3VyZXMgdGhhdCB0aGVyZSBpcyBub1xuXHQgKiBjbGFzaGluZyBvZiB2YXJpYWJsZSBuYW1lcyBhbmQgdGhhdCB0aGV5IGNhbiBlYXNpbHkgcmVmZXJlbmNlZCBmb3IgcmV1c2UuXG5cdCAqL1xuXHRcblx0XG5cdC8vIERlZmluZWQgZWxzZSB3aGVyZVxuXHQvLyAgX3NlbGVjdG9yX3J1blxuXHQvLyAgX3NlbGVjdG9yX29wdHNcblx0Ly8gIF9zZWxlY3Rvcl9maXJzdFxuXHQvLyAgX3NlbGVjdG9yX3Jvd19pbmRleGVzXG5cdFxuXHR2YXIgX2V4dDsgLy8gRGF0YVRhYmxlLmV4dFxuXHR2YXIgX0FwaTsgLy8gRGF0YVRhYmxlLkFwaVxuXHR2YXIgX2FwaV9yZWdpc3RlcjsgLy8gRGF0YVRhYmxlLkFwaS5yZWdpc3RlclxuXHR2YXIgX2FwaV9yZWdpc3RlclBsdXJhbDsgLy8gRGF0YVRhYmxlLkFwaS5yZWdpc3RlclBsdXJhbFxuXHRcblx0dmFyIF9yZV9kaWMgPSB7fTtcblx0dmFyIF9yZV9uZXdfbGluZXMgPSAvW1xcclxcblxcdTIwMjhdL2c7XG5cdHZhciBfcmVfaHRtbCA9IC88Lio/Pi9nO1xuXHRcblx0Ly8gVGhpcyBpcyBub3Qgc3RyaWN0IElTTzg2MDEgLSBEYXRlLnBhcnNlKCkgaXMgcXVpdGUgbGF4LCBhbHRob3VnaFxuXHQvLyBpbXBsZW1lbnRhdGlvbnMgZGlmZmVyIGJldHdlZW4gYnJvd3NlcnMuXG5cdHZhciBfcmVfZGF0ZSA9IC9eXFxkezIsNH1bXFwuXFwvXFwtXVxcZHsxLDJ9W1xcLlxcL1xcLV1cXGR7MSwyfShbVCBdezF9XFxkezEsMn1bOlxcLl1cXGR7Mn0oW1xcLjpdXFxkezJ9KT8pPyQvO1xuXHRcblx0Ly8gRXNjYXBlIHJlZ3VsYXIgZXhwcmVzc2lvbiBzcGVjaWFsIGNoYXJhY3RlcnNcblx0dmFyIF9yZV9lc2NhcGVfcmVnZXggPSBuZXcgUmVnRXhwKCAnKFxcXFwnICsgWyAnLycsICcuJywgJyonLCAnKycsICc/JywgJ3wnLCAnKCcsICcpJywgJ1snLCAnXScsICd7JywgJ30nLCAnXFxcXCcsICckJywgJ14nLCAnLScgXS5qb2luKCd8XFxcXCcpICsgJyknLCAnZycgKTtcblx0XG5cdC8vIGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRm9yZWlnbl9leGNoYW5nZV9tYXJrZXRcblx0Ly8gLSBcXHUyMEJEIC0gUnVzc2lhbiBydWJsZS5cblx0Ly8gLSBcXHUyMGE5IC0gU291dGggS29yZWFuIFdvblxuXHQvLyAtIFxcdTIwQkEgLSBUdXJraXNoIExpcmFcblx0Ly8gLSBcXHUyMEI5IC0gSW5kaWFuIFJ1cGVlXG5cdC8vIC0gUiAtIEJyYXppbCAoUiQpIGFuZCBTb3V0aCBBZnJpY2Fcblx0Ly8gLSBmciAtIFN3aXNzIEZyYW5jXG5cdC8vIC0ga3IgLSBTd2VkaXNoIGtyb25hLCBOb3J3ZWdpYW4ga3JvbmUgYW5kIERhbmlzaCBrcm9uZVxuXHQvLyAtIFxcdTIwMDkgaXMgdGhpbiBzcGFjZSBhbmQgXFx1MjAyRiBpcyBuYXJyb3cgbm8tYnJlYWsgc3BhY2UsIGJvdGggdXNlZCBpbiBtYW55XG5cdC8vIC0gyYMgLSBCaXRjb2luXG5cdC8vIC0gzp4gLSBFdGhlcmV1bVxuXHQvLyAgIHN0YW5kYXJkcyBhcyB0aG91c2FuZHMgc2VwYXJhdG9ycy5cblx0dmFyIF9yZV9mb3JtYXR0ZWRfbnVtZXJpYyA9IC9bJ1xcdTAwQTAsJMKj4oKswqUlXFx1MjAwOVxcdTIwMkZcXHUyMEJEXFx1MjBhOVxcdTIwQkFyZmvJg86eXS9naTtcblx0XG5cdFxuXHR2YXIgX2VtcHR5ID0gZnVuY3Rpb24gKCBkICkge1xuXHRcdHJldHVybiAhZCB8fCBkID09PSB0cnVlIHx8IGQgPT09ICctJyA/IHRydWUgOiBmYWxzZTtcblx0fTtcblx0XG5cdFxuXHR2YXIgX2ludFZhbCA9IGZ1bmN0aW9uICggcyApIHtcblx0XHR2YXIgaW50ZWdlciA9IHBhcnNlSW50KCBzLCAxMCApO1xuXHRcdHJldHVybiAhaXNOYU4oaW50ZWdlcikgJiYgaXNGaW5pdGUocykgPyBpbnRlZ2VyIDogbnVsbDtcblx0fTtcblx0XG5cdC8vIENvbnZlcnQgZnJvbSBhIGZvcm1hdHRlZCBudW1iZXIgd2l0aCBjaGFyYWN0ZXJzIG90aGVyIHRoYW4gYC5gIGFzIHRoZVxuXHQvLyBkZWNpbWFsIHBsYWNlLCB0byBhIEphdmFzY3JpcHQgbnVtYmVyXG5cdHZhciBfbnVtVG9EZWNpbWFsID0gZnVuY3Rpb24gKCBudW0sIGRlY2ltYWxQb2ludCApIHtcblx0XHQvLyBDYWNoZSBjcmVhdGVkIHJlZ3VsYXIgZXhwcmVzc2lvbnMgZm9yIHNwZWVkIGFzIHRoaXMgZnVuY3Rpb24gaXMgY2FsbGVkIG9mdGVuXG5cdFx0aWYgKCAhIF9yZV9kaWNbIGRlY2ltYWxQb2ludCBdICkge1xuXHRcdFx0X3JlX2RpY1sgZGVjaW1hbFBvaW50IF0gPSBuZXcgUmVnRXhwKCBfZm5Fc2NhcGVSZWdleCggZGVjaW1hbFBvaW50ICksICdnJyApO1xuXHRcdH1cblx0XHRyZXR1cm4gdHlwZW9mIG51bSA9PT0gJ3N0cmluZycgJiYgZGVjaW1hbFBvaW50ICE9PSAnLicgP1xuXHRcdFx0bnVtLnJlcGxhY2UoIC9cXC4vZywgJycgKS5yZXBsYWNlKCBfcmVfZGljWyBkZWNpbWFsUG9pbnQgXSwgJy4nICkgOlxuXHRcdFx0bnVtO1xuXHR9O1xuXHRcblx0XG5cdHZhciBfaXNOdW1iZXIgPSBmdW5jdGlvbiAoIGQsIGRlY2ltYWxQb2ludCwgZm9ybWF0dGVkICkge1xuXHRcdHZhciBzdHJUeXBlID0gdHlwZW9mIGQgPT09ICdzdHJpbmcnO1xuXHRcblx0XHQvLyBJZiBlbXB0eSByZXR1cm4gaW1tZWRpYXRlbHkgc28gdGhlcmUgbXVzdCBiZSBhIG51bWJlciBpZiBpdCBpcyBhXG5cdFx0Ly8gZm9ybWF0dGVkIHN0cmluZyAodGhpcyBzdG9wcyB0aGUgc3RyaW5nIFwia1wiLCBvciBcImtyXCIsIGV0YyBiZWluZyBkZXRlY3RlZFxuXHRcdC8vIGFzIGEgZm9ybWF0dGVkIG51bWJlciBmb3IgY3VycmVuY3lcblx0XHRpZiAoIF9lbXB0eSggZCApICkge1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fVxuXHRcblx0XHRpZiAoIGRlY2ltYWxQb2ludCAmJiBzdHJUeXBlICkge1xuXHRcdFx0ZCA9IF9udW1Ub0RlY2ltYWwoIGQsIGRlY2ltYWxQb2ludCApO1xuXHRcdH1cblx0XG5cdFx0aWYgKCBmb3JtYXR0ZWQgJiYgc3RyVHlwZSApIHtcblx0XHRcdGQgPSBkLnJlcGxhY2UoIF9yZV9mb3JtYXR0ZWRfbnVtZXJpYywgJycgKTtcblx0XHR9XG5cdFxuXHRcdHJldHVybiAhaXNOYU4oIHBhcnNlRmxvYXQoZCkgKSAmJiBpc0Zpbml0ZSggZCApO1xuXHR9O1xuXHRcblx0XG5cdC8vIEEgc3RyaW5nIHdpdGhvdXQgSFRNTCBpbiBpdCBjYW4gYmUgY29uc2lkZXJlZCB0byBiZSBIVE1MIHN0aWxsXG5cdHZhciBfaXNIdG1sID0gZnVuY3Rpb24gKCBkICkge1xuXHRcdHJldHVybiBfZW1wdHkoIGQgKSB8fCB0eXBlb2YgZCA9PT0gJ3N0cmluZyc7XG5cdH07XG5cdFxuXHRcblx0dmFyIF9odG1sTnVtZXJpYyA9IGZ1bmN0aW9uICggZCwgZGVjaW1hbFBvaW50LCBmb3JtYXR0ZWQgKSB7XG5cdFx0aWYgKCBfZW1wdHkoIGQgKSApIHtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH1cblx0XG5cdFx0dmFyIGh0bWwgPSBfaXNIdG1sKCBkICk7XG5cdFx0cmV0dXJuICEgaHRtbCA/XG5cdFx0XHRudWxsIDpcblx0XHRcdF9pc051bWJlciggX3N0cmlwSHRtbCggZCApLCBkZWNpbWFsUG9pbnQsIGZvcm1hdHRlZCApID9cblx0XHRcdFx0dHJ1ZSA6XG5cdFx0XHRcdG51bGw7XG5cdH07XG5cdFxuXHRcblx0dmFyIF9wbHVjayA9IGZ1bmN0aW9uICggYSwgcHJvcCwgcHJvcDIgKSB7XG5cdFx0dmFyIG91dCA9IFtdO1xuXHRcdHZhciBpPTAsIGllbj1hLmxlbmd0aDtcblx0XG5cdFx0Ly8gQ291bGQgaGF2ZSB0aGUgdGVzdCBpbiB0aGUgbG9vcCBmb3Igc2xpZ2h0bHkgc21hbGxlciBjb2RlLCBidXQgc3BlZWRcblx0XHQvLyBpcyBlc3NlbnRpYWwgaGVyZVxuXHRcdGlmICggcHJvcDIgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdGZvciAoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRcdGlmICggYVtpXSAmJiBhW2ldWyBwcm9wIF0gKSB7XG5cdFx0XHRcdFx0b3V0LnB1c2goIGFbaV1bIHByb3AgXVsgcHJvcDIgXSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGVsc2Uge1xuXHRcdFx0Zm9yICggOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdFx0aWYgKCBhW2ldICkge1xuXHRcdFx0XHRcdG91dC5wdXNoKCBhW2ldWyBwcm9wIF0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XG5cdFx0cmV0dXJuIG91dDtcblx0fTtcblx0XG5cdFxuXHQvLyBCYXNpY2FsbHkgdGhlIHNhbWUgYXMgX3BsdWNrLCBidXQgcmF0aGVyIHRoYW4gbG9vcGluZyBvdmVyIGBhYCB3ZSB1c2UgYG9yZGVyYFxuXHQvLyBhcyB0aGUgaW5kZXhlcyB0byBwaWNrIGZyb20gYGFgXG5cdHZhciBfcGx1Y2tfb3JkZXIgPSBmdW5jdGlvbiAoIGEsIG9yZGVyLCBwcm9wLCBwcm9wMiApXG5cdHtcblx0XHR2YXIgb3V0ID0gW107XG5cdFx0dmFyIGk9MCwgaWVuPW9yZGVyLmxlbmd0aDtcblx0XG5cdFx0Ly8gQ291bGQgaGF2ZSB0aGUgdGVzdCBpbiB0aGUgbG9vcCBmb3Igc2xpZ2h0bHkgc21hbGxlciBjb2RlLCBidXQgc3BlZWRcblx0XHQvLyBpcyBlc3NlbnRpYWwgaGVyZVxuXHRcdGlmICggcHJvcDIgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdGZvciAoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRcdGlmICggYVsgb3JkZXJbaV0gXVsgcHJvcCBdICkge1xuXHRcdFx0XHRcdG91dC5wdXNoKCBhWyBvcmRlcltpXSBdWyBwcm9wIF1bIHByb3AyIF0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XHRlbHNlIHtcblx0XHRcdGZvciAoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRcdG91dC5wdXNoKCBhWyBvcmRlcltpXSBdWyBwcm9wIF0gKTtcblx0XHRcdH1cblx0XHR9XG5cdFxuXHRcdHJldHVybiBvdXQ7XG5cdH07XG5cdFxuXHRcblx0dmFyIF9yYW5nZSA9IGZ1bmN0aW9uICggbGVuLCBzdGFydCApXG5cdHtcblx0XHR2YXIgb3V0ID0gW107XG5cdFx0dmFyIGVuZDtcblx0XG5cdFx0aWYgKCBzdGFydCA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0c3RhcnQgPSAwO1xuXHRcdFx0ZW5kID0gbGVuO1xuXHRcdH1cblx0XHRlbHNlIHtcblx0XHRcdGVuZCA9IHN0YXJ0O1xuXHRcdFx0c3RhcnQgPSBsZW47XG5cdFx0fVxuXHRcblx0XHRmb3IgKCB2YXIgaT1zdGFydCA7IGk8ZW5kIDsgaSsrICkge1xuXHRcdFx0b3V0LnB1c2goIGkgKTtcblx0XHR9XG5cdFxuXHRcdHJldHVybiBvdXQ7XG5cdH07XG5cdFxuXHRcblx0dmFyIF9yZW1vdmVFbXB0eSA9IGZ1bmN0aW9uICggYSApXG5cdHtcblx0XHR2YXIgb3V0ID0gW107XG5cdFxuXHRcdGZvciAoIHZhciBpPTAsIGllbj1hLmxlbmd0aCA7IGk8aWVuIDsgaSsrICkge1xuXHRcdFx0aWYgKCBhW2ldICkgeyAvLyBjYXJlZnVsIC0gd2lsbCByZW1vdmUgYWxsIGZhbHN5IHZhbHVlcyFcblx0XHRcdFx0b3V0LnB1c2goIGFbaV0gKTtcblx0XHRcdH1cblx0XHR9XG5cdFxuXHRcdHJldHVybiBvdXQ7XG5cdH07XG5cdFxuXHRcblx0dmFyIF9zdHJpcEh0bWwgPSBmdW5jdGlvbiAoIGQgKSB7XG5cdFx0cmV0dXJuIGQucmVwbGFjZSggX3JlX2h0bWwsICcnICk7XG5cdH07XG5cdFxuXHRcblx0LyoqXG5cdCAqIERldGVybWluZSBpZiBhbGwgdmFsdWVzIGluIHRoZSBhcnJheSBhcmUgdW5pcXVlLiBUaGlzIG1lYW5zIHdlIGNhbiBzaG9ydFxuXHQgKiBjdXQgdGhlIF91bmlxdWUgbWV0aG9kIGF0IHRoZSBjb3N0IG9mIGEgc2luZ2xlIGxvb3AuIEEgc29ydGVkIGFycmF5IGlzIHVzZWRcblx0ICogdG8gZWFzaWx5IGNoZWNrIHRoZSB2YWx1ZXMuXG5cdCAqXG5cdCAqIEBwYXJhbSAge2FycmF5fSBzcmMgU291cmNlIGFycmF5XG5cdCAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgaWYgYWxsIHVuaXF1ZSwgZmFsc2Ugb3RoZXJ3aXNlXG5cdCAqIEBpZ25vcmVcblx0ICovXG5cdHZhciBfYXJlQWxsVW5pcXVlID0gZnVuY3Rpb24gKCBzcmMgKSB7XG5cdFx0aWYgKCBzcmMubGVuZ3RoIDwgMiApIHtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH1cblx0XG5cdFx0dmFyIHNvcnRlZCA9IHNyYy5zbGljZSgpLnNvcnQoKTtcblx0XHR2YXIgbGFzdCA9IHNvcnRlZFswXTtcblx0XG5cdFx0Zm9yICggdmFyIGk9MSwgaWVuPXNvcnRlZC5sZW5ndGggOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdGlmICggc29ydGVkW2ldID09PSBsYXN0ICkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFxuXHRcdFx0bGFzdCA9IHNvcnRlZFtpXTtcblx0XHR9XG5cdFxuXHRcdHJldHVybiB0cnVlO1xuXHR9O1xuXHRcblx0XG5cdC8qKlxuXHQgKiBGaW5kIHRoZSB1bmlxdWUgZWxlbWVudHMgaW4gYSBzb3VyY2UgYXJyYXkuXG5cdCAqXG5cdCAqIEBwYXJhbSAge2FycmF5fSBzcmMgU291cmNlIGFycmF5XG5cdCAqIEByZXR1cm4ge2FycmF5fSBBcnJheSBvZiB1bmlxdWUgaXRlbXNcblx0ICogQGlnbm9yZVxuXHQgKi9cblx0dmFyIF91bmlxdWUgPSBmdW5jdGlvbiAoIHNyYyApXG5cdHtcblx0XHRpZiAoIF9hcmVBbGxVbmlxdWUoIHNyYyApICkge1xuXHRcdFx0cmV0dXJuIHNyYy5zbGljZSgpO1xuXHRcdH1cblx0XG5cdFx0Ly8gQSBmYXN0ZXIgdW5pcXVlIG1ldGhvZCBpcyB0byB1c2Ugb2JqZWN0IGtleXMgdG8gaWRlbnRpZnkgdXNlZCB2YWx1ZXMsXG5cdFx0Ly8gYnV0IHRoaXMgZG9lc24ndCB3b3JrIHdpdGggYXJyYXlzIG9yIG9iamVjdHMsIHdoaWNoIHdlIG11c3QgYWxzb1xuXHRcdC8vIGNvbnNpZGVyLiBTZWUganNwZXJmLmNvbS9jb21wYXJlLWFycmF5LXVuaXF1ZS12ZXJzaW9ucy80IGZvciBtb3JlXG5cdFx0Ly8gaW5mb3JtYXRpb24uXG5cdFx0dmFyXG5cdFx0XHRvdXQgPSBbXSxcblx0XHRcdHZhbCxcblx0XHRcdGksIGllbj1zcmMubGVuZ3RoLFxuXHRcdFx0aiwgaz0wO1xuXHRcblx0XHRhZ2FpbjogZm9yICggaT0wIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHR2YWwgPSBzcmNbaV07XG5cdFxuXHRcdFx0Zm9yICggaj0wIDsgajxrIDsgaisrICkge1xuXHRcdFx0XHRpZiAoIG91dFtqXSA9PT0gdmFsICkge1xuXHRcdFx0XHRcdGNvbnRpbnVlIGFnYWluO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFxuXHRcdFx0b3V0LnB1c2goIHZhbCApO1xuXHRcdFx0aysrO1xuXHRcdH1cblx0XG5cdFx0cmV0dXJuIG91dDtcblx0fTtcblx0XG5cdC8vIFN1cnByaXNpbmdseSB0aGlzIGlzIGZhc3RlciB0aGFuIFtdLmNvbmNhdC5hcHBseVxuXHQvLyBodHRwczovL2pzcGVyZi5jb20vZmxhdHRlbi1hbi1hcnJheS1sb29wLXZzLXJlZHVjZS8yXG5cdHZhciBfZmxhdHRlbiA9IGZ1bmN0aW9uIChvdXQsIHZhbCkge1xuXHRcdGlmIChBcnJheS5pc0FycmF5KHZhbCkpIHtcblx0XHRcdGZvciAodmFyIGk9MCA7IGk8dmFsLmxlbmd0aCA7IGkrKykge1xuXHRcdFx0XHRfZmxhdHRlbihvdXQsIHZhbFtpXSk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGVsc2Uge1xuXHRcdFx0b3V0LnB1c2godmFsKTtcblx0XHR9XG5cdCAgXG5cdFx0cmV0dXJuIG91dDtcblx0fVxuXHRcblx0dmFyIF9pbmNsdWRlcyA9IGZ1bmN0aW9uIChzZWFyY2gsIHN0YXJ0KSB7XG5cdFx0aWYgKHN0YXJ0ID09PSB1bmRlZmluZWQpIHtcblx0XHRcdHN0YXJ0ID0gMDtcblx0XHR9XG5cdFxuXHRcdHJldHVybiB0aGlzLmluZGV4T2Yoc2VhcmNoLCBzdGFydCkgIT09IC0xO1x0XG5cdH07XG5cdFxuXHQvLyBBcnJheS5pc0FycmF5IHBvbHlmaWxsLlxuXHQvLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9BcnJheS9pc0FycmF5XG5cdGlmICghIEFycmF5LmlzQXJyYXkpIHtcblx0ICAgIEFycmF5LmlzQXJyYXkgPSBmdW5jdGlvbihhcmcpIHtcblx0ICAgICAgICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGFyZykgPT09ICdbb2JqZWN0IEFycmF5XSc7XG5cdCAgICB9O1xuXHR9XG5cdFxuXHRpZiAoISBBcnJheS5wcm90b3R5cGUuaW5jbHVkZXMpIHtcblx0XHRBcnJheS5wcm90b3R5cGUuaW5jbHVkZXMgPSBfaW5jbHVkZXM7XG5cdH1cblx0XG5cdC8vIC50cmltKCkgcG9seWZpbGxcblx0Ly8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvU3RyaW5nL3RyaW1cblx0aWYgKCFTdHJpbmcucHJvdG90eXBlLnRyaW0pIHtcblx0ICBTdHJpbmcucHJvdG90eXBlLnRyaW0gPSBmdW5jdGlvbiAoKSB7XG5cdCAgICByZXR1cm4gdGhpcy5yZXBsYWNlKC9eW1xcc1xcdUZFRkZcXHhBMF0rfFtcXHNcXHVGRUZGXFx4QTBdKyQvZywgJycpO1xuXHQgIH07XG5cdH1cblx0XG5cdGlmICghIFN0cmluZy5wcm90b3R5cGUuaW5jbHVkZXMpIHtcblx0XHRTdHJpbmcucHJvdG90eXBlLmluY2x1ZGVzID0gX2luY2x1ZGVzO1xuXHR9XG5cdFxuXHQvKipcblx0ICogRGF0YVRhYmxlcyB1dGlsaXR5IG1ldGhvZHNcblx0ICogXG5cdCAqIFRoaXMgbmFtZXNwYWNlIHByb3ZpZGVzIGhlbHBlciBtZXRob2RzIHRoYXQgRGF0YVRhYmxlcyB1c2VzIGludGVybmFsbHkgdG9cblx0ICogY3JlYXRlIGEgRGF0YVRhYmxlLCBidXQgd2hpY2ggYXJlIG5vdCBleGNsdXNpdmVseSB1c2VkIG9ubHkgZm9yIERhdGFUYWJsZXMuXG5cdCAqIFRoZXNlIG1ldGhvZHMgY2FuIGJlIHVzZWQgYnkgZXh0ZW5zaW9uIGF1dGhvcnMgdG8gc2F2ZSB0aGUgZHVwbGljYXRpb24gb2Zcblx0ICogY29kZS5cblx0ICpcblx0ICogIEBuYW1lc3BhY2Vcblx0ICovXG5cdERhdGFUYWJsZS51dGlsID0ge1xuXHRcdC8qKlxuXHRcdCAqIFRocm90dGxlIHRoZSBjYWxscyB0byBhIGZ1bmN0aW9uLiBBcmd1bWVudHMgYW5kIGNvbnRleHQgYXJlIG1haW50YWluZWRcblx0XHQgKiBmb3IgdGhlIHRocm90dGxlZCBmdW5jdGlvbi5cblx0XHQgKlxuXHRcdCAqIEBwYXJhbSB7ZnVuY3Rpb259IGZuIEZ1bmN0aW9uIHRvIGJlIGNhbGxlZFxuXHRcdCAqIEBwYXJhbSB7aW50ZWdlcn0gZnJlcSBDYWxsIGZyZXF1ZW5jeSBpbiBtU1xuXHRcdCAqIEByZXR1cm4ge2Z1bmN0aW9ufSBXcmFwcGVkIGZ1bmN0aW9uXG5cdFx0ICovXG5cdFx0dGhyb3R0bGU6IGZ1bmN0aW9uICggZm4sIGZyZXEgKSB7XG5cdFx0XHR2YXJcblx0XHRcdFx0ZnJlcXVlbmN5ID0gZnJlcSAhPT0gdW5kZWZpbmVkID8gZnJlcSA6IDIwMCxcblx0XHRcdFx0bGFzdCxcblx0XHRcdFx0dGltZXI7XG5cdFxuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0dmFyXG5cdFx0XHRcdFx0dGhhdCA9IHRoaXMsXG5cdFx0XHRcdFx0bm93ICA9ICtuZXcgRGF0ZSgpLFxuXHRcdFx0XHRcdGFyZ3MgPSBhcmd1bWVudHM7XG5cdFxuXHRcdFx0XHRpZiAoIGxhc3QgJiYgbm93IDwgbGFzdCArIGZyZXF1ZW5jeSApIHtcblx0XHRcdFx0XHRjbGVhclRpbWVvdXQoIHRpbWVyICk7XG5cdFxuXHRcdFx0XHRcdHRpbWVyID0gc2V0VGltZW91dCggZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdFx0bGFzdCA9IHVuZGVmaW5lZDtcblx0XHRcdFx0XHRcdGZuLmFwcGx5KCB0aGF0LCBhcmdzICk7XG5cdFx0XHRcdFx0fSwgZnJlcXVlbmN5ICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0bGFzdCA9IG5vdztcblx0XHRcdFx0XHRmbi5hcHBseSggdGhhdCwgYXJncyApO1xuXHRcdFx0XHR9XG5cdFx0XHR9O1xuXHRcdH0sXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBFc2NhcGUgYSBzdHJpbmcgc3VjaCB0aGF0IGl0IGNhbiBiZSB1c2VkIGluIGEgcmVndWxhciBleHByZXNzaW9uXG5cdFx0ICpcblx0XHQgKiAgQHBhcmFtIHtzdHJpbmd9IHZhbCBzdHJpbmcgdG8gZXNjYXBlXG5cdFx0ICogIEByZXR1cm5zIHtzdHJpbmd9IGVzY2FwZWQgc3RyaW5nXG5cdFx0ICovXG5cdFx0ZXNjYXBlUmVnZXg6IGZ1bmN0aW9uICggdmFsICkge1xuXHRcdFx0cmV0dXJuIHZhbC5yZXBsYWNlKCBfcmVfZXNjYXBlX3JlZ2V4LCAnXFxcXCQxJyApO1xuXHRcdH0sXG5cdFxuXHRcdC8qKlxuXHRcdCAqIENyZWF0ZSBhIGZ1bmN0aW9uIHRoYXQgd2lsbCB3cml0ZSB0byBhIG5lc3RlZCBvYmplY3Qgb3IgYXJyYXlcblx0XHQgKiBAcGFyYW0geyp9IHNvdXJjZSBKU09OIG5vdGF0aW9uIHN0cmluZ1xuXHRcdCAqIEByZXR1cm5zIFdyaXRlIGZ1bmN0aW9uXG5cdFx0ICovXG5cdFx0c2V0OiBmdW5jdGlvbiAoIHNvdXJjZSApIHtcblx0XHRcdGlmICggJC5pc1BsYWluT2JqZWN0KCBzb3VyY2UgKSApIHtcblx0XHRcdFx0LyogVW5saWtlIGdldCwgb25seSB0aGUgdW5kZXJzY29yZSAoZ2xvYmFsKSBvcHRpb24gaXMgdXNlZCBmb3IgZm9yXG5cdFx0XHRcdCAqIHNldHRpbmcgZGF0YSBzaW5jZSB3ZSBkb24ndCBrbm93IHRoZSB0eXBlIGhlcmUuIFRoaXMgaXMgd2h5IGFuIG9iamVjdFxuXHRcdFx0XHQgKiBvcHRpb24gaXMgbm90IGRvY3VtZW50ZWQgZm9yIGBtRGF0YWAgKHdoaWNoIGlzIHJlYWQvd3JpdGUpLCBidXQgaXQgaXNcblx0XHRcdFx0ICogZm9yIGBtUmVuZGVyYCB3aGljaCBpcyByZWFkIG9ubHkuXG5cdFx0XHRcdCAqL1xuXHRcdFx0XHRyZXR1cm4gRGF0YVRhYmxlLnV0aWwuc2V0KCBzb3VyY2UuXyApO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSBpZiAoIHNvdXJjZSA9PT0gbnVsbCApIHtcblx0XHRcdFx0Ly8gTm90aGluZyB0byBkbyB3aGVuIHRoZSBkYXRhIHNvdXJjZSBpcyBudWxsXG5cdFx0XHRcdHJldHVybiBmdW5jdGlvbiAoKSB7fTtcblx0XHRcdH1cblx0XHRcdGVsc2UgaWYgKCB0eXBlb2Ygc291cmNlID09PSAnZnVuY3Rpb24nICkge1xuXHRcdFx0XHRyZXR1cm4gZnVuY3Rpb24gKGRhdGEsIHZhbCwgbWV0YSkge1xuXHRcdFx0XHRcdHNvdXJjZSggZGF0YSwgJ3NldCcsIHZhbCwgbWV0YSApO1xuXHRcdFx0XHR9O1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSBpZiAoIHR5cGVvZiBzb3VyY2UgPT09ICdzdHJpbmcnICYmIChzb3VyY2UuaW5kZXhPZignLicpICE9PSAtMSB8fFxuXHRcdFx0XHRcdCAgc291cmNlLmluZGV4T2YoJ1snKSAhPT0gLTEgfHwgc291cmNlLmluZGV4T2YoJygnKSAhPT0gLTEpIClcblx0XHRcdHtcblx0XHRcdFx0Ly8gTGlrZSB0aGUgZ2V0LCB3ZSBuZWVkIHRvIGdldCBkYXRhIGZyb20gYSBuZXN0ZWQgb2JqZWN0XG5cdFx0XHRcdHZhciBzZXREYXRhID0gZnVuY3Rpb24gKGRhdGEsIHZhbCwgc3JjKSB7XG5cdFx0XHRcdFx0dmFyIGEgPSBfZm5TcGxpdE9iak5vdGF0aW9uKCBzcmMgKSwgYjtcblx0XHRcdFx0XHR2YXIgYUxhc3QgPSBhW2EubGVuZ3RoLTFdO1xuXHRcdFx0XHRcdHZhciBhcnJheU5vdGF0aW9uLCBmdW5jTm90YXRpb24sIG8sIGlubmVyU3JjO1xuXHRcdFxuXHRcdFx0XHRcdGZvciAoIHZhciBpPTAsIGlMZW49YS5sZW5ndGgtMSA7IGk8aUxlbiA7IGkrKyApIHtcblx0XHRcdFx0XHRcdC8vIFByb3RlY3QgYWdhaW5zdCBwcm90b3R5cGUgcG9sbHV0aW9uXG5cdFx0XHRcdFx0XHRpZiAoYVtpXSA9PT0gJ19fcHJvdG9fXycgfHwgYVtpXSA9PT0gJ2NvbnN0cnVjdG9yJykge1xuXHRcdFx0XHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBzZXQgcHJvdG90eXBlIHZhbHVlcycpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFxuXHRcdFx0XHRcdFx0Ly8gQ2hlY2sgaWYgd2UgYXJlIGRlYWxpbmcgd2l0aCBhbiBhcnJheSBub3RhdGlvbiByZXF1ZXN0XG5cdFx0XHRcdFx0XHRhcnJheU5vdGF0aW9uID0gYVtpXS5tYXRjaChfX3JlQXJyYXkpO1xuXHRcdFx0XHRcdFx0ZnVuY05vdGF0aW9uID0gYVtpXS5tYXRjaChfX3JlRm4pO1xuXHRcdFxuXHRcdFx0XHRcdFx0aWYgKCBhcnJheU5vdGF0aW9uICkge1xuXHRcdFx0XHRcdFx0XHRhW2ldID0gYVtpXS5yZXBsYWNlKF9fcmVBcnJheSwgJycpO1xuXHRcdFx0XHRcdFx0XHRkYXRhWyBhW2ldIF0gPSBbXTtcblx0XHRcblx0XHRcdFx0XHRcdFx0Ly8gR2V0IHRoZSByZW1haW5kZXIgb2YgdGhlIG5lc3RlZCBvYmplY3QgdG8gc2V0IHNvIHdlIGNhbiByZWN1cnNlXG5cdFx0XHRcdFx0XHRcdGIgPSBhLnNsaWNlKCk7XG5cdFx0XHRcdFx0XHRcdGIuc3BsaWNlKCAwLCBpKzEgKTtcblx0XHRcdFx0XHRcdFx0aW5uZXJTcmMgPSBiLmpvaW4oJy4nKTtcblx0XHRcblx0XHRcdFx0XHRcdFx0Ly8gVHJhdmVyc2UgZWFjaCBlbnRyeSBpbiB0aGUgYXJyYXkgc2V0dGluZyB0aGUgcHJvcGVydGllcyByZXF1ZXN0ZWRcblx0XHRcdFx0XHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCB2YWwgKSApIHtcblx0XHRcdFx0XHRcdFx0XHRmb3IgKCB2YXIgaj0wLCBqTGVuPXZhbC5sZW5ndGggOyBqPGpMZW4gOyBqKysgKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRvID0ge307XG5cdFx0XHRcdFx0XHRcdFx0XHRzZXREYXRhKCBvLCB2YWxbal0sIGlubmVyU3JjICk7XG5cdFx0XHRcdFx0XHRcdFx0XHRkYXRhWyBhW2ldIF0ucHVzaCggbyApO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHQvLyBXZSd2ZSBiZWVuIGFza2VkIHRvIHNhdmUgZGF0YSB0byBhbiBhcnJheSwgYnV0IGl0XG5cdFx0XHRcdFx0XHRcdFx0Ly8gaXNuJ3QgYXJyYXkgZGF0YSB0byBiZSBzYXZlZC4gQmVzdCB0aGF0IGNhbiBiZSBkb25lXG5cdFx0XHRcdFx0XHRcdFx0Ly8gaXMgdG8ganVzdCBzYXZlIHRoZSB2YWx1ZS5cblx0XHRcdFx0XHRcdFx0XHRkYXRhWyBhW2ldIF0gPSB2YWw7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcblx0XHRcdFx0XHRcdFx0Ly8gVGhlIGlubmVyIGNhbGwgdG8gc2V0RGF0YSBoYXMgYWxyZWFkeSB0cmF2ZXJzZWQgdGhyb3VnaCB0aGUgcmVtYWluZGVyXG5cdFx0XHRcdFx0XHRcdC8vIG9mIHRoZSBzb3VyY2UgYW5kIGhhcyBzZXQgdGhlIGRhdGEsIHRodXMgd2UgY2FuIGV4aXQgaGVyZVxuXHRcdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRlbHNlIGlmICggZnVuY05vdGF0aW9uICkge1xuXHRcdFx0XHRcdFx0XHQvLyBGdW5jdGlvbiBjYWxsXG5cdFx0XHRcdFx0XHRcdGFbaV0gPSBhW2ldLnJlcGxhY2UoX19yZUZuLCAnJyk7XG5cdFx0XHRcdFx0XHRcdGRhdGEgPSBkYXRhWyBhW2ldIF0oIHZhbCApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFxuXHRcdFx0XHRcdFx0Ly8gSWYgdGhlIG5lc3RlZCBvYmplY3QgZG9lc24ndCBjdXJyZW50bHkgZXhpc3QgLSBzaW5jZSB3ZSBhcmVcblx0XHRcdFx0XHRcdC8vIHRyeWluZyB0byBzZXQgdGhlIHZhbHVlIC0gY3JlYXRlIGl0XG5cdFx0XHRcdFx0XHRpZiAoIGRhdGFbIGFbaV0gXSA9PT0gbnVsbCB8fCBkYXRhWyBhW2ldIF0gPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0XHRcdFx0ZGF0YVsgYVtpXSBdID0ge307XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRkYXRhID0gZGF0YVsgYVtpXSBdO1xuXHRcdFx0XHRcdH1cblx0XHRcblx0XHRcdFx0XHQvLyBMYXN0IGl0ZW0gaW4gdGhlIGlucHV0IC0gaS5lLCB0aGUgYWN0dWFsIHNldFxuXHRcdFx0XHRcdGlmICggYUxhc3QubWF0Y2goX19yZUZuICkgKSB7XG5cdFx0XHRcdFx0XHQvLyBGdW5jdGlvbiBjYWxsXG5cdFx0XHRcdFx0XHRkYXRhID0gZGF0YVsgYUxhc3QucmVwbGFjZShfX3JlRm4sICcnKSBdKCB2YWwgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHQvLyBJZiBhcnJheSBub3RhdGlvbiBpcyB1c2VkLCB3ZSBqdXN0IHdhbnQgdG8gc3RyaXAgaXQgYW5kIHVzZSB0aGUgcHJvcGVydHkgbmFtZVxuXHRcdFx0XHRcdFx0Ly8gYW5kIGFzc2lnbiB0aGUgdmFsdWUuIElmIGl0IGlzbid0IHVzZWQsIHRoZW4gd2UgZ2V0IHRoZSByZXN1bHQgd2Ugd2FudCBhbnl3YXlcblx0XHRcdFx0XHRcdGRhdGFbIGFMYXN0LnJlcGxhY2UoX19yZUFycmF5LCAnJykgXSA9IHZhbDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH07XG5cdFx0XG5cdFx0XHRcdHJldHVybiBmdW5jdGlvbiAoZGF0YSwgdmFsKSB7IC8vIG1ldGEgaXMgYWxzbyBwYXNzZWQgaW4sIGJ1dCBub3QgdXNlZFxuXHRcdFx0XHRcdHJldHVybiBzZXREYXRhKCBkYXRhLCB2YWwsIHNvdXJjZSApO1xuXHRcdFx0XHR9O1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSB7XG5cdFx0XHRcdC8vIEFycmF5IG9yIGZsYXQgb2JqZWN0IG1hcHBpbmdcblx0XHRcdFx0cmV0dXJuIGZ1bmN0aW9uIChkYXRhLCB2YWwpIHsgLy8gbWV0YSBpcyBhbHNvIHBhc3NlZCBpbiwgYnV0IG5vdCB1c2VkXG5cdFx0XHRcdFx0ZGF0YVtzb3VyY2VdID0gdmFsO1xuXHRcdFx0XHR9O1xuXHRcdFx0fVxuXHRcdH0sXG5cdFxuXHRcdC8qKlxuXHRcdCAqIENyZWF0ZSBhIGZ1bmN0aW9uIHRoYXQgd2lsbCByZWFkIG5lc3RlZCBvYmplY3RzIGZyb20gYXJyYXlzLCBiYXNlZCBvbiBKU09OIG5vdGF0aW9uXG5cdFx0ICogQHBhcmFtIHsqfSBzb3VyY2UgSlNPTiBub3RhdGlvbiBzdHJpbmdcblx0XHQgKiBAcmV0dXJucyBWYWx1ZSByZWFkXG5cdFx0ICovXG5cdFx0Z2V0OiBmdW5jdGlvbiAoIHNvdXJjZSApIHtcblx0XHRcdGlmICggJC5pc1BsYWluT2JqZWN0KCBzb3VyY2UgKSApIHtcblx0XHRcdFx0Ly8gQnVpbGQgYW4gb2JqZWN0IG9mIGdldCBmdW5jdGlvbnMsIGFuZCB3cmFwIHRoZW0gaW4gYSBzaW5nbGUgY2FsbFxuXHRcdFx0XHR2YXIgbyA9IHt9O1xuXHRcdFx0XHQkLmVhY2goIHNvdXJjZSwgZnVuY3Rpb24gKGtleSwgdmFsKSB7XG5cdFx0XHRcdFx0aWYgKCB2YWwgKSB7XG5cdFx0XHRcdFx0XHRvW2tleV0gPSBEYXRhVGFibGUudXRpbC5nZXQoIHZhbCApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHRcdFxuXHRcdFx0XHRyZXR1cm4gZnVuY3Rpb24gKGRhdGEsIHR5cGUsIHJvdywgbWV0YSkge1xuXHRcdFx0XHRcdHZhciB0ID0gb1t0eXBlXSB8fCBvLl87XG5cdFx0XHRcdFx0cmV0dXJuIHQgIT09IHVuZGVmaW5lZCA/XG5cdFx0XHRcdFx0XHR0KGRhdGEsIHR5cGUsIHJvdywgbWV0YSkgOlxuXHRcdFx0XHRcdFx0ZGF0YTtcblx0XHRcdFx0fTtcblx0XHRcdH1cblx0XHRcdGVsc2UgaWYgKCBzb3VyY2UgPT09IG51bGwgKSB7XG5cdFx0XHRcdC8vIEdpdmUgYW4gZW1wdHkgc3RyaW5nIGZvciByZW5kZXJpbmcgLyBzb3J0aW5nIGV0Y1xuXHRcdFx0XHRyZXR1cm4gZnVuY3Rpb24gKGRhdGEpIHsgLy8gdHlwZSwgcm93IGFuZCBtZXRhIGFsc28gcGFzc2VkLCBidXQgbm90IHVzZWRcblx0XHRcdFx0XHRyZXR1cm4gZGF0YTtcblx0XHRcdFx0fTtcblx0XHRcdH1cblx0XHRcdGVsc2UgaWYgKCB0eXBlb2Ygc291cmNlID09PSAnZnVuY3Rpb24nICkge1xuXHRcdFx0XHRyZXR1cm4gZnVuY3Rpb24gKGRhdGEsIHR5cGUsIHJvdywgbWV0YSkge1xuXHRcdFx0XHRcdHJldHVybiBzb3VyY2UoIGRhdGEsIHR5cGUsIHJvdywgbWV0YSApO1xuXHRcdFx0XHR9O1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSBpZiAoIHR5cGVvZiBzb3VyY2UgPT09ICdzdHJpbmcnICYmIChzb3VyY2UuaW5kZXhPZignLicpICE9PSAtMSB8fFxuXHRcdFx0XHRcdCAgc291cmNlLmluZGV4T2YoJ1snKSAhPT0gLTEgfHwgc291cmNlLmluZGV4T2YoJygnKSAhPT0gLTEpIClcblx0XHRcdHtcblx0XHRcdFx0LyogSWYgdGhlcmUgaXMgYSAuIGluIHRoZSBzb3VyY2Ugc3RyaW5nIHRoZW4gdGhlIGRhdGEgc291cmNlIGlzIGluIGFcblx0XHRcdFx0ICogbmVzdGVkIG9iamVjdCBzbyB3ZSBsb29wIG92ZXIgdGhlIGRhdGEgZm9yIGVhY2ggbGV2ZWwgdG8gZ2V0IHRoZSBuZXh0XG5cdFx0XHRcdCAqIGxldmVsIGRvd24uIE9uIGVhY2ggbG9vcCB3ZSB0ZXN0IGZvciB1bmRlZmluZWQsIGFuZCBpZiBmb3VuZCBpbW1lZGlhdGVseVxuXHRcdFx0XHQgKiByZXR1cm4uIFRoaXMgYWxsb3dzIGVudGlyZSBvYmplY3RzIHRvIGJlIG1pc3NpbmcgYW5kIHNEZWZhdWx0Q29udGVudCB0b1xuXHRcdFx0XHQgKiBiZSB1c2VkIGlmIGRlZmluZWQsIHJhdGhlciB0aGFuIHRocm93aW5nIGFuIGVycm9yXG5cdFx0XHRcdCAqL1xuXHRcdFx0XHR2YXIgZmV0Y2hEYXRhID0gZnVuY3Rpb24gKGRhdGEsIHR5cGUsIHNyYykge1xuXHRcdFx0XHRcdHZhciBhcnJheU5vdGF0aW9uLCBmdW5jTm90YXRpb24sIG91dCwgaW5uZXJTcmM7XG5cdFx0XG5cdFx0XHRcdFx0aWYgKCBzcmMgIT09IFwiXCIgKSB7XG5cdFx0XHRcdFx0XHR2YXIgYSA9IF9mblNwbGl0T2JqTm90YXRpb24oIHNyYyApO1xuXHRcdFxuXHRcdFx0XHRcdFx0Zm9yICggdmFyIGk9MCwgaUxlbj1hLmxlbmd0aCA7IGk8aUxlbiA7IGkrKyApIHtcblx0XHRcdFx0XHRcdFx0Ly8gQ2hlY2sgaWYgd2UgYXJlIGRlYWxpbmcgd2l0aCBzcGVjaWFsIG5vdGF0aW9uXG5cdFx0XHRcdFx0XHRcdGFycmF5Tm90YXRpb24gPSBhW2ldLm1hdGNoKF9fcmVBcnJheSk7XG5cdFx0XHRcdFx0XHRcdGZ1bmNOb3RhdGlvbiA9IGFbaV0ubWF0Y2goX19yZUZuKTtcblx0XHRcblx0XHRcdFx0XHRcdFx0aWYgKCBhcnJheU5vdGF0aW9uICkge1xuXHRcdFx0XHRcdFx0XHRcdC8vIEFycmF5IG5vdGF0aW9uXG5cdFx0XHRcdFx0XHRcdFx0YVtpXSA9IGFbaV0ucmVwbGFjZShfX3JlQXJyYXksICcnKTtcblx0XHRcblx0XHRcdFx0XHRcdFx0XHQvLyBDb25kaXRpb24gYWxsb3dzIHNpbXBseSBbXSB0byBiZSBwYXNzZWQgaW5cblx0XHRcdFx0XHRcdFx0XHRpZiAoIGFbaV0gIT09IFwiXCIgKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRkYXRhID0gZGF0YVsgYVtpXSBdO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRvdXQgPSBbXTtcblx0XHRcblx0XHRcdFx0XHRcdFx0XHQvLyBHZXQgdGhlIHJlbWFpbmRlciBvZiB0aGUgbmVzdGVkIG9iamVjdCB0byBnZXRcblx0XHRcdFx0XHRcdFx0XHRhLnNwbGljZSggMCwgaSsxICk7XG5cdFx0XHRcdFx0XHRcdFx0aW5uZXJTcmMgPSBhLmpvaW4oJy4nKTtcblx0XHRcblx0XHRcdFx0XHRcdFx0XHQvLyBUcmF2ZXJzZSBlYWNoIGVudHJ5IGluIHRoZSBhcnJheSBnZXR0aW5nIHRoZSBwcm9wZXJ0aWVzIHJlcXVlc3RlZFxuXHRcdFx0XHRcdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggZGF0YSApICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0Zm9yICggdmFyIGo9MCwgakxlbj1kYXRhLmxlbmd0aCA7IGo8akxlbiA7IGorKyApIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0b3V0LnB1c2goIGZldGNoRGF0YSggZGF0YVtqXSwgdHlwZSwgaW5uZXJTcmMgKSApO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcblx0XHRcdFx0XHRcdFx0XHQvLyBJZiBhIHN0cmluZyBpcyBnaXZlbiBpbiBiZXR3ZWVuIHRoZSBhcnJheSBub3RhdGlvbiBpbmRpY2F0b3JzLCB0aGF0XG5cdFx0XHRcdFx0XHRcdFx0Ly8gaXMgdXNlZCB0byBqb2luIHRoZSBzdHJpbmdzIHRvZ2V0aGVyLCBvdGhlcndpc2UgYW4gYXJyYXkgaXMgcmV0dXJuZWRcblx0XHRcdFx0XHRcdFx0XHR2YXIgam9pbiA9IGFycmF5Tm90YXRpb25bMF0uc3Vic3RyaW5nKDEsIGFycmF5Tm90YXRpb25bMF0ubGVuZ3RoLTEpO1xuXHRcdFx0XHRcdFx0XHRcdGRhdGEgPSAoam9pbj09PVwiXCIpID8gb3V0IDogb3V0LmpvaW4oam9pbik7XG5cdFx0XG5cdFx0XHRcdFx0XHRcdFx0Ly8gVGhlIGlubmVyIGNhbGwgdG8gZmV0Y2hEYXRhIGhhcyBhbHJlYWR5IHRyYXZlcnNlZCB0aHJvdWdoIHRoZSByZW1haW5kZXJcblx0XHRcdFx0XHRcdFx0XHQvLyBvZiB0aGUgc291cmNlIHJlcXVlc3RlZCwgc28gd2UgZXhpdCBmcm9tIHRoZSBsb29wXG5cdFx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0ZWxzZSBpZiAoIGZ1bmNOb3RhdGlvbiApIHtcblx0XHRcdFx0XHRcdFx0XHQvLyBGdW5jdGlvbiBjYWxsXG5cdFx0XHRcdFx0XHRcdFx0YVtpXSA9IGFbaV0ucmVwbGFjZShfX3JlRm4sICcnKTtcblx0XHRcdFx0XHRcdFx0XHRkYXRhID0gZGF0YVsgYVtpXSBdKCk7XG5cdFx0XHRcdFx0XHRcdFx0Y29udGludWU7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcblx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhID09PSBudWxsIHx8IGRhdGFbIGFbaV0gXSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdFx0XHRcdHJldHVybiB1bmRlZmluZWQ7XG5cdFx0XHRcdFx0XHRcdH1cblx0XG5cdFx0XHRcdFx0XHRcdGRhdGEgPSBkYXRhWyBhW2ldIF07XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFxuXHRcdFx0XHRcdHJldHVybiBkYXRhO1xuXHRcdFx0XHR9O1xuXHRcdFxuXHRcdFx0XHRyZXR1cm4gZnVuY3Rpb24gKGRhdGEsIHR5cGUpIHsgLy8gcm93IGFuZCBtZXRhIGFsc28gcGFzc2VkLCBidXQgbm90IHVzZWRcblx0XHRcdFx0XHRyZXR1cm4gZmV0Y2hEYXRhKCBkYXRhLCB0eXBlLCBzb3VyY2UgKTtcblx0XHRcdFx0fTtcblx0XHRcdH1cblx0XHRcdGVsc2Uge1xuXHRcdFx0XHQvLyBBcnJheSBvciBmbGF0IG9iamVjdCBtYXBwaW5nXG5cdFx0XHRcdHJldHVybiBmdW5jdGlvbiAoZGF0YSwgdHlwZSkgeyAvLyByb3cgYW5kIG1ldGEgYWxzbyBwYXNzZWQsIGJ1dCBub3QgdXNlZFxuXHRcdFx0XHRcdHJldHVybiBkYXRhW3NvdXJjZV07XG5cdFx0XHRcdH07XG5cdFx0XHR9XG5cdFx0fVxuXHR9O1xuXHRcblx0XG5cdFxuXHQvKipcblx0ICogQ3JlYXRlIGEgbWFwcGluZyBvYmplY3QgdGhhdCBhbGxvd3MgY2FtZWwgY2FzZSBwYXJhbWV0ZXJzIHRvIGJlIGxvb2tlZCB1cFxuXHQgKiBmb3IgdGhlaXIgSHVuZ2FyaWFuIGNvdW50ZXJwYXJ0cy4gVGhlIG1hcHBpbmcgaXMgc3RvcmVkIGluIGEgcHJpdmF0ZVxuXHQgKiBwYXJhbWV0ZXIgY2FsbGVkIGBfaHVuZ2FyaWFuTWFwYCB3aGljaCBjYW4gYmUgYWNjZXNzZWQgb24gdGhlIHNvdXJjZSBvYmplY3QuXG5cdCAqICBAcGFyYW0ge29iamVjdH0gb1xuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5IdW5nYXJpYW5NYXAgKCBvIClcblx0e1xuXHRcdHZhclxuXHRcdFx0aHVuZ2FyaWFuID0gJ2EgYWEgYWkgYW8gYXMgYiBmbiBpIG0gbyBzICcsXG5cdFx0XHRtYXRjaCxcblx0XHRcdG5ld0tleSxcblx0XHRcdG1hcCA9IHt9O1xuXHRcblx0XHQkLmVhY2goIG8sIGZ1bmN0aW9uIChrZXksIHZhbCkge1xuXHRcdFx0bWF0Y2ggPSBrZXkubWF0Y2goL14oW15BLVpdKz8pKFtBLVpdKS8pO1xuXHRcblx0XHRcdGlmICggbWF0Y2ggJiYgaHVuZ2FyaWFuLmluZGV4T2YobWF0Y2hbMV0rJyAnKSAhPT0gLTEgKVxuXHRcdFx0e1xuXHRcdFx0XHRuZXdLZXkgPSBrZXkucmVwbGFjZSggbWF0Y2hbMF0sIG1hdGNoWzJdLnRvTG93ZXJDYXNlKCkgKTtcblx0XHRcdFx0bWFwWyBuZXdLZXkgXSA9IGtleTtcblx0XG5cdFx0XHRcdGlmICggbWF0Y2hbMV0gPT09ICdvJyApXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRfZm5IdW5nYXJpYW5NYXAoIG9ba2V5XSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSApO1xuXHRcblx0XHRvLl9odW5nYXJpYW5NYXAgPSBtYXA7XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogQ29udmVydCBmcm9tIGNhbWVsIGNhc2UgcGFyYW1ldGVycyB0byBIdW5nYXJpYW4sIGJhc2VkIG9uIGEgSHVuZ2FyaWFuIG1hcFxuXHQgKiBjcmVhdGVkIGJ5IF9mbkh1bmdhcmlhbk1hcC5cblx0ICogIEBwYXJhbSB7b2JqZWN0fSBzcmMgVGhlIG1vZGVsIG9iamVjdCB3aGljaCBob2xkcyBhbGwgcGFyYW1ldGVycyB0aGF0IGNhbiBiZVxuXHQgKiAgICBtYXBwZWQuXG5cdCAqICBAcGFyYW0ge29iamVjdH0gdXNlciBUaGUgb2JqZWN0IHRvIGNvbnZlcnQgZnJvbSBjYW1lbCBjYXNlIHRvIEh1bmdhcmlhbi5cblx0ICogIEBwYXJhbSB7Ym9vbGVhbn0gZm9yY2UgV2hlbiBzZXQgdG8gYHRydWVgLCBwcm9wZXJ0aWVzIHdoaWNoIGFscmVhZHkgaGF2ZSBhXG5cdCAqICAgIEh1bmdhcmlhbiB2YWx1ZSBpbiB0aGUgYHVzZXJgIG9iamVjdCB3aWxsIGJlIG92ZXJ3cml0dGVuLiBPdGhlcndpc2UgdGhleVxuXHQgKiAgICB3b24ndCBiZS5cblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuQ2FtZWxUb0h1bmdhcmlhbiAoIHNyYywgdXNlciwgZm9yY2UgKVxuXHR7XG5cdFx0aWYgKCAhIHNyYy5faHVuZ2FyaWFuTWFwICkge1xuXHRcdFx0X2ZuSHVuZ2FyaWFuTWFwKCBzcmMgKTtcblx0XHR9XG5cdFxuXHRcdHZhciBodW5nYXJpYW5LZXk7XG5cdFxuXHRcdCQuZWFjaCggdXNlciwgZnVuY3Rpb24gKGtleSwgdmFsKSB7XG5cdFx0XHRodW5nYXJpYW5LZXkgPSBzcmMuX2h1bmdhcmlhbk1hcFsga2V5IF07XG5cdFxuXHRcdFx0aWYgKCBodW5nYXJpYW5LZXkgIT09IHVuZGVmaW5lZCAmJiAoZm9yY2UgfHwgdXNlcltodW5nYXJpYW5LZXldID09PSB1bmRlZmluZWQpIClcblx0XHRcdHtcblx0XHRcdFx0Ly8gRm9yIG9iamVjdHMsIHdlIG5lZWQgdG8gYnV6eiBkb3duIGludG8gdGhlIG9iamVjdCB0byBjb3B5IHBhcmFtZXRlcnNcblx0XHRcdFx0aWYgKCBodW5nYXJpYW5LZXkuY2hhckF0KDApID09PSAnbycgKVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0Ly8gQ29weSB0aGUgY2FtZWxDYXNlIG9wdGlvbnMgb3ZlciB0byB0aGUgaHVuZ2FyaWFuXG5cdFx0XHRcdFx0aWYgKCAhIHVzZXJbIGh1bmdhcmlhbktleSBdICkge1xuXHRcdFx0XHRcdFx0dXNlclsgaHVuZ2FyaWFuS2V5IF0gPSB7fTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0JC5leHRlbmQoIHRydWUsIHVzZXJbaHVuZ2FyaWFuS2V5XSwgdXNlcltrZXldICk7XG5cdFxuXHRcdFx0XHRcdF9mbkNhbWVsVG9IdW5nYXJpYW4oIHNyY1todW5nYXJpYW5LZXldLCB1c2VyW2h1bmdhcmlhbktleV0sIGZvcmNlICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0dXNlcltodW5nYXJpYW5LZXldID0gdXNlclsga2V5IF07XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9ICk7XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogTGFuZ3VhZ2UgY29tcGF0aWJpbGl0eSAtIHdoZW4gY2VydGFpbiBvcHRpb25zIGFyZSBnaXZlbiwgYW5kIG90aGVycyBhcmVuJ3QsIHdlXG5cdCAqIG5lZWQgdG8gZHVwbGljYXRlIHRoZSB2YWx1ZXMgb3ZlciwgaW4gb3JkZXIgdG8gcHJvdmlkZSBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eVxuXHQgKiB3aXRoIG9sZGVyIGxhbmd1YWdlIGZpbGVzLlxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IG9TZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5MYW5ndWFnZUNvbXBhdCggbGFuZyApXG5cdHtcblx0XHQvLyBOb3RlIHRoZSB1c2Ugb2YgdGhlIEh1bmdhcmlhbiBub3RhdGlvbiBmb3IgdGhlIHBhcmFtZXRlcnMgaW4gdGhpcyBtZXRob2QgYXNcblx0XHQvLyB0aGlzIGlzIGNhbGxlZCBhZnRlciB0aGUgbWFwcGluZyBvZiBjYW1lbENhc2UgdG8gSHVuZ2FyaWFuXG5cdFx0dmFyIGRlZmF1bHRzID0gRGF0YVRhYmxlLmRlZmF1bHRzLm9MYW5ndWFnZTtcblx0XG5cdFx0Ly8gRGVmYXVsdCBtYXBwaW5nXG5cdFx0dmFyIGRlZmF1bHREZWNpbWFsID0gZGVmYXVsdHMuc0RlY2ltYWw7XG5cdFx0aWYgKCBkZWZhdWx0RGVjaW1hbCApIHtcblx0XHRcdF9hZGROdW1lcmljU29ydCggZGVmYXVsdERlY2ltYWwgKTtcblx0XHR9XG5cdFxuXHRcdGlmICggbGFuZyApIHtcblx0XHRcdHZhciB6ZXJvUmVjb3JkcyA9IGxhbmcuc1plcm9SZWNvcmRzO1xuXHRcblx0XHRcdC8vIEJhY2t3YXJkcyBjb21wYXRpYmlsaXR5IC0gaWYgdGhlcmUgaXMgbm8gc0VtcHR5VGFibGUgZ2l2ZW4sIHRoZW4gdXNlIHRoZSBzYW1lIGFzXG5cdFx0XHQvLyBzWmVyb1JlY29yZHMgLSBhc3N1bWluZyB0aGF0IGlzIGdpdmVuLlxuXHRcdFx0aWYgKCAhIGxhbmcuc0VtcHR5VGFibGUgJiYgemVyb1JlY29yZHMgJiZcblx0XHRcdFx0ZGVmYXVsdHMuc0VtcHR5VGFibGUgPT09IFwiTm8gZGF0YSBhdmFpbGFibGUgaW4gdGFibGVcIiApXG5cdFx0XHR7XG5cdFx0XHRcdF9mbk1hcCggbGFuZywgbGFuZywgJ3NaZXJvUmVjb3JkcycsICdzRW1wdHlUYWJsZScgKTtcblx0XHRcdH1cblx0XG5cdFx0XHQvLyBMaWtld2lzZSB3aXRoIGxvYWRpbmcgcmVjb3Jkc1xuXHRcdFx0aWYgKCAhIGxhbmcuc0xvYWRpbmdSZWNvcmRzICYmIHplcm9SZWNvcmRzICYmXG5cdFx0XHRcdGRlZmF1bHRzLnNMb2FkaW5nUmVjb3JkcyA9PT0gXCJMb2FkaW5nLi4uXCIgKVxuXHRcdFx0e1xuXHRcdFx0XHRfZm5NYXAoIGxhbmcsIGxhbmcsICdzWmVyb1JlY29yZHMnLCAnc0xvYWRpbmdSZWNvcmRzJyApO1xuXHRcdFx0fVxuXHRcblx0XHRcdC8vIE9sZCBwYXJhbWV0ZXIgbmFtZSBvZiB0aGUgdGhvdXNhbmRzIHNlcGFyYXRvciBtYXBwZWQgb250byB0aGUgbmV3XG5cdFx0XHRpZiAoIGxhbmcuc0luZm9UaG91c2FuZHMgKSB7XG5cdFx0XHRcdGxhbmcuc1Rob3VzYW5kcyA9IGxhbmcuc0luZm9UaG91c2FuZHM7XG5cdFx0XHR9XG5cdFxuXHRcdFx0dmFyIGRlY2ltYWwgPSBsYW5nLnNEZWNpbWFsO1xuXHRcdFx0aWYgKCBkZWNpbWFsICYmIGRlZmF1bHREZWNpbWFsICE9PSBkZWNpbWFsICkge1xuXHRcdFx0XHRfYWRkTnVtZXJpY1NvcnQoIGRlY2ltYWwgKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogTWFwIG9uZSBwYXJhbWV0ZXIgb250byBhbm90aGVyXG5cdCAqICBAcGFyYW0ge29iamVjdH0gbyBPYmplY3QgdG8gbWFwXG5cdCAqICBAcGFyYW0geyp9IGtuZXcgVGhlIG5ldyBwYXJhbWV0ZXIgbmFtZVxuXHQgKiAgQHBhcmFtIHsqfSBvbGQgVGhlIG9sZCBwYXJhbWV0ZXIgbmFtZVxuXHQgKi9cblx0dmFyIF9mbkNvbXBhdE1hcCA9IGZ1bmN0aW9uICggbywga25ldywgb2xkICkge1xuXHRcdGlmICggb1sga25ldyBdICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRvWyBvbGQgXSA9IG9bIGtuZXcgXTtcblx0XHR9XG5cdH07XG5cdFxuXHRcblx0LyoqXG5cdCAqIFByb3ZpZGUgYmFja3dhcmRzIGNvbXBhdGliaWxpdHkgZm9yIHRoZSBtYWluIERUIG9wdGlvbnMuIE5vdGUgdGhhdCB0aGUgbmV3XG5cdCAqIG9wdGlvbnMgYXJlIG1hcHBlZCBvbnRvIHRoZSBvbGQgcGFyYW1ldGVycywgc28gdGhpcyBpcyBhbiBleHRlcm5hbCBpbnRlcmZhY2Vcblx0ICogY2hhbmdlIG9ubHkuXG5cdCAqICBAcGFyYW0ge29iamVjdH0gaW5pdCBPYmplY3QgdG8gbWFwXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5Db21wYXRPcHRzICggaW5pdCApXG5cdHtcblx0XHRfZm5Db21wYXRNYXAoIGluaXQsICdvcmRlcmluZycsICAgICAgJ2JTb3J0JyApO1xuXHRcdF9mbkNvbXBhdE1hcCggaW5pdCwgJ29yZGVyTXVsdGknLCAgICAnYlNvcnRNdWx0aScgKTtcblx0XHRfZm5Db21wYXRNYXAoIGluaXQsICdvcmRlckNsYXNzZXMnLCAgJ2JTb3J0Q2xhc3NlcycgKTtcblx0XHRfZm5Db21wYXRNYXAoIGluaXQsICdvcmRlckNlbGxzVG9wJywgJ2JTb3J0Q2VsbHNUb3AnICk7XG5cdFx0X2ZuQ29tcGF0TWFwKCBpbml0LCAnb3JkZXInLCAgICAgICAgICdhYVNvcnRpbmcnICk7XG5cdFx0X2ZuQ29tcGF0TWFwKCBpbml0LCAnb3JkZXJGaXhlZCcsICAgICdhYVNvcnRpbmdGaXhlZCcgKTtcblx0XHRfZm5Db21wYXRNYXAoIGluaXQsICdwYWdpbmcnLCAgICAgICAgJ2JQYWdpbmF0ZScgKTtcblx0XHRfZm5Db21wYXRNYXAoIGluaXQsICdwYWdpbmdUeXBlJywgICAgJ3NQYWdpbmF0aW9uVHlwZScgKTtcblx0XHRfZm5Db21wYXRNYXAoIGluaXQsICdwYWdlTGVuZ3RoJywgICAgJ2lEaXNwbGF5TGVuZ3RoJyApO1xuXHRcdF9mbkNvbXBhdE1hcCggaW5pdCwgJ3NlYXJjaGluZycsICAgICAnYkZpbHRlcicgKTtcblx0XG5cdFx0Ly8gQm9vbGVhbiBpbml0aWFsaXNhdGlvbiBvZiB4LXNjcm9sbGluZ1xuXHRcdGlmICggdHlwZW9mIGluaXQuc1Njcm9sbFggPT09ICdib29sZWFuJyApIHtcblx0XHRcdGluaXQuc1Njcm9sbFggPSBpbml0LnNTY3JvbGxYID8gJzEwMCUnIDogJyc7XG5cdFx0fVxuXHRcdGlmICggdHlwZW9mIGluaXQuc2Nyb2xsWCA9PT0gJ2Jvb2xlYW4nICkge1xuXHRcdFx0aW5pdC5zY3JvbGxYID0gaW5pdC5zY3JvbGxYID8gJzEwMCUnIDogJyc7XG5cdFx0fVxuXHRcblx0XHQvLyBDb2x1bW4gc2VhcmNoIG9iamVjdHMgYXJlIGluIGFuIGFycmF5LCBzbyBpdCBuZWVkcyB0byBiZSBjb252ZXJ0ZWRcblx0XHQvLyBlbGVtZW50IGJ5IGVsZW1lbnRcblx0XHR2YXIgc2VhcmNoQ29scyA9IGluaXQuYW9TZWFyY2hDb2xzO1xuXHRcblx0XHRpZiAoIHNlYXJjaENvbHMgKSB7XG5cdFx0XHRmb3IgKCB2YXIgaT0wLCBpZW49c2VhcmNoQ29scy5sZW5ndGggOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdFx0aWYgKCBzZWFyY2hDb2xzW2ldICkge1xuXHRcdFx0XHRcdF9mbkNhbWVsVG9IdW5nYXJpYW4oIERhdGFUYWJsZS5tb2RlbHMub1NlYXJjaCwgc2VhcmNoQ29sc1tpXSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIFByb3ZpZGUgYmFja3dhcmRzIGNvbXBhdGliaWxpdHkgZm9yIGNvbHVtbiBvcHRpb25zLiBOb3RlIHRoYXQgdGhlIG5ldyBvcHRpb25zXG5cdCAqIGFyZSBtYXBwZWQgb250byB0aGUgb2xkIHBhcmFtZXRlcnMsIHNvIHRoaXMgaXMgYW4gZXh0ZXJuYWwgaW50ZXJmYWNlIGNoYW5nZVxuXHQgKiBvbmx5LlxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IGluaXQgT2JqZWN0IHRvIG1hcFxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuQ29tcGF0Q29scyAoIGluaXQgKVxuXHR7XG5cdFx0X2ZuQ29tcGF0TWFwKCBpbml0LCAnb3JkZXJhYmxlJywgICAgICdiU29ydGFibGUnICk7XG5cdFx0X2ZuQ29tcGF0TWFwKCBpbml0LCAnb3JkZXJEYXRhJywgICAgICdhRGF0YVNvcnQnICk7XG5cdFx0X2ZuQ29tcGF0TWFwKCBpbml0LCAnb3JkZXJTZXF1ZW5jZScsICdhc1NvcnRpbmcnICk7XG5cdFx0X2ZuQ29tcGF0TWFwKCBpbml0LCAnb3JkZXJEYXRhVHlwZScsICdzb3J0RGF0YVR5cGUnICk7XG5cdFxuXHRcdC8vIG9yZGVyRGF0YSBjYW4gYmUgZ2l2ZW4gYXMgYW4gaW50ZWdlclxuXHRcdHZhciBkYXRhU29ydCA9IGluaXQuYURhdGFTb3J0O1xuXHRcdGlmICggdHlwZW9mIGRhdGFTb3J0ID09PSAnbnVtYmVyJyAmJiAhIEFycmF5LmlzQXJyYXkoIGRhdGFTb3J0ICkgKSB7XG5cdFx0XHRpbml0LmFEYXRhU29ydCA9IFsgZGF0YVNvcnQgXTtcblx0XHR9XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogQnJvd3NlciBmZWF0dXJlIGRldGVjdGlvbiBmb3IgY2FwYWJpbGl0aWVzLCBxdWlya3Ncblx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5Ccm93c2VyRGV0ZWN0KCBzZXR0aW5ncyApXG5cdHtcblx0XHQvLyBXZSBkb24ndCBuZWVkIHRvIGRvIHRoaXMgZXZlcnkgdGltZSBEYXRhVGFibGVzIGlzIGNvbnN0cnVjdGVkLCB0aGUgdmFsdWVzXG5cdFx0Ly8gY2FsY3VsYXRlZCBhcmUgc3BlY2lmaWMgdG8gdGhlIGJyb3dzZXIgYW5kIE9TIGNvbmZpZ3VyYXRpb24gd2hpY2ggd2Vcblx0XHQvLyBkb24ndCBleHBlY3QgdG8gY2hhbmdlIGJldHdlZW4gaW5pdGlhbGlzYXRpb25zXG5cdFx0aWYgKCAhIERhdGFUYWJsZS5fX2Jyb3dzZXIgKSB7XG5cdFx0XHR2YXIgYnJvd3NlciA9IHt9O1xuXHRcdFx0RGF0YVRhYmxlLl9fYnJvd3NlciA9IGJyb3dzZXI7XG5cdFxuXHRcdFx0Ly8gU2Nyb2xsaW5nIGZlYXR1cmUgLyBxdWlya3MgZGV0ZWN0aW9uXG5cdFx0XHR2YXIgbiA9ICQoJzxkaXYvPicpXG5cdFx0XHRcdC5jc3MoIHtcblx0XHRcdFx0XHRwb3NpdGlvbjogJ2ZpeGVkJyxcblx0XHRcdFx0XHR0b3A6IDAsXG5cdFx0XHRcdFx0bGVmdDogJCh3aW5kb3cpLnNjcm9sbExlZnQoKSotMSwgLy8gYWxsb3cgZm9yIHNjcm9sbGluZ1xuXHRcdFx0XHRcdGhlaWdodDogMSxcblx0XHRcdFx0XHR3aWR0aDogMSxcblx0XHRcdFx0XHRvdmVyZmxvdzogJ2hpZGRlbidcblx0XHRcdFx0fSApXG5cdFx0XHRcdC5hcHBlbmQoXG5cdFx0XHRcdFx0JCgnPGRpdi8+Jylcblx0XHRcdFx0XHRcdC5jc3MoIHtcblx0XHRcdFx0XHRcdFx0cG9zaXRpb246ICdhYnNvbHV0ZScsXG5cdFx0XHRcdFx0XHRcdHRvcDogMSxcblx0XHRcdFx0XHRcdFx0bGVmdDogMSxcblx0XHRcdFx0XHRcdFx0d2lkdGg6IDEwMCxcblx0XHRcdFx0XHRcdFx0b3ZlcmZsb3c6ICdzY3JvbGwnXG5cdFx0XHRcdFx0XHR9IClcblx0XHRcdFx0XHRcdC5hcHBlbmQoXG5cdFx0XHRcdFx0XHRcdCQoJzxkaXYvPicpXG5cdFx0XHRcdFx0XHRcdFx0LmNzcygge1xuXHRcdFx0XHRcdFx0XHRcdFx0d2lkdGg6ICcxMDAlJyxcblx0XHRcdFx0XHRcdFx0XHRcdGhlaWdodDogMTBcblx0XHRcdFx0XHRcdFx0XHR9IClcblx0XHRcdFx0XHRcdClcblx0XHRcdFx0KVxuXHRcdFx0XHQuYXBwZW5kVG8oICdib2R5JyApO1xuXHRcblx0XHRcdHZhciBvdXRlciA9IG4uY2hpbGRyZW4oKTtcblx0XHRcdHZhciBpbm5lciA9IG91dGVyLmNoaWxkcmVuKCk7XG5cdFxuXHRcdFx0Ly8gTnVtYmVycyBiZWxvdywgaW4gb3JkZXIsIGFyZTpcblx0XHRcdC8vIGlubmVyLm9mZnNldFdpZHRoLCBpbm5lci5jbGllbnRXaWR0aCwgb3V0ZXIub2Zmc2V0V2lkdGgsIG91dGVyLmNsaWVudFdpZHRoXG5cdFx0XHQvL1xuXHRcdFx0Ly8gSUU2IFhQOiAgICAgICAgICAgICAgICAgICAgICAgICAgIDEwMCAxMDAgMTAwICA4M1xuXHRcdFx0Ly8gSUU3IFZpc3RhOiAgICAgICAgICAgICAgICAgICAgICAgIDEwMCAxMDAgMTAwICA4M1xuXHRcdFx0Ly8gSUUgOCsgV2luZG93czogICAgICAgICAgICAgICAgICAgICA4MyAgODMgMTAwICA4M1xuXHRcdFx0Ly8gRXZlcmdyZWVuIFdpbmRvd3M6ICAgICAgICAgICAgICAgICA4MyAgODMgMTAwICA4M1xuXHRcdFx0Ly8gRXZlcmdyZWVuIE1hYyB3aXRoIHNjcm9sbGJhcnM6ICAgICA4NSAgODUgMTAwICA4NVxuXHRcdFx0Ly8gRXZlcmdyZWVuIE1hYyB3aXRob3V0IHNjcm9sbGJhcnM6IDEwMCAxMDAgMTAwIDEwMFxuXHRcblx0XHRcdC8vIEdldCBzY3JvbGxiYXIgd2lkdGhcblx0XHRcdGJyb3dzZXIuYmFyV2lkdGggPSBvdXRlclswXS5vZmZzZXRXaWR0aCAtIG91dGVyWzBdLmNsaWVudFdpZHRoO1xuXHRcblx0XHRcdC8vIElFNi83IHdpbGwgb3ZlcnNpemUgYSB3aWR0aCAxMDAlIGVsZW1lbnQgaW5zaWRlIGEgc2Nyb2xsaW5nIGVsZW1lbnQsIHRvXG5cdFx0XHQvLyBpbmNsdWRlIHRoZSB3aWR0aCBvZiB0aGUgc2Nyb2xsYmFyLCB3aGlsZSBvdGhlciBicm93c2VycyBlbnN1cmUgdGhlIGlubmVyXG5cdFx0XHQvLyBlbGVtZW50IGlzIGNvbnRhaW5lZCB3aXRob3V0IGZvcmNpbmcgc2Nyb2xsaW5nXG5cdFx0XHRicm93c2VyLmJTY3JvbGxPdmVyc2l6ZSA9IGlubmVyWzBdLm9mZnNldFdpZHRoID09PSAxMDAgJiYgb3V0ZXJbMF0uY2xpZW50V2lkdGggIT09IDEwMDtcblx0XG5cdFx0XHQvLyBJbiBydGwgdGV4dCBsYXlvdXQsIHNvbWUgYnJvd3NlcnMgKG1vc3QsIGJ1dCBub3QgYWxsKSB3aWxsIHBsYWNlIHRoZVxuXHRcdFx0Ly8gc2Nyb2xsYmFyIG9uIHRoZSBsZWZ0LCByYXRoZXIgdGhhbiB0aGUgcmlnaHQuXG5cdFx0XHRicm93c2VyLmJTY3JvbGxiYXJMZWZ0ID0gTWF0aC5yb3VuZCggaW5uZXIub2Zmc2V0KCkubGVmdCApICE9PSAxO1xuXHRcblx0XHRcdC8vIElFOC0gZG9uJ3QgcHJvdmlkZSBoZWlnaHQgYW5kIHdpZHRoIGZvciBnZXRCb3VuZGluZ0NsaWVudFJlY3Rcblx0XHRcdGJyb3dzZXIuYkJvdW5kaW5nID0gblswXS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS53aWR0aCA/IHRydWUgOiBmYWxzZTtcblx0XG5cdFx0XHRuLnJlbW92ZSgpO1xuXHRcdH1cblx0XG5cdFx0JC5leHRlbmQoIHNldHRpbmdzLm9Ccm93c2VyLCBEYXRhVGFibGUuX19icm93c2VyICk7XG5cdFx0c2V0dGluZ3Mub1Njcm9sbC5pQmFyV2lkdGggPSBEYXRhVGFibGUuX19icm93c2VyLmJhcldpZHRoO1xuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIEFycmF5LnByb3RvdHlwZSByZWR1Y2VbUmlnaHRdIG1ldGhvZCwgdXNlZCBmb3IgYnJvd3NlcnMgd2hpY2ggZG9uJ3Qgc3VwcG9ydFxuXHQgKiBKUyAxLjYuIERvbmUgdGhpcyB3YXkgdG8gcmVkdWNlIGNvZGUgc2l6ZSwgc2luY2Ugd2UgaXRlcmF0ZSBlaXRoZXIgd2F5XG5cdCAqICBAcGFyYW0ge29iamVjdH0gc2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuUmVkdWNlICggdGhhdCwgZm4sIGluaXQsIHN0YXJ0LCBlbmQsIGluYyApXG5cdHtcblx0XHR2YXJcblx0XHRcdGkgPSBzdGFydCxcblx0XHRcdHZhbHVlLFxuXHRcdFx0aXNTZXQgPSBmYWxzZTtcblx0XG5cdFx0aWYgKCBpbml0ICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHR2YWx1ZSA9IGluaXQ7XG5cdFx0XHRpc1NldCA9IHRydWU7XG5cdFx0fVxuXHRcblx0XHR3aGlsZSAoIGkgIT09IGVuZCApIHtcblx0XHRcdGlmICggISB0aGF0Lmhhc093blByb3BlcnR5KGkpICkge1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblx0XG5cdFx0XHR2YWx1ZSA9IGlzU2V0ID9cblx0XHRcdFx0Zm4oIHZhbHVlLCB0aGF0W2ldLCBpLCB0aGF0ICkgOlxuXHRcdFx0XHR0aGF0W2ldO1xuXHRcblx0XHRcdGlzU2V0ID0gdHJ1ZTtcblx0XHRcdGkgKz0gaW5jO1xuXHRcdH1cblx0XG5cdFx0cmV0dXJuIHZhbHVlO1xuXHR9XG5cdFxuXHQvKipcblx0ICogQWRkIGEgY29sdW1uIHRvIHRoZSBsaXN0IHVzZWQgZm9yIHRoZSB0YWJsZSB3aXRoIGRlZmF1bHQgdmFsdWVzXG5cdCAqICBAcGFyYW0ge29iamVjdH0gb1NldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAcGFyYW0ge25vZGV9IG5UaCBUaGUgdGggZWxlbWVudCBmb3IgdGhpcyBjb2x1bW5cblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuQWRkQ29sdW1uKCBvU2V0dGluZ3MsIG5UaCApXG5cdHtcblx0XHQvLyBBZGQgY29sdW1uIHRvIGFvQ29sdW1ucyBhcnJheVxuXHRcdHZhciBvRGVmYXVsdHMgPSBEYXRhVGFibGUuZGVmYXVsdHMuY29sdW1uO1xuXHRcdHZhciBpQ29sID0gb1NldHRpbmdzLmFvQ29sdW1ucy5sZW5ndGg7XG5cdFx0dmFyIG9Db2wgPSAkLmV4dGVuZCgge30sIERhdGFUYWJsZS5tb2RlbHMub0NvbHVtbiwgb0RlZmF1bHRzLCB7XG5cdFx0XHRcIm5UaFwiOiBuVGggPyBuVGggOiBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd0aCcpLFxuXHRcdFx0XCJzVGl0bGVcIjogICAgb0RlZmF1bHRzLnNUaXRsZSAgICA/IG9EZWZhdWx0cy5zVGl0bGUgICAgOiBuVGggPyBuVGguaW5uZXJIVE1MIDogJycsXG5cdFx0XHRcImFEYXRhU29ydFwiOiBvRGVmYXVsdHMuYURhdGFTb3J0ID8gb0RlZmF1bHRzLmFEYXRhU29ydCA6IFtpQ29sXSxcblx0XHRcdFwibURhdGFcIjogb0RlZmF1bHRzLm1EYXRhID8gb0RlZmF1bHRzLm1EYXRhIDogaUNvbCxcblx0XHRcdGlkeDogaUNvbFxuXHRcdH0gKTtcblx0XHRvU2V0dGluZ3MuYW9Db2x1bW5zLnB1c2goIG9Db2wgKTtcblx0XG5cdFx0Ly8gQWRkIHNlYXJjaCBvYmplY3QgZm9yIGNvbHVtbiBzcGVjaWZpYyBzZWFyY2guIE5vdGUgdGhhdCB0aGUgYHNlYXJjaENvbHNbIGlDb2wgXWBcblx0XHQvLyBwYXNzZWQgaW50byBleHRlbmQgY2FuIGJlIHVuZGVmaW5lZC4gVGhpcyBhbGxvd3MgdGhlIHVzZXIgdG8gZ2l2ZSBhIGRlZmF1bHRcblx0XHQvLyB3aXRoIG9ubHkgc29tZSBvZiB0aGUgcGFyYW1ldGVycyBkZWZpbmVkLCBhbmQgYWxzbyBub3QgZ2l2ZSBhIGRlZmF1bHRcblx0XHR2YXIgc2VhcmNoQ29scyA9IG9TZXR0aW5ncy5hb1ByZVNlYXJjaENvbHM7XG5cdFx0c2VhcmNoQ29sc1sgaUNvbCBdID0gJC5leHRlbmQoIHt9LCBEYXRhVGFibGUubW9kZWxzLm9TZWFyY2gsIHNlYXJjaENvbHNbIGlDb2wgXSApO1xuXHRcblx0XHQvLyBVc2UgdGhlIGRlZmF1bHQgY29sdW1uIG9wdGlvbnMgZnVuY3Rpb24gdG8gaW5pdGlhbGlzZSBjbGFzc2VzIGV0Y1xuXHRcdF9mbkNvbHVtbk9wdGlvbnMoIG9TZXR0aW5ncywgaUNvbCwgJChuVGgpLmRhdGEoKSApO1xuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIEFwcGx5IG9wdGlvbnMgZm9yIGEgY29sdW1uXG5cdCAqICBAcGFyYW0ge29iamVjdH0gb1NldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAcGFyYW0ge2ludH0gaUNvbCBjb2x1bW4gaW5kZXggdG8gY29uc2lkZXJcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvT3B0aW9ucyBvYmplY3Qgd2l0aCBzVHlwZSwgYlZpc2libGUgYW5kIGJTZWFyY2hhYmxlIGV0Y1xuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5Db2x1bW5PcHRpb25zKCBvU2V0dGluZ3MsIGlDb2wsIG9PcHRpb25zIClcblx0e1xuXHRcdHZhciBvQ29sID0gb1NldHRpbmdzLmFvQ29sdW1uc1sgaUNvbCBdO1xuXHRcdHZhciBvQ2xhc3NlcyA9IG9TZXR0aW5ncy5vQ2xhc3Nlcztcblx0XHR2YXIgdGggPSAkKG9Db2wublRoKTtcblx0XG5cdFx0Ly8gVHJ5IHRvIGdldCB3aWR0aCBpbmZvcm1hdGlvbiBmcm9tIHRoZSBET00uIFdlIGNhbid0IGdldCBpdCBmcm9tIENTU1xuXHRcdC8vIGFzIHdlJ2QgbmVlZCB0byBwYXJzZSB0aGUgQ1NTIHN0eWxlc2hlZXQuIGB3aWR0aGAgb3B0aW9uIGNhbiBvdmVycmlkZVxuXHRcdGlmICggISBvQ29sLnNXaWR0aE9yaWcgKSB7XG5cdFx0XHQvLyBXaWR0aCBhdHRyaWJ1dGVcblx0XHRcdG9Db2wuc1dpZHRoT3JpZyA9IHRoLmF0dHIoJ3dpZHRoJykgfHwgbnVsbDtcblx0XG5cdFx0XHQvLyBTdHlsZSBhdHRyaWJ1dGVcblx0XHRcdHZhciB0ID0gKHRoLmF0dHIoJ3N0eWxlJykgfHwgJycpLm1hdGNoKC93aWR0aDpcXHMqKFxcZCtbcHhlbSVdKykvKTtcblx0XHRcdGlmICggdCApIHtcblx0XHRcdFx0b0NvbC5zV2lkdGhPcmlnID0gdFsxXTtcblx0XHRcdH1cblx0XHR9XG5cdFxuXHRcdC8qIFVzZXIgc3BlY2lmaWVkIGNvbHVtbiBvcHRpb25zICovXG5cdFx0aWYgKCBvT3B0aW9ucyAhPT0gdW5kZWZpbmVkICYmIG9PcHRpb25zICE9PSBudWxsIClcblx0XHR7XG5cdFx0XHQvLyBCYWNrd2FyZHMgY29tcGF0aWJpbGl0eVxuXHRcdFx0X2ZuQ29tcGF0Q29scyggb09wdGlvbnMgKTtcblx0XG5cdFx0XHQvLyBNYXAgY2FtZWwgY2FzZSBwYXJhbWV0ZXJzIHRvIHRoZWlyIEh1bmdhcmlhbiBjb3VudGVycGFydHNcblx0XHRcdF9mbkNhbWVsVG9IdW5nYXJpYW4oIERhdGFUYWJsZS5kZWZhdWx0cy5jb2x1bW4sIG9PcHRpb25zLCB0cnVlICk7XG5cdFxuXHRcdFx0LyogQmFja3dhcmRzIGNvbXBhdGliaWxpdHkgZm9yIG1EYXRhUHJvcCAqL1xuXHRcdFx0aWYgKCBvT3B0aW9ucy5tRGF0YVByb3AgIT09IHVuZGVmaW5lZCAmJiAhb09wdGlvbnMubURhdGEgKVxuXHRcdFx0e1xuXHRcdFx0XHRvT3B0aW9ucy5tRGF0YSA9IG9PcHRpb25zLm1EYXRhUHJvcDtcblx0XHRcdH1cblx0XG5cdFx0XHRpZiAoIG9PcHRpb25zLnNUeXBlIClcblx0XHRcdHtcblx0XHRcdFx0b0NvbC5fc01hbnVhbFR5cGUgPSBvT3B0aW9ucy5zVHlwZTtcblx0XHRcdH1cblx0XG5cdFx0XHQvLyBgY2xhc3NgIGlzIGEgcmVzZXJ2ZWQgd29yZCBpbiBKYXZhc2NyaXB0LCBzbyB3ZSBuZWVkIHRvIHByb3ZpZGVcblx0XHRcdC8vIHRoZSBhYmlsaXR5IHRvIHVzZSBhIHZhbGlkIG5hbWUgZm9yIHRoZSBjYW1lbCBjYXNlIGlucHV0XG5cdFx0XHRpZiAoIG9PcHRpb25zLmNsYXNzTmFtZSAmJiAhIG9PcHRpb25zLnNDbGFzcyApXG5cdFx0XHR7XG5cdFx0XHRcdG9PcHRpb25zLnNDbGFzcyA9IG9PcHRpb25zLmNsYXNzTmFtZTtcblx0XHRcdH1cblx0XHRcdGlmICggb09wdGlvbnMuc0NsYXNzICkge1xuXHRcdFx0XHR0aC5hZGRDbGFzcyggb09wdGlvbnMuc0NsYXNzICk7XG5cdFx0XHR9XG5cdFxuXHRcdFx0JC5leHRlbmQoIG9Db2wsIG9PcHRpb25zICk7XG5cdFx0XHRfZm5NYXAoIG9Db2wsIG9PcHRpb25zLCBcInNXaWR0aFwiLCBcInNXaWR0aE9yaWdcIiApO1xuXHRcblx0XHRcdC8qIGlEYXRhU29ydCB0byBiZSBhcHBsaWVkIChiYWNrd2FyZHMgY29tcGF0aWJpbGl0eSksIGJ1dCBhRGF0YVNvcnQgd2lsbCB0YWtlXG5cdFx0XHQgKiBwcmlvcml0eSBpZiBkZWZpbmVkXG5cdFx0XHQgKi9cblx0XHRcdGlmICggb09wdGlvbnMuaURhdGFTb3J0ICE9PSB1bmRlZmluZWQgKVxuXHRcdFx0e1xuXHRcdFx0XHRvQ29sLmFEYXRhU29ydCA9IFsgb09wdGlvbnMuaURhdGFTb3J0IF07XG5cdFx0XHR9XG5cdFx0XHRfZm5NYXAoIG9Db2wsIG9PcHRpb25zLCBcImFEYXRhU29ydFwiICk7XG5cdFx0fVxuXHRcblx0XHQvKiBDYWNoZSB0aGUgZGF0YSBnZXQgYW5kIHNldCBmdW5jdGlvbnMgZm9yIHNwZWVkICovXG5cdFx0dmFyIG1EYXRhU3JjID0gb0NvbC5tRGF0YTtcblx0XHR2YXIgbURhdGEgPSBfZm5HZXRPYmplY3REYXRhRm4oIG1EYXRhU3JjICk7XG5cdFx0dmFyIG1SZW5kZXIgPSBvQ29sLm1SZW5kZXIgPyBfZm5HZXRPYmplY3REYXRhRm4oIG9Db2wubVJlbmRlciApIDogbnVsbDtcblx0XG5cdFx0dmFyIGF0dHJUZXN0ID0gZnVuY3Rpb24oIHNyYyApIHtcblx0XHRcdHJldHVybiB0eXBlb2Ygc3JjID09PSAnc3RyaW5nJyAmJiBzcmMuaW5kZXhPZignQCcpICE9PSAtMTtcblx0XHR9O1xuXHRcdG9Db2wuX2JBdHRyU3JjID0gJC5pc1BsYWluT2JqZWN0KCBtRGF0YVNyYyApICYmIChcblx0XHRcdGF0dHJUZXN0KG1EYXRhU3JjLnNvcnQpIHx8IGF0dHJUZXN0KG1EYXRhU3JjLnR5cGUpIHx8IGF0dHJUZXN0KG1EYXRhU3JjLmZpbHRlcilcblx0XHQpO1xuXHRcdG9Db2wuX3NldHRlciA9IG51bGw7XG5cdFxuXHRcdG9Db2wuZm5HZXREYXRhID0gZnVuY3Rpb24gKHJvd0RhdGEsIHR5cGUsIG1ldGEpIHtcblx0XHRcdHZhciBpbm5lckRhdGEgPSBtRGF0YSggcm93RGF0YSwgdHlwZSwgdW5kZWZpbmVkLCBtZXRhICk7XG5cdFxuXHRcdFx0cmV0dXJuIG1SZW5kZXIgJiYgdHlwZSA/XG5cdFx0XHRcdG1SZW5kZXIoIGlubmVyRGF0YSwgdHlwZSwgcm93RGF0YSwgbWV0YSApIDpcblx0XHRcdFx0aW5uZXJEYXRhO1xuXHRcdH07XG5cdFx0b0NvbC5mblNldERhdGEgPSBmdW5jdGlvbiAoIHJvd0RhdGEsIHZhbCwgbWV0YSApIHtcblx0XHRcdHJldHVybiBfZm5TZXRPYmplY3REYXRhRm4oIG1EYXRhU3JjICkoIHJvd0RhdGEsIHZhbCwgbWV0YSApO1xuXHRcdH07XG5cdFxuXHRcdC8vIEluZGljYXRlIGlmIERhdGFUYWJsZXMgc2hvdWxkIHJlYWQgRE9NIGRhdGEgYXMgYW4gb2JqZWN0IG9yIGFycmF5XG5cdFx0Ly8gVXNlZCBpbiBfZm5HZXRSb3dFbGVtZW50c1xuXHRcdGlmICggdHlwZW9mIG1EYXRhU3JjICE9PSAnbnVtYmVyJyApIHtcblx0XHRcdG9TZXR0aW5ncy5fcm93UmVhZE9iamVjdCA9IHRydWU7XG5cdFx0fVxuXHRcblx0XHQvKiBGZWF0dXJlIHNvcnRpbmcgb3ZlcnJpZGVzIGNvbHVtbiBzcGVjaWZpYyB3aGVuIG9mZiAqL1xuXHRcdGlmICggIW9TZXR0aW5ncy5vRmVhdHVyZXMuYlNvcnQgKVxuXHRcdHtcblx0XHRcdG9Db2wuYlNvcnRhYmxlID0gZmFsc2U7XG5cdFx0XHR0aC5hZGRDbGFzcyggb0NsYXNzZXMuc1NvcnRhYmxlTm9uZSApOyAvLyBIYXZlIHRvIGFkZCBjbGFzcyBoZXJlIGFzIG9yZGVyIGV2ZW50IGlzbid0IGNhbGxlZFxuXHRcdH1cblx0XG5cdFx0LyogQ2hlY2sgdGhhdCB0aGUgY2xhc3MgYXNzaWdubWVudCBpcyBjb3JyZWN0IGZvciBzb3J0aW5nICovXG5cdFx0dmFyIGJBc2MgPSAkLmluQXJyYXkoJ2FzYycsIG9Db2wuYXNTb3J0aW5nKSAhPT0gLTE7XG5cdFx0dmFyIGJEZXNjID0gJC5pbkFycmF5KCdkZXNjJywgb0NvbC5hc1NvcnRpbmcpICE9PSAtMTtcblx0XHRpZiAoICFvQ29sLmJTb3J0YWJsZSB8fCAoIWJBc2MgJiYgIWJEZXNjKSApXG5cdFx0e1xuXHRcdFx0b0NvbC5zU29ydGluZ0NsYXNzID0gb0NsYXNzZXMuc1NvcnRhYmxlTm9uZTtcblx0XHRcdG9Db2wuc1NvcnRpbmdDbGFzc0pVSSA9IFwiXCI7XG5cdFx0fVxuXHRcdGVsc2UgaWYgKCBiQXNjICYmICFiRGVzYyApXG5cdFx0e1xuXHRcdFx0b0NvbC5zU29ydGluZ0NsYXNzID0gb0NsYXNzZXMuc1NvcnRhYmxlQXNjO1xuXHRcdFx0b0NvbC5zU29ydGluZ0NsYXNzSlVJID0gb0NsYXNzZXMuc1NvcnRKVUlBc2NBbGxvd2VkO1xuXHRcdH1cblx0XHRlbHNlIGlmICggIWJBc2MgJiYgYkRlc2MgKVxuXHRcdHtcblx0XHRcdG9Db2wuc1NvcnRpbmdDbGFzcyA9IG9DbGFzc2VzLnNTb3J0YWJsZURlc2M7XG5cdFx0XHRvQ29sLnNTb3J0aW5nQ2xhc3NKVUkgPSBvQ2xhc3Nlcy5zU29ydEpVSURlc2NBbGxvd2VkO1xuXHRcdH1cblx0XHRlbHNlXG5cdFx0e1xuXHRcdFx0b0NvbC5zU29ydGluZ0NsYXNzID0gb0NsYXNzZXMuc1NvcnRhYmxlO1xuXHRcdFx0b0NvbC5zU29ydGluZ0NsYXNzSlVJID0gb0NsYXNzZXMuc1NvcnRKVUk7XG5cdFx0fVxuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIEFkanVzdCB0aGUgdGFibGUgY29sdW1uIHdpZHRocyBmb3IgbmV3IGRhdGEuIE5vdGU6IHlvdSB3b3VsZCBwcm9iYWJseSB3YW50IHRvXG5cdCAqIGRvIGEgcmVkcmF3IGFmdGVyIGNhbGxpbmcgdGhpcyBmdW5jdGlvbiFcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5BZGp1c3RDb2x1bW5TaXppbmcgKCBzZXR0aW5ncyApXG5cdHtcblx0XHQvKiBOb3QgaW50ZXJlc3RlZCBpbiBkb2luZyBjb2x1bW4gd2lkdGggY2FsY3VsYXRpb24gaWYgYXV0by13aWR0aCBpcyBkaXNhYmxlZCAqL1xuXHRcdGlmICggc2V0dGluZ3Mub0ZlYXR1cmVzLmJBdXRvV2lkdGggIT09IGZhbHNlIClcblx0XHR7XG5cdFx0XHR2YXIgY29sdW1ucyA9IHNldHRpbmdzLmFvQ29sdW1ucztcblx0XG5cdFx0XHRfZm5DYWxjdWxhdGVDb2x1bW5XaWR0aHMoIHNldHRpbmdzICk7XG5cdFx0XHRmb3IgKCB2YXIgaT0wICwgaUxlbj1jb2x1bW5zLmxlbmd0aCA7IGk8aUxlbiA7IGkrKyApXG5cdFx0XHR7XG5cdFx0XHRcdGNvbHVtbnNbaV0ublRoLnN0eWxlLndpZHRoID0gY29sdW1uc1tpXS5zV2lkdGg7XG5cdFx0XHR9XG5cdFx0fVxuXHRcblx0XHR2YXIgc2Nyb2xsID0gc2V0dGluZ3Mub1Njcm9sbDtcblx0XHRpZiAoIHNjcm9sbC5zWSAhPT0gJycgfHwgc2Nyb2xsLnNYICE9PSAnJylcblx0XHR7XG5cdFx0XHRfZm5TY3JvbGxEcmF3KCBzZXR0aW5ncyApO1xuXHRcdH1cblx0XG5cdFx0X2ZuQ2FsbGJhY2tGaXJlKCBzZXR0aW5ncywgbnVsbCwgJ2NvbHVtbi1zaXppbmcnLCBbc2V0dGluZ3NdICk7XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogQ29udmVydCB0aGUgaW5kZXggb2YgYSB2aXNpYmxlIGNvbHVtbiB0byB0aGUgaW5kZXggaW4gdGhlIGRhdGEgYXJyYXkgKHRha2UgYWNjb3VudFxuXHQgKiBvZiBoaWRkZW4gY29sdW1ucylcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBwYXJhbSB7aW50fSBpTWF0Y2ggVmlzaWJsZSBjb2x1bW4gaW5kZXggdG8gbG9va3VwXG5cdCAqICBAcmV0dXJucyB7aW50fSBpIHRoZSBkYXRhIGluZGV4XG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mblZpc2libGVUb0NvbHVtbkluZGV4KCBvU2V0dGluZ3MsIGlNYXRjaCApXG5cdHtcblx0XHR2YXIgYWlWaXMgPSBfZm5HZXRDb2x1bW5zKCBvU2V0dGluZ3MsICdiVmlzaWJsZScgKTtcblx0XG5cdFx0cmV0dXJuIHR5cGVvZiBhaVZpc1tpTWF0Y2hdID09PSAnbnVtYmVyJyA/XG5cdFx0XHRhaVZpc1tpTWF0Y2hdIDpcblx0XHRcdG51bGw7XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogQ29udmVydCB0aGUgaW5kZXggb2YgYW4gaW5kZXggaW4gdGhlIGRhdGEgYXJyYXkgYW5kIGNvbnZlcnQgaXQgdG8gdGhlIHZpc2libGVcblx0ICogICBjb2x1bW4gaW5kZXggKHRha2UgYWNjb3VudCBvZiBoaWRkZW4gY29sdW1ucylcblx0ICogIEBwYXJhbSB7aW50fSBpTWF0Y2ggQ29sdW1uIGluZGV4IHRvIGxvb2t1cFxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IG9TZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHJldHVybnMge2ludH0gaSB0aGUgZGF0YSBpbmRleFxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5Db2x1bW5JbmRleFRvVmlzaWJsZSggb1NldHRpbmdzLCBpTWF0Y2ggKVxuXHR7XG5cdFx0dmFyIGFpVmlzID0gX2ZuR2V0Q29sdW1ucyggb1NldHRpbmdzLCAnYlZpc2libGUnICk7XG5cdFx0dmFyIGlQb3MgPSAkLmluQXJyYXkoIGlNYXRjaCwgYWlWaXMgKTtcblx0XG5cdFx0cmV0dXJuIGlQb3MgIT09IC0xID8gaVBvcyA6IG51bGw7XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogR2V0IHRoZSBudW1iZXIgb2YgdmlzaWJsZSBjb2x1bW5zXG5cdCAqICBAcGFyYW0ge29iamVjdH0gb1NldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAcmV0dXJucyB7aW50fSBpIHRoZSBudW1iZXIgb2YgdmlzaWJsZSBjb2x1bW5zXG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mblZpc2JsZUNvbHVtbnMoIG9TZXR0aW5ncyApXG5cdHtcblx0XHR2YXIgdmlzID0gMDtcblx0XG5cdFx0Ly8gTm8gcmVkdWNlIGluIElFOCwgdXNlIGEgbG9vcCBmb3Igbm93XG5cdFx0JC5lYWNoKCBvU2V0dGluZ3MuYW9Db2x1bW5zLCBmdW5jdGlvbiAoIGksIGNvbCApIHtcblx0XHRcdGlmICggY29sLmJWaXNpYmxlICYmICQoY29sLm5UaCkuY3NzKCdkaXNwbGF5JykgIT09ICdub25lJyApIHtcblx0XHRcdFx0dmlzKys7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHRcblx0XHRyZXR1cm4gdmlzO1xuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIEdldCBhbiBhcnJheSBvZiBjb2x1bW4gaW5kZXhlcyB0aGF0IG1hdGNoIGEgZ2l2ZW4gcHJvcGVydHlcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBwYXJhbSB7c3RyaW5nfSBzUGFyYW0gUGFyYW1ldGVyIGluIGFvQ29sdW1ucyB0byBsb29rIGZvciAtIHR5cGljYWxseVxuXHQgKiAgICBiVmlzaWJsZSBvciBiU2VhcmNoYWJsZVxuXHQgKiAgQHJldHVybnMge2FycmF5fSBBcnJheSBvZiBpbmRleGVzIHdpdGggbWF0Y2hlZCBwcm9wZXJ0aWVzXG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mbkdldENvbHVtbnMoIG9TZXR0aW5ncywgc1BhcmFtIClcblx0e1xuXHRcdHZhciBhID0gW107XG5cdFxuXHRcdCQubWFwKCBvU2V0dGluZ3MuYW9Db2x1bW5zLCBmdW5jdGlvbih2YWwsIGkpIHtcblx0XHRcdGlmICggdmFsW3NQYXJhbV0gKSB7XG5cdFx0XHRcdGEucHVzaCggaSApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0XG5cdFx0cmV0dXJuIGE7XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogQ2FsY3VsYXRlIHRoZSAndHlwZScgb2YgYSBjb2x1bW5cblx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5Db2x1bW5UeXBlcyAoIHNldHRpbmdzIClcblx0e1xuXHRcdHZhciBjb2x1bW5zID0gc2V0dGluZ3MuYW9Db2x1bW5zO1xuXHRcdHZhciBkYXRhID0gc2V0dGluZ3MuYW9EYXRhO1xuXHRcdHZhciB0eXBlcyA9IERhdGFUYWJsZS5leHQudHlwZS5kZXRlY3Q7XG5cdFx0dmFyIGksIGllbiwgaiwgamVuLCBrLCBrZW47XG5cdFx0dmFyIGNvbCwgY2VsbCwgZGV0ZWN0ZWRUeXBlLCBjYWNoZTtcblx0XG5cdFx0Ly8gRm9yIGVhY2ggY29sdW1uLCBzcGluIG92ZXIgdGhlIFxuXHRcdGZvciAoIGk9MCwgaWVuPWNvbHVtbnMubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRjb2wgPSBjb2x1bW5zW2ldO1xuXHRcdFx0Y2FjaGUgPSBbXTtcblx0XG5cdFx0XHRpZiAoICEgY29sLnNUeXBlICYmIGNvbC5fc01hbnVhbFR5cGUgKSB7XG5cdFx0XHRcdGNvbC5zVHlwZSA9IGNvbC5fc01hbnVhbFR5cGU7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIGlmICggISBjb2wuc1R5cGUgKSB7XG5cdFx0XHRcdGZvciAoIGo9MCwgamVuPXR5cGVzLmxlbmd0aCA7IGo8amVuIDsgaisrICkge1xuXHRcdFx0XHRcdGZvciAoIGs9MCwga2VuPWRhdGEubGVuZ3RoIDsgazxrZW4gOyBrKysgKSB7XG5cdFx0XHRcdFx0XHQvLyBVc2UgYSBjYWNoZSBhcnJheSBzbyB3ZSBvbmx5IG5lZWQgdG8gZ2V0IHRoZSB0eXBlIGRhdGFcblx0XHRcdFx0XHRcdC8vIGZyb20gdGhlIGZvcm1hdHRlciBvbmNlICh3aGVuIHVzaW5nIG11bHRpcGxlIGRldGVjdG9ycylcblx0XHRcdFx0XHRcdGlmICggY2FjaGVba10gPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0XHRcdFx0Y2FjaGVba10gPSBfZm5HZXRDZWxsRGF0YSggc2V0dGluZ3MsIGssIGksICd0eXBlJyApO1xuXHRcdFx0XHRcdFx0fVxuXHRcblx0XHRcdFx0XHRcdGRldGVjdGVkVHlwZSA9IHR5cGVzW2pdKCBjYWNoZVtrXSwgc2V0dGluZ3MgKTtcblx0XG5cdFx0XHRcdFx0XHQvLyBJZiBudWxsLCB0aGVuIHRoaXMgdHlwZSBjYW4ndCBhcHBseSB0byB0aGlzIGNvbHVtbiwgc29cblx0XHRcdFx0XHRcdC8vIHJhdGhlciB0aGFuIHRlc3RpbmcgYWxsIGNlbGxzLCBicmVhayBvdXQuIFRoZXJlIGlzIGFuXG5cdFx0XHRcdFx0XHQvLyBleGNlcHRpb24gZm9yIHRoZSBsYXN0IHR5cGUgd2hpY2ggaXMgYGh0bWxgLiBXZSBuZWVkIHRvXG5cdFx0XHRcdFx0XHQvLyBzY2FuIGFsbCByb3dzIHNpbmNlIGl0IGlzIHBvc3NpYmxlIHRvIG1peCBzdHJpbmcgYW5kIEhUTUxcblx0XHRcdFx0XHRcdC8vIHR5cGVzXG5cdFx0XHRcdFx0XHRpZiAoICEgZGV0ZWN0ZWRUeXBlICYmIGogIT09IHR5cGVzLmxlbmd0aC0xICkge1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdH1cblx0XG5cdFx0XHRcdFx0XHQvLyBPbmx5IGEgc2luZ2xlIG1hdGNoIGlzIG5lZWRlZCBmb3IgaHRtbCB0eXBlIHNpbmNlIGl0IGlzXG5cdFx0XHRcdFx0XHQvLyBib3R0b20gb2YgdGhlIHBpbGUgYW5kIHZlcnkgc2ltaWxhciB0byBzdHJpbmcgLSBidXQgaXRcblx0XHRcdFx0XHRcdC8vIG11c3Qgbm90IGJlIGVtcHR5XG5cdFx0XHRcdFx0XHRpZiAoIGRldGVjdGVkVHlwZSA9PT0gJ2h0bWwnICYmICEgX2VtcHR5KGNhY2hlW2tdKSApIHtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcblx0XHRcdFx0XHQvLyBUeXBlIGlzIHZhbGlkIGZvciBhbGwgZGF0YSBwb2ludHMgaW4gdGhlIGNvbHVtbiAtIHVzZSB0aGlzXG5cdFx0XHRcdFx0Ly8gdHlwZVxuXHRcdFx0XHRcdGlmICggZGV0ZWN0ZWRUeXBlICkge1xuXHRcdFx0XHRcdFx0Y29sLnNUeXBlID0gZGV0ZWN0ZWRUeXBlO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFxuXHRcdFx0XHQvLyBGYWxsIGJhY2sgLSBpZiBubyB0eXBlIHdhcyBkZXRlY3RlZCwgYWx3YXlzIHVzZSBzdHJpbmdcblx0XHRcdFx0aWYgKCAhIGNvbC5zVHlwZSApIHtcblx0XHRcdFx0XHRjb2wuc1R5cGUgPSAnc3RyaW5nJztcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBUYWtlIHRoZSBjb2x1bW4gZGVmaW5pdGlvbnMgYW5kIHN0YXRpYyBjb2x1bW5zIGFycmF5cyBhbmQgY2FsY3VsYXRlIGhvd1xuXHQgKiB0aGV5IHJlbGF0ZSB0byBjb2x1bW4gaW5kZXhlcy4gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHdpbGwgdGhlbiBhcHBseSB0aGVcblx0ICogZGVmaW5pdGlvbiBmb3VuZCBmb3IgYSBjb2x1bW4gdG8gYSBzdWl0YWJsZSBjb25maWd1cmF0aW9uIG9iamVjdC5cblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBwYXJhbSB7YXJyYXl9IGFvQ29sRGVmcyBUaGUgYW9Db2x1bW5EZWZzIGFycmF5IHRoYXQgaXMgdG8gYmUgYXBwbGllZFxuXHQgKiAgQHBhcmFtIHthcnJheX0gYW9Db2xzIFRoZSBhb0NvbHVtbnMgYXJyYXkgdGhhdCBkZWZpbmVzIGNvbHVtbnMgaW5kaXZpZHVhbGx5XG5cdCAqICBAcGFyYW0ge2Z1bmN0aW9ufSBmbiBDYWxsYmFjayBmdW5jdGlvbiAtIHRha2VzIHR3byBwYXJhbWV0ZXJzLCB0aGUgY2FsY3VsYXRlZFxuXHQgKiAgICBjb2x1bW4gaW5kZXggYW5kIHRoZSBkZWZpbml0aW9uIGZvciB0aGF0IGNvbHVtbi5cblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuQXBwbHlDb2x1bW5EZWZzKCBvU2V0dGluZ3MsIGFvQ29sRGVmcywgYW9Db2xzLCBmbiApXG5cdHtcblx0XHR2YXIgaSwgaUxlbiwgaiwgakxlbiwgaywga0xlbiwgZGVmO1xuXHRcdHZhciBjb2x1bW5zID0gb1NldHRpbmdzLmFvQ29sdW1ucztcblx0XG5cdFx0Ly8gQ29sdW1uIGRlZmluaXRpb25zIHdpdGggYVRhcmdldHNcblx0XHRpZiAoIGFvQ29sRGVmcyApXG5cdFx0e1xuXHRcdFx0LyogTG9vcCBvdmVyIHRoZSBkZWZpbml0aW9ucyBhcnJheSAtIGxvb3AgaW4gcmV2ZXJzZSBzbyBmaXJzdCBpbnN0YW5jZSBoYXMgcHJpb3JpdHkgKi9cblx0XHRcdGZvciAoIGk9YW9Db2xEZWZzLmxlbmd0aC0xIDsgaT49MCA7IGktLSApXG5cdFx0XHR7XG5cdFx0XHRcdGRlZiA9IGFvQ29sRGVmc1tpXTtcblx0XG5cdFx0XHRcdC8qIEVhY2ggZGVmaW5pdGlvbiBjYW4gdGFyZ2V0IG11bHRpcGxlIGNvbHVtbnMsIGFzIGl0IGlzIGFuIGFycmF5ICovXG5cdFx0XHRcdHZhciBhVGFyZ2V0cyA9IGRlZi50YXJnZXRzICE9PSB1bmRlZmluZWQgP1xuXHRcdFx0XHRcdGRlZi50YXJnZXRzIDpcblx0XHRcdFx0XHRkZWYuYVRhcmdldHM7XG5cdFxuXHRcdFx0XHRpZiAoICEgQXJyYXkuaXNBcnJheSggYVRhcmdldHMgKSApXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRhVGFyZ2V0cyA9IFsgYVRhcmdldHMgXTtcblx0XHRcdFx0fVxuXHRcblx0XHRcdFx0Zm9yICggaj0wLCBqTGVuPWFUYXJnZXRzLmxlbmd0aCA7IGo8akxlbiA7IGorKyApXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRpZiAoIHR5cGVvZiBhVGFyZ2V0c1tqXSA9PT0gJ251bWJlcicgJiYgYVRhcmdldHNbal0gPj0gMCApXG5cdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0LyogQWRkIGNvbHVtbnMgdGhhdCB3ZSBkb24ndCB5ZXQga25vdyBhYm91dCAqL1xuXHRcdFx0XHRcdFx0d2hpbGUoIGNvbHVtbnMubGVuZ3RoIDw9IGFUYXJnZXRzW2pdIClcblx0XHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdFx0X2ZuQWRkQ29sdW1uKCBvU2V0dGluZ3MgKTtcblx0XHRcdFx0XHRcdH1cblx0XG5cdFx0XHRcdFx0XHQvKiBJbnRlZ2VyLCBiYXNpYyBpbmRleCAqL1xuXHRcdFx0XHRcdFx0Zm4oIGFUYXJnZXRzW2pdLCBkZWYgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZSBpZiAoIHR5cGVvZiBhVGFyZ2V0c1tqXSA9PT0gJ251bWJlcicgJiYgYVRhcmdldHNbal0gPCAwIClcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHQvKiBOZWdhdGl2ZSBpbnRlZ2VyLCByaWdodCB0byBsZWZ0IGNvbHVtbiBjb3VudGluZyAqL1xuXHRcdFx0XHRcdFx0Zm4oIGNvbHVtbnMubGVuZ3RoK2FUYXJnZXRzW2pdLCBkZWYgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZSBpZiAoIHR5cGVvZiBhVGFyZ2V0c1tqXSA9PT0gJ3N0cmluZycgKVxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdC8qIENsYXNzIG5hbWUgbWF0Y2hpbmcgb24gVEggZWxlbWVudCAqL1xuXHRcdFx0XHRcdFx0Zm9yICggaz0wLCBrTGVuPWNvbHVtbnMubGVuZ3RoIDsgazxrTGVuIDsgaysrIClcblx0XHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdFx0aWYgKCBhVGFyZ2V0c1tqXSA9PSBcIl9hbGxcIiB8fFxuXHRcdFx0XHRcdFx0XHQgICAgICQoY29sdW1uc1trXS5uVGgpLmhhc0NsYXNzKCBhVGFyZ2V0c1tqXSApIClcblx0XHRcdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0XHRcdGZuKCBrLCBkZWYgKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XG5cdFx0Ly8gU3RhdGljYWxseSBkZWZpbmVkIGNvbHVtbnMgYXJyYXlcblx0XHRpZiAoIGFvQ29scyApXG5cdFx0e1xuXHRcdFx0Zm9yICggaT0wLCBpTGVuPWFvQ29scy5sZW5ndGggOyBpPGlMZW4gOyBpKysgKVxuXHRcdFx0e1xuXHRcdFx0XHRmbiggaSwgYW9Db2xzW2ldICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cdFxuXHQvKipcblx0ICogQWRkIGEgZGF0YSBhcnJheSB0byB0aGUgdGFibGUsIGNyZWF0aW5nIERPTSBub2RlIGV0Yy4gVGhpcyBpcyB0aGUgcGFyYWxsZWwgdG9cblx0ICogX2ZuR2F0aGVyRGF0YSwgYnV0IGZvciBhZGRpbmcgcm93cyBmcm9tIGEgSmF2YXNjcmlwdCBzb3VyY2UsIHJhdGhlciB0aGFuIGFcblx0ICogRE9NIHNvdXJjZS5cblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBwYXJhbSB7YXJyYXl9IGFEYXRhIGRhdGEgYXJyYXkgdG8gYmUgYWRkZWRcblx0ICogIEBwYXJhbSB7bm9kZX0gW25Ucl0gVFIgZWxlbWVudCB0byBhZGQgdG8gdGhlIHRhYmxlIC0gb3B0aW9uYWwuIElmIG5vdCBnaXZlbixcblx0ICogICAgRGF0YVRhYmxlcyB3aWxsIGNyZWF0ZSBhIHJvdyBhdXRvbWF0aWNhbGx5XG5cdCAqICBAcGFyYW0ge2FycmF5fSBbYW5UZHNdIEFycmF5IG9mIFREfFRIIGVsZW1lbnRzIGZvciB0aGUgcm93IC0gbXVzdCBiZSBnaXZlblxuXHQgKiAgICBpZiBuVHIgaXMuXG5cdCAqICBAcmV0dXJucyB7aW50fSA+PTAgaWYgc3VjY2Vzc2Z1bCAoaW5kZXggb2YgbmV3IGFvRGF0YSBlbnRyeSksIC0xIGlmIGZhaWxlZFxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5BZGREYXRhICggb1NldHRpbmdzLCBhRGF0YUluLCBuVHIsIGFuVGRzIClcblx0e1xuXHRcdC8qIENyZWF0ZSB0aGUgb2JqZWN0IGZvciBzdG9yaW5nIGluZm9ybWF0aW9uIGFib3V0IHRoaXMgbmV3IHJvdyAqL1xuXHRcdHZhciBpUm93ID0gb1NldHRpbmdzLmFvRGF0YS5sZW5ndGg7XG5cdFx0dmFyIG9EYXRhID0gJC5leHRlbmQoIHRydWUsIHt9LCBEYXRhVGFibGUubW9kZWxzLm9Sb3csIHtcblx0XHRcdHNyYzogblRyID8gJ2RvbScgOiAnZGF0YScsXG5cdFx0XHRpZHg6IGlSb3dcblx0XHR9ICk7XG5cdFxuXHRcdG9EYXRhLl9hRGF0YSA9IGFEYXRhSW47XG5cdFx0b1NldHRpbmdzLmFvRGF0YS5wdXNoKCBvRGF0YSApO1xuXHRcblx0XHQvKiBDcmVhdGUgdGhlIGNlbGxzICovXG5cdFx0dmFyIG5UZCwgc1RoaXNUeXBlO1xuXHRcdHZhciBjb2x1bW5zID0gb1NldHRpbmdzLmFvQ29sdW1ucztcblx0XG5cdFx0Ly8gSW52YWxpZGF0ZSB0aGUgY29sdW1uIHR5cGVzIGFzIHRoZSBuZXcgZGF0YSBuZWVkcyB0byBiZSByZXZhbGlkYXRlZFxuXHRcdGZvciAoIHZhciBpPTAsIGlMZW49Y29sdW1ucy5sZW5ndGggOyBpPGlMZW4gOyBpKysgKVxuXHRcdHtcblx0XHRcdGNvbHVtbnNbaV0uc1R5cGUgPSBudWxsO1xuXHRcdH1cblx0XG5cdFx0LyogQWRkIHRvIHRoZSBkaXNwbGF5IGFycmF5ICovXG5cdFx0b1NldHRpbmdzLmFpRGlzcGxheU1hc3Rlci5wdXNoKCBpUm93ICk7XG5cdFxuXHRcdHZhciBpZCA9IG9TZXR0aW5ncy5yb3dJZEZuKCBhRGF0YUluICk7XG5cdFx0aWYgKCBpZCAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0b1NldHRpbmdzLmFJZHNbIGlkIF0gPSBvRGF0YTtcblx0XHR9XG5cdFxuXHRcdC8qIENyZWF0ZSB0aGUgRE9NIGluZm9ybWF0aW9uLCBvciByZWdpc3RlciBpdCBpZiBhbHJlYWR5IHByZXNlbnQgKi9cblx0XHRpZiAoIG5UciB8fCAhIG9TZXR0aW5ncy5vRmVhdHVyZXMuYkRlZmVyUmVuZGVyIClcblx0XHR7XG5cdFx0XHRfZm5DcmVhdGVUciggb1NldHRpbmdzLCBpUm93LCBuVHIsIGFuVGRzICk7XG5cdFx0fVxuXHRcblx0XHRyZXR1cm4gaVJvdztcblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBBZGQgb25lIG9yIG1vcmUgVFIgZWxlbWVudHMgdG8gdGhlIHRhYmxlLiBHZW5lcmFsbHkgd2UnZCBleHBlY3QgdG9cblx0ICogdXNlIHRoaXMgZm9yIHJlYWRpbmcgZGF0YSBmcm9tIGEgRE9NIHNvdXJjZWQgdGFibGUsIGJ1dCBpdCBjb3VsZCBiZVxuXHQgKiB1c2VkIGZvciBhbiBUUiBlbGVtZW50LiBOb3RlIHRoYXQgaWYgYSBUUiBpcyBnaXZlbiwgaXQgaXMgdXNlZCAoaS5lLlxuXHQgKiBpdCBpcyBub3QgY2xvbmVkKS5cblx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHBhcmFtIHthcnJheXxub2RlfGpRdWVyeX0gdHJzIFRoZSBUUiBlbGVtZW50KHMpIHRvIGFkZCB0byB0aGUgdGFibGVcblx0ICogIEByZXR1cm5zIHthcnJheX0gQXJyYXkgb2YgaW5kZXhlcyBmb3IgdGhlIGFkZGVkIHJvd3Ncblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuQWRkVHIoIHNldHRpbmdzLCB0cnMgKVxuXHR7XG5cdFx0dmFyIHJvdztcblx0XG5cdFx0Ly8gQWxsb3cgYW4gaW5kaXZpZHVhbCBub2RlIHRvIGJlIHBhc3NlZCBpblxuXHRcdGlmICggISAodHJzIGluc3RhbmNlb2YgJCkgKSB7XG5cdFx0XHR0cnMgPSAkKHRycyk7XG5cdFx0fVxuXHRcblx0XHRyZXR1cm4gdHJzLm1hcCggZnVuY3Rpb24gKGksIGVsKSB7XG5cdFx0XHRyb3cgPSBfZm5HZXRSb3dFbGVtZW50cyggc2V0dGluZ3MsIGVsICk7XG5cdFx0XHRyZXR1cm4gX2ZuQWRkRGF0YSggc2V0dGluZ3MsIHJvdy5kYXRhLCBlbCwgcm93LmNlbGxzICk7XG5cdFx0fSApO1xuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIFRha2UgYSBUUiBlbGVtZW50IGFuZCBjb252ZXJ0IGl0IHRvIGFuIGluZGV4IGluIGFvRGF0YVxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IG9TZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHBhcmFtIHtub2RlfSBuIHRoZSBUUiBlbGVtZW50IHRvIGZpbmRcblx0ICogIEByZXR1cm5zIHtpbnR9IGluZGV4IGlmIHRoZSBub2RlIGlzIGZvdW5kLCBudWxsIGlmIG5vdFxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5Ob2RlVG9EYXRhSW5kZXgoIG9TZXR0aW5ncywgbiApXG5cdHtcblx0XHRyZXR1cm4gKG4uX0RUX1Jvd0luZGV4IT09dW5kZWZpbmVkKSA/IG4uX0RUX1Jvd0luZGV4IDogbnVsbDtcblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBUYWtlIGEgVEQgZWxlbWVudCBhbmQgY29udmVydCBpdCBpbnRvIGEgY29sdW1uIGRhdGEgaW5kZXggKG5vdCB0aGUgdmlzaWJsZSBpbmRleClcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBwYXJhbSB7aW50fSBpUm93IFRoZSByb3cgbnVtYmVyIHRoZSBURC9USCBjYW4gYmUgZm91bmQgaW5cblx0ICogIEBwYXJhbSB7bm9kZX0gbiBUaGUgVEQvVEggZWxlbWVudCB0byBmaW5kXG5cdCAqICBAcmV0dXJucyB7aW50fSBpbmRleCBpZiB0aGUgbm9kZSBpcyBmb3VuZCwgLTEgaWYgbm90XG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mbk5vZGVUb0NvbHVtbkluZGV4KCBvU2V0dGluZ3MsIGlSb3csIG4gKVxuXHR7XG5cdFx0cmV0dXJuICQuaW5BcnJheSggbiwgb1NldHRpbmdzLmFvRGF0YVsgaVJvdyBdLmFuQ2VsbHMgKTtcblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBHZXQgdGhlIGRhdGEgZm9yIGEgZ2l2ZW4gY2VsbCBmcm9tIHRoZSBpbnRlcm5hbCBjYWNoZSwgdGFraW5nIGludG8gYWNjb3VudCBkYXRhIG1hcHBpbmdcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHBhcmFtIHtpbnR9IHJvd0lkeCBhb0RhdGEgcm93IGlkXG5cdCAqICBAcGFyYW0ge2ludH0gY29sSWR4IENvbHVtbiBpbmRleFxuXHQgKiAgQHBhcmFtIHtzdHJpbmd9IHR5cGUgZGF0YSBnZXQgdHlwZSAoJ2Rpc3BsYXknLCAndHlwZScgJ2ZpbHRlcnxzZWFyY2gnICdzb3J0fG9yZGVyJylcblx0ICogIEByZXR1cm5zIHsqfSBDZWxsIGRhdGFcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuR2V0Q2VsbERhdGEoIHNldHRpbmdzLCByb3dJZHgsIGNvbElkeCwgdHlwZSApXG5cdHtcblx0XHRpZiAodHlwZSA9PT0gJ3NlYXJjaCcpIHtcblx0XHRcdHR5cGUgPSAnZmlsdGVyJztcblx0XHR9XG5cdFx0ZWxzZSBpZiAodHlwZSA9PT0gJ29yZGVyJykge1xuXHRcdFx0dHlwZSA9ICdzb3J0Jztcblx0XHR9XG5cdFxuXHRcdHZhciBkcmF3ICAgICAgICAgICA9IHNldHRpbmdzLmlEcmF3O1xuXHRcdHZhciBjb2wgICAgICAgICAgICA9IHNldHRpbmdzLmFvQ29sdW1uc1tjb2xJZHhdO1xuXHRcdHZhciByb3dEYXRhICAgICAgICA9IHNldHRpbmdzLmFvRGF0YVtyb3dJZHhdLl9hRGF0YTtcblx0XHR2YXIgZGVmYXVsdENvbnRlbnQgPSBjb2wuc0RlZmF1bHRDb250ZW50O1xuXHRcdHZhciBjZWxsRGF0YSAgICAgICA9IGNvbC5mbkdldERhdGEoIHJvd0RhdGEsIHR5cGUsIHtcblx0XHRcdHNldHRpbmdzOiBzZXR0aW5ncyxcblx0XHRcdHJvdzogICAgICByb3dJZHgsXG5cdFx0XHRjb2w6ICAgICAgY29sSWR4XG5cdFx0fSApO1xuXHRcblx0XHRpZiAoIGNlbGxEYXRhID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRpZiAoIHNldHRpbmdzLmlEcmF3RXJyb3IgIT0gZHJhdyAmJiBkZWZhdWx0Q29udGVudCA9PT0gbnVsbCApIHtcblx0XHRcdFx0X2ZuTG9nKCBzZXR0aW5ncywgMCwgXCJSZXF1ZXN0ZWQgdW5rbm93biBwYXJhbWV0ZXIgXCIrXG5cdFx0XHRcdFx0KHR5cGVvZiBjb2wubURhdGE9PSdmdW5jdGlvbicgPyAne2Z1bmN0aW9ufScgOiBcIidcIitjb2wubURhdGErXCInXCIpK1xuXHRcdFx0XHRcdFwiIGZvciByb3cgXCIrcm93SWR4K1wiLCBjb2x1bW4gXCIrY29sSWR4LCA0ICk7XG5cdFx0XHRcdHNldHRpbmdzLmlEcmF3RXJyb3IgPSBkcmF3O1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGRlZmF1bHRDb250ZW50O1xuXHRcdH1cblx0XG5cdFx0Ly8gV2hlbiB0aGUgZGF0YSBzb3VyY2UgaXMgbnVsbCBhbmQgYSBzcGVjaWZpYyBkYXRhIHR5cGUgaXMgcmVxdWVzdGVkIChpLmUuXG5cdFx0Ly8gbm90IHRoZSBvcmlnaW5hbCBkYXRhKSwgd2UgY2FuIHVzZSBkZWZhdWx0IGNvbHVtbiBkYXRhXG5cdFx0aWYgKCAoY2VsbERhdGEgPT09IHJvd0RhdGEgfHwgY2VsbERhdGEgPT09IG51bGwpICYmIGRlZmF1bHRDb250ZW50ICE9PSBudWxsICYmIHR5cGUgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdGNlbGxEYXRhID0gZGVmYXVsdENvbnRlbnQ7XG5cdFx0fVxuXHRcdGVsc2UgaWYgKCB0eXBlb2YgY2VsbERhdGEgPT09ICdmdW5jdGlvbicgKSB7XG5cdFx0XHQvLyBJZiB0aGUgZGF0YSBzb3VyY2UgaXMgYSBmdW5jdGlvbiwgdGhlbiB3ZSBydW4gaXQgYW5kIHVzZSB0aGUgcmV0dXJuLFxuXHRcdFx0Ly8gZXhlY3V0aW5nIGluIHRoZSBzY29wZSBvZiB0aGUgZGF0YSBvYmplY3QgKGZvciBpbnN0YW5jZXMpXG5cdFx0XHRyZXR1cm4gY2VsbERhdGEuY2FsbCggcm93RGF0YSApO1xuXHRcdH1cblx0XG5cdFx0aWYgKCBjZWxsRGF0YSA9PT0gbnVsbCAmJiB0eXBlID09PSAnZGlzcGxheScgKSB7XG5cdFx0XHRyZXR1cm4gJyc7XG5cdFx0fVxuXHRcblx0XHRpZiAoIHR5cGUgPT09ICdmaWx0ZXInICkge1xuXHRcdFx0dmFyIGZvbWF0dGVycyA9IERhdGFUYWJsZS5leHQudHlwZS5zZWFyY2g7XG5cdFxuXHRcdFx0aWYgKCBmb21hdHRlcnNbIGNvbC5zVHlwZSBdICkge1xuXHRcdFx0XHRjZWxsRGF0YSA9IGZvbWF0dGVyc1sgY29sLnNUeXBlIF0oIGNlbGxEYXRhICk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcblx0XHRyZXR1cm4gY2VsbERhdGE7XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogU2V0IHRoZSB2YWx1ZSBmb3IgYSBzcGVjaWZpYyBjZWxsLCBpbnRvIHRoZSBpbnRlcm5hbCBkYXRhIGNhY2hlXG5cdCAqICBAcGFyYW0ge29iamVjdH0gc2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBwYXJhbSB7aW50fSByb3dJZHggYW9EYXRhIHJvdyBpZFxuXHQgKiAgQHBhcmFtIHtpbnR9IGNvbElkeCBDb2x1bW4gaW5kZXhcblx0ICogIEBwYXJhbSB7Kn0gdmFsIFZhbHVlIHRvIHNldFxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5TZXRDZWxsRGF0YSggc2V0dGluZ3MsIHJvd0lkeCwgY29sSWR4LCB2YWwgKVxuXHR7XG5cdFx0dmFyIGNvbCAgICAgPSBzZXR0aW5ncy5hb0NvbHVtbnNbY29sSWR4XTtcblx0XHR2YXIgcm93RGF0YSA9IHNldHRpbmdzLmFvRGF0YVtyb3dJZHhdLl9hRGF0YTtcblx0XG5cdFx0Y29sLmZuU2V0RGF0YSggcm93RGF0YSwgdmFsLCB7XG5cdFx0XHRzZXR0aW5nczogc2V0dGluZ3MsXG5cdFx0XHRyb3c6ICAgICAgcm93SWR4LFxuXHRcdFx0Y29sOiAgICAgIGNvbElkeFxuXHRcdH0gICk7XG5cdH1cblx0XG5cdFxuXHQvLyBQcml2YXRlIHZhcmlhYmxlIHRoYXQgaXMgdXNlZCB0byBtYXRjaCBhY3Rpb24gc3ludGF4IGluIHRoZSBkYXRhIHByb3BlcnR5IG9iamVjdFxuXHR2YXIgX19yZUFycmF5ID0gL1xcWy4qP1xcXSQvO1xuXHR2YXIgX19yZUZuID0gL1xcKFxcKSQvO1xuXHRcblx0LyoqXG5cdCAqIFNwbGl0IHN0cmluZyBvbiBwZXJpb2RzLCB0YWtpbmcgaW50byBhY2NvdW50IGVzY2FwZWQgcGVyaW9kc1xuXHQgKiBAcGFyYW0gIHtzdHJpbmd9IHN0ciBTdHJpbmcgdG8gc3BsaXRcblx0ICogQHJldHVybiB7YXJyYXl9IFNwbGl0IHN0cmluZ1xuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuU3BsaXRPYmpOb3RhdGlvbiggc3RyIClcblx0e1xuXHRcdHJldHVybiAkLm1hcCggc3RyLm1hdGNoKC8oXFxcXC58W15cXC5dKSsvZykgfHwgWycnXSwgZnVuY3Rpb24gKCBzICkge1xuXHRcdFx0cmV0dXJuIHMucmVwbGFjZSgvXFxcXFxcLi9nLCAnLicpO1xuXHRcdH0gKTtcblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBSZXR1cm4gYSBmdW5jdGlvbiB0aGF0IGNhbiBiZSB1c2VkIHRvIGdldCBkYXRhIGZyb20gYSBzb3VyY2Ugb2JqZWN0LCB0YWtpbmdcblx0ICogaW50byBhY2NvdW50IHRoZSBhYmlsaXR5IHRvIHVzZSBuZXN0ZWQgb2JqZWN0cyBhcyBhIHNvdXJjZVxuXHQgKiAgQHBhcmFtIHtzdHJpbmd8aW50fGZ1bmN0aW9ufSBtU291cmNlIFRoZSBkYXRhIHNvdXJjZSBmb3IgdGhlIG9iamVjdFxuXHQgKiAgQHJldHVybnMge2Z1bmN0aW9ufSBEYXRhIGdldCBmdW5jdGlvblxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHR2YXIgX2ZuR2V0T2JqZWN0RGF0YUZuID0gRGF0YVRhYmxlLnV0aWwuZ2V0O1xuXHRcblx0XG5cdC8qKlxuXHQgKiBSZXR1cm4gYSBmdW5jdGlvbiB0aGF0IGNhbiBiZSB1c2VkIHRvIHNldCBkYXRhIGZyb20gYSBzb3VyY2Ugb2JqZWN0LCB0YWtpbmdcblx0ICogaW50byBhY2NvdW50IHRoZSBhYmlsaXR5IHRvIHVzZSBuZXN0ZWQgb2JqZWN0cyBhcyBhIHNvdXJjZVxuXHQgKiAgQHBhcmFtIHtzdHJpbmd8aW50fGZ1bmN0aW9ufSBtU291cmNlIFRoZSBkYXRhIHNvdXJjZSBmb3IgdGhlIG9iamVjdFxuXHQgKiAgQHJldHVybnMge2Z1bmN0aW9ufSBEYXRhIHNldCBmdW5jdGlvblxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHR2YXIgX2ZuU2V0T2JqZWN0RGF0YUZuID0gRGF0YVRhYmxlLnV0aWwuc2V0O1xuXHRcblx0XG5cdC8qKlxuXHQgKiBSZXR1cm4gYW4gYXJyYXkgd2l0aCB0aGUgZnVsbCB0YWJsZSBkYXRhXG5cdCAqICBAcGFyYW0ge29iamVjdH0gb1NldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAcmV0dXJucyBhcnJheSB7YXJyYXl9IGFEYXRhIE1hc3RlciBkYXRhIGFycmF5XG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mbkdldERhdGFNYXN0ZXIgKCBzZXR0aW5ncyApXG5cdHtcblx0XHRyZXR1cm4gX3BsdWNrKCBzZXR0aW5ncy5hb0RhdGEsICdfYURhdGEnICk7XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogTnVrZSB0aGUgdGFibGVcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuQ2xlYXJUYWJsZSggc2V0dGluZ3MgKVxuXHR7XG5cdFx0c2V0dGluZ3MuYW9EYXRhLmxlbmd0aCA9IDA7XG5cdFx0c2V0dGluZ3MuYWlEaXNwbGF5TWFzdGVyLmxlbmd0aCA9IDA7XG5cdFx0c2V0dGluZ3MuYWlEaXNwbGF5Lmxlbmd0aCA9IDA7XG5cdFx0c2V0dGluZ3MuYUlkcyA9IHt9O1xuXHR9XG5cdFxuXHRcblx0IC8qKlxuXHQgKiBUYWtlIGFuIGFycmF5IG9mIGludGVnZXJzIChpbmRleCBhcnJheSkgYW5kIHJlbW92ZSBhIHRhcmdldCBpbnRlZ2VyICh2YWx1ZSAtIG5vdFxuXHQgKiB0aGUga2V5ISlcblx0ICogIEBwYXJhbSB7YXJyYXl9IGEgSW5kZXggYXJyYXkgdG8gdGFyZ2V0XG5cdCAqICBAcGFyYW0ge2ludH0gaVRhcmdldCB2YWx1ZSB0byBmaW5kXG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mbkRlbGV0ZUluZGV4KCBhLCBpVGFyZ2V0LCBzcGxpY2UgKVxuXHR7XG5cdFx0dmFyIGlUYXJnZXRJbmRleCA9IC0xO1xuXHRcblx0XHRmb3IgKCB2YXIgaT0wLCBpTGVuPWEubGVuZ3RoIDsgaTxpTGVuIDsgaSsrIClcblx0XHR7XG5cdFx0XHRpZiAoIGFbaV0gPT0gaVRhcmdldCApXG5cdFx0XHR7XG5cdFx0XHRcdGlUYXJnZXRJbmRleCA9IGk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIGlmICggYVtpXSA+IGlUYXJnZXQgKVxuXHRcdFx0e1xuXHRcdFx0XHRhW2ldLS07XG5cdFx0XHR9XG5cdFx0fVxuXHRcblx0XHRpZiAoIGlUYXJnZXRJbmRleCAhPSAtMSAmJiBzcGxpY2UgPT09IHVuZGVmaW5lZCApXG5cdFx0e1xuXHRcdFx0YS5zcGxpY2UoIGlUYXJnZXRJbmRleCwgMSApO1xuXHRcdH1cblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBNYXJrIGNhY2hlZCBkYXRhIGFzIGludmFsaWQgc3VjaCB0aGF0IGEgcmUtcmVhZCBvZiB0aGUgZGF0YSB3aWxsIG9jY3VyIHdoZW5cblx0ICogdGhlIGNhY2hlZCBkYXRhIGlzIG5leHQgcmVxdWVzdGVkLiBBbHNvIHVwZGF0ZSBmcm9tIHRoZSBkYXRhIHNvdXJjZSBvYmplY3QuXG5cdCAqXG5cdCAqIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBEYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiBAcGFyYW0ge2ludH0gICAgcm93SWR4ICAgUm93IGluZGV4IHRvIGludmFsaWRhdGVcblx0ICogQHBhcmFtIHtzdHJpbmd9IFtzcmNdICAgIFNvdXJjZSB0byBpbnZhbGlkYXRlIGZyb206IHVuZGVmaW5lZCwgJ2F1dG8nLCAnZG9tJ1xuXHQgKiAgICAgb3IgJ2RhdGEnXG5cdCAqIEBwYXJhbSB7aW50fSAgICBbY29sSWR4XSBDb2x1bW4gaW5kZXggdG8gaW52YWxpZGF0ZS4gSWYgdW5kZWZpbmVkIHRoZSB3aG9sZVxuXHQgKiAgICAgcm93IHdpbGwgYmUgaW52YWxpZGF0ZWRcblx0ICogQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqXG5cdCAqIEB0b2RvIEZvciB0aGUgbW9kdWxhcmlzYXRpb24gb2YgdjEuMTEgdGhpcyB3aWxsIG5lZWQgdG8gYmVjb21lIGEgY2FsbGJhY2ssIHNvXG5cdCAqICAgdGhlIHNvcnQgYW5kIGZpbHRlciBtZXRob2RzIGNhbiBzdWJzY3JpYmUgdG8gaXQuIFRoYXQgd2lsbCByZXF1aXJlZFxuXHQgKiAgIGluaXRpYWxpc2F0aW9uIG9wdGlvbnMgZm9yIHNvcnRpbmcsIHdoaWNoIGlzIHdoeSBpdCBpcyBub3QgYWxyZWFkeSBiYWtlZCBpblxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuSW52YWxpZGF0ZSggc2V0dGluZ3MsIHJvd0lkeCwgc3JjLCBjb2xJZHggKVxuXHR7XG5cdFx0dmFyIHJvdyA9IHNldHRpbmdzLmFvRGF0YVsgcm93SWR4IF07XG5cdFx0dmFyIGksIGllbjtcblx0XHR2YXIgY2VsbFdyaXRlID0gZnVuY3Rpb24gKCBjZWxsLCBjb2wgKSB7XG5cdFx0XHQvLyBUaGlzIGlzIHZlcnkgZnJ1c3RyYXRpbmcsIGJ1dCBpbiBJRSBpZiB5b3UganVzdCB3cml0ZSBkaXJlY3RseVxuXHRcdFx0Ly8gdG8gaW5uZXJIVE1MLCBhbmQgZWxlbWVudHMgdGhhdCBhcmUgb3ZlcndyaXR0ZW4gYXJlIEdDJ2VkLFxuXHRcdFx0Ly8gZXZlbiBpZiB0aGVyZSBpcyBhIHJlZmVyZW5jZSB0byB0aGVtIGVsc2V3aGVyZVxuXHRcdFx0d2hpbGUgKCBjZWxsLmNoaWxkTm9kZXMubGVuZ3RoICkge1xuXHRcdFx0XHRjZWxsLnJlbW92ZUNoaWxkKCBjZWxsLmZpcnN0Q2hpbGQgKTtcblx0XHRcdH1cblx0XG5cdFx0XHRjZWxsLmlubmVySFRNTCA9IF9mbkdldENlbGxEYXRhKCBzZXR0aW5ncywgcm93SWR4LCBjb2wsICdkaXNwbGF5JyApO1xuXHRcdH07XG5cdFxuXHRcdC8vIEFyZSB3ZSByZWFkaW5nIGxhc3QgZGF0YSBmcm9tIERPTSBvciB0aGUgZGF0YSBvYmplY3Q/XG5cdFx0aWYgKCBzcmMgPT09ICdkb20nIHx8ICgoISBzcmMgfHwgc3JjID09PSAnYXV0bycpICYmIHJvdy5zcmMgPT09ICdkb20nKSApIHtcblx0XHRcdC8vIFJlYWQgdGhlIGRhdGEgZnJvbSB0aGUgRE9NXG5cdFx0XHRyb3cuX2FEYXRhID0gX2ZuR2V0Um93RWxlbWVudHMoXG5cdFx0XHRcdFx0c2V0dGluZ3MsIHJvdywgY29sSWR4LCBjb2xJZHggPT09IHVuZGVmaW5lZCA/IHVuZGVmaW5lZCA6IHJvdy5fYURhdGFcblx0XHRcdFx0KVxuXHRcdFx0XHQuZGF0YTtcblx0XHR9XG5cdFx0ZWxzZSB7XG5cdFx0XHQvLyBSZWFkaW5nIGZyb20gZGF0YSBvYmplY3QsIHVwZGF0ZSB0aGUgRE9NXG5cdFx0XHR2YXIgY2VsbHMgPSByb3cuYW5DZWxscztcblx0XG5cdFx0XHRpZiAoIGNlbGxzICkge1xuXHRcdFx0XHRpZiAoIGNvbElkeCAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdGNlbGxXcml0ZSggY2VsbHNbY29sSWR4XSwgY29sSWR4ICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0Zm9yICggaT0wLCBpZW49Y2VsbHMubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRcdFx0XHRjZWxsV3JpdGUoIGNlbGxzW2ldLCBpICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHRcblx0XHQvLyBGb3IgYm90aCByb3cgYW5kIGNlbGwgaW52YWxpZGF0aW9uLCB0aGUgY2FjaGVkIGRhdGEgZm9yIHNvcnRpbmcgYW5kXG5cdFx0Ly8gZmlsdGVyaW5nIGlzIG51bGxlZCBvdXRcblx0XHRyb3cuX2FTb3J0RGF0YSA9IG51bGw7XG5cdFx0cm93Ll9hRmlsdGVyRGF0YSA9IG51bGw7XG5cdFxuXHRcdC8vIEludmFsaWRhdGUgdGhlIHR5cGUgZm9yIGEgc3BlY2lmaWMgY29sdW1uIChpZiBnaXZlbikgb3IgYWxsIGNvbHVtbnMgc2luY2Vcblx0XHQvLyB0aGUgZGF0YSBtaWdodCBoYXZlIGNoYW5nZWRcblx0XHR2YXIgY29scyA9IHNldHRpbmdzLmFvQ29sdW1ucztcblx0XHRpZiAoIGNvbElkeCAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0Y29sc1sgY29sSWR4IF0uc1R5cGUgPSBudWxsO1xuXHRcdH1cblx0XHRlbHNlIHtcblx0XHRcdGZvciAoIGk9MCwgaWVuPWNvbHMubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRcdGNvbHNbaV0uc1R5cGUgPSBudWxsO1xuXHRcdFx0fVxuXHRcblx0XHRcdC8vIFVwZGF0ZSBEYXRhVGFibGVzIHNwZWNpYWwgYERUXypgIGF0dHJpYnV0ZXMgZm9yIHRoZSByb3dcblx0XHRcdF9mblJvd0F0dHJpYnV0ZXMoIHNldHRpbmdzLCByb3cgKTtcblx0XHR9XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogQnVpbGQgYSBkYXRhIHNvdXJjZSBvYmplY3QgZnJvbSBhbiBIVE1MIHJvdywgcmVhZGluZyB0aGUgY29udGVudHMgb2YgdGhlXG5cdCAqIGNlbGxzIHRoYXQgYXJlIGluIHRoZSByb3cuXG5cdCAqXG5cdCAqIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBEYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiBAcGFyYW0ge25vZGV8b2JqZWN0fSBUUiBlbGVtZW50IGZyb20gd2hpY2ggdG8gcmVhZCBkYXRhIG9yIGV4aXN0aW5nIHJvd1xuXHQgKiAgIG9iamVjdCBmcm9tIHdoaWNoIHRvIHJlLXJlYWQgdGhlIGRhdGEgZnJvbSB0aGUgY2VsbHNcblx0ICogQHBhcmFtIHtpbnR9IFtjb2xJZHhdIE9wdGlvbmFsIGNvbHVtbiBpbmRleFxuXHQgKiBAcGFyYW0ge2FycmF5fG9iamVjdH0gW2RdIERhdGEgc291cmNlIG9iamVjdC4gSWYgYGNvbElkeGAgaXMgZ2l2ZW4gdGhlbiB0aGlzXG5cdCAqICAgcGFyYW1ldGVyIHNob3VsZCBhbHNvIGJlIGdpdmVuIGFuZCB3aWxsIGJlIHVzZWQgdG8gd3JpdGUgdGhlIGRhdGEgaW50by5cblx0ICogICBPbmx5IHRoZSBjb2x1bW4gaW4gcXVlc3Rpb24gd2lsbCBiZSB3cml0dGVuXG5cdCAqIEByZXR1cm5zIHtvYmplY3R9IE9iamVjdCB3aXRoIHR3byBwYXJhbWV0ZXJzOiBgZGF0YWAgdGhlIGRhdGEgcmVhZCwgaW5cblx0ICogICBkb2N1bWVudCBvcmRlciwgYW5kIGBjZWxsc2AgYW5kIGFycmF5IG9mIG5vZGVzICh0aGV5IGNhbiBiZSB1c2VmdWwgdG8gdGhlXG5cdCAqICAgY2FsbGVyLCBzbyByYXRoZXIgdGhhbiBuZWVkaW5nIGEgc2Vjb25kIHRyYXZlcnNhbCB0byBnZXQgdGhlbSwganVzdCByZXR1cm5cblx0ICogICB0aGVtIGZyb20gaGVyZSkuXG5cdCAqIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuR2V0Um93RWxlbWVudHMoIHNldHRpbmdzLCByb3csIGNvbElkeCwgZCApXG5cdHtcblx0XHR2YXJcblx0XHRcdHRkcyA9IFtdLFxuXHRcdFx0dGQgPSByb3cuZmlyc3RDaGlsZCxcblx0XHRcdG5hbWUsIGNvbCwgbywgaT0wLCBjb250ZW50cyxcblx0XHRcdGNvbHVtbnMgPSBzZXR0aW5ncy5hb0NvbHVtbnMsXG5cdFx0XHRvYmplY3RSZWFkID0gc2V0dGluZ3MuX3Jvd1JlYWRPYmplY3Q7XG5cdFxuXHRcdC8vIEFsbG93IHRoZSBkYXRhIG9iamVjdCB0byBiZSBwYXNzZWQgaW4sIG9yIGNvbnN0cnVjdFxuXHRcdGQgPSBkICE9PSB1bmRlZmluZWQgP1xuXHRcdFx0ZCA6XG5cdFx0XHRvYmplY3RSZWFkID9cblx0XHRcdFx0e30gOlxuXHRcdFx0XHRbXTtcblx0XG5cdFx0dmFyIGF0dHIgPSBmdW5jdGlvbiAoIHN0ciwgdGQgICkge1xuXHRcdFx0aWYgKCB0eXBlb2Ygc3RyID09PSAnc3RyaW5nJyApIHtcblx0XHRcdFx0dmFyIGlkeCA9IHN0ci5pbmRleE9mKCdAJyk7XG5cdFxuXHRcdFx0XHRpZiAoIGlkeCAhPT0gLTEgKSB7XG5cdFx0XHRcdFx0dmFyIGF0dHIgPSBzdHIuc3Vic3RyaW5nKCBpZHgrMSApO1xuXHRcdFx0XHRcdHZhciBzZXR0ZXIgPSBfZm5TZXRPYmplY3REYXRhRm4oIHN0ciApO1xuXHRcdFx0XHRcdHNldHRlciggZCwgdGQuZ2V0QXR0cmlidXRlKCBhdHRyICkgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH07XG5cdFxuXHRcdC8vIFJlYWQgZGF0YSBmcm9tIGEgY2VsbCBhbmQgc3RvcmUgaW50byB0aGUgZGF0YSBvYmplY3Rcblx0XHR2YXIgY2VsbFByb2Nlc3MgPSBmdW5jdGlvbiAoIGNlbGwgKSB7XG5cdFx0XHRpZiAoIGNvbElkeCA9PT0gdW5kZWZpbmVkIHx8IGNvbElkeCA9PT0gaSApIHtcblx0XHRcdFx0Y29sID0gY29sdW1uc1tpXTtcblx0XHRcdFx0Y29udGVudHMgPSAoY2VsbC5pbm5lckhUTUwpLnRyaW0oKTtcblx0XG5cdFx0XHRcdGlmICggY29sICYmIGNvbC5fYkF0dHJTcmMgKSB7XG5cdFx0XHRcdFx0dmFyIHNldHRlciA9IF9mblNldE9iamVjdERhdGFGbiggY29sLm1EYXRhLl8gKTtcblx0XHRcdFx0XHRzZXR0ZXIoIGQsIGNvbnRlbnRzICk7XG5cdFxuXHRcdFx0XHRcdGF0dHIoIGNvbC5tRGF0YS5zb3J0LCBjZWxsICk7XG5cdFx0XHRcdFx0YXR0ciggY29sLm1EYXRhLnR5cGUsIGNlbGwgKTtcblx0XHRcdFx0XHRhdHRyKCBjb2wubURhdGEuZmlsdGVyLCBjZWxsICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0Ly8gRGVwZW5kaW5nIG9uIHRoZSBgZGF0YWAgb3B0aW9uIGZvciB0aGUgY29sdW1ucyB0aGUgZGF0YSBjYW5cblx0XHRcdFx0XHQvLyBiZSByZWFkIHRvIGVpdGhlciBhbiBvYmplY3Qgb3IgYW4gYXJyYXkuXG5cdFx0XHRcdFx0aWYgKCBvYmplY3RSZWFkICkge1xuXHRcdFx0XHRcdFx0aWYgKCAhIGNvbC5fc2V0dGVyICkge1xuXHRcdFx0XHRcdFx0XHQvLyBDYWNoZSB0aGUgc2V0dGVyIGZ1bmN0aW9uXG5cdFx0XHRcdFx0XHRcdGNvbC5fc2V0dGVyID0gX2ZuU2V0T2JqZWN0RGF0YUZuKCBjb2wubURhdGEgKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGNvbC5fc2V0dGVyKCBkLCBjb250ZW50cyApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRcdGRbaV0gPSBjb250ZW50cztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XG5cdFx0XHRpKys7XG5cdFx0fTtcblx0XG5cdFx0aWYgKCB0ZCApIHtcblx0XHRcdC8vIGB0cmAgZWxlbWVudCB3YXMgcGFzc2VkIGluXG5cdFx0XHR3aGlsZSAoIHRkICkge1xuXHRcdFx0XHRuYW1lID0gdGQubm9kZU5hbWUudG9VcHBlckNhc2UoKTtcblx0XG5cdFx0XHRcdGlmICggbmFtZSA9PSBcIlREXCIgfHwgbmFtZSA9PSBcIlRIXCIgKSB7XG5cdFx0XHRcdFx0Y2VsbFByb2Nlc3MoIHRkICk7XG5cdFx0XHRcdFx0dGRzLnB1c2goIHRkICk7XG5cdFx0XHRcdH1cblx0XG5cdFx0XHRcdHRkID0gdGQubmV4dFNpYmxpbmc7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGVsc2Uge1xuXHRcdFx0Ly8gRXhpc3Rpbmcgcm93IG9iamVjdCBwYXNzZWQgaW5cblx0XHRcdHRkcyA9IHJvdy5hbkNlbGxzO1xuXHRcblx0XHRcdGZvciAoIHZhciBqPTAsIGplbj10ZHMubGVuZ3RoIDsgajxqZW4gOyBqKysgKSB7XG5cdFx0XHRcdGNlbGxQcm9jZXNzKCB0ZHNbal0gKTtcblx0XHRcdH1cblx0XHR9XG5cdFxuXHRcdC8vIFJlYWQgdGhlIElEIGZyb20gdGhlIERPTSBpZiBwcmVzZW50XG5cdFx0dmFyIHJvd05vZGUgPSByb3cuZmlyc3RDaGlsZCA/IHJvdyA6IHJvdy5uVHI7XG5cdFxuXHRcdGlmICggcm93Tm9kZSApIHtcblx0XHRcdHZhciBpZCA9IHJvd05vZGUuZ2V0QXR0cmlidXRlKCAnaWQnICk7XG5cdFxuXHRcdFx0aWYgKCBpZCApIHtcblx0XHRcdFx0X2ZuU2V0T2JqZWN0RGF0YUZuKCBzZXR0aW5ncy5yb3dJZCApKCBkLCBpZCApO1xuXHRcdFx0fVxuXHRcdH1cblx0XG5cdFx0cmV0dXJuIHtcblx0XHRcdGRhdGE6IGQsXG5cdFx0XHRjZWxsczogdGRzXG5cdFx0fTtcblx0fVxuXHQvKipcblx0ICogQ3JlYXRlIGEgbmV3IFRSIGVsZW1lbnQgKGFuZCBpdCdzIFREIGNoaWxkcmVuKSBmb3IgYSByb3dcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBwYXJhbSB7aW50fSBpUm93IFJvdyB0byBjb25zaWRlclxuXHQgKiAgQHBhcmFtIHtub2RlfSBbblRySW5dIFRSIGVsZW1lbnQgdG8gYWRkIHRvIHRoZSB0YWJsZSAtIG9wdGlvbmFsLiBJZiBub3QgZ2l2ZW4sXG5cdCAqICAgIERhdGFUYWJsZXMgd2lsbCBjcmVhdGUgYSByb3cgYXV0b21hdGljYWxseVxuXHQgKiAgQHBhcmFtIHthcnJheX0gW2FuVGRzXSBBcnJheSBvZiBURHxUSCBlbGVtZW50cyBmb3IgdGhlIHJvdyAtIG11c3QgYmUgZ2l2ZW5cblx0ICogICAgaWYgblRyIGlzLlxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5DcmVhdGVUciAoIG9TZXR0aW5ncywgaVJvdywgblRySW4sIGFuVGRzIClcblx0e1xuXHRcdHZhclxuXHRcdFx0cm93ID0gb1NldHRpbmdzLmFvRGF0YVtpUm93XSxcblx0XHRcdHJvd0RhdGEgPSByb3cuX2FEYXRhLFxuXHRcdFx0Y2VsbHMgPSBbXSxcblx0XHRcdG5UciwgblRkLCBvQ29sLFxuXHRcdFx0aSwgaUxlbiwgY3JlYXRlO1xuXHRcblx0XHRpZiAoIHJvdy5uVHIgPT09IG51bGwgKVxuXHRcdHtcblx0XHRcdG5UciA9IG5UckluIHx8IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3RyJyk7XG5cdFxuXHRcdFx0cm93Lm5UciA9IG5Ucjtcblx0XHRcdHJvdy5hbkNlbGxzID0gY2VsbHM7XG5cdFxuXHRcdFx0LyogVXNlIGEgcHJpdmF0ZSBwcm9wZXJ0eSBvbiB0aGUgbm9kZSB0byBhbGxvdyByZXNlcnZlIG1hcHBpbmcgZnJvbSB0aGUgbm9kZVxuXHRcdFx0ICogdG8gdGhlIGFvRGF0YSBhcnJheSBmb3IgZmFzdCBsb29rIHVwXG5cdFx0XHQgKi9cblx0XHRcdG5Uci5fRFRfUm93SW5kZXggPSBpUm93O1xuXHRcblx0XHRcdC8qIFNwZWNpYWwgcGFyYW1ldGVycyBjYW4gYmUgZ2l2ZW4gYnkgdGhlIGRhdGEgc291cmNlIHRvIGJlIHVzZWQgb24gdGhlIHJvdyAqL1xuXHRcdFx0X2ZuUm93QXR0cmlidXRlcyggb1NldHRpbmdzLCByb3cgKTtcblx0XG5cdFx0XHQvKiBQcm9jZXNzIGVhY2ggY29sdW1uICovXG5cdFx0XHRmb3IgKCBpPTAsIGlMZW49b1NldHRpbmdzLmFvQ29sdW1ucy5sZW5ndGggOyBpPGlMZW4gOyBpKysgKVxuXHRcdFx0e1xuXHRcdFx0XHRvQ29sID0gb1NldHRpbmdzLmFvQ29sdW1uc1tpXTtcblx0XHRcdFx0Y3JlYXRlID0gblRySW4gPyBmYWxzZSA6IHRydWU7XG5cdFxuXHRcdFx0XHRuVGQgPSBjcmVhdGUgPyBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBvQ29sLnNDZWxsVHlwZSApIDogYW5UZHNbaV07XG5cdFx0XHRcdG5UZC5fRFRfQ2VsbEluZGV4ID0ge1xuXHRcdFx0XHRcdHJvdzogaVJvdyxcblx0XHRcdFx0XHRjb2x1bW46IGlcblx0XHRcdFx0fTtcblx0XHRcdFx0XG5cdFx0XHRcdGNlbGxzLnB1c2goIG5UZCApO1xuXHRcblx0XHRcdFx0Ly8gTmVlZCB0byBjcmVhdGUgdGhlIEhUTUwgaWYgbmV3LCBvciBpZiBhIHJlbmRlcmluZyBmdW5jdGlvbiBpcyBkZWZpbmVkXG5cdFx0XHRcdGlmICggY3JlYXRlIHx8ICgob0NvbC5tUmVuZGVyIHx8IG9Db2wubURhdGEgIT09IGkpICYmXG5cdFx0XHRcdFx0ICghJC5pc1BsYWluT2JqZWN0KG9Db2wubURhdGEpIHx8IG9Db2wubURhdGEuXyAhPT0gaSsnLmRpc3BsYXknKVxuXHRcdFx0XHQpKSB7XG5cdFx0XHRcdFx0blRkLmlubmVySFRNTCA9IF9mbkdldENlbGxEYXRhKCBvU2V0dGluZ3MsIGlSb3csIGksICdkaXNwbGF5JyApO1xuXHRcdFx0XHR9XG5cdFxuXHRcdFx0XHQvKiBBZGQgdXNlciBkZWZpbmVkIGNsYXNzICovXG5cdFx0XHRcdGlmICggb0NvbC5zQ2xhc3MgKVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0blRkLmNsYXNzTmFtZSArPSAnICcrb0NvbC5zQ2xhc3M7XG5cdFx0XHRcdH1cblx0XG5cdFx0XHRcdC8vIFZpc2liaWxpdHkgLSBhZGQgb3IgcmVtb3ZlIGFzIHJlcXVpcmVkXG5cdFx0XHRcdGlmICggb0NvbC5iVmlzaWJsZSAmJiAhIG5UckluIClcblx0XHRcdFx0e1xuXHRcdFx0XHRcdG5Uci5hcHBlbmRDaGlsZCggblRkICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSBpZiAoICEgb0NvbC5iVmlzaWJsZSAmJiBuVHJJbiApXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRuVGQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCggblRkICk7XG5cdFx0XHRcdH1cblx0XG5cdFx0XHRcdGlmICggb0NvbC5mbkNyZWF0ZWRDZWxsIClcblx0XHRcdFx0e1xuXHRcdFx0XHRcdG9Db2wuZm5DcmVhdGVkQ2VsbC5jYWxsKCBvU2V0dGluZ3Mub0luc3RhbmNlLFxuXHRcdFx0XHRcdFx0blRkLCBfZm5HZXRDZWxsRGF0YSggb1NldHRpbmdzLCBpUm93LCBpICksIHJvd0RhdGEsIGlSb3csIGlcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFxuXHRcdFx0X2ZuQ2FsbGJhY2tGaXJlKCBvU2V0dGluZ3MsICdhb1Jvd0NyZWF0ZWRDYWxsYmFjaycsIG51bGwsIFtuVHIsIHJvd0RhdGEsIGlSb3csIGNlbGxzXSApO1xuXHRcdH1cblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBBZGQgYXR0cmlidXRlcyB0byBhIHJvdyBiYXNlZCBvbiB0aGUgc3BlY2lhbCBgRFRfKmAgcGFyYW1ldGVycyBpbiBhIGRhdGFcblx0ICogc291cmNlIG9iamVjdC5cblx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBEYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IERhdGFUYWJsZXMgcm93IG9iamVjdCBmb3IgdGhlIHJvdyB0byBiZSBtb2RpZmllZFxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5Sb3dBdHRyaWJ1dGVzKCBzZXR0aW5ncywgcm93IClcblx0e1xuXHRcdHZhciB0ciA9IHJvdy5uVHI7XG5cdFx0dmFyIGRhdGEgPSByb3cuX2FEYXRhO1xuXHRcblx0XHRpZiAoIHRyICkge1xuXHRcdFx0dmFyIGlkID0gc2V0dGluZ3Mucm93SWRGbiggZGF0YSApO1xuXHRcblx0XHRcdGlmICggaWQgKSB7XG5cdFx0XHRcdHRyLmlkID0gaWQ7XG5cdFx0XHR9XG5cdFxuXHRcdFx0aWYgKCBkYXRhLkRUX1Jvd0NsYXNzICkge1xuXHRcdFx0XHQvLyBSZW1vdmUgYW55IGNsYXNzZXMgYWRkZWQgYnkgRFRfUm93Q2xhc3MgYmVmb3JlXG5cdFx0XHRcdHZhciBhID0gZGF0YS5EVF9Sb3dDbGFzcy5zcGxpdCgnICcpO1xuXHRcdFx0XHRyb3cuX19yb3djID0gcm93Ll9fcm93YyA/XG5cdFx0XHRcdFx0X3VuaXF1ZSggcm93Ll9fcm93Yy5jb25jYXQoIGEgKSApIDpcblx0XHRcdFx0XHRhO1xuXHRcblx0XHRcdFx0JCh0cilcblx0XHRcdFx0XHQucmVtb3ZlQ2xhc3MoIHJvdy5fX3Jvd2Muam9pbignICcpIClcblx0XHRcdFx0XHQuYWRkQ2xhc3MoIGRhdGEuRFRfUm93Q2xhc3MgKTtcblx0XHRcdH1cblx0XG5cdFx0XHRpZiAoIGRhdGEuRFRfUm93QXR0ciApIHtcblx0XHRcdFx0JCh0cikuYXR0ciggZGF0YS5EVF9Sb3dBdHRyICk7XG5cdFx0XHR9XG5cdFxuXHRcdFx0aWYgKCBkYXRhLkRUX1Jvd0RhdGEgKSB7XG5cdFx0XHRcdCQodHIpLmRhdGEoIGRhdGEuRFRfUm93RGF0YSApO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBDcmVhdGUgdGhlIEhUTUwgaGVhZGVyIGZvciB0aGUgdGFibGVcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuQnVpbGRIZWFkKCBvU2V0dGluZ3MgKVxuXHR7XG5cdFx0dmFyIGksIGllbiwgY2VsbCwgcm93LCBjb2x1bW47XG5cdFx0dmFyIHRoZWFkID0gb1NldHRpbmdzLm5USGVhZDtcblx0XHR2YXIgdGZvb3QgPSBvU2V0dGluZ3MublRGb290O1xuXHRcdHZhciBjcmVhdGVIZWFkZXIgPSAkKCd0aCwgdGQnLCB0aGVhZCkubGVuZ3RoID09PSAwO1xuXHRcdHZhciBjbGFzc2VzID0gb1NldHRpbmdzLm9DbGFzc2VzO1xuXHRcdHZhciBjb2x1bW5zID0gb1NldHRpbmdzLmFvQ29sdW1ucztcblx0XG5cdFx0aWYgKCBjcmVhdGVIZWFkZXIgKSB7XG5cdFx0XHRyb3cgPSAkKCc8dHIvPicpLmFwcGVuZFRvKCB0aGVhZCApO1xuXHRcdH1cblx0XG5cdFx0Zm9yICggaT0wLCBpZW49Y29sdW1ucy5sZW5ndGggOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdGNvbHVtbiA9IGNvbHVtbnNbaV07XG5cdFx0XHRjZWxsID0gJCggY29sdW1uLm5UaCApLmFkZENsYXNzKCBjb2x1bW4uc0NsYXNzICk7XG5cdFxuXHRcdFx0aWYgKCBjcmVhdGVIZWFkZXIgKSB7XG5cdFx0XHRcdGNlbGwuYXBwZW5kVG8oIHJvdyApO1xuXHRcdFx0fVxuXHRcblx0XHRcdC8vIDEuMTEgbW92ZSBpbnRvIHNvcnRpbmdcblx0XHRcdGlmICggb1NldHRpbmdzLm9GZWF0dXJlcy5iU29ydCApIHtcblx0XHRcdFx0Y2VsbC5hZGRDbGFzcyggY29sdW1uLnNTb3J0aW5nQ2xhc3MgKTtcblx0XG5cdFx0XHRcdGlmICggY29sdW1uLmJTb3J0YWJsZSAhPT0gZmFsc2UgKSB7XG5cdFx0XHRcdFx0Y2VsbFxuXHRcdFx0XHRcdFx0LmF0dHIoICd0YWJpbmRleCcsIG9TZXR0aW5ncy5pVGFiSW5kZXggKVxuXHRcdFx0XHRcdFx0LmF0dHIoICdhcmlhLWNvbnRyb2xzJywgb1NldHRpbmdzLnNUYWJsZUlkICk7XG5cdFxuXHRcdFx0XHRcdF9mblNvcnRBdHRhY2hMaXN0ZW5lciggb1NldHRpbmdzLCBjb2x1bW4ublRoLCBpICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XG5cdFx0XHRpZiAoIGNvbHVtbi5zVGl0bGUgIT0gY2VsbFswXS5pbm5lckhUTUwgKSB7XG5cdFx0XHRcdGNlbGwuaHRtbCggY29sdW1uLnNUaXRsZSApO1xuXHRcdFx0fVxuXHRcblx0XHRcdF9mblJlbmRlcmVyKCBvU2V0dGluZ3MsICdoZWFkZXInICkoXG5cdFx0XHRcdG9TZXR0aW5ncywgY2VsbCwgY29sdW1uLCBjbGFzc2VzXG5cdFx0XHQpO1xuXHRcdH1cblx0XG5cdFx0aWYgKCBjcmVhdGVIZWFkZXIgKSB7XG5cdFx0XHRfZm5EZXRlY3RIZWFkZXIoIG9TZXR0aW5ncy5hb0hlYWRlciwgdGhlYWQgKTtcblx0XHR9XG5cdFxuXHRcdC8qIERlYWwgd2l0aCB0aGUgZm9vdGVyIC0gYWRkIGNsYXNzZXMgaWYgcmVxdWlyZWQgKi9cblx0XHQkKHRoZWFkKS5jaGlsZHJlbigndHInKS5jaGlsZHJlbigndGgsIHRkJykuYWRkQ2xhc3MoIGNsYXNzZXMuc0hlYWRlclRIICk7XG5cdFx0JCh0Zm9vdCkuY2hpbGRyZW4oJ3RyJykuY2hpbGRyZW4oJ3RoLCB0ZCcpLmFkZENsYXNzKCBjbGFzc2VzLnNGb290ZXJUSCApO1xuXHRcblx0XHQvLyBDYWNoZSB0aGUgZm9vdGVyIGNlbGxzLiBOb3RlIHRoYXQgd2Ugb25seSB0YWtlIHRoZSBjZWxscyBmcm9tIHRoZSBmaXJzdFxuXHRcdC8vIHJvdyBpbiB0aGUgZm9vdGVyLiBJZiB0aGVyZSBpcyBtb3JlIHRoYW4gb25lIHJvdyB0aGUgdXNlciB3YW50cyB0b1xuXHRcdC8vIGludGVyYWN0IHdpdGgsIHRoZXkgbmVlZCB0byB1c2UgdGhlIHRhYmxlKCkuZm9vdCgpIG1ldGhvZC4gTm90ZSBhbHNvIHRoaXNcblx0XHQvLyBhbGxvd3MgY2VsbHMgdG8gYmUgdXNlZCBmb3IgbXVsdGlwbGUgY29sdW1ucyB1c2luZyBjb2xzcGFuXG5cdFx0aWYgKCB0Zm9vdCAhPT0gbnVsbCApIHtcblx0XHRcdHZhciBjZWxscyA9IG9TZXR0aW5ncy5hb0Zvb3RlclswXTtcblx0XG5cdFx0XHRmb3IgKCBpPTAsIGllbj1jZWxscy5sZW5ndGggOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdFx0Y29sdW1uID0gY29sdW1uc1tpXTtcblx0XHRcdFx0Y29sdW1uLm5UZiA9IGNlbGxzW2ldLmNlbGw7XG5cdFxuXHRcdFx0XHRpZiAoIGNvbHVtbi5zQ2xhc3MgKSB7XG5cdFx0XHRcdFx0JChjb2x1bW4ublRmKS5hZGRDbGFzcyggY29sdW1uLnNDbGFzcyApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIERyYXcgdGhlIGhlYWRlciAob3IgZm9vdGVyKSBlbGVtZW50IGJhc2VkIG9uIHRoZSBjb2x1bW4gdmlzaWJpbGl0eSBzdGF0ZXMuIFRoZVxuXHQgKiBtZXRob2RvbG9neSBoZXJlIGlzIHRvIHVzZSB0aGUgbGF5b3V0IGFycmF5IGZyb20gX2ZuRGV0ZWN0SGVhZGVyLCBtb2RpZmllZCBmb3Jcblx0ICogdGhlIGluc3RhbnRhbmVvdXMgY29sdW1uIHZpc2liaWxpdHksIHRvIGNvbnN0cnVjdCB0aGUgbmV3IGxheW91dC4gVGhlIGdyaWQgaXNcblx0ICogdHJhdmVyc2VkIG92ZXIgY2VsbCBhdCBhIHRpbWUgaW4gYSByb3dzIHggY29sdW1ucyBncmlkIGZhc2hpb24sIGFsdGhvdWdoIGVhY2hcblx0ICogY2VsbCBpbnNlcnQgY2FuIGNvdmVyIG11bHRpcGxlIGVsZW1lbnRzIGluIHRoZSBncmlkIC0gd2hpY2ggaXMgdHJhY2tzIHVzaW5nIHRoZVxuXHQgKiBhQXBwbGllZCBhcnJheS4gQ2VsbCBpbnNlcnRzIGluIHRoZSBncmlkIHdpbGwgb25seSBvY2N1ciB3aGVyZSB0aGVyZSBpc24ndFxuXHQgKiBhbHJlYWR5IGEgY2VsbCBpbiB0aGF0IHBvc2l0aW9uLlxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IG9TZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHBhcmFtIGFycmF5IHtvYmplY3RzfSBhb1NvdXJjZSBMYXlvdXQgYXJyYXkgZnJvbSBfZm5EZXRlY3RIZWFkZXJcblx0ICogIEBwYXJhbSB7Ym9vbGVhbn0gW2JJbmNsdWRlSGlkZGVuPWZhbHNlXSBJZiB0cnVlIHRoZW4gaW5jbHVkZSB0aGUgaGlkZGVuIGNvbHVtbnMgaW4gdGhlIGNhbGMsXG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mbkRyYXdIZWFkKCBvU2V0dGluZ3MsIGFvU291cmNlLCBiSW5jbHVkZUhpZGRlbiApXG5cdHtcblx0XHR2YXIgaSwgaUxlbiwgaiwgakxlbiwgaywga0xlbiwgbiwgbkxvY2FsVHI7XG5cdFx0dmFyIGFvTG9jYWwgPSBbXTtcblx0XHR2YXIgYUFwcGxpZWQgPSBbXTtcblx0XHR2YXIgaUNvbHVtbnMgPSBvU2V0dGluZ3MuYW9Db2x1bW5zLmxlbmd0aDtcblx0XHR2YXIgaVJvd3NwYW4sIGlDb2xzcGFuO1xuXHRcblx0XHRpZiAoICEgYW9Tb3VyY2UgKVxuXHRcdHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFxuXHRcdGlmICggIGJJbmNsdWRlSGlkZGVuID09PSB1bmRlZmluZWQgKVxuXHRcdHtcblx0XHRcdGJJbmNsdWRlSGlkZGVuID0gZmFsc2U7XG5cdFx0fVxuXHRcblx0XHQvKiBNYWtlIGEgY29weSBvZiB0aGUgbWFzdGVyIGxheW91dCBhcnJheSwgYnV0IHdpdGhvdXQgdGhlIHZpc2libGUgY29sdW1ucyBpbiBpdCAqL1xuXHRcdGZvciAoIGk9MCwgaUxlbj1hb1NvdXJjZS5sZW5ndGggOyBpPGlMZW4gOyBpKysgKVxuXHRcdHtcblx0XHRcdGFvTG9jYWxbaV0gPSBhb1NvdXJjZVtpXS5zbGljZSgpO1xuXHRcdFx0YW9Mb2NhbFtpXS5uVHIgPSBhb1NvdXJjZVtpXS5uVHI7XG5cdFxuXHRcdFx0LyogUmVtb3ZlIGFueSBjb2x1bW5zIHdoaWNoIGFyZSBjdXJyZW50bHkgaGlkZGVuICovXG5cdFx0XHRmb3IgKCBqPWlDb2x1bW5zLTEgOyBqPj0wIDsgai0tIClcblx0XHRcdHtcblx0XHRcdFx0aWYgKCAhb1NldHRpbmdzLmFvQ29sdW1uc1tqXS5iVmlzaWJsZSAmJiAhYkluY2x1ZGVIaWRkZW4gKVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0YW9Mb2NhbFtpXS5zcGxpY2UoIGosIDEgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcblx0XHRcdC8qIFByZXAgdGhlIGFwcGxpZWQgYXJyYXkgLSBpdCBuZWVkcyBhbiBlbGVtZW50IGZvciBlYWNoIHJvdyAqL1xuXHRcdFx0YUFwcGxpZWQucHVzaCggW10gKTtcblx0XHR9XG5cdFxuXHRcdGZvciAoIGk9MCwgaUxlbj1hb0xvY2FsLmxlbmd0aCA7IGk8aUxlbiA7IGkrKyApXG5cdFx0e1xuXHRcdFx0bkxvY2FsVHIgPSBhb0xvY2FsW2ldLm5Ucjtcblx0XG5cdFx0XHQvKiBBbGwgY2VsbHMgYXJlIGdvaW5nIHRvIGJlIHJlcGxhY2VkLCBzbyBlbXB0eSBvdXQgdGhlIHJvdyAqL1xuXHRcdFx0aWYgKCBuTG9jYWxUciApXG5cdFx0XHR7XG5cdFx0XHRcdHdoaWxlKCAobiA9IG5Mb2NhbFRyLmZpcnN0Q2hpbGQpIClcblx0XHRcdFx0e1xuXHRcdFx0XHRcdG5Mb2NhbFRyLnJlbW92ZUNoaWxkKCBuICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XG5cdFx0XHRmb3IgKCBqPTAsIGpMZW49YW9Mb2NhbFtpXS5sZW5ndGggOyBqPGpMZW4gOyBqKysgKVxuXHRcdFx0e1xuXHRcdFx0XHRpUm93c3BhbiA9IDE7XG5cdFx0XHRcdGlDb2xzcGFuID0gMTtcblx0XG5cdFx0XHRcdC8qIENoZWNrIHRvIHNlZSBpZiB0aGVyZSBpcyBhbHJlYWR5IGEgY2VsbCAocm93L2NvbHNwYW4pIGNvdmVyaW5nIG91ciB0YXJnZXRcblx0XHRcdFx0ICogaW5zZXJ0IHBvaW50LiBJZiB0aGVyZSBpcywgdGhlbiB0aGVyZSBpcyBub3RoaW5nIHRvIGRvLlxuXHRcdFx0XHQgKi9cblx0XHRcdFx0aWYgKCBhQXBwbGllZFtpXVtqXSA9PT0gdW5kZWZpbmVkIClcblx0XHRcdFx0e1xuXHRcdFx0XHRcdG5Mb2NhbFRyLmFwcGVuZENoaWxkKCBhb0xvY2FsW2ldW2pdLmNlbGwgKTtcblx0XHRcdFx0XHRhQXBwbGllZFtpXVtqXSA9IDE7XG5cdFxuXHRcdFx0XHRcdC8qIEV4cGFuZCB0aGUgY2VsbCB0byBjb3ZlciBhcyBtYW55IHJvd3MgYXMgbmVlZGVkICovXG5cdFx0XHRcdFx0d2hpbGUgKCBhb0xvY2FsW2kraVJvd3NwYW5dICE9PSB1bmRlZmluZWQgJiZcblx0XHRcdFx0XHQgICAgICAgIGFvTG9jYWxbaV1bal0uY2VsbCA9PSBhb0xvY2FsW2kraVJvd3NwYW5dW2pdLmNlbGwgKVxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdGFBcHBsaWVkW2kraVJvd3NwYW5dW2pdID0gMTtcblx0XHRcdFx0XHRcdGlSb3dzcGFuKys7XG5cdFx0XHRcdFx0fVxuXHRcblx0XHRcdFx0XHQvKiBFeHBhbmQgdGhlIGNlbGwgdG8gY292ZXIgYXMgbWFueSBjb2x1bW5zIGFzIG5lZWRlZCAqL1xuXHRcdFx0XHRcdHdoaWxlICggYW9Mb2NhbFtpXVtqK2lDb2xzcGFuXSAhPT0gdW5kZWZpbmVkICYmXG5cdFx0XHRcdFx0ICAgICAgICBhb0xvY2FsW2ldW2pdLmNlbGwgPT0gYW9Mb2NhbFtpXVtqK2lDb2xzcGFuXS5jZWxsIClcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHQvKiBNdXN0IHVwZGF0ZSB0aGUgYXBwbGllZCBhcnJheSBvdmVyIHRoZSByb3dzIGZvciB0aGUgY29sdW1ucyAqL1xuXHRcdFx0XHRcdFx0Zm9yICggaz0wIDsgazxpUm93c3BhbiA7IGsrKyApXG5cdFx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRcdGFBcHBsaWVkW2kra11baitpQ29sc3Bhbl0gPSAxO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aUNvbHNwYW4rKztcblx0XHRcdFx0XHR9XG5cdFxuXHRcdFx0XHRcdC8qIERvIHRoZSBhY3R1YWwgZXhwYW5zaW9uIGluIHRoZSBET00gKi9cblx0XHRcdFx0XHQkKGFvTG9jYWxbaV1bal0uY2VsbClcblx0XHRcdFx0XHRcdC5hdHRyKCdyb3dzcGFuJywgaVJvd3NwYW4pXG5cdFx0XHRcdFx0XHQuYXR0cignY29sc3BhbicsIGlDb2xzcGFuKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBJbnNlcnQgdGhlIHJlcXVpcmVkIFRSIG5vZGVzIGludG8gdGhlIHRhYmxlIGZvciBkaXNwbGF5XG5cdCAqICBAcGFyYW0ge29iamVjdH0gb1NldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAcGFyYW0gYWpheENvbXBsZXRlIHRydWUgYWZ0ZXIgYWpheCBjYWxsIHRvIGNvbXBsZXRlIHJlbmRlcmluZ1xuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5EcmF3KCBvU2V0dGluZ3MsIGFqYXhDb21wbGV0ZSApXG5cdHtcblx0XHQvKiBQcm92aWRlIGEgcHJlLWNhbGxiYWNrIGZ1bmN0aW9uIHdoaWNoIGNhbiBiZSB1c2VkIHRvIGNhbmNlbCB0aGUgZHJhdyBpcyBmYWxzZSBpcyByZXR1cm5lZCAqL1xuXHRcdHZhciBhUHJlRHJhdyA9IF9mbkNhbGxiYWNrRmlyZSggb1NldHRpbmdzLCAnYW9QcmVEcmF3Q2FsbGJhY2snLCAncHJlRHJhdycsIFtvU2V0dGluZ3NdICk7XG5cdFx0aWYgKCAkLmluQXJyYXkoIGZhbHNlLCBhUHJlRHJhdyApICE9PSAtMSApXG5cdFx0e1xuXHRcdFx0X2ZuUHJvY2Vzc2luZ0Rpc3BsYXkoIG9TZXR0aW5ncywgZmFsc2UgKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFxuXHRcdHZhciBpLCBpTGVuLCBuO1xuXHRcdHZhciBhblJvd3MgPSBbXTtcblx0XHR2YXIgaVJvd0NvdW50ID0gMDtcblx0XHR2YXIgYXNTdHJpcGVDbGFzc2VzID0gb1NldHRpbmdzLmFzU3RyaXBlQ2xhc3Nlcztcblx0XHR2YXIgaVN0cmlwZXMgPSBhc1N0cmlwZUNsYXNzZXMubGVuZ3RoO1xuXHRcdHZhciBpT3BlblJvd3MgPSBvU2V0dGluZ3MuYW9PcGVuUm93cy5sZW5ndGg7XG5cdFx0dmFyIG9MYW5nID0gb1NldHRpbmdzLm9MYW5ndWFnZTtcblx0XHR2YXIgaUluaXREaXNwbGF5U3RhcnQgPSBvU2V0dGluZ3MuaUluaXREaXNwbGF5U3RhcnQ7XG5cdFx0dmFyIGJTZXJ2ZXJTaWRlID0gX2ZuRGF0YVNvdXJjZSggb1NldHRpbmdzICkgPT0gJ3NzcCc7XG5cdFx0dmFyIGFpRGlzcGxheSA9IG9TZXR0aW5ncy5haURpc3BsYXk7XG5cdFxuXHRcdG9TZXR0aW5ncy5iRHJhd2luZyA9IHRydWU7XG5cdFxuXHRcdC8qIENoZWNrIGFuZCBzZWUgaWYgd2UgaGF2ZSBhbiBpbml0aWFsIGRyYXcgcG9zaXRpb24gZnJvbSBzdGF0ZSBzYXZpbmcgKi9cblx0XHRpZiAoIGlJbml0RGlzcGxheVN0YXJ0ICE9PSB1bmRlZmluZWQgJiYgaUluaXREaXNwbGF5U3RhcnQgIT09IC0xIClcblx0XHR7XG5cdFx0XHRvU2V0dGluZ3MuX2lEaXNwbGF5U3RhcnQgPSBiU2VydmVyU2lkZSA/XG5cdFx0XHRcdGlJbml0RGlzcGxheVN0YXJ0IDpcblx0XHRcdFx0aUluaXREaXNwbGF5U3RhcnQgPj0gb1NldHRpbmdzLmZuUmVjb3Jkc0Rpc3BsYXkoKSA/XG5cdFx0XHRcdFx0MCA6XG5cdFx0XHRcdFx0aUluaXREaXNwbGF5U3RhcnQ7XG5cdFxuXHRcdFx0b1NldHRpbmdzLmlJbml0RGlzcGxheVN0YXJ0ID0gLTE7XG5cdFx0fVxuXHRcblx0XHR2YXIgaURpc3BsYXlTdGFydCA9IG9TZXR0aW5ncy5faURpc3BsYXlTdGFydDtcblx0XHR2YXIgaURpc3BsYXlFbmQgPSBvU2V0dGluZ3MuZm5EaXNwbGF5RW5kKCk7XG5cdFxuXHRcdC8qIFNlcnZlci1zaWRlIHByb2Nlc3NpbmcgZHJhdyBpbnRlcmNlcHQgKi9cblx0XHRpZiAoIG9TZXR0aW5ncy5iRGVmZXJMb2FkaW5nIClcblx0XHR7XG5cdFx0XHRvU2V0dGluZ3MuYkRlZmVyTG9hZGluZyA9IGZhbHNlO1xuXHRcdFx0b1NldHRpbmdzLmlEcmF3Kys7XG5cdFx0XHRfZm5Qcm9jZXNzaW5nRGlzcGxheSggb1NldHRpbmdzLCBmYWxzZSApO1xuXHRcdH1cblx0XHRlbHNlIGlmICggIWJTZXJ2ZXJTaWRlIClcblx0XHR7XG5cdFx0XHRvU2V0dGluZ3MuaURyYXcrKztcblx0XHR9XG5cdFx0ZWxzZSBpZiAoICFvU2V0dGluZ3MuYkRlc3Ryb3lpbmcgJiYgIWFqYXhDb21wbGV0ZSlcblx0XHR7XG5cdFx0XHRfZm5BamF4VXBkYXRlKCBvU2V0dGluZ3MgKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFxuXHRcdGlmICggYWlEaXNwbGF5Lmxlbmd0aCAhPT0gMCApXG5cdFx0e1xuXHRcdFx0dmFyIGlTdGFydCA9IGJTZXJ2ZXJTaWRlID8gMCA6IGlEaXNwbGF5U3RhcnQ7XG5cdFx0XHR2YXIgaUVuZCA9IGJTZXJ2ZXJTaWRlID8gb1NldHRpbmdzLmFvRGF0YS5sZW5ndGggOiBpRGlzcGxheUVuZDtcblx0XG5cdFx0XHRmb3IgKCB2YXIgaj1pU3RhcnQgOyBqPGlFbmQgOyBqKysgKVxuXHRcdFx0e1xuXHRcdFx0XHR2YXIgaURhdGFJbmRleCA9IGFpRGlzcGxheVtqXTtcblx0XHRcdFx0dmFyIGFvRGF0YSA9IG9TZXR0aW5ncy5hb0RhdGFbIGlEYXRhSW5kZXggXTtcblx0XHRcdFx0aWYgKCBhb0RhdGEublRyID09PSBudWxsIClcblx0XHRcdFx0e1xuXHRcdFx0XHRcdF9mbkNyZWF0ZVRyKCBvU2V0dGluZ3MsIGlEYXRhSW5kZXggKTtcblx0XHRcdFx0fVxuXHRcblx0XHRcdFx0dmFyIG5Sb3cgPSBhb0RhdGEublRyO1xuXHRcblx0XHRcdFx0LyogUmVtb3ZlIHRoZSBvbGQgc3RyaXBpbmcgY2xhc3NlcyBhbmQgdGhlbiBhZGQgdGhlIG5ldyBvbmUgKi9cblx0XHRcdFx0aWYgKCBpU3RyaXBlcyAhPT0gMCApXG5cdFx0XHRcdHtcblx0XHRcdFx0XHR2YXIgc1N0cmlwZSA9IGFzU3RyaXBlQ2xhc3Nlc1sgaVJvd0NvdW50ICUgaVN0cmlwZXMgXTtcblx0XHRcdFx0XHRpZiAoIGFvRGF0YS5fc1Jvd1N0cmlwZSAhPSBzU3RyaXBlIClcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHQkKG5Sb3cpLnJlbW92ZUNsYXNzKCBhb0RhdGEuX3NSb3dTdHJpcGUgKS5hZGRDbGFzcyggc1N0cmlwZSApO1xuXHRcdFx0XHRcdFx0YW9EYXRhLl9zUm93U3RyaXBlID0gc1N0cmlwZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XG5cdFx0XHRcdC8vIFJvdyBjYWxsYmFjayBmdW5jdGlvbnMgLSBtaWdodCB3YW50IHRvIG1hbmlwdWxhdGUgdGhlIHJvd1xuXHRcdFx0XHQvLyBpUm93Q291bnQgYW5kIGogYXJlIG5vdCBjdXJyZW50bHkgZG9jdW1lbnRlZC4gQXJlIHRoZXkgYXQgYWxsXG5cdFx0XHRcdC8vIHVzZWZ1bD9cblx0XHRcdFx0X2ZuQ2FsbGJhY2tGaXJlKCBvU2V0dGluZ3MsICdhb1Jvd0NhbGxiYWNrJywgbnVsbCxcblx0XHRcdFx0XHRbblJvdywgYW9EYXRhLl9hRGF0YSwgaVJvd0NvdW50LCBqLCBpRGF0YUluZGV4XSApO1xuXHRcblx0XHRcdFx0YW5Sb3dzLnB1c2goIG5Sb3cgKTtcblx0XHRcdFx0aVJvd0NvdW50Kys7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHR7XG5cdFx0XHQvKiBUYWJsZSBpcyBlbXB0eSAtIGNyZWF0ZSBhIHJvdyB3aXRoIGFuIGVtcHR5IG1lc3NhZ2UgaW4gaXQgKi9cblx0XHRcdHZhciBzWmVybyA9IG9MYW5nLnNaZXJvUmVjb3Jkcztcblx0XHRcdGlmICggb1NldHRpbmdzLmlEcmF3ID09IDEgJiYgIF9mbkRhdGFTb3VyY2UoIG9TZXR0aW5ncyApID09ICdhamF4JyApXG5cdFx0XHR7XG5cdFx0XHRcdHNaZXJvID0gb0xhbmcuc0xvYWRpbmdSZWNvcmRzO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSBpZiAoIG9MYW5nLnNFbXB0eVRhYmxlICYmIG9TZXR0aW5ncy5mblJlY29yZHNUb3RhbCgpID09PSAwIClcblx0XHRcdHtcblx0XHRcdFx0c1plcm8gPSBvTGFuZy5zRW1wdHlUYWJsZTtcblx0XHRcdH1cblx0XG5cdFx0XHRhblJvd3NbIDAgXSA9ICQoICc8dHIvPicsIHsgJ2NsYXNzJzogaVN0cmlwZXMgPyBhc1N0cmlwZUNsYXNzZXNbMF0gOiAnJyB9IClcblx0XHRcdFx0LmFwcGVuZCggJCgnPHRkIC8+Jywge1xuXHRcdFx0XHRcdCd2YWxpZ24nOiAgJ3RvcCcsXG5cdFx0XHRcdFx0J2NvbFNwYW4nOiBfZm5WaXNibGVDb2x1bW5zKCBvU2V0dGluZ3MgKSxcblx0XHRcdFx0XHQnY2xhc3MnOiAgIG9TZXR0aW5ncy5vQ2xhc3Nlcy5zUm93RW1wdHlcblx0XHRcdFx0fSApLmh0bWwoIHNaZXJvICkgKVswXTtcblx0XHR9XG5cdFxuXHRcdC8qIEhlYWRlciBhbmQgZm9vdGVyIGNhbGxiYWNrcyAqL1xuXHRcdF9mbkNhbGxiYWNrRmlyZSggb1NldHRpbmdzLCAnYW9IZWFkZXJDYWxsYmFjaycsICdoZWFkZXInLCBbICQob1NldHRpbmdzLm5USGVhZCkuY2hpbGRyZW4oJ3RyJylbMF0sXG5cdFx0XHRfZm5HZXREYXRhTWFzdGVyKCBvU2V0dGluZ3MgKSwgaURpc3BsYXlTdGFydCwgaURpc3BsYXlFbmQsIGFpRGlzcGxheSBdICk7XG5cdFxuXHRcdF9mbkNhbGxiYWNrRmlyZSggb1NldHRpbmdzLCAnYW9Gb290ZXJDYWxsYmFjaycsICdmb290ZXInLCBbICQob1NldHRpbmdzLm5URm9vdCkuY2hpbGRyZW4oJ3RyJylbMF0sXG5cdFx0XHRfZm5HZXREYXRhTWFzdGVyKCBvU2V0dGluZ3MgKSwgaURpc3BsYXlTdGFydCwgaURpc3BsYXlFbmQsIGFpRGlzcGxheSBdICk7XG5cdFxuXHRcdHZhciBib2R5ID0gJChvU2V0dGluZ3MublRCb2R5KTtcblx0XG5cdFx0Ym9keS5jaGlsZHJlbigpLmRldGFjaCgpO1xuXHRcdGJvZHkuYXBwZW5kKCAkKGFuUm93cykgKTtcblx0XG5cdFx0LyogQ2FsbCBhbGwgcmVxdWlyZWQgY2FsbGJhY2sgZnVuY3Rpb25zIGZvciB0aGUgZW5kIG9mIGEgZHJhdyAqL1xuXHRcdF9mbkNhbGxiYWNrRmlyZSggb1NldHRpbmdzLCAnYW9EcmF3Q2FsbGJhY2snLCAnZHJhdycsIFtvU2V0dGluZ3NdICk7XG5cdFxuXHRcdC8qIERyYXcgaXMgY29tcGxldGUsIHNvcnRpbmcgYW5kIGZpbHRlcmluZyBtdXN0IGJlIGFzIHdlbGwgKi9cblx0XHRvU2V0dGluZ3MuYlNvcnRlZCA9IGZhbHNlO1xuXHRcdG9TZXR0aW5ncy5iRmlsdGVyZWQgPSBmYWxzZTtcblx0XHRvU2V0dGluZ3MuYkRyYXdpbmcgPSBmYWxzZTtcblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBSZWRyYXcgdGhlIHRhYmxlIC0gdGFraW5nIGFjY291bnQgb2YgdGhlIHZhcmlvdXMgZmVhdHVyZXMgd2hpY2ggYXJlIGVuYWJsZWRcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBwYXJhbSB7Ym9vbGVhbn0gW2hvbGRQb3NpdGlvbl0gS2VlcCB0aGUgY3VycmVudCBwYWdpbmcgcG9zaXRpb24uIEJ5IGRlZmF1bHRcblx0ICogICAgdGhlIHBhZ2luZyBpcyByZXNldCB0byB0aGUgZmlyc3QgcGFnZVxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5SZURyYXcoIHNldHRpbmdzLCBob2xkUG9zaXRpb24gKVxuXHR7XG5cdFx0dmFyXG5cdFx0XHRmZWF0dXJlcyA9IHNldHRpbmdzLm9GZWF0dXJlcyxcblx0XHRcdHNvcnQgICAgID0gZmVhdHVyZXMuYlNvcnQsXG5cdFx0XHRmaWx0ZXIgICA9IGZlYXR1cmVzLmJGaWx0ZXI7XG5cdFxuXHRcdGlmICggc29ydCApIHtcblx0XHRcdF9mblNvcnQoIHNldHRpbmdzICk7XG5cdFx0fVxuXHRcblx0XHRpZiAoIGZpbHRlciApIHtcblx0XHRcdF9mbkZpbHRlckNvbXBsZXRlKCBzZXR0aW5ncywgc2V0dGluZ3Mub1ByZXZpb3VzU2VhcmNoICk7XG5cdFx0fVxuXHRcdGVsc2Uge1xuXHRcdFx0Ly8gTm8gZmlsdGVyaW5nLCBzbyB3ZSB3YW50IHRvIGp1c3QgdXNlIHRoZSBkaXNwbGF5IG1hc3RlclxuXHRcdFx0c2V0dGluZ3MuYWlEaXNwbGF5ID0gc2V0dGluZ3MuYWlEaXNwbGF5TWFzdGVyLnNsaWNlKCk7XG5cdFx0fVxuXHRcblx0XHRpZiAoIGhvbGRQb3NpdGlvbiAhPT0gdHJ1ZSApIHtcblx0XHRcdHNldHRpbmdzLl9pRGlzcGxheVN0YXJ0ID0gMDtcblx0XHR9XG5cdFxuXHRcdC8vIExldCBhbnkgbW9kdWxlcyBrbm93IGFib3V0IHRoZSBkcmF3IGhvbGQgcG9zaXRpb24gc3RhdGUgKHVzZWQgYnlcblx0XHQvLyBzY3JvbGxpbmcgaW50ZXJuYWxseSlcblx0XHRzZXR0aW5ncy5fZHJhd0hvbGQgPSBob2xkUG9zaXRpb247XG5cdFxuXHRcdF9mbkRyYXcoIHNldHRpbmdzICk7XG5cdFxuXHRcdHNldHRpbmdzLl9kcmF3SG9sZCA9IGZhbHNlO1xuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIEFkZCB0aGUgb3B0aW9ucyB0byB0aGUgcGFnZSBIVE1MIGZvciB0aGUgdGFibGVcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuQWRkT3B0aW9uc0h0bWwgKCBvU2V0dGluZ3MgKVxuXHR7XG5cdFx0dmFyIGNsYXNzZXMgPSBvU2V0dGluZ3Mub0NsYXNzZXM7XG5cdFx0dmFyIHRhYmxlID0gJChvU2V0dGluZ3MublRhYmxlKTtcblx0XHR2YXIgaG9sZGluZyA9ICQoJzxkaXYvPicpLmluc2VydEJlZm9yZSggdGFibGUgKTsgLy8gSG9sZGluZyBlbGVtZW50IGZvciBzcGVlZFxuXHRcdHZhciBmZWF0dXJlcyA9IG9TZXR0aW5ncy5vRmVhdHVyZXM7XG5cdFxuXHRcdC8vIEFsbCBEYXRhVGFibGVzIGFyZSB3cmFwcGVkIGluIGEgZGl2XG5cdFx0dmFyIGluc2VydCA9ICQoJzxkaXYvPicsIHtcblx0XHRcdGlkOiAgICAgIG9TZXR0aW5ncy5zVGFibGVJZCsnX3dyYXBwZXInLFxuXHRcdFx0J2NsYXNzJzogY2xhc3Nlcy5zV3JhcHBlciArIChvU2V0dGluZ3MublRGb290ID8gJycgOiAnICcrY2xhc3Nlcy5zTm9Gb290ZXIpXG5cdFx0fSApO1xuXHRcblx0XHRvU2V0dGluZ3MubkhvbGRpbmcgPSBob2xkaW5nWzBdO1xuXHRcdG9TZXR0aW5ncy5uVGFibGVXcmFwcGVyID0gaW5zZXJ0WzBdO1xuXHRcdG9TZXR0aW5ncy5uVGFibGVSZWluc2VydEJlZm9yZSA9IG9TZXR0aW5ncy5uVGFibGUubmV4dFNpYmxpbmc7XG5cdFxuXHRcdC8qIExvb3Agb3ZlciB0aGUgdXNlciBzZXQgcG9zaXRpb25pbmcgYW5kIHBsYWNlIHRoZSBlbGVtZW50cyBhcyBuZWVkZWQgKi9cblx0XHR2YXIgYURvbSA9IG9TZXR0aW5ncy5zRG9tLnNwbGl0KCcnKTtcblx0XHR2YXIgZmVhdHVyZU5vZGUsIGNPcHRpb24sIG5OZXdOb2RlLCBjTmV4dCwgc0F0dHIsIGo7XG5cdFx0Zm9yICggdmFyIGk9MCA7IGk8YURvbS5sZW5ndGggOyBpKysgKVxuXHRcdHtcblx0XHRcdGZlYXR1cmVOb2RlID0gbnVsbDtcblx0XHRcdGNPcHRpb24gPSBhRG9tW2ldO1xuXHRcblx0XHRcdGlmICggY09wdGlvbiA9PSAnPCcgKVxuXHRcdFx0e1xuXHRcdFx0XHQvKiBOZXcgY29udGFpbmVyIGRpdiAqL1xuXHRcdFx0XHRuTmV3Tm9kZSA9ICQoJzxkaXYvPicpWzBdO1xuXHRcblx0XHRcdFx0LyogQ2hlY2sgdG8gc2VlIGlmIHdlIHNob3VsZCBhcHBlbmQgYW4gaWQgYW5kL29yIGEgY2xhc3MgbmFtZSB0byB0aGUgY29udGFpbmVyICovXG5cdFx0XHRcdGNOZXh0ID0gYURvbVtpKzFdO1xuXHRcdFx0XHRpZiAoIGNOZXh0ID09IFwiJ1wiIHx8IGNOZXh0ID09ICdcIicgKVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0c0F0dHIgPSBcIlwiO1xuXHRcdFx0XHRcdGogPSAyO1xuXHRcdFx0XHRcdHdoaWxlICggYURvbVtpK2pdICE9IGNOZXh0IClcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRzQXR0ciArPSBhRG9tW2kral07XG5cdFx0XHRcdFx0XHRqKys7XG5cdFx0XHRcdFx0fVxuXHRcblx0XHRcdFx0XHQvKiBSZXBsYWNlIGpRdWVyeSBVSSBjb25zdGFudHMgQHRvZG8gZGVwcmVjaWF0ZWQgKi9cblx0XHRcdFx0XHRpZiAoIHNBdHRyID09IFwiSFwiIClcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRzQXR0ciA9IGNsYXNzZXMuc0pVSUhlYWRlcjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZSBpZiAoIHNBdHRyID09IFwiRlwiIClcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRzQXR0ciA9IGNsYXNzZXMuc0pVSUZvb3Rlcjtcblx0XHRcdFx0XHR9XG5cdFxuXHRcdFx0XHRcdC8qIFRoZSBhdHRyaWJ1dGUgY2FuIGJlIGluIHRoZSBmb3JtYXQgb2YgXCIjaWQuY2xhc3NcIiwgXCIjaWRcIiBvciBcImNsYXNzXCIgVGhpcyBsb2dpY1xuXHRcdFx0XHRcdCAqIGJyZWFrcyB0aGUgc3RyaW5nIGludG8gcGFydHMgYW5kIGFwcGxpZXMgdGhlbSBhcyBuZWVkZWRcblx0XHRcdFx0XHQgKi9cblx0XHRcdFx0XHRpZiAoIHNBdHRyLmluZGV4T2YoJy4nKSAhPSAtMSApXG5cdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0dmFyIGFTcGxpdCA9IHNBdHRyLnNwbGl0KCcuJyk7XG5cdFx0XHRcdFx0XHRuTmV3Tm9kZS5pZCA9IGFTcGxpdFswXS5zdWJzdHIoMSwgYVNwbGl0WzBdLmxlbmd0aC0xKTtcblx0XHRcdFx0XHRcdG5OZXdOb2RlLmNsYXNzTmFtZSA9IGFTcGxpdFsxXTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZSBpZiAoIHNBdHRyLmNoYXJBdCgwKSA9PSBcIiNcIiApXG5cdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0bk5ld05vZGUuaWQgPSBzQXR0ci5zdWJzdHIoMSwgc0F0dHIubGVuZ3RoLTEpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbHNlXG5cdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0bk5ld05vZGUuY2xhc3NOYW1lID0gc0F0dHI7XG5cdFx0XHRcdFx0fVxuXHRcblx0XHRcdFx0XHRpICs9IGo7IC8qIE1vdmUgYWxvbmcgdGhlIHBvc2l0aW9uIGFycmF5ICovXG5cdFx0XHRcdH1cblx0XG5cdFx0XHRcdGluc2VydC5hcHBlbmQoIG5OZXdOb2RlICk7XG5cdFx0XHRcdGluc2VydCA9ICQobk5ld05vZGUpO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSBpZiAoIGNPcHRpb24gPT0gJz4nIClcblx0XHRcdHtcblx0XHRcdFx0LyogRW5kIGNvbnRhaW5lciBkaXYgKi9cblx0XHRcdFx0aW5zZXJ0ID0gaW5zZXJ0LnBhcmVudCgpO1xuXHRcdFx0fVxuXHRcdFx0Ly8gQHRvZG8gTW92ZSBvcHRpb25zIGludG8gdGhlaXIgb3duIHBsdWdpbnM/XG5cdFx0XHRlbHNlIGlmICggY09wdGlvbiA9PSAnbCcgJiYgZmVhdHVyZXMuYlBhZ2luYXRlICYmIGZlYXR1cmVzLmJMZW5ndGhDaGFuZ2UgKVxuXHRcdFx0e1xuXHRcdFx0XHQvKiBMZW5ndGggKi9cblx0XHRcdFx0ZmVhdHVyZU5vZGUgPSBfZm5GZWF0dXJlSHRtbExlbmd0aCggb1NldHRpbmdzICk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIGlmICggY09wdGlvbiA9PSAnZicgJiYgZmVhdHVyZXMuYkZpbHRlciApXG5cdFx0XHR7XG5cdFx0XHRcdC8qIEZpbHRlciAqL1xuXHRcdFx0XHRmZWF0dXJlTm9kZSA9IF9mbkZlYXR1cmVIdG1sRmlsdGVyKCBvU2V0dGluZ3MgKTtcblx0XHRcdH1cblx0XHRcdGVsc2UgaWYgKCBjT3B0aW9uID09ICdyJyAmJiBmZWF0dXJlcy5iUHJvY2Vzc2luZyApXG5cdFx0XHR7XG5cdFx0XHRcdC8qIHBSb2Nlc3NpbmcgKi9cblx0XHRcdFx0ZmVhdHVyZU5vZGUgPSBfZm5GZWF0dXJlSHRtbFByb2Nlc3NpbmcoIG9TZXR0aW5ncyApO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSBpZiAoIGNPcHRpb24gPT0gJ3QnIClcblx0XHRcdHtcblx0XHRcdFx0LyogVGFibGUgKi9cblx0XHRcdFx0ZmVhdHVyZU5vZGUgPSBfZm5GZWF0dXJlSHRtbFRhYmxlKCBvU2V0dGluZ3MgKTtcblx0XHRcdH1cblx0XHRcdGVsc2UgaWYgKCBjT3B0aW9uID09ICAnaScgJiYgZmVhdHVyZXMuYkluZm8gKVxuXHRcdFx0e1xuXHRcdFx0XHQvKiBJbmZvICovXG5cdFx0XHRcdGZlYXR1cmVOb2RlID0gX2ZuRmVhdHVyZUh0bWxJbmZvKCBvU2V0dGluZ3MgKTtcblx0XHRcdH1cblx0XHRcdGVsc2UgaWYgKCBjT3B0aW9uID09ICdwJyAmJiBmZWF0dXJlcy5iUGFnaW5hdGUgKVxuXHRcdFx0e1xuXHRcdFx0XHQvKiBQYWdpbmF0aW9uICovXG5cdFx0XHRcdGZlYXR1cmVOb2RlID0gX2ZuRmVhdHVyZUh0bWxQYWdpbmF0ZSggb1NldHRpbmdzICk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIGlmICggRGF0YVRhYmxlLmV4dC5mZWF0dXJlLmxlbmd0aCAhPT0gMCApXG5cdFx0XHR7XG5cdFx0XHRcdC8qIFBsdWctaW4gZmVhdHVyZXMgKi9cblx0XHRcdFx0dmFyIGFvRmVhdHVyZXMgPSBEYXRhVGFibGUuZXh0LmZlYXR1cmU7XG5cdFx0XHRcdGZvciAoIHZhciBrPTAsIGtMZW49YW9GZWF0dXJlcy5sZW5ndGggOyBrPGtMZW4gOyBrKysgKVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0aWYgKCBjT3B0aW9uID09IGFvRmVhdHVyZXNba10uY0ZlYXR1cmUgKVxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdGZlYXR1cmVOb2RlID0gYW9GZWF0dXJlc1trXS5mbkluaXQoIG9TZXR0aW5ncyApO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFxuXHRcdFx0LyogQWRkIHRvIHRoZSAyRCBmZWF0dXJlcyBhcnJheSAqL1xuXHRcdFx0aWYgKCBmZWF0dXJlTm9kZSApXG5cdFx0XHR7XG5cdFx0XHRcdHZhciBhYW5GZWF0dXJlcyA9IG9TZXR0aW5ncy5hYW5GZWF0dXJlcztcblx0XG5cdFx0XHRcdGlmICggISBhYW5GZWF0dXJlc1tjT3B0aW9uXSApXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRhYW5GZWF0dXJlc1tjT3B0aW9uXSA9IFtdO1xuXHRcdFx0XHR9XG5cdFxuXHRcdFx0XHRhYW5GZWF0dXJlc1tjT3B0aW9uXS5wdXNoKCBmZWF0dXJlTm9kZSApO1xuXHRcdFx0XHRpbnNlcnQuYXBwZW5kKCBmZWF0dXJlTm9kZSApO1xuXHRcdFx0fVxuXHRcdH1cblx0XG5cdFx0LyogQnVpbHQgb3VyIERPTSBzdHJ1Y3R1cmUgLSByZXBsYWNlIHRoZSBob2xkaW5nIGRpdiB3aXRoIHdoYXQgd2Ugd2FudCAqL1xuXHRcdGhvbGRpbmcucmVwbGFjZVdpdGgoIGluc2VydCApO1xuXHRcdG9TZXR0aW5ncy5uSG9sZGluZyA9IG51bGw7XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogVXNlIHRoZSBET00gc291cmNlIHRvIGNyZWF0ZSB1cCBhbiBhcnJheSBvZiBoZWFkZXIgY2VsbHMuIFRoZSBpZGVhIGhlcmUgaXMgdG9cblx0ICogY3JlYXRlIGEgbGF5b3V0IGdyaWQgKGFycmF5KSBvZiByb3dzIHggY29sdW1ucywgd2hpY2ggY29udGFpbnMgYSByZWZlcmVuY2Vcblx0ICogdG8gdGhlIGNlbGwgdGhhdCB0aGF0IHBvaW50IGluIHRoZSBncmlkIChyZWdhcmRsZXNzIG9mIGNvbC9yb3dzcGFuKSwgc3VjaCB0aGF0XG5cdCAqIGFueSBjb2x1bW4gLyByb3cgY291bGQgYmUgcmVtb3ZlZCBhbmQgdGhlIG5ldyBncmlkIGNvbnN0cnVjdGVkXG5cdCAqICBAcGFyYW0gYXJyYXkge29iamVjdH0gYUxheW91dCBBcnJheSB0byBzdG9yZSB0aGUgY2FsY3VsYXRlZCBsYXlvdXQgaW5cblx0ICogIEBwYXJhbSB7bm9kZX0gblRoZWFkIFRoZSBoZWFkZXIvZm9vdGVyIGVsZW1lbnQgZm9yIHRoZSB0YWJsZVxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5EZXRlY3RIZWFkZXIgKCBhTGF5b3V0LCBuVGhlYWQgKVxuXHR7XG5cdFx0dmFyIG5UcnMgPSAkKG5UaGVhZCkuY2hpbGRyZW4oJ3RyJyk7XG5cdFx0dmFyIG5UciwgbkNlbGw7XG5cdFx0dmFyIGksIGssIGwsIGlMZW4sIGpMZW4sIGlDb2xTaGlmdGVkLCBpQ29sdW1uLCBpQ29sc3BhbiwgaVJvd3NwYW47XG5cdFx0dmFyIGJVbmlxdWU7XG5cdFx0dmFyIGZuU2hpZnRDb2wgPSBmdW5jdGlvbiAoIGEsIGksIGogKSB7XG5cdFx0XHR2YXIgayA9IGFbaV07XG5cdCAgICAgICAgICAgICAgICB3aGlsZSAoIGtbal0gKSB7XG5cdFx0XHRcdGorKztcblx0XHRcdH1cblx0XHRcdHJldHVybiBqO1xuXHRcdH07XG5cdFxuXHRcdGFMYXlvdXQuc3BsaWNlKCAwLCBhTGF5b3V0Lmxlbmd0aCApO1xuXHRcblx0XHQvKiBXZSBrbm93IGhvdyBtYW55IHJvd3MgdGhlcmUgYXJlIGluIHRoZSBsYXlvdXQgLSBzbyBwcmVwIGl0ICovXG5cdFx0Zm9yICggaT0wLCBpTGVuPW5UcnMubGVuZ3RoIDsgaTxpTGVuIDsgaSsrIClcblx0XHR7XG5cdFx0XHRhTGF5b3V0LnB1c2goIFtdICk7XG5cdFx0fVxuXHRcblx0XHQvKiBDYWxjdWxhdGUgYSBsYXlvdXQgYXJyYXkgKi9cblx0XHRmb3IgKCBpPTAsIGlMZW49blRycy5sZW5ndGggOyBpPGlMZW4gOyBpKysgKVxuXHRcdHtcblx0XHRcdG5UciA9IG5UcnNbaV07XG5cdFx0XHRpQ29sdW1uID0gMDtcblx0XG5cdFx0XHQvKiBGb3IgZXZlcnkgY2VsbCBpbiB0aGUgcm93Li4uICovXG5cdFx0XHRuQ2VsbCA9IG5Uci5maXJzdENoaWxkO1xuXHRcdFx0d2hpbGUgKCBuQ2VsbCApIHtcblx0XHRcdFx0aWYgKCBuQ2VsbC5ub2RlTmFtZS50b1VwcGVyQ2FzZSgpID09IFwiVERcIiB8fFxuXHRcdFx0XHQgICAgIG5DZWxsLm5vZGVOYW1lLnRvVXBwZXJDYXNlKCkgPT0gXCJUSFwiIClcblx0XHRcdFx0e1xuXHRcdFx0XHRcdC8qIEdldCB0aGUgY29sIGFuZCByb3dzcGFuIGF0dHJpYnV0ZXMgZnJvbSB0aGUgRE9NIGFuZCBzYW5pdGlzZSB0aGVtICovXG5cdFx0XHRcdFx0aUNvbHNwYW4gPSBuQ2VsbC5nZXRBdHRyaWJ1dGUoJ2NvbHNwYW4nKSAqIDE7XG5cdFx0XHRcdFx0aVJvd3NwYW4gPSBuQ2VsbC5nZXRBdHRyaWJ1dGUoJ3Jvd3NwYW4nKSAqIDE7XG5cdFx0XHRcdFx0aUNvbHNwYW4gPSAoIWlDb2xzcGFuIHx8IGlDb2xzcGFuPT09MCB8fCBpQ29sc3Bhbj09PTEpID8gMSA6IGlDb2xzcGFuO1xuXHRcdFx0XHRcdGlSb3dzcGFuID0gKCFpUm93c3BhbiB8fCBpUm93c3Bhbj09PTAgfHwgaVJvd3NwYW49PT0xKSA/IDEgOiBpUm93c3Bhbjtcblx0XG5cdFx0XHRcdFx0LyogVGhlcmUgbWlnaHQgYmUgY29sc3BhbiBjZWxscyBhbHJlYWR5IGluIHRoaXMgcm93LCBzbyBzaGlmdCBvdXIgdGFyZ2V0XG5cdFx0XHRcdFx0ICogYWNjb3JkaW5nbHlcblx0XHRcdFx0XHQgKi9cblx0XHRcdFx0XHRpQ29sU2hpZnRlZCA9IGZuU2hpZnRDb2woIGFMYXlvdXQsIGksIGlDb2x1bW4gKTtcblx0XG5cdFx0XHRcdFx0LyogQ2FjaGUgY2FsY3VsYXRpb24gZm9yIHVuaXF1ZSBjb2x1bW5zICovXG5cdFx0XHRcdFx0YlVuaXF1ZSA9IGlDb2xzcGFuID09PSAxID8gdHJ1ZSA6IGZhbHNlO1xuXHRcblx0XHRcdFx0XHQvKiBJZiB0aGVyZSBpcyBjb2wgLyByb3dzcGFuLCBjb3B5IHRoZSBpbmZvcm1hdGlvbiBpbnRvIHRoZSBsYXlvdXQgZ3JpZCAqL1xuXHRcdFx0XHRcdGZvciAoIGw9MCA7IGw8aUNvbHNwYW4gOyBsKysgKVxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdGZvciAoIGs9MCA7IGs8aVJvd3NwYW4gOyBrKysgKVxuXHRcdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0XHRhTGF5b3V0W2kra11baUNvbFNoaWZ0ZWQrbF0gPSB7XG5cdFx0XHRcdFx0XHRcdFx0XCJjZWxsXCI6IG5DZWxsLFxuXHRcdFx0XHRcdFx0XHRcdFwidW5pcXVlXCI6IGJVbmlxdWVcblx0XHRcdFx0XHRcdFx0fTtcblx0XHRcdFx0XHRcdFx0YUxheW91dFtpK2tdLm5UciA9IG5Ucjtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0bkNlbGwgPSBuQ2VsbC5uZXh0U2libGluZztcblx0XHRcdH1cblx0XHR9XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogR2V0IGFuIGFycmF5IG9mIHVuaXF1ZSB0aCBlbGVtZW50cywgb25lIGZvciBlYWNoIGNvbHVtblxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IG9TZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHBhcmFtIHtub2RlfSBuSGVhZGVyIGF1dG9tYXRpY2FsbHkgZGV0ZWN0IHRoZSBsYXlvdXQgZnJvbSB0aGlzIG5vZGUgLSBvcHRpb25hbFxuXHQgKiAgQHBhcmFtIHthcnJheX0gYUxheW91dCB0aGVhZC90Zm9vdCBsYXlvdXQgZnJvbSBfZm5EZXRlY3RIZWFkZXIgLSBvcHRpb25hbFxuXHQgKiAgQHJldHVybnMgYXJyYXkge25vZGV9IGFSZXR1cm4gbGlzdCBvZiB1bmlxdWUgdGgnc1xuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5HZXRVbmlxdWVUaHMgKCBvU2V0dGluZ3MsIG5IZWFkZXIsIGFMYXlvdXQgKVxuXHR7XG5cdFx0dmFyIGFSZXR1cm4gPSBbXTtcblx0XHRpZiAoICFhTGF5b3V0IClcblx0XHR7XG5cdFx0XHRhTGF5b3V0ID0gb1NldHRpbmdzLmFvSGVhZGVyO1xuXHRcdFx0aWYgKCBuSGVhZGVyIClcblx0XHRcdHtcblx0XHRcdFx0YUxheW91dCA9IFtdO1xuXHRcdFx0XHRfZm5EZXRlY3RIZWFkZXIoIGFMYXlvdXQsIG5IZWFkZXIgKTtcblx0XHRcdH1cblx0XHR9XG5cdFxuXHRcdGZvciAoIHZhciBpPTAsIGlMZW49YUxheW91dC5sZW5ndGggOyBpPGlMZW4gOyBpKysgKVxuXHRcdHtcblx0XHRcdGZvciAoIHZhciBqPTAsIGpMZW49YUxheW91dFtpXS5sZW5ndGggOyBqPGpMZW4gOyBqKysgKVxuXHRcdFx0e1xuXHRcdFx0XHRpZiAoIGFMYXlvdXRbaV1bal0udW5pcXVlICYmXG5cdFx0XHRcdFx0ICghYVJldHVybltqXSB8fCAhb1NldHRpbmdzLmJTb3J0Q2VsbHNUb3ApIClcblx0XHRcdFx0e1xuXHRcdFx0XHRcdGFSZXR1cm5bal0gPSBhTGF5b3V0W2ldW2pdLmNlbGw7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdFxuXHRcdHJldHVybiBhUmV0dXJuO1xuXHR9XG5cdFxuXHQvKipcblx0ICogQ3JlYXRlIGFuIEFqYXggY2FsbCBiYXNlZCBvbiB0aGUgdGFibGUncyBzZXR0aW5ncywgdGFraW5nIGludG8gYWNjb3VudCB0aGF0XG5cdCAqIHBhcmFtZXRlcnMgY2FuIGhhdmUgbXVsdGlwbGUgZm9ybXMsIGFuZCBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eS5cblx0ICpcblx0ICogQHBhcmFtIHtvYmplY3R9IG9TZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiBAcGFyYW0ge2FycmF5fSBkYXRhIERhdGEgdG8gc2VuZCB0byB0aGUgc2VydmVyLCByZXF1aXJlZCBieVxuXHQgKiAgICAgRGF0YVRhYmxlcyAtIG1heSBiZSBhdWdtZW50ZWQgYnkgZGV2ZWxvcGVyIGNhbGxiYWNrc1xuXHQgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmbiBDYWxsYmFjayBmdW5jdGlvbiB0byBydW4gd2hlbiBkYXRhIGlzIG9idGFpbmVkXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5CdWlsZEFqYXgoIG9TZXR0aW5ncywgZGF0YSwgZm4gKVxuXHR7XG5cdFx0Ly8gQ29tcGF0aWJpbGl0eSB3aXRoIDEuOS0sIGFsbG93IGZuU2VydmVyRGF0YSBhbmQgZXZlbnQgdG8gbWFuaXB1bGF0ZVxuXHRcdF9mbkNhbGxiYWNrRmlyZSggb1NldHRpbmdzLCAnYW9TZXJ2ZXJQYXJhbXMnLCAnc2VydmVyUGFyYW1zJywgW2RhdGFdICk7XG5cdFxuXHRcdC8vIENvbnZlcnQgdG8gb2JqZWN0IGJhc2VkIGZvciAxLjEwKyBpZiB1c2luZyB0aGUgb2xkIGFycmF5IHNjaGVtZSB3aGljaCBjYW5cblx0XHQvLyBjb21lIGZyb20gc2VydmVyLXNpZGUgcHJvY2Vzc2luZyBvciBzZXJ2ZXJQYXJhbXNcblx0XHRpZiAoIGRhdGEgJiYgQXJyYXkuaXNBcnJheShkYXRhKSApIHtcblx0XHRcdHZhciB0bXAgPSB7fTtcblx0XHRcdHZhciByYnJhY2tldCA9IC8oLio/KVxcW1xcXSQvO1xuXHRcblx0XHRcdCQuZWFjaCggZGF0YSwgZnVuY3Rpb24gKGtleSwgdmFsKSB7XG5cdFx0XHRcdHZhciBtYXRjaCA9IHZhbC5uYW1lLm1hdGNoKHJicmFja2V0KTtcblx0XG5cdFx0XHRcdGlmICggbWF0Y2ggKSB7XG5cdFx0XHRcdFx0Ly8gU3VwcG9ydCBmb3IgYXJyYXlzXG5cdFx0XHRcdFx0dmFyIG5hbWUgPSBtYXRjaFswXTtcblx0XG5cdFx0XHRcdFx0aWYgKCAhIHRtcFsgbmFtZSBdICkge1xuXHRcdFx0XHRcdFx0dG1wWyBuYW1lIF0gPSBbXTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dG1wWyBuYW1lIF0ucHVzaCggdmFsLnZhbHVlICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0dG1wW3ZhbC5uYW1lXSA9IHZhbC52YWx1ZTtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcdFx0ZGF0YSA9IHRtcDtcblx0XHR9XG5cdFxuXHRcdHZhciBhamF4RGF0YTtcblx0XHR2YXIgYWpheCA9IG9TZXR0aW5ncy5hamF4O1xuXHRcdHZhciBpbnN0YW5jZSA9IG9TZXR0aW5ncy5vSW5zdGFuY2U7XG5cdFx0dmFyIGNhbGxiYWNrID0gZnVuY3Rpb24gKCBqc29uICkge1xuXHRcdFx0dmFyIHN0YXR1cyA9IG9TZXR0aW5ncy5qcVhoclxuXHRcdFx0XHQ/IG9TZXR0aW5ncy5qcVhoci5zdGF0dXNcblx0XHRcdFx0OiBudWxsO1xuXHRcblx0XHRcdGlmICgganNvbiA9PT0gbnVsbCB8fCAodHlwZW9mIHN0YXR1cyA9PT0gJ251bWJlcicgJiYgc3RhdHVzID09IDIwNCApICkge1xuXHRcdFx0XHRqc29uID0ge307XG5cdFx0XHRcdF9mbkFqYXhEYXRhU3JjKCBvU2V0dGluZ3MsIGpzb24sIFtdICk7XG5cdFx0XHR9XG5cdFxuXHRcdFx0dmFyIGVycm9yID0ganNvbi5lcnJvciB8fCBqc29uLnNFcnJvcjtcblx0XHRcdGlmICggZXJyb3IgKSB7XG5cdFx0XHRcdF9mbkxvZyggb1NldHRpbmdzLCAwLCBlcnJvciApO1xuXHRcdFx0fVxuXHRcblx0XHRcdG9TZXR0aW5ncy5qc29uID0ganNvbjtcblx0XG5cdFx0XHRfZm5DYWxsYmFja0ZpcmUoIG9TZXR0aW5ncywgbnVsbCwgJ3hocicsIFtvU2V0dGluZ3MsIGpzb24sIG9TZXR0aW5ncy5qcVhIUl0gKTtcblx0XHRcdGZuKCBqc29uICk7XG5cdFx0fTtcblx0XG5cdFx0aWYgKCAkLmlzUGxhaW5PYmplY3QoIGFqYXggKSAmJiBhamF4LmRhdGEgKVxuXHRcdHtcblx0XHRcdGFqYXhEYXRhID0gYWpheC5kYXRhO1xuXHRcblx0XHRcdHZhciBuZXdEYXRhID0gdHlwZW9mIGFqYXhEYXRhID09PSAnZnVuY3Rpb24nID9cblx0XHRcdFx0YWpheERhdGEoIGRhdGEsIG9TZXR0aW5ncyApIDogIC8vIGZuIGNhbiBtYW5pcHVsYXRlIGRhdGEgb3IgcmV0dXJuXG5cdFx0XHRcdGFqYXhEYXRhOyAgICAgICAgICAgICAgICAgICAgICAvLyBhbiBvYmplY3Qgb2JqZWN0IG9yIGFycmF5IHRvIG1lcmdlXG5cdFxuXHRcdFx0Ly8gSWYgdGhlIGZ1bmN0aW9uIHJldHVybmVkIHNvbWV0aGluZywgdXNlIHRoYXQgYWxvbmVcblx0XHRcdGRhdGEgPSB0eXBlb2YgYWpheERhdGEgPT09ICdmdW5jdGlvbicgJiYgbmV3RGF0YSA/XG5cdFx0XHRcdG5ld0RhdGEgOlxuXHRcdFx0XHQkLmV4dGVuZCggdHJ1ZSwgZGF0YSwgbmV3RGF0YSApO1xuXHRcblx0XHRcdC8vIFJlbW92ZSB0aGUgZGF0YSBwcm9wZXJ0eSBhcyB3ZSd2ZSByZXNvbHZlZCBpdCBhbHJlYWR5IGFuZCBkb24ndCB3YW50XG5cdFx0XHQvLyBqUXVlcnkgdG8gZG8gaXQgYWdhaW4gKGl0IGlzIHJlc3RvcmVkIGF0IHRoZSBlbmQgb2YgdGhlIGZ1bmN0aW9uKVxuXHRcdFx0ZGVsZXRlIGFqYXguZGF0YTtcblx0XHR9XG5cdFxuXHRcdHZhciBiYXNlQWpheCA9IHtcblx0XHRcdFwiZGF0YVwiOiBkYXRhLFxuXHRcdFx0XCJzdWNjZXNzXCI6IGNhbGxiYWNrLFxuXHRcdFx0XCJkYXRhVHlwZVwiOiBcImpzb25cIixcblx0XHRcdFwiY2FjaGVcIjogZmFsc2UsXG5cdFx0XHRcInR5cGVcIjogb1NldHRpbmdzLnNTZXJ2ZXJNZXRob2QsXG5cdFx0XHRcImVycm9yXCI6IGZ1bmN0aW9uICh4aHIsIGVycm9yLCB0aHJvd24pIHtcblx0XHRcdFx0dmFyIHJldCA9IF9mbkNhbGxiYWNrRmlyZSggb1NldHRpbmdzLCBudWxsLCAneGhyJywgW29TZXR0aW5ncywgbnVsbCwgb1NldHRpbmdzLmpxWEhSXSApO1xuXHRcblx0XHRcdFx0aWYgKCAkLmluQXJyYXkoIHRydWUsIHJldCApID09PSAtMSApIHtcblx0XHRcdFx0XHRpZiAoIGVycm9yID09IFwicGFyc2VyZXJyb3JcIiApIHtcblx0XHRcdFx0XHRcdF9mbkxvZyggb1NldHRpbmdzLCAwLCAnSW52YWxpZCBKU09OIHJlc3BvbnNlJywgMSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbHNlIGlmICggeGhyLnJlYWR5U3RhdGUgPT09IDQgKSB7XG5cdFx0XHRcdFx0XHRfZm5Mb2coIG9TZXR0aW5ncywgMCwgJ0FqYXggZXJyb3InLCA3ICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFxuXHRcdFx0XHRfZm5Qcm9jZXNzaW5nRGlzcGxheSggb1NldHRpbmdzLCBmYWxzZSApO1xuXHRcdFx0fVxuXHRcdH07XG5cdFxuXHRcdC8vIFN0b3JlIHRoZSBkYXRhIHN1Ym1pdHRlZCBmb3IgdGhlIEFQSVxuXHRcdG9TZXR0aW5ncy5vQWpheERhdGEgPSBkYXRhO1xuXHRcblx0XHQvLyBBbGxvdyBwbHVnLWlucyBhbmQgZXh0ZXJuYWwgcHJvY2Vzc2VzIHRvIG1vZGlmeSB0aGUgZGF0YVxuXHRcdF9mbkNhbGxiYWNrRmlyZSggb1NldHRpbmdzLCBudWxsLCAncHJlWGhyJywgW29TZXR0aW5ncywgZGF0YV0gKTtcblx0XG5cdFx0aWYgKCBvU2V0dGluZ3MuZm5TZXJ2ZXJEYXRhIClcblx0XHR7XG5cdFx0XHQvLyBEYXRhVGFibGVzIDEuOS0gY29tcGF0aWJpbGl0eVxuXHRcdFx0b1NldHRpbmdzLmZuU2VydmVyRGF0YS5jYWxsKCBpbnN0YW5jZSxcblx0XHRcdFx0b1NldHRpbmdzLnNBamF4U291cmNlLFxuXHRcdFx0XHQkLm1hcCggZGF0YSwgZnVuY3Rpb24gKHZhbCwga2V5KSB7IC8vIE5lZWQgdG8gY29udmVydCBiYWNrIHRvIDEuOSB0cmFkIGZvcm1hdFxuXHRcdFx0XHRcdHJldHVybiB7IG5hbWU6IGtleSwgdmFsdWU6IHZhbCB9O1xuXHRcdFx0XHR9ICksXG5cdFx0XHRcdGNhbGxiYWNrLFxuXHRcdFx0XHRvU2V0dGluZ3Ncblx0XHRcdCk7XG5cdFx0fVxuXHRcdGVsc2UgaWYgKCBvU2V0dGluZ3Muc0FqYXhTb3VyY2UgfHwgdHlwZW9mIGFqYXggPT09ICdzdHJpbmcnIClcblx0XHR7XG5cdFx0XHQvLyBEYXRhVGFibGVzIDEuOS0gY29tcGF0aWJpbGl0eVxuXHRcdFx0b1NldHRpbmdzLmpxWEhSID0gJC5hamF4KCAkLmV4dGVuZCggYmFzZUFqYXgsIHtcblx0XHRcdFx0dXJsOiBhamF4IHx8IG9TZXR0aW5ncy5zQWpheFNvdXJjZVxuXHRcdFx0fSApICk7XG5cdFx0fVxuXHRcdGVsc2UgaWYgKCB0eXBlb2YgYWpheCA9PT0gJ2Z1bmN0aW9uJyApXG5cdFx0e1xuXHRcdFx0Ly8gSXMgYSBmdW5jdGlvbiAtIGxldCB0aGUgY2FsbGVyIGRlZmluZSB3aGF0IG5lZWRzIHRvIGJlIGRvbmVcblx0XHRcdG9TZXR0aW5ncy5qcVhIUiA9IGFqYXguY2FsbCggaW5zdGFuY2UsIGRhdGEsIGNhbGxiYWNrLCBvU2V0dGluZ3MgKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdHtcblx0XHRcdC8vIE9iamVjdCB0byBleHRlbmQgdGhlIGJhc2Ugc2V0dGluZ3Ncblx0XHRcdG9TZXR0aW5ncy5qcVhIUiA9ICQuYWpheCggJC5leHRlbmQoIGJhc2VBamF4LCBhamF4ICkgKTtcblx0XG5cdFx0XHQvLyBSZXN0b3JlIGZvciBuZXh0IHRpbWUgYXJvdW5kXG5cdFx0XHRhamF4LmRhdGEgPSBhamF4RGF0YTtcblx0XHR9XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogVXBkYXRlIHRoZSB0YWJsZSB1c2luZyBhbiBBamF4IGNhbGxcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHJldHVybnMge2Jvb2xlYW59IEJsb2NrIHRoZSB0YWJsZSBkcmF3aW5nIG9yIG5vdFxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5BamF4VXBkYXRlKCBzZXR0aW5ncyApXG5cdHtcblx0XHRzZXR0aW5ncy5pRHJhdysrO1xuXHRcdF9mblByb2Nlc3NpbmdEaXNwbGF5KCBzZXR0aW5ncywgdHJ1ZSApO1xuXHRcblx0XHRfZm5CdWlsZEFqYXgoXG5cdFx0XHRzZXR0aW5ncyxcblx0XHRcdF9mbkFqYXhQYXJhbWV0ZXJzKCBzZXR0aW5ncyApLFxuXHRcdFx0ZnVuY3Rpb24oanNvbikge1xuXHRcdFx0XHRfZm5BamF4VXBkYXRlRHJhdyggc2V0dGluZ3MsIGpzb24gKTtcblx0XHRcdH1cblx0XHQpO1xuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIEJ1aWxkIHVwIHRoZSBwYXJhbWV0ZXJzIGluIGFuIG9iamVjdCBuZWVkZWQgZm9yIGEgc2VydmVyLXNpZGUgcHJvY2Vzc2luZ1xuXHQgKiByZXF1ZXN0LiBOb3RlIHRoYXQgdGhpcyBpcyBiYXNpY2FsbHkgZG9uZSB0d2ljZSwgaXMgZGlmZmVyZW50IHdheXMgLSBhIG1vZGVyblxuXHQgKiBtZXRob2Qgd2hpY2ggaXMgdXNlZCBieSBkZWZhdWx0IGluIERhdGFUYWJsZXMgMS4xMCB3aGljaCB1c2VzIG9iamVjdHMgYW5kXG5cdCAqIGFycmF5cywgb3IgdGhlIDEuOS0gbWV0aG9kIHdpdGggaXMgbmFtZSAvIHZhbHVlIHBhaXJzLiAxLjkgbWV0aG9kIGlzIHVzZWQgaWZcblx0ICogdGhlIHNBamF4U291cmNlIG9wdGlvbiBpcyB1c2VkIGluIHRoZSBpbml0aWFsaXNhdGlvbiwgb3IgdGhlIGxlZ2FjeUFqYXhcblx0ICogb3B0aW9uIGlzIHNldC5cblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEByZXR1cm5zIHtib29sfSBibG9jayB0aGUgdGFibGUgZHJhd2luZyBvciBub3Rcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuQWpheFBhcmFtZXRlcnMoIHNldHRpbmdzIClcblx0e1xuXHRcdHZhclxuXHRcdFx0Y29sdW1ucyA9IHNldHRpbmdzLmFvQ29sdW1ucyxcblx0XHRcdGNvbHVtbkNvdW50ID0gY29sdW1ucy5sZW5ndGgsXG5cdFx0XHRmZWF0dXJlcyA9IHNldHRpbmdzLm9GZWF0dXJlcyxcblx0XHRcdHByZVNlYXJjaCA9IHNldHRpbmdzLm9QcmV2aW91c1NlYXJjaCxcblx0XHRcdHByZUNvbFNlYXJjaCA9IHNldHRpbmdzLmFvUHJlU2VhcmNoQ29scyxcblx0XHRcdGksIGRhdGEgPSBbXSwgZGF0YVByb3AsIGNvbHVtbiwgY29sdW1uU2VhcmNoLFxuXHRcdFx0c29ydCA9IF9mblNvcnRGbGF0dGVuKCBzZXR0aW5ncyApLFxuXHRcdFx0ZGlzcGxheVN0YXJ0ID0gc2V0dGluZ3MuX2lEaXNwbGF5U3RhcnQsXG5cdFx0XHRkaXNwbGF5TGVuZ3RoID0gZmVhdHVyZXMuYlBhZ2luYXRlICE9PSBmYWxzZSA/XG5cdFx0XHRcdHNldHRpbmdzLl9pRGlzcGxheUxlbmd0aCA6XG5cdFx0XHRcdC0xO1xuXHRcblx0XHR2YXIgcGFyYW0gPSBmdW5jdGlvbiAoIG5hbWUsIHZhbHVlICkge1xuXHRcdFx0ZGF0YS5wdXNoKCB7ICduYW1lJzogbmFtZSwgJ3ZhbHVlJzogdmFsdWUgfSApO1xuXHRcdH07XG5cdFxuXHRcdC8vIERhdGFUYWJsZXMgMS45LSBjb21wYXRpYmxlIG1ldGhvZFxuXHRcdHBhcmFtKCAnc0VjaG8nLCAgICAgICAgICBzZXR0aW5ncy5pRHJhdyApO1xuXHRcdHBhcmFtKCAnaUNvbHVtbnMnLCAgICAgICBjb2x1bW5Db3VudCApO1xuXHRcdHBhcmFtKCAnc0NvbHVtbnMnLCAgICAgICBfcGx1Y2soIGNvbHVtbnMsICdzTmFtZScgKS5qb2luKCcsJykgKTtcblx0XHRwYXJhbSggJ2lEaXNwbGF5U3RhcnQnLCAgZGlzcGxheVN0YXJ0ICk7XG5cdFx0cGFyYW0oICdpRGlzcGxheUxlbmd0aCcsIGRpc3BsYXlMZW5ndGggKTtcblx0XG5cdFx0Ly8gRGF0YVRhYmxlcyAxLjEwKyBtZXRob2Rcblx0XHR2YXIgZCA9IHtcblx0XHRcdGRyYXc6ICAgIHNldHRpbmdzLmlEcmF3LFxuXHRcdFx0Y29sdW1uczogW10sXG5cdFx0XHRvcmRlcjogICBbXSxcblx0XHRcdHN0YXJ0OiAgIGRpc3BsYXlTdGFydCxcblx0XHRcdGxlbmd0aDogIGRpc3BsYXlMZW5ndGgsXG5cdFx0XHRzZWFyY2g6ICB7XG5cdFx0XHRcdHZhbHVlOiBwcmVTZWFyY2guc1NlYXJjaCxcblx0XHRcdFx0cmVnZXg6IHByZVNlYXJjaC5iUmVnZXhcblx0XHRcdH1cblx0XHR9O1xuXHRcblx0XHRmb3IgKCBpPTAgOyBpPGNvbHVtbkNvdW50IDsgaSsrICkge1xuXHRcdFx0Y29sdW1uID0gY29sdW1uc1tpXTtcblx0XHRcdGNvbHVtblNlYXJjaCA9IHByZUNvbFNlYXJjaFtpXTtcblx0XHRcdGRhdGFQcm9wID0gdHlwZW9mIGNvbHVtbi5tRGF0YT09XCJmdW5jdGlvblwiID8gJ2Z1bmN0aW9uJyA6IGNvbHVtbi5tRGF0YSA7XG5cdFxuXHRcdFx0ZC5jb2x1bW5zLnB1c2goIHtcblx0XHRcdFx0ZGF0YTogICAgICAgZGF0YVByb3AsXG5cdFx0XHRcdG5hbWU6ICAgICAgIGNvbHVtbi5zTmFtZSxcblx0XHRcdFx0c2VhcmNoYWJsZTogY29sdW1uLmJTZWFyY2hhYmxlLFxuXHRcdFx0XHRvcmRlcmFibGU6ICBjb2x1bW4uYlNvcnRhYmxlLFxuXHRcdFx0XHRzZWFyY2g6ICAgICB7XG5cdFx0XHRcdFx0dmFsdWU6IGNvbHVtblNlYXJjaC5zU2VhcmNoLFxuXHRcdFx0XHRcdHJlZ2V4OiBjb2x1bW5TZWFyY2guYlJlZ2V4XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0XG5cdFx0XHRwYXJhbSggXCJtRGF0YVByb3BfXCIraSwgZGF0YVByb3AgKTtcblx0XG5cdFx0XHRpZiAoIGZlYXR1cmVzLmJGaWx0ZXIgKSB7XG5cdFx0XHRcdHBhcmFtKCAnc1NlYXJjaF8nK2ksICAgICBjb2x1bW5TZWFyY2guc1NlYXJjaCApO1xuXHRcdFx0XHRwYXJhbSggJ2JSZWdleF8nK2ksICAgICAgY29sdW1uU2VhcmNoLmJSZWdleCApO1xuXHRcdFx0XHRwYXJhbSggJ2JTZWFyY2hhYmxlXycraSwgY29sdW1uLmJTZWFyY2hhYmxlICk7XG5cdFx0XHR9XG5cdFxuXHRcdFx0aWYgKCBmZWF0dXJlcy5iU29ydCApIHtcblx0XHRcdFx0cGFyYW0oICdiU29ydGFibGVfJytpLCBjb2x1bW4uYlNvcnRhYmxlICk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcblx0XHRpZiAoIGZlYXR1cmVzLmJGaWx0ZXIgKSB7XG5cdFx0XHRwYXJhbSggJ3NTZWFyY2gnLCBwcmVTZWFyY2guc1NlYXJjaCApO1xuXHRcdFx0cGFyYW0oICdiUmVnZXgnLCBwcmVTZWFyY2guYlJlZ2V4ICk7XG5cdFx0fVxuXHRcblx0XHRpZiAoIGZlYXR1cmVzLmJTb3J0ICkge1xuXHRcdFx0JC5lYWNoKCBzb3J0LCBmdW5jdGlvbiAoIGksIHZhbCApIHtcblx0XHRcdFx0ZC5vcmRlci5wdXNoKCB7IGNvbHVtbjogdmFsLmNvbCwgZGlyOiB2YWwuZGlyIH0gKTtcblx0XG5cdFx0XHRcdHBhcmFtKCAnaVNvcnRDb2xfJytpLCB2YWwuY29sICk7XG5cdFx0XHRcdHBhcmFtKCAnc1NvcnREaXJfJytpLCB2YWwuZGlyICk7XG5cdFx0XHR9ICk7XG5cdFxuXHRcdFx0cGFyYW0oICdpU29ydGluZ0NvbHMnLCBzb3J0Lmxlbmd0aCApO1xuXHRcdH1cblx0XG5cdFx0Ly8gSWYgdGhlIGxlZ2FjeS5hamF4IHBhcmFtZXRlciBpcyBudWxsLCB0aGVuIHdlIGF1dG9tYXRpY2FsbHkgZGVjaWRlIHdoaWNoXG5cdFx0Ly8gZm9ybSB0byB1c2UsIGJhc2VkIG9uIHNBamF4U291cmNlXG5cdFx0dmFyIGxlZ2FjeSA9IERhdGFUYWJsZS5leHQubGVnYWN5LmFqYXg7XG5cdFx0aWYgKCBsZWdhY3kgPT09IG51bGwgKSB7XG5cdFx0XHRyZXR1cm4gc2V0dGluZ3Muc0FqYXhTb3VyY2UgPyBkYXRhIDogZDtcblx0XHR9XG5cdFxuXHRcdC8vIE90aGVyd2lzZSwgaWYgbGVnYWN5IGhhcyBiZWVuIHNwZWNpZmllZCB0aGVuIHdlIHVzZSB0aGF0IHRvIGRlY2lkZSBvbiB0aGVcblx0XHQvLyBmb3JtXG5cdFx0cmV0dXJuIGxlZ2FjeSA/IGRhdGEgOiBkO1xuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIERhdGEgdGhlIGRhdGEgZnJvbSB0aGUgc2VydmVyIChudWtpbmcgdGhlIG9sZCkgYW5kIHJlZHJhdyB0aGUgdGFibGVcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBqc29uIGpzb24gZGF0YSByZXR1cm4gZnJvbSB0aGUgc2VydmVyLlxuXHQgKiAgQHBhcmFtIHtzdHJpbmd9IGpzb24uc0VjaG8gVHJhY2tpbmcgZmxhZyBmb3IgRGF0YVRhYmxlcyB0byBtYXRjaCByZXF1ZXN0c1xuXHQgKiAgQHBhcmFtIHtpbnR9IGpzb24uaVRvdGFsUmVjb3JkcyBOdW1iZXIgb2YgcmVjb3JkcyBpbiB0aGUgZGF0YSBzZXQsIG5vdCBhY2NvdW50aW5nIGZvciBmaWx0ZXJpbmdcblx0ICogIEBwYXJhbSB7aW50fSBqc29uLmlUb3RhbERpc3BsYXlSZWNvcmRzIE51bWJlciBvZiByZWNvcmRzIGluIHRoZSBkYXRhIHNldCwgYWNjb3VudGluZyBmb3IgZmlsdGVyaW5nXG5cdCAqICBAcGFyYW0ge2FycmF5fSBqc29uLmFhRGF0YSBUaGUgZGF0YSB0byBkaXNwbGF5IG9uIHRoaXMgcGFnZVxuXHQgKiAgQHBhcmFtIHtzdHJpbmd9IFtqc29uLnNDb2x1bW5zXSBDb2x1bW4gb3JkZXJpbmcgKHNOYW1lLCBjb21tYSBzZXBhcmF0ZWQpXG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mbkFqYXhVcGRhdGVEcmF3ICggc2V0dGluZ3MsIGpzb24gKVxuXHR7XG5cdFx0Ly8gdjEuMTAgdXNlcyBjYW1lbENhc2UgdmFyaWFibGVzLCB3aGlsZSAxLjkgdXNlcyBIdW5nYXJpYW4gbm90YXRpb24uXG5cdFx0Ly8gU3VwcG9ydCBib3RoXG5cdFx0dmFyIGNvbXBhdCA9IGZ1bmN0aW9uICggb2xkLCBtb2Rlcm4gKSB7XG5cdFx0XHRyZXR1cm4ganNvbltvbGRdICE9PSB1bmRlZmluZWQgPyBqc29uW29sZF0gOiBqc29uW21vZGVybl07XG5cdFx0fTtcblx0XG5cdFx0dmFyIGRhdGEgPSBfZm5BamF4RGF0YVNyYyggc2V0dGluZ3MsIGpzb24gKTtcblx0XHR2YXIgZHJhdyAgICAgICAgICAgID0gY29tcGF0KCAnc0VjaG8nLCAgICAgICAgICAgICAgICAnZHJhdycgKTtcblx0XHR2YXIgcmVjb3Jkc1RvdGFsICAgID0gY29tcGF0KCAnaVRvdGFsUmVjb3JkcycsICAgICAgICAncmVjb3Jkc1RvdGFsJyApO1xuXHRcdHZhciByZWNvcmRzRmlsdGVyZWQgPSBjb21wYXQoICdpVG90YWxEaXNwbGF5UmVjb3JkcycsICdyZWNvcmRzRmlsdGVyZWQnICk7XG5cdFxuXHRcdGlmICggZHJhdyAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0Ly8gUHJvdGVjdCBhZ2FpbnN0IG91dCBvZiBzZXF1ZW5jZSByZXR1cm5zXG5cdFx0XHRpZiAoIGRyYXcqMSA8IHNldHRpbmdzLmlEcmF3ICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cdFx0XHRzZXR0aW5ncy5pRHJhdyA9IGRyYXcgKiAxO1xuXHRcdH1cblx0XG5cdFx0Ly8gTm8gZGF0YSBpbiByZXR1cm5lZCBvYmplY3QsIHNvIHJhdGhlciB0aGFuIGFuIGFycmF5LCB3ZSBzaG93IGFuIGVtcHR5IHRhYmxlXG5cdFx0aWYgKCAhIGRhdGEgKSB7XG5cdFx0XHRkYXRhID0gW107XG5cdFx0fVxuXHRcblx0XHRfZm5DbGVhclRhYmxlKCBzZXR0aW5ncyApO1xuXHRcdHNldHRpbmdzLl9pUmVjb3Jkc1RvdGFsICAgPSBwYXJzZUludChyZWNvcmRzVG90YWwsIDEwKTtcblx0XHRzZXR0aW5ncy5faVJlY29yZHNEaXNwbGF5ID0gcGFyc2VJbnQocmVjb3Jkc0ZpbHRlcmVkLCAxMCk7XG5cdFxuXHRcdGZvciAoIHZhciBpPTAsIGllbj1kYXRhLmxlbmd0aCA7IGk8aWVuIDsgaSsrICkge1xuXHRcdFx0X2ZuQWRkRGF0YSggc2V0dGluZ3MsIGRhdGFbaV0gKTtcblx0XHR9XG5cdFx0c2V0dGluZ3MuYWlEaXNwbGF5ID0gc2V0dGluZ3MuYWlEaXNwbGF5TWFzdGVyLnNsaWNlKCk7XG5cdFxuXHRcdF9mbkRyYXcoIHNldHRpbmdzLCB0cnVlICk7XG5cdFxuXHRcdGlmICggISBzZXR0aW5ncy5fYkluaXRDb21wbGV0ZSApIHtcblx0XHRcdF9mbkluaXRDb21wbGV0ZSggc2V0dGluZ3MsIGpzb24gKTtcblx0XHR9XG5cdFxuXHRcdF9mblByb2Nlc3NpbmdEaXNwbGF5KCBzZXR0aW5ncywgZmFsc2UgKTtcblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBHZXQgdGhlIGRhdGEgZnJvbSB0aGUgSlNPTiBkYXRhIHNvdXJjZSB0byB1c2UgZm9yIGRyYXdpbmcgYSB0YWJsZS4gVXNpbmdcblx0ICogYF9mbkdldE9iamVjdERhdGFGbmAgYWxsb3dzIHRoZSBkYXRhIHRvIGJlIHNvdXJjZWQgZnJvbSBhIHByb3BlcnR5IG9mIHRoZVxuXHQgKiBzb3VyY2Ugb2JqZWN0LCBvciBmcm9tIGEgcHJvY2Vzc2luZyBmdW5jdGlvbi5cblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBwYXJhbSAge29iamVjdH0ganNvbiBEYXRhIHNvdXJjZSBvYmplY3QgLyBhcnJheSBmcm9tIHRoZSBzZXJ2ZXJcblx0ICogIEByZXR1cm4ge2FycmF5fSBBcnJheSBvZiBkYXRhIHRvIHVzZVxuXHQgKi9cblx0IGZ1bmN0aW9uIF9mbkFqYXhEYXRhU3JjICggb1NldHRpbmdzLCBqc29uLCB3cml0ZSApXG5cdCB7XG5cdFx0dmFyIGRhdGFTcmMgPSAkLmlzUGxhaW5PYmplY3QoIG9TZXR0aW5ncy5hamF4ICkgJiYgb1NldHRpbmdzLmFqYXguZGF0YVNyYyAhPT0gdW5kZWZpbmVkID9cblx0XHRcdG9TZXR0aW5ncy5hamF4LmRhdGFTcmMgOlxuXHRcdFx0b1NldHRpbmdzLnNBamF4RGF0YVByb3A7IC8vIENvbXBhdGliaWxpdHkgd2l0aCAxLjktLlxuXHRcblx0XHRpZiAoICEgd3JpdGUgKSB7XG5cdFx0XHRpZiAoIGRhdGFTcmMgPT09ICdkYXRhJyApIHtcblx0XHRcdFx0Ly8gSWYgdGhlIGRlZmF1bHQsIHRoZW4gd2Ugc3RpbGwgd2FudCB0byBzdXBwb3J0IHRoZSBvbGQgc3R5bGUsIGFuZCBzYWZlbHkgaWdub3JlXG5cdFx0XHRcdC8vIGl0IGlmIHBvc3NpYmxlXG5cdFx0XHRcdHJldHVybiBqc29uLmFhRGF0YSB8fCBqc29uW2RhdGFTcmNdO1xuXHRcdFx0fVxuXHRcblx0XHRcdHJldHVybiBkYXRhU3JjICE9PSBcIlwiID9cblx0XHRcdFx0X2ZuR2V0T2JqZWN0RGF0YUZuKCBkYXRhU3JjICkoIGpzb24gKSA6XG5cdFx0XHRcdGpzb247XG5cdFx0fVxuXHRcblx0XHQvLyBzZXRcblx0XHRfZm5TZXRPYmplY3REYXRhRm4oIGRhdGFTcmMgKSgganNvbiwgd3JpdGUgKTtcblx0fVxuXHRcblx0LyoqXG5cdCAqIEdlbmVyYXRlIHRoZSBub2RlIHJlcXVpcmVkIGZvciBmaWx0ZXJpbmcgdGV4dFxuXHQgKiAgQHJldHVybnMge25vZGV9IEZpbHRlciBjb250cm9sIGVsZW1lbnRcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuRmVhdHVyZUh0bWxGaWx0ZXIgKCBzZXR0aW5ncyApXG5cdHtcblx0XHR2YXIgY2xhc3NlcyA9IHNldHRpbmdzLm9DbGFzc2VzO1xuXHRcdHZhciB0YWJsZUlkID0gc2V0dGluZ3Muc1RhYmxlSWQ7XG5cdFx0dmFyIGxhbmd1YWdlID0gc2V0dGluZ3Mub0xhbmd1YWdlO1xuXHRcdHZhciBwcmV2aW91c1NlYXJjaCA9IHNldHRpbmdzLm9QcmV2aW91c1NlYXJjaDtcblx0XHR2YXIgZmVhdHVyZXMgPSBzZXR0aW5ncy5hYW5GZWF0dXJlcztcblx0XHR2YXIgaW5wdXQgPSAnPGlucHV0IHR5cGU9XCJzZWFyY2hcIiBjbGFzcz1cIicrY2xhc3Nlcy5zRmlsdGVySW5wdXQrJ1wiLz4nO1xuXHRcblx0XHR2YXIgc3RyID0gbGFuZ3VhZ2Uuc1NlYXJjaDtcblx0XHRzdHIgPSBzdHIubWF0Y2goL19JTlBVVF8vKSA/XG5cdFx0XHRzdHIucmVwbGFjZSgnX0lOUFVUXycsIGlucHV0KSA6XG5cdFx0XHRzdHIraW5wdXQ7XG5cdFxuXHRcdHZhciBmaWx0ZXIgPSAkKCc8ZGl2Lz4nLCB7XG5cdFx0XHRcdCdpZCc6ICEgZmVhdHVyZXMuZiA/IHRhYmxlSWQrJ19maWx0ZXInIDogbnVsbCxcblx0XHRcdFx0J2NsYXNzJzogY2xhc3Nlcy5zRmlsdGVyXG5cdFx0XHR9IClcblx0XHRcdC5hcHBlbmQoICQoJzxsYWJlbC8+JyApLmFwcGVuZCggc3RyICkgKTtcblx0XG5cdFx0dmFyIHNlYXJjaEZuID0gZnVuY3Rpb24oZXZlbnQpIHtcblx0XHRcdC8qIFVwZGF0ZSBhbGwgb3RoZXIgZmlsdGVyIGlucHV0IGVsZW1lbnRzIGZvciB0aGUgbmV3IGRpc3BsYXkgKi9cblx0XHRcdHZhciBuID0gZmVhdHVyZXMuZjtcblx0XHRcdHZhciB2YWwgPSAhdGhpcy52YWx1ZSA/IFwiXCIgOiB0aGlzLnZhbHVlOyAvLyBtZW50YWwgSUU4IGZpeCA6LShcblx0XHRcdGlmKHByZXZpb3VzU2VhcmNoLnJldHVybiAmJiBldmVudC5rZXkgIT09IFwiRW50ZXJcIikge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cdFx0XHQvKiBOb3cgZG8gdGhlIGZpbHRlciAqL1xuXHRcdFx0aWYgKCB2YWwgIT0gcHJldmlvdXNTZWFyY2guc1NlYXJjaCApIHtcblx0XHRcdFx0X2ZuRmlsdGVyQ29tcGxldGUoIHNldHRpbmdzLCB7XG5cdFx0XHRcdFx0XCJzU2VhcmNoXCI6IHZhbCxcblx0XHRcdFx0XHRcImJSZWdleFwiOiBwcmV2aW91c1NlYXJjaC5iUmVnZXgsXG5cdFx0XHRcdFx0XCJiU21hcnRcIjogcHJldmlvdXNTZWFyY2guYlNtYXJ0ICxcblx0XHRcdFx0XHRcImJDYXNlSW5zZW5zaXRpdmVcIjogcHJldmlvdXNTZWFyY2guYkNhc2VJbnNlbnNpdGl2ZSxcblx0XHRcdFx0XHRcInJldHVyblwiOiBwcmV2aW91c1NlYXJjaC5yZXR1cm5cblx0XHRcdFx0fSApO1xuXHRcblx0XHRcdFx0Ly8gTmVlZCB0byByZWRyYXcsIHdpdGhvdXQgcmVzb3J0aW5nXG5cdFx0XHRcdHNldHRpbmdzLl9pRGlzcGxheVN0YXJ0ID0gMDtcblx0XHRcdFx0X2ZuRHJhdyggc2V0dGluZ3MgKTtcblx0XHRcdH1cblx0XHR9O1xuXHRcblx0XHR2YXIgc2VhcmNoRGVsYXkgPSBzZXR0aW5ncy5zZWFyY2hEZWxheSAhPT0gbnVsbCA/XG5cdFx0XHRzZXR0aW5ncy5zZWFyY2hEZWxheSA6XG5cdFx0XHRfZm5EYXRhU291cmNlKCBzZXR0aW5ncyApID09PSAnc3NwJyA/XG5cdFx0XHRcdDQwMCA6XG5cdFx0XHRcdDA7XG5cdFxuXHRcdHZhciBqcUZpbHRlciA9ICQoJ2lucHV0JywgZmlsdGVyKVxuXHRcdFx0LnZhbCggcHJldmlvdXNTZWFyY2guc1NlYXJjaCApXG5cdFx0XHQuYXR0ciggJ3BsYWNlaG9sZGVyJywgbGFuZ3VhZ2Uuc1NlYXJjaFBsYWNlaG9sZGVyIClcblx0XHRcdC5vbihcblx0XHRcdFx0J2tleXVwLkRUIHNlYXJjaC5EVCBpbnB1dC5EVCBwYXN0ZS5EVCBjdXQuRFQnLFxuXHRcdFx0XHRzZWFyY2hEZWxheSA/XG5cdFx0XHRcdFx0X2ZuVGhyb3R0bGUoIHNlYXJjaEZuLCBzZWFyY2hEZWxheSApIDpcblx0XHRcdFx0XHRzZWFyY2hGblxuXHRcdFx0KVxuXHRcdFx0Lm9uKCAnbW91c2V1cCcsIGZ1bmN0aW9uKGUpIHtcblx0XHRcdFx0Ly8gRWRnZSBmaXghIEVkZ2UgMTcgZG9lcyBub3QgdHJpZ2dlciBhbnl0aGluZyBvdGhlciB0aGFuIG1vdXNlIGV2ZW50cyB3aGVuIGNsaWNraW5nXG5cdFx0XHRcdC8vIG9uIHRoZSBjbGVhciBpY29uIChFZGdlIGJ1ZyAxNzU4NDUxNSkuIFRoaXMgaXMgc2FmZSBpbiBvdGhlciBicm93c2VycyBhcyBgc2VhcmNoRm5gXG5cdFx0XHRcdC8vIGNoZWNrcyB0aGUgdmFsdWUgdG8gc2VlIGlmIGl0IGhhcyBjaGFuZ2VkLiBJbiBvdGhlciBicm93c2VycyBpdCB3b24ndCBoYXZlLlxuXHRcdFx0XHRzZXRUaW1lb3V0KCBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0c2VhcmNoRm4uY2FsbChqcUZpbHRlclswXSwgZSk7XG5cdFx0XHRcdH0sIDEwKTtcblx0XHRcdH0gKVxuXHRcdFx0Lm9uKCAna2V5cHJlc3MuRFQnLCBmdW5jdGlvbihlKSB7XG5cdFx0XHRcdC8qIFByZXZlbnQgZm9ybSBzdWJtaXNzaW9uICovXG5cdFx0XHRcdGlmICggZS5rZXlDb2RlID09IDEzICkge1xuXHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0fVxuXHRcdFx0fSApXG5cdFx0XHQuYXR0cignYXJpYS1jb250cm9scycsIHRhYmxlSWQpO1xuXHRcblx0XHQvLyBVcGRhdGUgdGhlIGlucHV0IGVsZW1lbnRzIHdoZW5ldmVyIHRoZSB0YWJsZSBpcyBmaWx0ZXJlZFxuXHRcdCQoc2V0dGluZ3MublRhYmxlKS5vbiggJ3NlYXJjaC5kdC5EVCcsIGZ1bmN0aW9uICggZXYsIHMgKSB7XG5cdFx0XHRpZiAoIHNldHRpbmdzID09PSBzICkge1xuXHRcdFx0XHQvLyBJRTkgdGhyb3dzIGFuICd1bmtub3duIGVycm9yJyBpZiBkb2N1bWVudC5hY3RpdmVFbGVtZW50IGlzIHVzZWRcblx0XHRcdFx0Ly8gaW5zaWRlIGFuIGlmcmFtZSBvciBmcmFtZS4uLlxuXHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdGlmICgganFGaWx0ZXJbMF0gIT09IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQgKSB7XG5cdFx0XHRcdFx0XHRqcUZpbHRlci52YWwoIHByZXZpb3VzU2VhcmNoLnNTZWFyY2ggKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0Y2F0Y2ggKCBlICkge31cblx0XHRcdH1cblx0XHR9ICk7XG5cdFxuXHRcdHJldHVybiBmaWx0ZXJbMF07XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogRmlsdGVyIHRoZSB0YWJsZSB1c2luZyBib3RoIHRoZSBnbG9iYWwgZmlsdGVyIGFuZCBjb2x1bW4gYmFzZWQgZmlsdGVyaW5nXG5cdCAqICBAcGFyYW0ge29iamVjdH0gb1NldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAcGFyYW0ge29iamVjdH0gb1NlYXJjaCBzZWFyY2ggaW5mb3JtYXRpb25cblx0ICogIEBwYXJhbSB7aW50fSBbaUZvcmNlXSBmb3JjZSBhIHJlc2VhcmNoIG9mIHRoZSBtYXN0ZXIgYXJyYXkgKDEpIG9yIG5vdCAodW5kZWZpbmVkIG9yIDApXG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mbkZpbHRlckNvbXBsZXRlICggb1NldHRpbmdzLCBvSW5wdXQsIGlGb3JjZSApXG5cdHtcblx0XHR2YXIgb1ByZXZTZWFyY2ggPSBvU2V0dGluZ3Mub1ByZXZpb3VzU2VhcmNoO1xuXHRcdHZhciBhb1ByZXZTZWFyY2ggPSBvU2V0dGluZ3MuYW9QcmVTZWFyY2hDb2xzO1xuXHRcdHZhciBmblNhdmVGaWx0ZXIgPSBmdW5jdGlvbiAoIG9GaWx0ZXIgKSB7XG5cdFx0XHQvKiBTYXZlIHRoZSBmaWx0ZXJpbmcgdmFsdWVzICovXG5cdFx0XHRvUHJldlNlYXJjaC5zU2VhcmNoID0gb0ZpbHRlci5zU2VhcmNoO1xuXHRcdFx0b1ByZXZTZWFyY2guYlJlZ2V4ID0gb0ZpbHRlci5iUmVnZXg7XG5cdFx0XHRvUHJldlNlYXJjaC5iU21hcnQgPSBvRmlsdGVyLmJTbWFydDtcblx0XHRcdG9QcmV2U2VhcmNoLmJDYXNlSW5zZW5zaXRpdmUgPSBvRmlsdGVyLmJDYXNlSW5zZW5zaXRpdmU7XG5cdFx0XHRvUHJldlNlYXJjaC5yZXR1cm4gPSBvRmlsdGVyLnJldHVybjtcblx0XHR9O1xuXHRcdHZhciBmblJlZ2V4ID0gZnVuY3Rpb24gKCBvICkge1xuXHRcdFx0Ly8gQmFja3dhcmRzIGNvbXBhdGliaWxpdHkgd2l0aCB0aGUgYkVzY2FwZVJlZ2V4IG9wdGlvblxuXHRcdFx0cmV0dXJuIG8uYkVzY2FwZVJlZ2V4ICE9PSB1bmRlZmluZWQgPyAhby5iRXNjYXBlUmVnZXggOiBvLmJSZWdleDtcblx0XHR9O1xuXHRcblx0XHQvLyBSZXNvbHZlIGFueSBjb2x1bW4gdHlwZXMgdGhhdCBhcmUgdW5rbm93biBkdWUgdG8gYWRkaXRpb24gb3IgaW52YWxpZGF0aW9uXG5cdFx0Ly8gQHRvZG8gQXMgcGVyIHNvcnQgLSBjYW4gdGhpcyBiZSBtb3ZlZCBpbnRvIGFuIGV2ZW50IGhhbmRsZXI/XG5cdFx0X2ZuQ29sdW1uVHlwZXMoIG9TZXR0aW5ncyApO1xuXHRcblx0XHQvKiBJbiBzZXJ2ZXItc2lkZSBwcm9jZXNzaW5nIGFsbCBmaWx0ZXJpbmcgaXMgZG9uZSBieSB0aGUgc2VydmVyLCBzbyBubyBwb2ludCBoYW5naW5nIGFyb3VuZCBoZXJlICovXG5cdFx0aWYgKCBfZm5EYXRhU291cmNlKCBvU2V0dGluZ3MgKSAhPSAnc3NwJyApXG5cdFx0e1xuXHRcdFx0LyogR2xvYmFsIGZpbHRlciAqL1xuXHRcdFx0X2ZuRmlsdGVyKCBvU2V0dGluZ3MsIG9JbnB1dC5zU2VhcmNoLCBpRm9yY2UsIGZuUmVnZXgob0lucHV0KSwgb0lucHV0LmJTbWFydCwgb0lucHV0LmJDYXNlSW5zZW5zaXRpdmUsIG9JbnB1dC5yZXR1cm4gKTtcblx0XHRcdGZuU2F2ZUZpbHRlciggb0lucHV0ICk7XG5cdFxuXHRcdFx0LyogTm93IGRvIHRoZSBpbmRpdmlkdWFsIGNvbHVtbiBmaWx0ZXIgKi9cblx0XHRcdGZvciAoIHZhciBpPTAgOyBpPGFvUHJldlNlYXJjaC5sZW5ndGggOyBpKysgKVxuXHRcdFx0e1xuXHRcdFx0XHRfZm5GaWx0ZXJDb2x1bW4oIG9TZXR0aW5ncywgYW9QcmV2U2VhcmNoW2ldLnNTZWFyY2gsIGksIGZuUmVnZXgoYW9QcmV2U2VhcmNoW2ldKSxcblx0XHRcdFx0XHRhb1ByZXZTZWFyY2hbaV0uYlNtYXJ0LCBhb1ByZXZTZWFyY2hbaV0uYkNhc2VJbnNlbnNpdGl2ZSApO1xuXHRcdFx0fVxuXHRcblx0XHRcdC8qIEN1c3RvbSBmaWx0ZXJpbmcgKi9cblx0XHRcdF9mbkZpbHRlckN1c3RvbSggb1NldHRpbmdzICk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHR7XG5cdFx0XHRmblNhdmVGaWx0ZXIoIG9JbnB1dCApO1xuXHRcdH1cblx0XG5cdFx0LyogVGVsbCB0aGUgZHJhdyBmdW5jdGlvbiB3ZSBoYXZlIGJlZW4gZmlsdGVyaW5nICovXG5cdFx0b1NldHRpbmdzLmJGaWx0ZXJlZCA9IHRydWU7XG5cdFx0X2ZuQ2FsbGJhY2tGaXJlKCBvU2V0dGluZ3MsIG51bGwsICdzZWFyY2gnLCBbb1NldHRpbmdzXSApO1xuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIEFwcGx5IGN1c3RvbSBmaWx0ZXJpbmcgZnVuY3Rpb25zXG5cdCAqICBAcGFyYW0ge29iamVjdH0gb1NldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mbkZpbHRlckN1c3RvbSggc2V0dGluZ3MgKVxuXHR7XG5cdFx0dmFyIGZpbHRlcnMgPSBEYXRhVGFibGUuZXh0LnNlYXJjaDtcblx0XHR2YXIgZGlzcGxheVJvd3MgPSBzZXR0aW5ncy5haURpc3BsYXk7XG5cdFx0dmFyIHJvdywgcm93SWR4O1xuXHRcblx0XHRmb3IgKCB2YXIgaT0wLCBpZW49ZmlsdGVycy5sZW5ndGggOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdHZhciByb3dzID0gW107XG5cdFxuXHRcdFx0Ly8gTG9vcCBvdmVyIGVhY2ggcm93IGFuZCBzZWUgaWYgaXQgc2hvdWxkIGJlIGluY2x1ZGVkXG5cdFx0XHRmb3IgKCB2YXIgaj0wLCBqZW49ZGlzcGxheVJvd3MubGVuZ3RoIDsgajxqZW4gOyBqKysgKSB7XG5cdFx0XHRcdHJvd0lkeCA9IGRpc3BsYXlSb3dzWyBqIF07XG5cdFx0XHRcdHJvdyA9IHNldHRpbmdzLmFvRGF0YVsgcm93SWR4IF07XG5cdFxuXHRcdFx0XHRpZiAoIGZpbHRlcnNbaV0oIHNldHRpbmdzLCByb3cuX2FGaWx0ZXJEYXRhLCByb3dJZHgsIHJvdy5fYURhdGEsIGogKSApIHtcblx0XHRcdFx0XHRyb3dzLnB1c2goIHJvd0lkeCApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFxuXHRcdFx0Ly8gU28gdGhlIGFycmF5IHJlZmVyZW5jZSBkb2Vzbid0IGJyZWFrIHNldCB0aGUgcmVzdWx0cyBpbnRvIHRoZVxuXHRcdFx0Ly8gZXhpc3RpbmcgYXJyYXlcblx0XHRcdGRpc3BsYXlSb3dzLmxlbmd0aCA9IDA7XG5cdFx0XHQkLm1lcmdlKCBkaXNwbGF5Um93cywgcm93cyApO1xuXHRcdH1cblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBGaWx0ZXIgdGhlIHRhYmxlIG9uIGEgcGVyLWNvbHVtbiBiYXNpc1xuXHQgKiAgQHBhcmFtIHtvYmplY3R9IG9TZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHBhcmFtIHtzdHJpbmd9IHNJbnB1dCBzdHJpbmcgdG8gZmlsdGVyIG9uXG5cdCAqICBAcGFyYW0ge2ludH0gaUNvbHVtbiBjb2x1bW4gdG8gZmlsdGVyXG5cdCAqICBAcGFyYW0ge2Jvb2x9IGJSZWdleCB0cmVhdCBzZWFyY2ggc3RyaW5nIGFzIGEgcmVndWxhciBleHByZXNzaW9uIG9yIG5vdFxuXHQgKiAgQHBhcmFtIHtib29sfSBiU21hcnQgdXNlIHNtYXJ0IGZpbHRlcmluZyBvciBub3Rcblx0ICogIEBwYXJhbSB7Ym9vbH0gYkNhc2VJbnNlbnNpdGl2ZSBEbyBjYXNlIGluc2Vuc2l0aXZlIG1hdGNoaW5nIG9yIG5vdFxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5GaWx0ZXJDb2x1bW4gKCBzZXR0aW5ncywgc2VhcmNoU3RyLCBjb2xJZHgsIHJlZ2V4LCBzbWFydCwgY2FzZUluc2Vuc2l0aXZlIClcblx0e1xuXHRcdGlmICggc2VhcmNoU3RyID09PSAnJyApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFxuXHRcdHZhciBkYXRhO1xuXHRcdHZhciBvdXQgPSBbXTtcblx0XHR2YXIgZGlzcGxheSA9IHNldHRpbmdzLmFpRGlzcGxheTtcblx0XHR2YXIgcnBTZWFyY2ggPSBfZm5GaWx0ZXJDcmVhdGVTZWFyY2goIHNlYXJjaFN0ciwgcmVnZXgsIHNtYXJ0LCBjYXNlSW5zZW5zaXRpdmUgKTtcblx0XG5cdFx0Zm9yICggdmFyIGk9MCA7IGk8ZGlzcGxheS5sZW5ndGggOyBpKysgKSB7XG5cdFx0XHRkYXRhID0gc2V0dGluZ3MuYW9EYXRhWyBkaXNwbGF5W2ldIF0uX2FGaWx0ZXJEYXRhWyBjb2xJZHggXTtcblx0XG5cdFx0XHRpZiAoIHJwU2VhcmNoLnRlc3QoIGRhdGEgKSApIHtcblx0XHRcdFx0b3V0LnB1c2goIGRpc3BsYXlbaV0gKTtcblx0XHRcdH1cblx0XHR9XG5cdFxuXHRcdHNldHRpbmdzLmFpRGlzcGxheSA9IG91dDtcblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBGaWx0ZXIgdGhlIGRhdGEgdGFibGUgYmFzZWQgb24gdXNlciBpbnB1dCBhbmQgZHJhdyB0aGUgdGFibGVcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHBhcmFtIHtzdHJpbmd9IGlucHV0IHN0cmluZyB0byBmaWx0ZXIgb25cblx0ICogIEBwYXJhbSB7aW50fSBmb3JjZSBvcHRpb25hbCAtIGZvcmNlIGEgcmVzZWFyY2ggb2YgdGhlIG1hc3RlciBhcnJheSAoMSkgb3Igbm90ICh1bmRlZmluZWQgb3IgMClcblx0ICogIEBwYXJhbSB7Ym9vbH0gcmVnZXggdHJlYXQgYXMgYSByZWd1bGFyIGV4cHJlc3Npb24gb3Igbm90XG5cdCAqICBAcGFyYW0ge2Jvb2x9IHNtYXJ0IHBlcmZvcm0gc21hcnQgZmlsdGVyaW5nIG9yIG5vdFxuXHQgKiAgQHBhcmFtIHtib29sfSBjYXNlSW5zZW5zaXRpdmUgRG8gY2FzZSBpbnNlbnNpdGl2ZSBtYXRjaGluZyBvciBub3Rcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuRmlsdGVyKCBzZXR0aW5ncywgaW5wdXQsIGZvcmNlLCByZWdleCwgc21hcnQsIGNhc2VJbnNlbnNpdGl2ZSApXG5cdHtcblx0XHR2YXIgcnBTZWFyY2ggPSBfZm5GaWx0ZXJDcmVhdGVTZWFyY2goIGlucHV0LCByZWdleCwgc21hcnQsIGNhc2VJbnNlbnNpdGl2ZSApO1xuXHRcdHZhciBwcmV2U2VhcmNoID0gc2V0dGluZ3Mub1ByZXZpb3VzU2VhcmNoLnNTZWFyY2g7XG5cdFx0dmFyIGRpc3BsYXlNYXN0ZXIgPSBzZXR0aW5ncy5haURpc3BsYXlNYXN0ZXI7XG5cdFx0dmFyIGRpc3BsYXksIGludmFsaWRhdGVkLCBpO1xuXHRcdHZhciBmaWx0ZXJlZCA9IFtdO1xuXHRcblx0XHQvLyBOZWVkIHRvIHRha2UgYWNjb3VudCBvZiBjdXN0b20gZmlsdGVyaW5nIGZ1bmN0aW9ucyAtIGFsd2F5cyBmaWx0ZXJcblx0XHRpZiAoIERhdGFUYWJsZS5leHQuc2VhcmNoLmxlbmd0aCAhPT0gMCApIHtcblx0XHRcdGZvcmNlID0gdHJ1ZTtcblx0XHR9XG5cdFxuXHRcdC8vIENoZWNrIGlmIGFueSBvZiB0aGUgcm93cyB3ZXJlIGludmFsaWRhdGVkXG5cdFx0aW52YWxpZGF0ZWQgPSBfZm5GaWx0ZXJEYXRhKCBzZXR0aW5ncyApO1xuXHRcblx0XHQvLyBJZiB0aGUgaW5wdXQgaXMgYmxhbmsgLSB3ZSBqdXN0IHdhbnQgdGhlIGZ1bGwgZGF0YSBzZXRcblx0XHRpZiAoIGlucHV0Lmxlbmd0aCA8PSAwICkge1xuXHRcdFx0c2V0dGluZ3MuYWlEaXNwbGF5ID0gZGlzcGxheU1hc3Rlci5zbGljZSgpO1xuXHRcdH1cblx0XHRlbHNlIHtcblx0XHRcdC8vIE5ldyBzZWFyY2ggLSBzdGFydCBmcm9tIHRoZSBtYXN0ZXIgYXJyYXlcblx0XHRcdGlmICggaW52YWxpZGF0ZWQgfHxcblx0XHRcdFx0IGZvcmNlIHx8XG5cdFx0XHRcdCByZWdleCB8fFxuXHRcdFx0XHQgcHJldlNlYXJjaC5sZW5ndGggPiBpbnB1dC5sZW5ndGggfHxcblx0XHRcdFx0IGlucHV0LmluZGV4T2YocHJldlNlYXJjaCkgIT09IDAgfHxcblx0XHRcdFx0IHNldHRpbmdzLmJTb3J0ZWQgLy8gT24gcmVzb3J0LCB0aGUgZGlzcGxheSBtYXN0ZXIgbmVlZHMgdG8gYmVcblx0XHRcdFx0ICAgICAgICAgICAgICAgICAgLy8gcmUtZmlsdGVyZWQgc2luY2UgaW5kZXhlcyB3aWxsIGhhdmUgY2hhbmdlZFxuXHRcdFx0KSB7XG5cdFx0XHRcdHNldHRpbmdzLmFpRGlzcGxheSA9IGRpc3BsYXlNYXN0ZXIuc2xpY2UoKTtcblx0XHRcdH1cblx0XG5cdFx0XHQvLyBTZWFyY2ggdGhlIGRpc3BsYXkgYXJyYXlcblx0XHRcdGRpc3BsYXkgPSBzZXR0aW5ncy5haURpc3BsYXk7XG5cdFxuXHRcdFx0Zm9yICggaT0wIDsgaTxkaXNwbGF5Lmxlbmd0aCA7IGkrKyApIHtcblx0XHRcdFx0aWYgKCBycFNlYXJjaC50ZXN0KCBzZXR0aW5ncy5hb0RhdGFbIGRpc3BsYXlbaV0gXS5fc0ZpbHRlclJvdyApICkge1xuXHRcdFx0XHRcdGZpbHRlcmVkLnB1c2goIGRpc3BsYXlbaV0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcblx0XHRcdHNldHRpbmdzLmFpRGlzcGxheSA9IGZpbHRlcmVkO1xuXHRcdH1cblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBCdWlsZCBhIHJlZ3VsYXIgZXhwcmVzc2lvbiBvYmplY3Qgc3VpdGFibGUgZm9yIHNlYXJjaGluZyBhIHRhYmxlXG5cdCAqICBAcGFyYW0ge3N0cmluZ30gc1NlYXJjaCBzdHJpbmcgdG8gc2VhcmNoIGZvclxuXHQgKiAgQHBhcmFtIHtib29sfSBiUmVnZXggdHJlYXQgYXMgYSByZWd1bGFyIGV4cHJlc3Npb24gb3Igbm90XG5cdCAqICBAcGFyYW0ge2Jvb2x9IGJTbWFydCBwZXJmb3JtIHNtYXJ0IGZpbHRlcmluZyBvciBub3Rcblx0ICogIEBwYXJhbSB7Ym9vbH0gYkNhc2VJbnNlbnNpdGl2ZSBEbyBjYXNlIGluc2Vuc2l0aXZlIG1hdGNoaW5nIG9yIG5vdFxuXHQgKiAgQHJldHVybnMge1JlZ0V4cH0gY29uc3RydWN0ZWQgb2JqZWN0XG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mbkZpbHRlckNyZWF0ZVNlYXJjaCggc2VhcmNoLCByZWdleCwgc21hcnQsIGNhc2VJbnNlbnNpdGl2ZSApXG5cdHtcblx0XHRzZWFyY2ggPSByZWdleCA/XG5cdFx0XHRzZWFyY2ggOlxuXHRcdFx0X2ZuRXNjYXBlUmVnZXgoIHNlYXJjaCApO1xuXHRcdFxuXHRcdGlmICggc21hcnQgKSB7XG5cdFx0XHQvKiBGb3Igc21hcnQgZmlsdGVyaW5nIHdlIHdhbnQgdG8gYWxsb3cgdGhlIHNlYXJjaCB0byB3b3JrIHJlZ2FyZGxlc3Mgb2Zcblx0XHRcdCAqIHdvcmQgb3JkZXIuIFdlIGFsc28gd2FudCBkb3VibGUgcXVvdGVkIHRleHQgdG8gYmUgcHJlc2VydmVkLCBzbyB3b3JkXG5cdFx0XHQgKiBvcmRlciBpcyBpbXBvcnRhbnQgLSBhIGxhIGdvb2dsZS4gU28gdGhpcyBpcyB3aGF0IHdlIHdhbnQgdG9cblx0XHRcdCAqIGdlbmVyYXRlOlxuXHRcdFx0ICogXG5cdFx0XHQgKiBeKD89Lio/XFxib25lXFxiKSg/PS4qP1xcYnR3byB0aHJlZVxcYikoPz0uKj9cXGJmb3VyXFxiKS4qJFxuXHRcdFx0ICovXG5cdFx0XHR2YXIgYSA9ICQubWFwKCBzZWFyY2gubWF0Y2goIC9cIlteXCJdK1wifFteIF0rL2cgKSB8fCBbJyddLCBmdW5jdGlvbiAoIHdvcmQgKSB7XG5cdFx0XHRcdGlmICggd29yZC5jaGFyQXQoMCkgPT09ICdcIicgKSB7XG5cdFx0XHRcdFx0dmFyIG0gPSB3b3JkLm1hdGNoKCAvXlwiKC4qKVwiJC8gKTtcblx0XHRcdFx0XHR3b3JkID0gbSA/IG1bMV0gOiB3b3JkO1xuXHRcdFx0XHR9XG5cdFxuXHRcdFx0XHRyZXR1cm4gd29yZC5yZXBsYWNlKCdcIicsICcnKTtcblx0XHRcdH0gKTtcblx0XG5cdFx0XHRzZWFyY2ggPSAnXig/PS4qPycrYS5qb2luKCAnKSg/PS4qPycgKSsnKS4qJCc7XG5cdFx0fVxuXHRcblx0XHRyZXR1cm4gbmV3IFJlZ0V4cCggc2VhcmNoLCBjYXNlSW5zZW5zaXRpdmUgPyAnaScgOiAnJyApO1xuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIEVzY2FwZSBhIHN0cmluZyBzdWNoIHRoYXQgaXQgY2FuIGJlIHVzZWQgaW4gYSByZWd1bGFyIGV4cHJlc3Npb25cblx0ICogIEBwYXJhbSB7c3RyaW5nfSBzVmFsIHN0cmluZyB0byBlc2NhcGVcblx0ICogIEByZXR1cm5zIHtzdHJpbmd9IGVzY2FwZWQgc3RyaW5nXG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdHZhciBfZm5Fc2NhcGVSZWdleCA9IERhdGFUYWJsZS51dGlsLmVzY2FwZVJlZ2V4O1xuXHRcblx0dmFyIF9fZmlsdGVyX2RpdiA9ICQoJzxkaXY+JylbMF07XG5cdHZhciBfX2ZpbHRlcl9kaXZfdGV4dENvbnRlbnQgPSBfX2ZpbHRlcl9kaXYudGV4dENvbnRlbnQgIT09IHVuZGVmaW5lZDtcblx0XG5cdC8vIFVwZGF0ZSB0aGUgZmlsdGVyaW5nIGRhdGEgZm9yIGVhY2ggcm93IGlmIG5lZWRlZCAoYnkgaW52YWxpZGF0aW9uIG9yIGZpcnN0IHJ1bilcblx0ZnVuY3Rpb24gX2ZuRmlsdGVyRGF0YSAoIHNldHRpbmdzIClcblx0e1xuXHRcdHZhciBjb2x1bW5zID0gc2V0dGluZ3MuYW9Db2x1bW5zO1xuXHRcdHZhciBjb2x1bW47XG5cdFx0dmFyIGksIGosIGllbiwgamVuLCBmaWx0ZXJEYXRhLCBjZWxsRGF0YSwgcm93O1xuXHRcdHZhciB3YXNJbnZhbGlkYXRlZCA9IGZhbHNlO1xuXHRcblx0XHRmb3IgKCBpPTAsIGllbj1zZXR0aW5ncy5hb0RhdGEubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRyb3cgPSBzZXR0aW5ncy5hb0RhdGFbaV07XG5cdFxuXHRcdFx0aWYgKCAhIHJvdy5fYUZpbHRlckRhdGEgKSB7XG5cdFx0XHRcdGZpbHRlckRhdGEgPSBbXTtcblx0XG5cdFx0XHRcdGZvciAoIGo9MCwgamVuPWNvbHVtbnMubGVuZ3RoIDsgajxqZW4gOyBqKysgKSB7XG5cdFx0XHRcdFx0Y29sdW1uID0gY29sdW1uc1tqXTtcblx0XG5cdFx0XHRcdFx0aWYgKCBjb2x1bW4uYlNlYXJjaGFibGUgKSB7XG5cdFx0XHRcdFx0XHRjZWxsRGF0YSA9IF9mbkdldENlbGxEYXRhKCBzZXR0aW5ncywgaSwgaiwgJ2ZpbHRlcicgKTtcblx0XG5cdFx0XHRcdFx0XHQvLyBTZWFyY2ggaW4gRGF0YVRhYmxlcyAxLjEwIGlzIHN0cmluZyBiYXNlZC4gSW4gMS4xMSB0aGlzXG5cdFx0XHRcdFx0XHQvLyBzaG91bGQgYmUgYWx0ZXJlZCB0byBhbHNvIGFsbG93IHN0cmljdCB0eXBlIGNoZWNraW5nLlxuXHRcdFx0XHRcdFx0aWYgKCBjZWxsRGF0YSA9PT0gbnVsbCApIHtcblx0XHRcdFx0XHRcdFx0Y2VsbERhdGEgPSAnJztcblx0XHRcdFx0XHRcdH1cblx0XG5cdFx0XHRcdFx0XHRpZiAoIHR5cGVvZiBjZWxsRGF0YSAhPT0gJ3N0cmluZycgJiYgY2VsbERhdGEudG9TdHJpbmcgKSB7XG5cdFx0XHRcdFx0XHRcdGNlbGxEYXRhID0gY2VsbERhdGEudG9TdHJpbmcoKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRjZWxsRGF0YSA9ICcnO1xuXHRcdFx0XHRcdH1cblx0XG5cdFx0XHRcdFx0Ly8gSWYgaXQgbG9va3MgbGlrZSB0aGVyZSBpcyBhbiBIVE1MIGVudGl0eSBpbiB0aGUgc3RyaW5nLFxuXHRcdFx0XHRcdC8vIGF0dGVtcHQgdG8gZGVjb2RlIGl0IHNvIHNvcnRpbmcgd29ya3MgYXMgZXhwZWN0ZWQuIE5vdGUgdGhhdFxuXHRcdFx0XHRcdC8vIHdlIGNvdWxkIHVzZSBhIHNpbmdsZSBsaW5lIG9mIGpRdWVyeSB0byBkbyB0aGlzLCBidXQgdGhlIERPTVxuXHRcdFx0XHRcdC8vIG1ldGhvZCB1c2VkIGhlcmUgaXMgbXVjaCBmYXN0ZXIgaHR0cDovL2pzcGVyZi5jb20vaHRtbC1kZWNvZGVcblx0XHRcdFx0XHRpZiAoIGNlbGxEYXRhLmluZGV4T2YgJiYgY2VsbERhdGEuaW5kZXhPZignJicpICE9PSAtMSApIHtcblx0XHRcdFx0XHRcdF9fZmlsdGVyX2Rpdi5pbm5lckhUTUwgPSBjZWxsRGF0YTtcblx0XHRcdFx0XHRcdGNlbGxEYXRhID0gX19maWx0ZXJfZGl2X3RleHRDb250ZW50ID9cblx0XHRcdFx0XHRcdFx0X19maWx0ZXJfZGl2LnRleHRDb250ZW50IDpcblx0XHRcdFx0XHRcdFx0X19maWx0ZXJfZGl2LmlubmVyVGV4dDtcblx0XHRcdFx0XHR9XG5cdFxuXHRcdFx0XHRcdGlmICggY2VsbERhdGEucmVwbGFjZSApIHtcblx0XHRcdFx0XHRcdGNlbGxEYXRhID0gY2VsbERhdGEucmVwbGFjZSgvW1xcclxcblxcdTIwMjhdL2csICcnKTtcblx0XHRcdFx0XHR9XG5cdFxuXHRcdFx0XHRcdGZpbHRlckRhdGEucHVzaCggY2VsbERhdGEgKTtcblx0XHRcdFx0fVxuXHRcblx0XHRcdFx0cm93Ll9hRmlsdGVyRGF0YSA9IGZpbHRlckRhdGE7XG5cdFx0XHRcdHJvdy5fc0ZpbHRlclJvdyA9IGZpbHRlckRhdGEuam9pbignICAnKTtcblx0XHRcdFx0d2FzSW52YWxpZGF0ZWQgPSB0cnVlO1xuXHRcdFx0fVxuXHRcdH1cblx0XG5cdFx0cmV0dXJuIHdhc0ludmFsaWRhdGVkO1xuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIENvbnZlcnQgZnJvbSB0aGUgaW50ZXJuYWwgSHVuZ2FyaWFuIG5vdGF0aW9uIHRvIGNhbWVsQ2FzZSBmb3IgZXh0ZXJuYWxcblx0ICogaW50ZXJhY3Rpb25cblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvYmogT2JqZWN0IHRvIGNvbnZlcnRcblx0ICogIEByZXR1cm5zIHtvYmplY3R9IEludmVydGVkIG9iamVjdFxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5TZWFyY2hUb0NhbWVsICggb2JqIClcblx0e1xuXHRcdHJldHVybiB7XG5cdFx0XHRzZWFyY2g6ICAgICAgICAgIG9iai5zU2VhcmNoLFxuXHRcdFx0c21hcnQ6ICAgICAgICAgICBvYmouYlNtYXJ0LFxuXHRcdFx0cmVnZXg6ICAgICAgICAgICBvYmouYlJlZ2V4LFxuXHRcdFx0Y2FzZUluc2Vuc2l0aXZlOiBvYmouYkNhc2VJbnNlbnNpdGl2ZVxuXHRcdH07XG5cdH1cblx0XG5cdFxuXHRcblx0LyoqXG5cdCAqIENvbnZlcnQgZnJvbSBjYW1lbENhc2Ugbm90YXRpb24gdG8gdGhlIGludGVybmFsIEh1bmdhcmlhbi4gV2UgY291bGQgdXNlIHRoZVxuXHQgKiBIdW5nYXJpYW4gY29udmVydCBmdW5jdGlvbiBoZXJlLCBidXQgdGhpcyBpcyBjbGVhbmVyXG5cdCAqICBAcGFyYW0ge29iamVjdH0gb2JqIE9iamVjdCB0byBjb252ZXJ0XG5cdCAqICBAcmV0dXJucyB7b2JqZWN0fSBJbnZlcnRlZCBvYmplY3Rcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuU2VhcmNoVG9IdW5nICggb2JqIClcblx0e1xuXHRcdHJldHVybiB7XG5cdFx0XHRzU2VhcmNoOiAgICAgICAgICBvYmouc2VhcmNoLFxuXHRcdFx0YlNtYXJ0OiAgICAgICAgICAgb2JqLnNtYXJ0LFxuXHRcdFx0YlJlZ2V4OiAgICAgICAgICAgb2JqLnJlZ2V4LFxuXHRcdFx0YkNhc2VJbnNlbnNpdGl2ZTogb2JqLmNhc2VJbnNlbnNpdGl2ZVxuXHRcdH07XG5cdH1cblx0XG5cdC8qKlxuXHQgKiBHZW5lcmF0ZSB0aGUgbm9kZSByZXF1aXJlZCBmb3IgdGhlIGluZm8gZGlzcGxheVxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IG9TZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHJldHVybnMge25vZGV9IEluZm9ybWF0aW9uIGVsZW1lbnRcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuRmVhdHVyZUh0bWxJbmZvICggc2V0dGluZ3MgKVxuXHR7XG5cdFx0dmFyXG5cdFx0XHR0aWQgPSBzZXR0aW5ncy5zVGFibGVJZCxcblx0XHRcdG5vZGVzID0gc2V0dGluZ3MuYWFuRmVhdHVyZXMuaSxcblx0XHRcdG4gPSAkKCc8ZGl2Lz4nLCB7XG5cdFx0XHRcdCdjbGFzcyc6IHNldHRpbmdzLm9DbGFzc2VzLnNJbmZvLFxuXHRcdFx0XHQnaWQnOiAhIG5vZGVzID8gdGlkKydfaW5mbycgOiBudWxsXG5cdFx0XHR9ICk7XG5cdFxuXHRcdGlmICggISBub2RlcyApIHtcblx0XHRcdC8vIFVwZGF0ZSBkaXNwbGF5IG9uIGVhY2ggZHJhd1xuXHRcdFx0c2V0dGluZ3MuYW9EcmF3Q2FsbGJhY2sucHVzaCgge1xuXHRcdFx0XHRcImZuXCI6IF9mblVwZGF0ZUluZm8sXG5cdFx0XHRcdFwic05hbWVcIjogXCJpbmZvcm1hdGlvblwiXG5cdFx0XHR9ICk7XG5cdFxuXHRcdFx0blxuXHRcdFx0XHQuYXR0ciggJ3JvbGUnLCAnc3RhdHVzJyApXG5cdFx0XHRcdC5hdHRyKCAnYXJpYS1saXZlJywgJ3BvbGl0ZScgKTtcblx0XG5cdFx0XHQvLyBUYWJsZSBpcyBkZXNjcmliZWQgYnkgb3VyIGluZm8gZGl2XG5cdFx0XHQkKHNldHRpbmdzLm5UYWJsZSkuYXR0ciggJ2FyaWEtZGVzY3JpYmVkYnknLCB0aWQrJ19pbmZvJyApO1xuXHRcdH1cblx0XG5cdFx0cmV0dXJuIG5bMF07XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogVXBkYXRlIHRoZSBpbmZvcm1hdGlvbiBlbGVtZW50cyBpbiB0aGUgZGlzcGxheVxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IHNldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mblVwZGF0ZUluZm8gKCBzZXR0aW5ncyApXG5cdHtcblx0XHQvKiBTaG93IGluZm9ybWF0aW9uIGFib3V0IHRoZSB0YWJsZSAqL1xuXHRcdHZhciBub2RlcyA9IHNldHRpbmdzLmFhbkZlYXR1cmVzLmk7XG5cdFx0aWYgKCBub2Rlcy5sZW5ndGggPT09IDAgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcblx0XHR2YXJcblx0XHRcdGxhbmcgID0gc2V0dGluZ3Mub0xhbmd1YWdlLFxuXHRcdFx0c3RhcnQgPSBzZXR0aW5ncy5faURpc3BsYXlTdGFydCsxLFxuXHRcdFx0ZW5kICAgPSBzZXR0aW5ncy5mbkRpc3BsYXlFbmQoKSxcblx0XHRcdG1heCAgID0gc2V0dGluZ3MuZm5SZWNvcmRzVG90YWwoKSxcblx0XHRcdHRvdGFsID0gc2V0dGluZ3MuZm5SZWNvcmRzRGlzcGxheSgpLFxuXHRcdFx0b3V0ICAgPSB0b3RhbCA/XG5cdFx0XHRcdGxhbmcuc0luZm8gOlxuXHRcdFx0XHRsYW5nLnNJbmZvRW1wdHk7XG5cdFxuXHRcdGlmICggdG90YWwgIT09IG1heCApIHtcblx0XHRcdC8qIFJlY29yZCBzZXQgYWZ0ZXIgZmlsdGVyaW5nICovXG5cdFx0XHRvdXQgKz0gJyAnICsgbGFuZy5zSW5mb0ZpbHRlcmVkO1xuXHRcdH1cblx0XG5cdFx0Ly8gQ29udmVydCB0aGUgbWFjcm9zXG5cdFx0b3V0ICs9IGxhbmcuc0luZm9Qb3N0Rml4O1xuXHRcdG91dCA9IF9mbkluZm9NYWNyb3MoIHNldHRpbmdzLCBvdXQgKTtcblx0XG5cdFx0dmFyIGNhbGxiYWNrID0gbGFuZy5mbkluZm9DYWxsYmFjaztcblx0XHRpZiAoIGNhbGxiYWNrICE9PSBudWxsICkge1xuXHRcdFx0b3V0ID0gY2FsbGJhY2suY2FsbCggc2V0dGluZ3Mub0luc3RhbmNlLFxuXHRcdFx0XHRzZXR0aW5ncywgc3RhcnQsIGVuZCwgbWF4LCB0b3RhbCwgb3V0XG5cdFx0XHQpO1xuXHRcdH1cblx0XG5cdFx0JChub2RlcykuaHRtbCggb3V0ICk7XG5cdH1cblx0XG5cdFxuXHRmdW5jdGlvbiBfZm5JbmZvTWFjcm9zICggc2V0dGluZ3MsIHN0ciApXG5cdHtcblx0XHQvLyBXaGVuIGluZmluaXRlIHNjcm9sbGluZywgd2UgYXJlIGFsd2F5cyBzdGFydGluZyBhdCAxLiBfaURpc3BsYXlTdGFydCBpcyB1c2VkIG9ubHlcblx0XHQvLyBpbnRlcm5hbGx5XG5cdFx0dmFyXG5cdFx0XHRmb3JtYXR0ZXIgID0gc2V0dGluZ3MuZm5Gb3JtYXROdW1iZXIsXG5cdFx0XHRzdGFydCAgICAgID0gc2V0dGluZ3MuX2lEaXNwbGF5U3RhcnQrMSxcblx0XHRcdGxlbiAgICAgICAgPSBzZXR0aW5ncy5faURpc3BsYXlMZW5ndGgsXG5cdFx0XHR2aXMgICAgICAgID0gc2V0dGluZ3MuZm5SZWNvcmRzRGlzcGxheSgpLFxuXHRcdFx0YWxsICAgICAgICA9IGxlbiA9PT0gLTE7XG5cdFxuXHRcdHJldHVybiBzdHIuXG5cdFx0XHRyZXBsYWNlKC9fU1RBUlRfL2csIGZvcm1hdHRlci5jYWxsKCBzZXR0aW5ncywgc3RhcnQgKSApLlxuXHRcdFx0cmVwbGFjZSgvX0VORF8vZywgICBmb3JtYXR0ZXIuY2FsbCggc2V0dGluZ3MsIHNldHRpbmdzLmZuRGlzcGxheUVuZCgpICkgKS5cblx0XHRcdHJlcGxhY2UoL19NQVhfL2csICAgZm9ybWF0dGVyLmNhbGwoIHNldHRpbmdzLCBzZXR0aW5ncy5mblJlY29yZHNUb3RhbCgpICkgKS5cblx0XHRcdHJlcGxhY2UoL19UT1RBTF8vZywgZm9ybWF0dGVyLmNhbGwoIHNldHRpbmdzLCB2aXMgKSApLlxuXHRcdFx0cmVwbGFjZSgvX1BBR0VfL2csICBmb3JtYXR0ZXIuY2FsbCggc2V0dGluZ3MsIGFsbCA/IDEgOiBNYXRoLmNlaWwoIHN0YXJ0IC8gbGVuICkgKSApLlxuXHRcdFx0cmVwbGFjZSgvX1BBR0VTXy9nLCBmb3JtYXR0ZXIuY2FsbCggc2V0dGluZ3MsIGFsbCA/IDEgOiBNYXRoLmNlaWwoIHZpcyAvIGxlbiApICkgKTtcblx0fVxuXHRcblx0XG5cdFxuXHQvKipcblx0ICogRHJhdyB0aGUgdGFibGUgZm9yIHRoZSBmaXJzdCB0aW1lLCBhZGRpbmcgYWxsIHJlcXVpcmVkIGZlYXR1cmVzXG5cdCAqICBAcGFyYW0ge29iamVjdH0gc2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuSW5pdGlhbGlzZSAoIHNldHRpbmdzIClcblx0e1xuXHRcdHZhciBpLCBpTGVuLCBpQWpheFN0YXJ0PXNldHRpbmdzLmlJbml0RGlzcGxheVN0YXJ0O1xuXHRcdHZhciBjb2x1bW5zID0gc2V0dGluZ3MuYW9Db2x1bW5zLCBjb2x1bW47XG5cdFx0dmFyIGZlYXR1cmVzID0gc2V0dGluZ3Mub0ZlYXR1cmVzO1xuXHRcdHZhciBkZWZlckxvYWRpbmcgPSBzZXR0aW5ncy5iRGVmZXJMb2FkaW5nOyAvLyB2YWx1ZSBtb2RpZmllZCBieSB0aGUgZHJhd1xuXHRcblx0XHQvKiBFbnN1cmUgdGhhdCB0aGUgdGFibGUgZGF0YSBpcyBmdWxseSBpbml0aWFsaXNlZCAqL1xuXHRcdGlmICggISBzZXR0aW5ncy5iSW5pdGlhbGlzZWQgKSB7XG5cdFx0XHRzZXRUaW1lb3V0KCBmdW5jdGlvbigpeyBfZm5Jbml0aWFsaXNlKCBzZXR0aW5ncyApOyB9LCAyMDAgKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFxuXHRcdC8qIFNob3cgdGhlIGRpc3BsYXkgSFRNTCBvcHRpb25zICovXG5cdFx0X2ZuQWRkT3B0aW9uc0h0bWwoIHNldHRpbmdzICk7XG5cdFxuXHRcdC8qIEJ1aWxkIGFuZCBkcmF3IHRoZSBoZWFkZXIgLyBmb290ZXIgZm9yIHRoZSB0YWJsZSAqL1xuXHRcdF9mbkJ1aWxkSGVhZCggc2V0dGluZ3MgKTtcblx0XHRfZm5EcmF3SGVhZCggc2V0dGluZ3MsIHNldHRpbmdzLmFvSGVhZGVyICk7XG5cdFx0X2ZuRHJhd0hlYWQoIHNldHRpbmdzLCBzZXR0aW5ncy5hb0Zvb3RlciApO1xuXHRcblx0XHQvKiBPa2F5IHRvIHNob3cgdGhhdCBzb21ldGhpbmcgaXMgZ29pbmcgb24gbm93ICovXG5cdFx0X2ZuUHJvY2Vzc2luZ0Rpc3BsYXkoIHNldHRpbmdzLCB0cnVlICk7XG5cdFxuXHRcdC8qIENhbGN1bGF0ZSBzaXplcyBmb3IgY29sdW1ucyAqL1xuXHRcdGlmICggZmVhdHVyZXMuYkF1dG9XaWR0aCApIHtcblx0XHRcdF9mbkNhbGN1bGF0ZUNvbHVtbldpZHRocyggc2V0dGluZ3MgKTtcblx0XHR9XG5cdFxuXHRcdGZvciAoIGk9MCwgaUxlbj1jb2x1bW5zLmxlbmd0aCA7IGk8aUxlbiA7IGkrKyApIHtcblx0XHRcdGNvbHVtbiA9IGNvbHVtbnNbaV07XG5cdFxuXHRcdFx0aWYgKCBjb2x1bW4uc1dpZHRoICkge1xuXHRcdFx0XHRjb2x1bW4ublRoLnN0eWxlLndpZHRoID0gX2ZuU3RyaW5nVG9Dc3MoIGNvbHVtbi5zV2lkdGggKTtcblx0XHRcdH1cblx0XHR9XG5cdFxuXHRcdF9mbkNhbGxiYWNrRmlyZSggc2V0dGluZ3MsIG51bGwsICdwcmVJbml0JywgW3NldHRpbmdzXSApO1xuXHRcblx0XHQvLyBJZiB0aGVyZSBpcyBkZWZhdWx0IHNvcnRpbmcgcmVxdWlyZWQgLSBsZXQncyBkbyBpdC4gVGhlIHNvcnQgZnVuY3Rpb25cblx0XHQvLyB3aWxsIGRvIHRoZSBkcmF3aW5nIGZvciB1cy4gT3RoZXJ3aXNlIHdlIGRyYXcgdGhlIHRhYmxlIHJlZ2FyZGxlc3Mgb2YgdGhlXG5cdFx0Ly8gQWpheCBzb3VyY2UgLSB0aGlzIGFsbG93cyB0aGUgdGFibGUgdG8gbG9vayBpbml0aWFsaXNlZCBmb3IgQWpheCBzb3VyY2luZ1xuXHRcdC8vIGRhdGEgKHNob3cgJ2xvYWRpbmcnIG1lc3NhZ2UgcG9zc2libHkpXG5cdFx0X2ZuUmVEcmF3KCBzZXR0aW5ncyApO1xuXHRcblx0XHQvLyBTZXJ2ZXItc2lkZSBwcm9jZXNzaW5nIGluaXQgY29tcGxldGUgaXMgZG9uZSBieSBfZm5BamF4VXBkYXRlRHJhd1xuXHRcdHZhciBkYXRhU3JjID0gX2ZuRGF0YVNvdXJjZSggc2V0dGluZ3MgKTtcblx0XHRpZiAoIGRhdGFTcmMgIT0gJ3NzcCcgfHwgZGVmZXJMb2FkaW5nICkge1xuXHRcdFx0Ly8gaWYgdGhlcmUgaXMgYW4gYWpheCBzb3VyY2UgbG9hZCB0aGUgZGF0YVxuXHRcdFx0aWYgKCBkYXRhU3JjID09ICdhamF4JyApIHtcblx0XHRcdFx0X2ZuQnVpbGRBamF4KCBzZXR0aW5ncywgW10sIGZ1bmN0aW9uKGpzb24pIHtcblx0XHRcdFx0XHR2YXIgYURhdGEgPSBfZm5BamF4RGF0YVNyYyggc2V0dGluZ3MsIGpzb24gKTtcblx0XG5cdFx0XHRcdFx0Ly8gR290IHRoZSBkYXRhIC0gYWRkIGl0IHRvIHRoZSB0YWJsZVxuXHRcdFx0XHRcdGZvciAoIGk9MCA7IGk8YURhdGEubGVuZ3RoIDsgaSsrICkge1xuXHRcdFx0XHRcdFx0X2ZuQWRkRGF0YSggc2V0dGluZ3MsIGFEYXRhW2ldICk7XG5cdFx0XHRcdFx0fVxuXHRcblx0XHRcdFx0XHQvLyBSZXNldCB0aGUgaW5pdCBkaXNwbGF5IGZvciBjb29raWUgc2F2aW5nLiBXZSd2ZSBhbHJlYWR5IGRvbmVcblx0XHRcdFx0XHQvLyBhIGZpbHRlciwgYW5kIHRoZXJlZm9yZSBjbGVhcmVkIGl0IGJlZm9yZS4gU28gd2UgbmVlZCB0byBtYWtlXG5cdFx0XHRcdFx0Ly8gaXQgYXBwZWFyICdmcmVzaCdcblx0XHRcdFx0XHRzZXR0aW5ncy5pSW5pdERpc3BsYXlTdGFydCA9IGlBamF4U3RhcnQ7XG5cdFxuXHRcdFx0XHRcdF9mblJlRHJhdyggc2V0dGluZ3MgKTtcblx0XG5cdFx0XHRcdFx0X2ZuUHJvY2Vzc2luZ0Rpc3BsYXkoIHNldHRpbmdzLCBmYWxzZSApO1xuXHRcdFx0XHRcdF9mbkluaXRDb21wbGV0ZSggc2V0dGluZ3MsIGpzb24gKTtcblx0XHRcdFx0fSwgc2V0dGluZ3MgKTtcblx0XHRcdH1cblx0XHRcdGVsc2Uge1xuXHRcdFx0XHRfZm5Qcm9jZXNzaW5nRGlzcGxheSggc2V0dGluZ3MsIGZhbHNlICk7XG5cdFx0XHRcdF9mbkluaXRDb21wbGV0ZSggc2V0dGluZ3MgKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogRHJhdyB0aGUgdGFibGUgZm9yIHRoZSBmaXJzdCB0aW1lLCBhZGRpbmcgYWxsIHJlcXVpcmVkIGZlYXR1cmVzXG5cdCAqICBAcGFyYW0ge29iamVjdH0gb1NldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAcGFyYW0ge29iamVjdH0gW2pzb25dIEpTT04gZnJvbSB0aGUgc2VydmVyIHRoYXQgY29tcGxldGVkIHRoZSB0YWJsZSwgaWYgdXNpbmcgQWpheCBzb3VyY2Vcblx0ICogICAgd2l0aCBjbGllbnQtc2lkZSBwcm9jZXNzaW5nIChvcHRpb25hbClcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuSW5pdENvbXBsZXRlICggc2V0dGluZ3MsIGpzb24gKVxuXHR7XG5cdFx0c2V0dGluZ3MuX2JJbml0Q29tcGxldGUgPSB0cnVlO1xuXHRcblx0XHQvLyBXaGVuIGRhdGEgd2FzIGFkZGVkIGFmdGVyIHRoZSBpbml0aWFsaXNhdGlvbiAoZGF0YSBvciBBamF4KSB3ZSBuZWVkIHRvXG5cdFx0Ly8gY2FsY3VsYXRlIHRoZSBjb2x1bW4gc2l6aW5nXG5cdFx0aWYgKCBqc29uIHx8IHNldHRpbmdzLm9Jbml0LmFhRGF0YSApIHtcblx0XHRcdF9mbkFkanVzdENvbHVtblNpemluZyggc2V0dGluZ3MgKTtcblx0XHR9XG5cdFxuXHRcdF9mbkNhbGxiYWNrRmlyZSggc2V0dGluZ3MsIG51bGwsICdwbHVnaW4taW5pdCcsIFtzZXR0aW5ncywganNvbl0gKTtcblx0XHRfZm5DYWxsYmFja0ZpcmUoIHNldHRpbmdzLCAnYW9Jbml0Q29tcGxldGUnLCAnaW5pdCcsIFtzZXR0aW5ncywganNvbl0gKTtcblx0fVxuXHRcblx0XG5cdGZ1bmN0aW9uIF9mbkxlbmd0aENoYW5nZSAoIHNldHRpbmdzLCB2YWwgKVxuXHR7XG5cdFx0dmFyIGxlbiA9IHBhcnNlSW50KCB2YWwsIDEwICk7XG5cdFx0c2V0dGluZ3MuX2lEaXNwbGF5TGVuZ3RoID0gbGVuO1xuXHRcblx0XHRfZm5MZW5ndGhPdmVyZmxvdyggc2V0dGluZ3MgKTtcblx0XG5cdFx0Ly8gRmlyZSBsZW5ndGggY2hhbmdlIGV2ZW50XG5cdFx0X2ZuQ2FsbGJhY2tGaXJlKCBzZXR0aW5ncywgbnVsbCwgJ2xlbmd0aCcsIFtzZXR0aW5ncywgbGVuXSApO1xuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIEdlbmVyYXRlIHRoZSBub2RlIHJlcXVpcmVkIGZvciB1c2VyIGRpc3BsYXkgbGVuZ3RoIGNoYW5naW5nXG5cdCAqICBAcGFyYW0ge29iamVjdH0gc2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEByZXR1cm5zIHtub2RlfSBEaXNwbGF5IGxlbmd0aCBmZWF0dXJlIG5vZGVcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuRmVhdHVyZUh0bWxMZW5ndGggKCBzZXR0aW5ncyApXG5cdHtcblx0XHR2YXJcblx0XHRcdGNsYXNzZXMgID0gc2V0dGluZ3Mub0NsYXNzZXMsXG5cdFx0XHR0YWJsZUlkICA9IHNldHRpbmdzLnNUYWJsZUlkLFxuXHRcdFx0bWVudSAgICAgPSBzZXR0aW5ncy5hTGVuZ3RoTWVudSxcblx0XHRcdGQyICAgICAgID0gQXJyYXkuaXNBcnJheSggbWVudVswXSApLFxuXHRcdFx0bGVuZ3RocyAgPSBkMiA/IG1lbnVbMF0gOiBtZW51LFxuXHRcdFx0bGFuZ3VhZ2UgPSBkMiA/IG1lbnVbMV0gOiBtZW51O1xuXHRcblx0XHR2YXIgc2VsZWN0ID0gJCgnPHNlbGVjdC8+Jywge1xuXHRcdFx0J25hbWUnOiAgICAgICAgICB0YWJsZUlkKydfbGVuZ3RoJyxcblx0XHRcdCdhcmlhLWNvbnRyb2xzJzogdGFibGVJZCxcblx0XHRcdCdjbGFzcyc6ICAgICAgICAgY2xhc3Nlcy5zTGVuZ3RoU2VsZWN0XG5cdFx0fSApO1xuXHRcblx0XHRmb3IgKCB2YXIgaT0wLCBpZW49bGVuZ3Rocy5sZW5ndGggOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdHNlbGVjdFswXVsgaSBdID0gbmV3IE9wdGlvbihcblx0XHRcdFx0dHlwZW9mIGxhbmd1YWdlW2ldID09PSAnbnVtYmVyJyA/XG5cdFx0XHRcdFx0c2V0dGluZ3MuZm5Gb3JtYXROdW1iZXIoIGxhbmd1YWdlW2ldICkgOlxuXHRcdFx0XHRcdGxhbmd1YWdlW2ldLFxuXHRcdFx0XHRsZW5ndGhzW2ldXG5cdFx0XHQpO1xuXHRcdH1cblx0XG5cdFx0dmFyIGRpdiA9ICQoJzxkaXY+PGxhYmVsLz48L2Rpdj4nKS5hZGRDbGFzcyggY2xhc3Nlcy5zTGVuZ3RoICk7XG5cdFx0aWYgKCAhIHNldHRpbmdzLmFhbkZlYXR1cmVzLmwgKSB7XG5cdFx0XHRkaXZbMF0uaWQgPSB0YWJsZUlkKydfbGVuZ3RoJztcblx0XHR9XG5cdFxuXHRcdGRpdi5jaGlsZHJlbigpLmFwcGVuZChcblx0XHRcdHNldHRpbmdzLm9MYW5ndWFnZS5zTGVuZ3RoTWVudS5yZXBsYWNlKCAnX01FTlVfJywgc2VsZWN0WzBdLm91dGVySFRNTCApXG5cdFx0KTtcblx0XG5cdFx0Ly8gQ2FuJ3QgdXNlIGBzZWxlY3RgIHZhcmlhYmxlIGFzIHVzZXIgbWlnaHQgcHJvdmlkZSB0aGVpciBvd24gYW5kIHRoZVxuXHRcdC8vIHJlZmVyZW5jZSBpcyBicm9rZW4gYnkgdGhlIHVzZSBvZiBvdXRlckhUTUxcblx0XHQkKCdzZWxlY3QnLCBkaXYpXG5cdFx0XHQudmFsKCBzZXR0aW5ncy5faURpc3BsYXlMZW5ndGggKVxuXHRcdFx0Lm9uKCAnY2hhbmdlLkRUJywgZnVuY3Rpb24oZSkge1xuXHRcdFx0XHRfZm5MZW5ndGhDaGFuZ2UoIHNldHRpbmdzLCAkKHRoaXMpLnZhbCgpICk7XG5cdFx0XHRcdF9mbkRyYXcoIHNldHRpbmdzICk7XG5cdFx0XHR9ICk7XG5cdFxuXHRcdC8vIFVwZGF0ZSBub2RlIHZhbHVlIHdoZW5ldmVyIGFueXRoaW5nIGNoYW5nZXMgdGhlIHRhYmxlJ3MgbGVuZ3RoXG5cdFx0JChzZXR0aW5ncy5uVGFibGUpLm9uKCAnbGVuZ3RoLmR0LkRUJywgZnVuY3Rpb24gKGUsIHMsIGxlbikge1xuXHRcdFx0aWYgKCBzZXR0aW5ncyA9PT0gcyApIHtcblx0XHRcdFx0JCgnc2VsZWN0JywgZGl2KS52YWwoIGxlbiApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0XG5cdFx0cmV0dXJuIGRpdlswXTtcblx0fVxuXHRcblx0XG5cdFxuXHQvKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKlxuXHQgKiBOb3RlIHRoYXQgbW9zdCBvZiB0aGUgcGFnaW5nIGxvZ2ljIGlzIGRvbmUgaW5cblx0ICogRGF0YVRhYmxlLmV4dC5wYWdlclxuXHQgKi9cblx0XG5cdC8qKlxuXHQgKiBHZW5lcmF0ZSB0aGUgbm9kZSByZXF1aXJlZCBmb3IgZGVmYXVsdCBwYWdpbmF0aW9uXG5cdCAqICBAcGFyYW0ge29iamVjdH0gb1NldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAcmV0dXJucyB7bm9kZX0gUGFnaW5hdGlvbiBmZWF0dXJlIG5vZGVcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuRmVhdHVyZUh0bWxQYWdpbmF0ZSAoIHNldHRpbmdzIClcblx0e1xuXHRcdHZhclxuXHRcdFx0dHlwZSAgID0gc2V0dGluZ3Muc1BhZ2luYXRpb25UeXBlLFxuXHRcdFx0cGx1Z2luID0gRGF0YVRhYmxlLmV4dC5wYWdlclsgdHlwZSBdLFxuXHRcdFx0bW9kZXJuID0gdHlwZW9mIHBsdWdpbiA9PT0gJ2Z1bmN0aW9uJyxcblx0XHRcdHJlZHJhdyA9IGZ1bmN0aW9uKCBzZXR0aW5ncyApIHtcblx0XHRcdFx0X2ZuRHJhdyggc2V0dGluZ3MgKTtcblx0XHRcdH0sXG5cdFx0XHRub2RlID0gJCgnPGRpdi8+JykuYWRkQ2xhc3MoIHNldHRpbmdzLm9DbGFzc2VzLnNQYWdpbmcgKyB0eXBlIClbMF0sXG5cdFx0XHRmZWF0dXJlcyA9IHNldHRpbmdzLmFhbkZlYXR1cmVzO1xuXHRcblx0XHRpZiAoICEgbW9kZXJuICkge1xuXHRcdFx0cGx1Z2luLmZuSW5pdCggc2V0dGluZ3MsIG5vZGUsIHJlZHJhdyApO1xuXHRcdH1cblx0XG5cdFx0LyogQWRkIGEgZHJhdyBjYWxsYmFjayBmb3IgdGhlIHBhZ2luYXRpb24gb24gZmlyc3QgaW5zdGFuY2UsIHRvIHVwZGF0ZSB0aGUgcGFnaW5nIGRpc3BsYXkgKi9cblx0XHRpZiAoICEgZmVhdHVyZXMucCApXG5cdFx0e1xuXHRcdFx0bm9kZS5pZCA9IHNldHRpbmdzLnNUYWJsZUlkKydfcGFnaW5hdGUnO1xuXHRcblx0XHRcdHNldHRpbmdzLmFvRHJhd0NhbGxiYWNrLnB1c2goIHtcblx0XHRcdFx0XCJmblwiOiBmdW5jdGlvbiggc2V0dGluZ3MgKSB7XG5cdFx0XHRcdFx0aWYgKCBtb2Rlcm4gKSB7XG5cdFx0XHRcdFx0XHR2YXJcblx0XHRcdFx0XHRcdFx0c3RhcnQgICAgICA9IHNldHRpbmdzLl9pRGlzcGxheVN0YXJ0LFxuXHRcdFx0XHRcdFx0XHRsZW4gICAgICAgID0gc2V0dGluZ3MuX2lEaXNwbGF5TGVuZ3RoLFxuXHRcdFx0XHRcdFx0XHR2aXNSZWNvcmRzID0gc2V0dGluZ3MuZm5SZWNvcmRzRGlzcGxheSgpLFxuXHRcdFx0XHRcdFx0XHRhbGwgICAgICAgID0gbGVuID09PSAtMSxcblx0XHRcdFx0XHRcdFx0cGFnZSA9IGFsbCA/IDAgOiBNYXRoLmNlaWwoIHN0YXJ0IC8gbGVuICksXG5cdFx0XHRcdFx0XHRcdHBhZ2VzID0gYWxsID8gMSA6IE1hdGguY2VpbCggdmlzUmVjb3JkcyAvIGxlbiApLFxuXHRcdFx0XHRcdFx0XHRidXR0b25zID0gcGx1Z2luKHBhZ2UsIHBhZ2VzKSxcblx0XHRcdFx0XHRcdFx0aSwgaWVuO1xuXHRcblx0XHRcdFx0XHRcdGZvciAoIGk9MCwgaWVuPWZlYXR1cmVzLnAubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRcdFx0XHRcdF9mblJlbmRlcmVyKCBzZXR0aW5ncywgJ3BhZ2VCdXR0b24nICkoXG5cdFx0XHRcdFx0XHRcdFx0c2V0dGluZ3MsIGZlYXR1cmVzLnBbaV0sIGksIGJ1dHRvbnMsIHBhZ2UsIHBhZ2VzXG5cdFx0XHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0cGx1Z2luLmZuVXBkYXRlKCBzZXR0aW5ncywgcmVkcmF3ICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9LFxuXHRcdFx0XHRcInNOYW1lXCI6IFwicGFnaW5hdGlvblwiXG5cdFx0XHR9ICk7XG5cdFx0fVxuXHRcblx0XHRyZXR1cm4gbm9kZTtcblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBBbHRlciB0aGUgZGlzcGxheSBzZXR0aW5ncyB0byBjaGFuZ2UgdGhlIHBhZ2Vcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBEYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHBhcmFtIHtzdHJpbmd8aW50fSBhY3Rpb24gUGFnaW5nIGFjdGlvbiB0byB0YWtlOiBcImZpcnN0XCIsIFwicHJldmlvdXNcIixcblx0ICogICAgXCJuZXh0XCIgb3IgXCJsYXN0XCIgb3IgcGFnZSBudW1iZXIgdG8ganVtcCB0byAoaW50ZWdlcilcblx0ICogIEBwYXJhbSBbYm9vbF0gcmVkcmF3IEF1dG9tYXRpY2FsbHkgZHJhdyB0aGUgdXBkYXRlIG9yIG5vdFxuXHQgKiAgQHJldHVybnMge2Jvb2x9IHRydWUgcGFnZSBoYXMgY2hhbmdlZCwgZmFsc2UgLSBubyBjaGFuZ2Vcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuUGFnZUNoYW5nZSAoIHNldHRpbmdzLCBhY3Rpb24sIHJlZHJhdyApXG5cdHtcblx0XHR2YXJcblx0XHRcdHN0YXJ0ICAgICA9IHNldHRpbmdzLl9pRGlzcGxheVN0YXJ0LFxuXHRcdFx0bGVuICAgICAgID0gc2V0dGluZ3MuX2lEaXNwbGF5TGVuZ3RoLFxuXHRcdFx0cmVjb3JkcyAgID0gc2V0dGluZ3MuZm5SZWNvcmRzRGlzcGxheSgpO1xuXHRcblx0XHRpZiAoIHJlY29yZHMgPT09IDAgfHwgbGVuID09PSAtMSApXG5cdFx0e1xuXHRcdFx0c3RhcnQgPSAwO1xuXHRcdH1cblx0XHRlbHNlIGlmICggdHlwZW9mIGFjdGlvbiA9PT0gXCJudW1iZXJcIiApXG5cdFx0e1xuXHRcdFx0c3RhcnQgPSBhY3Rpb24gKiBsZW47XG5cdFxuXHRcdFx0aWYgKCBzdGFydCA+IHJlY29yZHMgKVxuXHRcdFx0e1xuXHRcdFx0XHRzdGFydCA9IDA7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGVsc2UgaWYgKCBhY3Rpb24gPT0gXCJmaXJzdFwiIClcblx0XHR7XG5cdFx0XHRzdGFydCA9IDA7XG5cdFx0fVxuXHRcdGVsc2UgaWYgKCBhY3Rpb24gPT0gXCJwcmV2aW91c1wiIClcblx0XHR7XG5cdFx0XHRzdGFydCA9IGxlbiA+PSAwID9cblx0XHRcdFx0c3RhcnQgLSBsZW4gOlxuXHRcdFx0XHQwO1xuXHRcblx0XHRcdGlmICggc3RhcnQgPCAwIClcblx0XHRcdHtcblx0XHRcdCAgc3RhcnQgPSAwO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRlbHNlIGlmICggYWN0aW9uID09IFwibmV4dFwiIClcblx0XHR7XG5cdFx0XHRpZiAoIHN0YXJ0ICsgbGVuIDwgcmVjb3JkcyApXG5cdFx0XHR7XG5cdFx0XHRcdHN0YXJ0ICs9IGxlbjtcblx0XHRcdH1cblx0XHR9XG5cdFx0ZWxzZSBpZiAoIGFjdGlvbiA9PSBcImxhc3RcIiApXG5cdFx0e1xuXHRcdFx0c3RhcnQgPSBNYXRoLmZsb29yKCAocmVjb3Jkcy0xKSAvIGxlbikgKiBsZW47XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHR7XG5cdFx0XHRfZm5Mb2coIHNldHRpbmdzLCAwLCBcIlVua25vd24gcGFnaW5nIGFjdGlvbjogXCIrYWN0aW9uLCA1ICk7XG5cdFx0fVxuXHRcblx0XHR2YXIgY2hhbmdlZCA9IHNldHRpbmdzLl9pRGlzcGxheVN0YXJ0ICE9PSBzdGFydDtcblx0XHRzZXR0aW5ncy5faURpc3BsYXlTdGFydCA9IHN0YXJ0O1xuXHRcblx0XHRpZiAoIGNoYW5nZWQgKSB7XG5cdFx0XHRfZm5DYWxsYmFja0ZpcmUoIHNldHRpbmdzLCBudWxsLCAncGFnZScsIFtzZXR0aW5nc10gKTtcblx0XG5cdFx0XHRpZiAoIHJlZHJhdyApIHtcblx0XHRcdFx0X2ZuRHJhdyggc2V0dGluZ3MgKTtcblx0XHRcdH1cblx0XHR9XG5cdFxuXHRcdHJldHVybiBjaGFuZ2VkO1xuXHR9XG5cdFxuXHRcblx0XG5cdC8qKlxuXHQgKiBHZW5lcmF0ZSB0aGUgbm9kZSByZXF1aXJlZCBmb3IgdGhlIHByb2Nlc3Npbmcgbm9kZVxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IHNldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAcmV0dXJucyB7bm9kZX0gUHJvY2Vzc2luZyBlbGVtZW50XG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mbkZlYXR1cmVIdG1sUHJvY2Vzc2luZyAoIHNldHRpbmdzIClcblx0e1xuXHRcdHJldHVybiAkKCc8ZGl2Lz4nLCB7XG5cdFx0XHRcdCdpZCc6ICEgc2V0dGluZ3MuYWFuRmVhdHVyZXMuciA/IHNldHRpbmdzLnNUYWJsZUlkKydfcHJvY2Vzc2luZycgOiBudWxsLFxuXHRcdFx0XHQnY2xhc3MnOiBzZXR0aW5ncy5vQ2xhc3Nlcy5zUHJvY2Vzc2luZ1xuXHRcdFx0fSApXG5cdFx0XHQuaHRtbCggc2V0dGluZ3Mub0xhbmd1YWdlLnNQcm9jZXNzaW5nIClcblx0XHRcdC5pbnNlcnRCZWZvcmUoIHNldHRpbmdzLm5UYWJsZSApWzBdO1xuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIERpc3BsYXkgb3IgaGlkZSB0aGUgcHJvY2Vzc2luZyBpbmRpY2F0b3Jcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHBhcmFtIHtib29sfSBzaG93IFNob3cgdGhlIHByb2Nlc3NpbmcgaW5kaWNhdG9yICh0cnVlKSBvciBub3QgKGZhbHNlKVxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5Qcm9jZXNzaW5nRGlzcGxheSAoIHNldHRpbmdzLCBzaG93IClcblx0e1xuXHRcdGlmICggc2V0dGluZ3Mub0ZlYXR1cmVzLmJQcm9jZXNzaW5nICkge1xuXHRcdFx0JChzZXR0aW5ncy5hYW5GZWF0dXJlcy5yKS5jc3MoICdkaXNwbGF5Jywgc2hvdyA/ICdibG9jaycgOiAnbm9uZScgKTtcblx0XHR9XG5cdFxuXHRcdF9mbkNhbGxiYWNrRmlyZSggc2V0dGluZ3MsIG51bGwsICdwcm9jZXNzaW5nJywgW3NldHRpbmdzLCBzaG93XSApO1xuXHR9XG5cdFxuXHQvKipcblx0ICogQWRkIGFueSBjb250cm9sIGVsZW1lbnRzIGZvciB0aGUgdGFibGUgLSBzcGVjaWZpY2FsbHkgc2Nyb2xsaW5nXG5cdCAqICBAcGFyYW0ge29iamVjdH0gc2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEByZXR1cm5zIHtub2RlfSBOb2RlIHRvIGFkZCB0byB0aGUgRE9NXG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mbkZlYXR1cmVIdG1sVGFibGUgKCBzZXR0aW5ncyApXG5cdHtcblx0XHR2YXIgdGFibGUgPSAkKHNldHRpbmdzLm5UYWJsZSk7XG5cdFxuXHRcdC8vIFNjcm9sbGluZyBmcm9tIGhlcmUgb24gaW5cblx0XHR2YXIgc2Nyb2xsID0gc2V0dGluZ3Mub1Njcm9sbDtcblx0XG5cdFx0aWYgKCBzY3JvbGwuc1ggPT09ICcnICYmIHNjcm9sbC5zWSA9PT0gJycgKSB7XG5cdFx0XHRyZXR1cm4gc2V0dGluZ3MublRhYmxlO1xuXHRcdH1cblx0XG5cdFx0dmFyIHNjcm9sbFggPSBzY3JvbGwuc1g7XG5cdFx0dmFyIHNjcm9sbFkgPSBzY3JvbGwuc1k7XG5cdFx0dmFyIGNsYXNzZXMgPSBzZXR0aW5ncy5vQ2xhc3Nlcztcblx0XHR2YXIgY2FwdGlvbiA9IHRhYmxlLmNoaWxkcmVuKCdjYXB0aW9uJyk7XG5cdFx0dmFyIGNhcHRpb25TaWRlID0gY2FwdGlvbi5sZW5ndGggPyBjYXB0aW9uWzBdLl9jYXB0aW9uU2lkZSA6IG51bGw7XG5cdFx0dmFyIGhlYWRlckNsb25lID0gJCggdGFibGVbMF0uY2xvbmVOb2RlKGZhbHNlKSApO1xuXHRcdHZhciBmb290ZXJDbG9uZSA9ICQoIHRhYmxlWzBdLmNsb25lTm9kZShmYWxzZSkgKTtcblx0XHR2YXIgZm9vdGVyID0gdGFibGUuY2hpbGRyZW4oJ3Rmb290Jyk7XG5cdFx0dmFyIF9kaXYgPSAnPGRpdi8+Jztcblx0XHR2YXIgc2l6ZSA9IGZ1bmN0aW9uICggcyApIHtcblx0XHRcdHJldHVybiAhcyA/IG51bGwgOiBfZm5TdHJpbmdUb0NzcyggcyApO1xuXHRcdH07XG5cdFxuXHRcdGlmICggISBmb290ZXIubGVuZ3RoICkge1xuXHRcdFx0Zm9vdGVyID0gbnVsbDtcblx0XHR9XG5cdFxuXHRcdC8qXG5cdFx0ICogVGhlIEhUTUwgc3RydWN0dXJlIHRoYXQgd2Ugd2FudCB0byBnZW5lcmF0ZSBpbiB0aGlzIGZ1bmN0aW9uIGlzOlxuXHRcdCAqICBkaXYgLSBzY3JvbGxlclxuXHRcdCAqICAgIGRpdiAtIHNjcm9sbCBoZWFkXG5cdFx0ICogICAgICBkaXYgLSBzY3JvbGwgaGVhZCBpbm5lclxuXHRcdCAqICAgICAgICB0YWJsZSAtIHNjcm9sbCBoZWFkIHRhYmxlXG5cdFx0ICogICAgICAgICAgdGhlYWQgLSB0aGVhZFxuXHRcdCAqICAgIGRpdiAtIHNjcm9sbCBib2R5XG5cdFx0ICogICAgICB0YWJsZSAtIHRhYmxlIChtYXN0ZXIgdGFibGUpXG5cdFx0ICogICAgICAgIHRoZWFkIC0gdGhlYWQgY2xvbmUgZm9yIHNpemluZ1xuXHRcdCAqICAgICAgICB0Ym9keSAtIHRib2R5XG5cdFx0ICogICAgZGl2IC0gc2Nyb2xsIGZvb3Rcblx0XHQgKiAgICAgIGRpdiAtIHNjcm9sbCBmb290IGlubmVyXG5cdFx0ICogICAgICAgIHRhYmxlIC0gc2Nyb2xsIGZvb3QgdGFibGVcblx0XHQgKiAgICAgICAgICB0Zm9vdCAtIHRmb290XG5cdFx0ICovXG5cdFx0dmFyIHNjcm9sbGVyID0gJCggX2RpdiwgeyAnY2xhc3MnOiBjbGFzc2VzLnNTY3JvbGxXcmFwcGVyIH0gKVxuXHRcdFx0LmFwcGVuZChcblx0XHRcdFx0JChfZGl2LCB7ICdjbGFzcyc6IGNsYXNzZXMuc1Njcm9sbEhlYWQgfSApXG5cdFx0XHRcdFx0LmNzcygge1xuXHRcdFx0XHRcdFx0b3ZlcmZsb3c6ICdoaWRkZW4nLFxuXHRcdFx0XHRcdFx0cG9zaXRpb246ICdyZWxhdGl2ZScsXG5cdFx0XHRcdFx0XHRib3JkZXI6IDAsXG5cdFx0XHRcdFx0XHR3aWR0aDogc2Nyb2xsWCA/IHNpemUoc2Nyb2xsWCkgOiAnMTAwJSdcblx0XHRcdFx0XHR9IClcblx0XHRcdFx0XHQuYXBwZW5kKFxuXHRcdFx0XHRcdFx0JChfZGl2LCB7ICdjbGFzcyc6IGNsYXNzZXMuc1Njcm9sbEhlYWRJbm5lciB9IClcblx0XHRcdFx0XHRcdFx0LmNzcygge1xuXHRcdFx0XHRcdFx0XHRcdCdib3gtc2l6aW5nJzogJ2NvbnRlbnQtYm94Jyxcblx0XHRcdFx0XHRcdFx0XHR3aWR0aDogc2Nyb2xsLnNYSW5uZXIgfHwgJzEwMCUnXG5cdFx0XHRcdFx0XHRcdH0gKVxuXHRcdFx0XHRcdFx0XHQuYXBwZW5kKFxuXHRcdFx0XHRcdFx0XHRcdGhlYWRlckNsb25lXG5cdFx0XHRcdFx0XHRcdFx0XHQucmVtb3ZlQXR0cignaWQnKVxuXHRcdFx0XHRcdFx0XHRcdFx0LmNzcyggJ21hcmdpbi1sZWZ0JywgMCApXG5cdFx0XHRcdFx0XHRcdFx0XHQuYXBwZW5kKCBjYXB0aW9uU2lkZSA9PT0gJ3RvcCcgPyBjYXB0aW9uIDogbnVsbCApXG5cdFx0XHRcdFx0XHRcdFx0XHQuYXBwZW5kKFxuXHRcdFx0XHRcdFx0XHRcdFx0XHR0YWJsZS5jaGlsZHJlbigndGhlYWQnKVxuXHRcdFx0XHRcdFx0XHRcdFx0KVxuXHRcdFx0XHRcdFx0XHQpXG5cdFx0XHRcdFx0KVxuXHRcdFx0KVxuXHRcdFx0LmFwcGVuZChcblx0XHRcdFx0JChfZGl2LCB7ICdjbGFzcyc6IGNsYXNzZXMuc1Njcm9sbEJvZHkgfSApXG5cdFx0XHRcdFx0LmNzcygge1xuXHRcdFx0XHRcdFx0cG9zaXRpb246ICdyZWxhdGl2ZScsXG5cdFx0XHRcdFx0XHRvdmVyZmxvdzogJ2F1dG8nLFxuXHRcdFx0XHRcdFx0d2lkdGg6IHNpemUoIHNjcm9sbFggKVxuXHRcdFx0XHRcdH0gKVxuXHRcdFx0XHRcdC5hcHBlbmQoIHRhYmxlIClcblx0XHRcdCk7XG5cdFxuXHRcdGlmICggZm9vdGVyICkge1xuXHRcdFx0c2Nyb2xsZXIuYXBwZW5kKFxuXHRcdFx0XHQkKF9kaXYsIHsgJ2NsYXNzJzogY2xhc3Nlcy5zU2Nyb2xsRm9vdCB9IClcblx0XHRcdFx0XHQuY3NzKCB7XG5cdFx0XHRcdFx0XHRvdmVyZmxvdzogJ2hpZGRlbicsXG5cdFx0XHRcdFx0XHRib3JkZXI6IDAsXG5cdFx0XHRcdFx0XHR3aWR0aDogc2Nyb2xsWCA/IHNpemUoc2Nyb2xsWCkgOiAnMTAwJSdcblx0XHRcdFx0XHR9IClcblx0XHRcdFx0XHQuYXBwZW5kKFxuXHRcdFx0XHRcdFx0JChfZGl2LCB7ICdjbGFzcyc6IGNsYXNzZXMuc1Njcm9sbEZvb3RJbm5lciB9IClcblx0XHRcdFx0XHRcdFx0LmFwcGVuZChcblx0XHRcdFx0XHRcdFx0XHRmb290ZXJDbG9uZVxuXHRcdFx0XHRcdFx0XHRcdFx0LnJlbW92ZUF0dHIoJ2lkJylcblx0XHRcdFx0XHRcdFx0XHRcdC5jc3MoICdtYXJnaW4tbGVmdCcsIDAgKVxuXHRcdFx0XHRcdFx0XHRcdFx0LmFwcGVuZCggY2FwdGlvblNpZGUgPT09ICdib3R0b20nID8gY2FwdGlvbiA6IG51bGwgKVxuXHRcdFx0XHRcdFx0XHRcdFx0LmFwcGVuZChcblx0XHRcdFx0XHRcdFx0XHRcdFx0dGFibGUuY2hpbGRyZW4oJ3Rmb290Jylcblx0XHRcdFx0XHRcdFx0XHRcdClcblx0XHRcdFx0XHRcdFx0KVxuXHRcdFx0XHRcdClcblx0XHRcdCk7XG5cdFx0fVxuXHRcblx0XHR2YXIgY2hpbGRyZW4gPSBzY3JvbGxlci5jaGlsZHJlbigpO1xuXHRcdHZhciBzY3JvbGxIZWFkID0gY2hpbGRyZW5bMF07XG5cdFx0dmFyIHNjcm9sbEJvZHkgPSBjaGlsZHJlblsxXTtcblx0XHR2YXIgc2Nyb2xsRm9vdCA9IGZvb3RlciA/IGNoaWxkcmVuWzJdIDogbnVsbDtcblx0XG5cdFx0Ly8gV2hlbiB0aGUgYm9keSBpcyBzY3JvbGxlZCwgdGhlbiB3ZSBhbHNvIHdhbnQgdG8gc2Nyb2xsIHRoZSBoZWFkZXJzXG5cdFx0aWYgKCBzY3JvbGxYICkge1xuXHRcdFx0JChzY3JvbGxCb2R5KS5vbiggJ3Njcm9sbC5EVCcsIGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdHZhciBzY3JvbGxMZWZ0ID0gdGhpcy5zY3JvbGxMZWZ0O1xuXHRcblx0XHRcdFx0c2Nyb2xsSGVhZC5zY3JvbGxMZWZ0ID0gc2Nyb2xsTGVmdDtcblx0XG5cdFx0XHRcdGlmICggZm9vdGVyICkge1xuXHRcdFx0XHRcdHNjcm9sbEZvb3Quc2Nyb2xsTGVmdCA9IHNjcm9sbExlZnQ7XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0XHR9XG5cdFxuXHRcdCQoc2Nyb2xsQm9keSkuY3NzKCdtYXgtaGVpZ2h0Jywgc2Nyb2xsWSk7XG5cdFx0aWYgKCEgc2Nyb2xsLmJDb2xsYXBzZSkge1xuXHRcdFx0JChzY3JvbGxCb2R5KS5jc3MoJ2hlaWdodCcsIHNjcm9sbFkpO1xuXHRcdH1cblx0XG5cdFx0c2V0dGluZ3MublNjcm9sbEhlYWQgPSBzY3JvbGxIZWFkO1xuXHRcdHNldHRpbmdzLm5TY3JvbGxCb2R5ID0gc2Nyb2xsQm9keTtcblx0XHRzZXR0aW5ncy5uU2Nyb2xsRm9vdCA9IHNjcm9sbEZvb3Q7XG5cdFxuXHRcdC8vIE9uIHJlZHJhdyAtIGFsaWduIGNvbHVtbnNcblx0XHRzZXR0aW5ncy5hb0RyYXdDYWxsYmFjay5wdXNoKCB7XG5cdFx0XHRcImZuXCI6IF9mblNjcm9sbERyYXcsXG5cdFx0XHRcInNOYW1lXCI6IFwic2Nyb2xsaW5nXCJcblx0XHR9ICk7XG5cdFxuXHRcdHJldHVybiBzY3JvbGxlclswXTtcblx0fVxuXHRcblx0XG5cdFxuXHQvKipcblx0ICogVXBkYXRlIHRoZSBoZWFkZXIsIGZvb3RlciBhbmQgYm9keSB0YWJsZXMgZm9yIHJlc2l6aW5nIC0gaS5lLiBjb2x1bW5cblx0ICogYWxpZ25tZW50LlxuXHQgKlxuXHQgKiBXZWxjb21lIHRvIHRoZSBtb3N0IGhvcnJpYmxlIGZ1bmN0aW9uIERhdGFUYWJsZXMuIFRoZSBwcm9jZXNzIHRoYXQgdGhpc1xuXHQgKiBmdW5jdGlvbiBmb2xsb3dzIGlzIGJhc2ljYWxseTpcblx0ICogICAxLiBSZS1jcmVhdGUgdGhlIHRhYmxlIGluc2lkZSB0aGUgc2Nyb2xsaW5nIGRpdlxuXHQgKiAgIDIuIFRha2UgbGl2ZSBtZWFzdXJlbWVudHMgZnJvbSB0aGUgRE9NXG5cdCAqICAgMy4gQXBwbHkgdGhlIG1lYXN1cmVtZW50cyB0byBhbGlnbiB0aGUgY29sdW1uc1xuXHQgKiAgIDQuIENsZWFuIHVwXG5cdCAqXG5cdCAqICBAcGFyYW0ge29iamVjdH0gc2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuU2Nyb2xsRHJhdyAoIHNldHRpbmdzIClcblx0e1xuXHRcdC8vIEdpdmVuIHRoYXQgdGhpcyBpcyBzdWNoIGEgbW9uc3RlciBmdW5jdGlvbiwgYSBsb3Qgb2YgdmFyaWFibGVzIGFyZSB1c2Vcblx0XHQvLyB0byB0cnkgYW5kIGtlZXAgdGhlIG1pbmltaXNlZCBzaXplIGFzIHNtYWxsIGFzIHBvc3NpYmxlXG5cdFx0dmFyXG5cdFx0XHRzY3JvbGwgICAgICAgICA9IHNldHRpbmdzLm9TY3JvbGwsXG5cdFx0XHRzY3JvbGxYICAgICAgICA9IHNjcm9sbC5zWCxcblx0XHRcdHNjcm9sbFhJbm5lciAgID0gc2Nyb2xsLnNYSW5uZXIsXG5cdFx0XHRzY3JvbGxZICAgICAgICA9IHNjcm9sbC5zWSxcblx0XHRcdGJhcldpZHRoICAgICAgID0gc2Nyb2xsLmlCYXJXaWR0aCxcblx0XHRcdGRpdkhlYWRlciAgICAgID0gJChzZXR0aW5ncy5uU2Nyb2xsSGVhZCksXG5cdFx0XHRkaXZIZWFkZXJTdHlsZSA9IGRpdkhlYWRlclswXS5zdHlsZSxcblx0XHRcdGRpdkhlYWRlcklubmVyID0gZGl2SGVhZGVyLmNoaWxkcmVuKCdkaXYnKSxcblx0XHRcdGRpdkhlYWRlcklubmVyU3R5bGUgPSBkaXZIZWFkZXJJbm5lclswXS5zdHlsZSxcblx0XHRcdGRpdkhlYWRlclRhYmxlID0gZGl2SGVhZGVySW5uZXIuY2hpbGRyZW4oJ3RhYmxlJyksXG5cdFx0XHRkaXZCb2R5RWwgICAgICA9IHNldHRpbmdzLm5TY3JvbGxCb2R5LFxuXHRcdFx0ZGl2Qm9keSAgICAgICAgPSAkKGRpdkJvZHlFbCksXG5cdFx0XHRkaXZCb2R5U3R5bGUgICA9IGRpdkJvZHlFbC5zdHlsZSxcblx0XHRcdGRpdkZvb3RlciAgICAgID0gJChzZXR0aW5ncy5uU2Nyb2xsRm9vdCksXG5cdFx0XHRkaXZGb290ZXJJbm5lciA9IGRpdkZvb3Rlci5jaGlsZHJlbignZGl2JyksXG5cdFx0XHRkaXZGb290ZXJUYWJsZSA9IGRpdkZvb3RlcklubmVyLmNoaWxkcmVuKCd0YWJsZScpLFxuXHRcdFx0aGVhZGVyICAgICAgICAgPSAkKHNldHRpbmdzLm5USGVhZCksXG5cdFx0XHR0YWJsZSAgICAgICAgICA9ICQoc2V0dGluZ3MublRhYmxlKSxcblx0XHRcdHRhYmxlRWwgICAgICAgID0gdGFibGVbMF0sXG5cdFx0XHR0YWJsZVN0eWxlICAgICA9IHRhYmxlRWwuc3R5bGUsXG5cdFx0XHRmb290ZXIgICAgICAgICA9IHNldHRpbmdzLm5URm9vdCA/ICQoc2V0dGluZ3MublRGb290KSA6IG51bGwsXG5cdFx0XHRicm93c2VyICAgICAgICA9IHNldHRpbmdzLm9Ccm93c2VyLFxuXHRcdFx0aWU2NyAgICAgICAgICAgPSBicm93c2VyLmJTY3JvbGxPdmVyc2l6ZSxcblx0XHRcdGR0SGVhZGVyQ2VsbHMgID0gX3BsdWNrKCBzZXR0aW5ncy5hb0NvbHVtbnMsICduVGgnICksXG5cdFx0XHRoZWFkZXJUcmdFbHMsIGZvb3RlclRyZ0Vscyxcblx0XHRcdGhlYWRlclNyY0VscywgZm9vdGVyU3JjRWxzLFxuXHRcdFx0aGVhZGVyQ29weSwgZm9vdGVyQ29weSxcblx0XHRcdGhlYWRlcldpZHRocz1bXSwgZm9vdGVyV2lkdGhzPVtdLFxuXHRcdFx0aGVhZGVyQ29udGVudD1bXSwgZm9vdGVyQ29udGVudD1bXSxcblx0XHRcdGlkeCwgY29ycmVjdGlvbiwgc2FuaXR5V2lkdGgsXG5cdFx0XHR6ZXJvT3V0ID0gZnVuY3Rpb24oblNpemVyKSB7XG5cdFx0XHRcdHZhciBzdHlsZSA9IG5TaXplci5zdHlsZTtcblx0XHRcdFx0c3R5bGUucGFkZGluZ1RvcCA9IFwiMFwiO1xuXHRcdFx0XHRzdHlsZS5wYWRkaW5nQm90dG9tID0gXCIwXCI7XG5cdFx0XHRcdHN0eWxlLmJvcmRlclRvcFdpZHRoID0gXCIwXCI7XG5cdFx0XHRcdHN0eWxlLmJvcmRlckJvdHRvbVdpZHRoID0gXCIwXCI7XG5cdFx0XHRcdHN0eWxlLmhlaWdodCA9IDA7XG5cdFx0XHR9O1xuXHRcblx0XHQvLyBJZiB0aGUgc2Nyb2xsYmFyIHZpc2liaWxpdHkgaGFzIGNoYW5nZWQgZnJvbSB0aGUgbGFzdCBkcmF3LCB3ZSBuZWVkIHRvXG5cdFx0Ly8gYWRqdXN0IHRoZSBjb2x1bW4gc2l6ZXMgYXMgdGhlIHRhYmxlIHdpZHRoIHdpbGwgaGF2ZSBjaGFuZ2VkIHRvIGFjY291bnRcblx0XHQvLyBmb3IgdGhlIHNjcm9sbGJhclxuXHRcdHZhciBzY3JvbGxCYXJWaXMgPSBkaXZCb2R5RWwuc2Nyb2xsSGVpZ2h0ID4gZGl2Qm9keUVsLmNsaWVudEhlaWdodDtcblx0XHRcblx0XHRpZiAoIHNldHRpbmdzLnNjcm9sbEJhclZpcyAhPT0gc2Nyb2xsQmFyVmlzICYmIHNldHRpbmdzLnNjcm9sbEJhclZpcyAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0c2V0dGluZ3Muc2Nyb2xsQmFyVmlzID0gc2Nyb2xsQmFyVmlzO1xuXHRcdFx0X2ZuQWRqdXN0Q29sdW1uU2l6aW5nKCBzZXR0aW5ncyApO1xuXHRcdFx0cmV0dXJuOyAvLyBhZGp1c3QgY29sdW1uIHNpemluZyB3aWxsIGNhbGwgdGhpcyBmdW5jdGlvbiBhZ2FpblxuXHRcdH1cblx0XHRlbHNlIHtcblx0XHRcdHNldHRpbmdzLnNjcm9sbEJhclZpcyA9IHNjcm9sbEJhclZpcztcblx0XHR9XG5cdFxuXHRcdC8qXG5cdFx0ICogMS4gUmUtY3JlYXRlIHRoZSB0YWJsZSBpbnNpZGUgdGhlIHNjcm9sbGluZyBkaXZcblx0XHQgKi9cblx0XG5cdFx0Ly8gUmVtb3ZlIHRoZSBvbGQgbWluaW1pc2VkIHRoZWFkIGFuZCB0Zm9vdCBlbGVtZW50cyBpbiB0aGUgaW5uZXIgdGFibGVcblx0XHR0YWJsZS5jaGlsZHJlbigndGhlYWQsIHRmb290JykucmVtb3ZlKCk7XG5cdFxuXHRcdGlmICggZm9vdGVyICkge1xuXHRcdFx0Zm9vdGVyQ29weSA9IGZvb3Rlci5jbG9uZSgpLnByZXBlbmRUbyggdGFibGUgKTtcblx0XHRcdGZvb3RlclRyZ0VscyA9IGZvb3Rlci5maW5kKCd0cicpOyAvLyB0aGUgb3JpZ2luYWwgdGZvb3QgaXMgaW4gaXRzIG93biB0YWJsZSBhbmQgbXVzdCBiZSBzaXplZFxuXHRcdFx0Zm9vdGVyU3JjRWxzID0gZm9vdGVyQ29weS5maW5kKCd0cicpO1xuXHRcdH1cblx0XG5cdFx0Ly8gQ2xvbmUgdGhlIGN1cnJlbnQgaGVhZGVyIGFuZCBmb290ZXIgZWxlbWVudHMgYW5kIHRoZW4gcGxhY2UgaXQgaW50byB0aGUgaW5uZXIgdGFibGVcblx0XHRoZWFkZXJDb3B5ID0gaGVhZGVyLmNsb25lKCkucHJlcGVuZFRvKCB0YWJsZSApO1xuXHRcdGhlYWRlclRyZ0VscyA9IGhlYWRlci5maW5kKCd0cicpOyAvLyBvcmlnaW5hbCBoZWFkZXIgaXMgaW4gaXRzIG93biB0YWJsZVxuXHRcdGhlYWRlclNyY0VscyA9IGhlYWRlckNvcHkuZmluZCgndHInKTtcblx0XHRoZWFkZXJDb3B5LmZpbmQoJ3RoLCB0ZCcpLnJlbW92ZUF0dHIoJ3RhYmluZGV4Jyk7XG5cdFxuXHRcblx0XHQvKlxuXHRcdCAqIDIuIFRha2UgbGl2ZSBtZWFzdXJlbWVudHMgZnJvbSB0aGUgRE9NIC0gZG8gbm90IGFsdGVyIHRoZSBET00gaXRzZWxmIVxuXHRcdCAqL1xuXHRcblx0XHQvLyBSZW1vdmUgb2xkIHNpemluZyBhbmQgYXBwbHkgdGhlIGNhbGN1bGF0ZWQgY29sdW1uIHdpZHRoc1xuXHRcdC8vIEdldCB0aGUgdW5pcXVlIGNvbHVtbiBoZWFkZXJzIGluIHRoZSBuZXdseSBjcmVhdGVkIChjbG9uZWQpIGhlYWRlci4gV2Ugd2FudCB0byBhcHBseSB0aGVcblx0XHQvLyBjYWxjdWxhdGVkIHNpemVzIHRvIHRoaXMgaGVhZGVyXG5cdFx0aWYgKCAhIHNjcm9sbFggKVxuXHRcdHtcblx0XHRcdGRpdkJvZHlTdHlsZS53aWR0aCA9ICcxMDAlJztcblx0XHRcdGRpdkhlYWRlclswXS5zdHlsZS53aWR0aCA9ICcxMDAlJztcblx0XHR9XG5cdFxuXHRcdCQuZWFjaCggX2ZuR2V0VW5pcXVlVGhzKCBzZXR0aW5ncywgaGVhZGVyQ29weSApLCBmdW5jdGlvbiAoIGksIGVsICkge1xuXHRcdFx0aWR4ID0gX2ZuVmlzaWJsZVRvQ29sdW1uSW5kZXgoIHNldHRpbmdzLCBpICk7XG5cdFx0XHRlbC5zdHlsZS53aWR0aCA9IHNldHRpbmdzLmFvQ29sdW1uc1tpZHhdLnNXaWR0aDtcblx0XHR9ICk7XG5cdFxuXHRcdGlmICggZm9vdGVyICkge1xuXHRcdFx0X2ZuQXBwbHlUb0NoaWxkcmVuKCBmdW5jdGlvbihuKSB7XG5cdFx0XHRcdG4uc3R5bGUud2lkdGggPSBcIlwiO1xuXHRcdFx0fSwgZm9vdGVyU3JjRWxzICk7XG5cdFx0fVxuXHRcblx0XHQvLyBTaXplIHRoZSB0YWJsZSBhcyBhIHdob2xlXG5cdFx0c2FuaXR5V2lkdGggPSB0YWJsZS5vdXRlcldpZHRoKCk7XG5cdFx0aWYgKCBzY3JvbGxYID09PSBcIlwiICkge1xuXHRcdFx0Ly8gTm8geCBzY3JvbGxpbmdcblx0XHRcdHRhYmxlU3R5bGUud2lkdGggPSBcIjEwMCVcIjtcblx0XG5cdFx0XHQvLyBJRTcgd2lsbCBtYWtlIHRoZSB3aWR0aCBvZiB0aGUgdGFibGUgd2hlbiAxMDAlIGluY2x1ZGUgdGhlIHNjcm9sbGJhclxuXHRcdFx0Ly8gLSB3aGljaCBpcyBzaG91bGRuJ3QuIFdoZW4gdGhlcmUgaXMgYSBzY3JvbGxiYXIgd2UgbmVlZCB0byB0YWtlIHRoaXNcblx0XHRcdC8vIGludG8gYWNjb3VudC5cblx0XHRcdGlmICggaWU2NyAmJiAodGFibGUuZmluZCgndGJvZHknKS5oZWlnaHQoKSA+IGRpdkJvZHlFbC5vZmZzZXRIZWlnaHQgfHxcblx0XHRcdFx0ZGl2Qm9keS5jc3MoJ292ZXJmbG93LXknKSA9PSBcInNjcm9sbFwiKVxuXHRcdFx0KSB7XG5cdFx0XHRcdHRhYmxlU3R5bGUud2lkdGggPSBfZm5TdHJpbmdUb0NzcyggdGFibGUub3V0ZXJXaWR0aCgpIC0gYmFyV2lkdGgpO1xuXHRcdFx0fVxuXHRcblx0XHRcdC8vIFJlY2FsY3VsYXRlIHRoZSBzYW5pdHkgd2lkdGhcblx0XHRcdHNhbml0eVdpZHRoID0gdGFibGUub3V0ZXJXaWR0aCgpO1xuXHRcdH1cblx0XHRlbHNlIGlmICggc2Nyb2xsWElubmVyICE9PSBcIlwiICkge1xuXHRcdFx0Ly8gbGVnYWN5IHggc2Nyb2xsIGlubmVyIGhhcyBiZWVuIGdpdmVuIC0gdXNlIGl0XG5cdFx0XHR0YWJsZVN0eWxlLndpZHRoID0gX2ZuU3RyaW5nVG9Dc3Moc2Nyb2xsWElubmVyKTtcblx0XG5cdFx0XHQvLyBSZWNhbGN1bGF0ZSB0aGUgc2FuaXR5IHdpZHRoXG5cdFx0XHRzYW5pdHlXaWR0aCA9IHRhYmxlLm91dGVyV2lkdGgoKTtcblx0XHR9XG5cdFxuXHRcdC8vIEhpZGRlbiBoZWFkZXIgc2hvdWxkIGhhdmUgemVybyBoZWlnaHQsIHNvIHJlbW92ZSBwYWRkaW5nIGFuZCBib3JkZXJzLiBUaGVuXG5cdFx0Ly8gc2V0IHRoZSB3aWR0aCBiYXNlZCBvbiB0aGUgcmVhbCBoZWFkZXJzXG5cdFxuXHRcdC8vIEFwcGx5IGFsbCBzdHlsZXMgaW4gb25lIHBhc3Ncblx0XHRfZm5BcHBseVRvQ2hpbGRyZW4oIHplcm9PdXQsIGhlYWRlclNyY0VscyApO1xuXHRcblx0XHQvLyBSZWFkIGFsbCB3aWR0aHMgaW4gbmV4dCBwYXNzXG5cdFx0X2ZuQXBwbHlUb0NoaWxkcmVuKCBmdW5jdGlvbihuU2l6ZXIpIHtcblx0XHRcdHZhciBzdHlsZSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlID9cblx0XHRcdFx0d2luZG93LmdldENvbXB1dGVkU3R5bGUoblNpemVyKS53aWR0aCA6XG5cdFx0XHRcdF9mblN0cmluZ1RvQ3NzKCAkKG5TaXplcikud2lkdGgoKSApO1xuXHRcblx0XHRcdGhlYWRlckNvbnRlbnQucHVzaCggblNpemVyLmlubmVySFRNTCApO1xuXHRcdFx0aGVhZGVyV2lkdGhzLnB1c2goIHN0eWxlICk7XG5cdFx0fSwgaGVhZGVyU3JjRWxzICk7XG5cdFxuXHRcdC8vIEFwcGx5IGFsbCB3aWR0aHMgaW4gZmluYWwgcGFzc1xuXHRcdF9mbkFwcGx5VG9DaGlsZHJlbiggZnVuY3Rpb24oblRvU2l6ZSwgaSkge1xuXHRcdFx0blRvU2l6ZS5zdHlsZS53aWR0aCA9IGhlYWRlcldpZHRoc1tpXTtcblx0XHR9LCBoZWFkZXJUcmdFbHMgKTtcblx0XG5cdFx0JChoZWFkZXJTcmNFbHMpLmhlaWdodCgwKTtcblx0XG5cdFx0LyogU2FtZSBhZ2FpbiB3aXRoIHRoZSBmb290ZXIgaWYgd2UgaGF2ZSBvbmUgKi9cblx0XHRpZiAoIGZvb3RlciApXG5cdFx0e1xuXHRcdFx0X2ZuQXBwbHlUb0NoaWxkcmVuKCB6ZXJvT3V0LCBmb290ZXJTcmNFbHMgKTtcblx0XG5cdFx0XHRfZm5BcHBseVRvQ2hpbGRyZW4oIGZ1bmN0aW9uKG5TaXplcikge1xuXHRcdFx0XHRmb290ZXJDb250ZW50LnB1c2goIG5TaXplci5pbm5lckhUTUwgKTtcblx0XHRcdFx0Zm9vdGVyV2lkdGhzLnB1c2goIF9mblN0cmluZ1RvQ3NzKCAkKG5TaXplcikuY3NzKCd3aWR0aCcpICkgKTtcblx0XHRcdH0sIGZvb3RlclNyY0VscyApO1xuXHRcblx0XHRcdF9mbkFwcGx5VG9DaGlsZHJlbiggZnVuY3Rpb24oblRvU2l6ZSwgaSkge1xuXHRcdFx0XHRuVG9TaXplLnN0eWxlLndpZHRoID0gZm9vdGVyV2lkdGhzW2ldO1xuXHRcdFx0fSwgZm9vdGVyVHJnRWxzICk7XG5cdFxuXHRcdFx0JChmb290ZXJTcmNFbHMpLmhlaWdodCgwKTtcblx0XHR9XG5cdFxuXHRcblx0XHQvKlxuXHRcdCAqIDMuIEFwcGx5IHRoZSBtZWFzdXJlbWVudHNcblx0XHQgKi9cblx0XG5cdFx0Ly8gXCJIaWRlXCIgdGhlIGhlYWRlciBhbmQgZm9vdGVyIHRoYXQgd2UgdXNlZCBmb3IgdGhlIHNpemluZy4gV2UgbmVlZCB0byBrZWVwXG5cdFx0Ly8gdGhlIGNvbnRlbnQgb2YgdGhlIGNlbGwgc28gdGhhdCB0aGUgd2lkdGggYXBwbGllZCB0byB0aGUgaGVhZGVyIGFuZCBib2R5XG5cdFx0Ly8gYm90aCBtYXRjaCwgYnV0IHdlIHdhbnQgdG8gaGlkZSBpdCBjb21wbGV0ZWx5LiBXZSB3YW50IHRvIGFsc28gZml4IHRoZWlyXG5cdFx0Ly8gd2lkdGggdG8gd2hhdCB0aGV5IGN1cnJlbnRseSBhcmVcblx0XHRfZm5BcHBseVRvQ2hpbGRyZW4oIGZ1bmN0aW9uKG5TaXplciwgaSkge1xuXHRcdFx0blNpemVyLmlubmVySFRNTCA9ICc8ZGl2IGNsYXNzPVwiZGF0YVRhYmxlc19zaXppbmdcIj4nK2hlYWRlckNvbnRlbnRbaV0rJzwvZGl2Pic7XG5cdFx0XHRuU2l6ZXIuY2hpbGROb2Rlc1swXS5zdHlsZS5oZWlnaHQgPSBcIjBcIjtcblx0XHRcdG5TaXplci5jaGlsZE5vZGVzWzBdLnN0eWxlLm92ZXJmbG93ID0gXCJoaWRkZW5cIjtcblx0XHRcdG5TaXplci5zdHlsZS53aWR0aCA9IGhlYWRlcldpZHRoc1tpXTtcblx0XHR9LCBoZWFkZXJTcmNFbHMgKTtcblx0XG5cdFx0aWYgKCBmb290ZXIgKVxuXHRcdHtcblx0XHRcdF9mbkFwcGx5VG9DaGlsZHJlbiggZnVuY3Rpb24oblNpemVyLCBpKSB7XG5cdFx0XHRcdG5TaXplci5pbm5lckhUTUwgPSAnPGRpdiBjbGFzcz1cImRhdGFUYWJsZXNfc2l6aW5nXCI+Jytmb290ZXJDb250ZW50W2ldKyc8L2Rpdj4nO1xuXHRcdFx0XHRuU2l6ZXIuY2hpbGROb2Rlc1swXS5zdHlsZS5oZWlnaHQgPSBcIjBcIjtcblx0XHRcdFx0blNpemVyLmNoaWxkTm9kZXNbMF0uc3R5bGUub3ZlcmZsb3cgPSBcImhpZGRlblwiO1xuXHRcdFx0XHRuU2l6ZXIuc3R5bGUud2lkdGggPSBmb290ZXJXaWR0aHNbaV07XG5cdFx0XHR9LCBmb290ZXJTcmNFbHMgKTtcblx0XHR9XG5cdFxuXHRcdC8vIFNhbml0eSBjaGVjayB0aGF0IHRoZSB0YWJsZSBpcyBvZiBhIHNlbnNpYmxlIHdpZHRoLiBJZiBub3QgdGhlbiB3ZSBhcmUgZ29pbmcgdG8gZ2V0XG5cdFx0Ly8gbWlzYWxpZ25tZW50IC0gdHJ5IHRvIHByZXZlbnQgdGhpcyBieSBub3QgYWxsb3dpbmcgdGhlIHRhYmxlIHRvIHNocmluayBiZWxvdyBpdHMgbWluIHdpZHRoXG5cdFx0aWYgKCB0YWJsZS5vdXRlcldpZHRoKCkgPCBzYW5pdHlXaWR0aCApXG5cdFx0e1xuXHRcdFx0Ly8gVGhlIG1pbiB3aWR0aCBkZXBlbmRzIHVwb24gaWYgd2UgaGF2ZSBhIHZlcnRpY2FsIHNjcm9sbGJhciB2aXNpYmxlIG9yIG5vdCAqL1xuXHRcdFx0Y29ycmVjdGlvbiA9ICgoZGl2Qm9keUVsLnNjcm9sbEhlaWdodCA+IGRpdkJvZHlFbC5vZmZzZXRIZWlnaHQgfHxcblx0XHRcdFx0ZGl2Qm9keS5jc3MoJ292ZXJmbG93LXknKSA9PSBcInNjcm9sbFwiKSkgP1xuXHRcdFx0XHRcdHNhbml0eVdpZHRoK2JhcldpZHRoIDpcblx0XHRcdFx0XHRzYW5pdHlXaWR0aDtcblx0XG5cdFx0XHQvLyBJRTYvNyBhcmUgYSBsYXcgdW50byB0aGVtc2VsdmVzLi4uXG5cdFx0XHRpZiAoIGllNjcgJiYgKGRpdkJvZHlFbC5zY3JvbGxIZWlnaHQgPlxuXHRcdFx0XHRkaXZCb2R5RWwub2Zmc2V0SGVpZ2h0IHx8IGRpdkJvZHkuY3NzKCdvdmVyZmxvdy15JykgPT0gXCJzY3JvbGxcIilcblx0XHRcdCkge1xuXHRcdFx0XHR0YWJsZVN0eWxlLndpZHRoID0gX2ZuU3RyaW5nVG9Dc3MoIGNvcnJlY3Rpb24tYmFyV2lkdGggKTtcblx0XHRcdH1cblx0XG5cdFx0XHQvLyBBbmQgZ2l2ZSB0aGUgdXNlciBhIHdhcm5pbmcgdGhhdCB3ZSd2ZSBzdG9wcGVkIHRoZSB0YWJsZSBnZXR0aW5nIHRvbyBzbWFsbFxuXHRcdFx0aWYgKCBzY3JvbGxYID09PSBcIlwiIHx8IHNjcm9sbFhJbm5lciAhPT0gXCJcIiApIHtcblx0XHRcdFx0X2ZuTG9nKCBzZXR0aW5ncywgMSwgJ1Bvc3NpYmxlIGNvbHVtbiBtaXNhbGlnbm1lbnQnLCA2ICk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHR7XG5cdFx0XHRjb3JyZWN0aW9uID0gJzEwMCUnO1xuXHRcdH1cblx0XG5cdFx0Ly8gQXBwbHkgdG8gdGhlIGNvbnRhaW5lciBlbGVtZW50c1xuXHRcdGRpdkJvZHlTdHlsZS53aWR0aCA9IF9mblN0cmluZ1RvQ3NzKCBjb3JyZWN0aW9uICk7XG5cdFx0ZGl2SGVhZGVyU3R5bGUud2lkdGggPSBfZm5TdHJpbmdUb0NzcyggY29ycmVjdGlvbiApO1xuXHRcblx0XHRpZiAoIGZvb3RlciApIHtcblx0XHRcdHNldHRpbmdzLm5TY3JvbGxGb290LnN0eWxlLndpZHRoID0gX2ZuU3RyaW5nVG9Dc3MoIGNvcnJlY3Rpb24gKTtcblx0XHR9XG5cdFxuXHRcblx0XHQvKlxuXHRcdCAqIDQuIENsZWFuIHVwXG5cdFx0ICovXG5cdFx0aWYgKCAhIHNjcm9sbFkgKSB7XG5cdFx0XHQvKiBJRTc8IHB1dHMgYSB2ZXJ0aWNhbCBzY3JvbGxiYXIgaW4gcGxhY2UgKHdoZW4gaXQgc2hvdWxkbid0IGJlKSBkdWUgdG8gc3VidHJhY3Rpbmdcblx0XHRcdCAqIHRoZSBzY3JvbGxiYXIgaGVpZ2h0IGZyb20gdGhlIHZpc2libGUgZGlzcGxheSwgcmF0aGVyIHRoYW4gYWRkaW5nIGl0IG9uLiBXZSBuZWVkIHRvXG5cdFx0XHQgKiBzZXQgdGhlIGhlaWdodCBpbiBvcmRlciB0byBzb3J0IHRoaXMuIERvbid0IHdhbnQgdG8gZG8gaXQgaW4gYW55IG90aGVyIGJyb3dzZXJzLlxuXHRcdFx0ICovXG5cdFx0XHRpZiAoIGllNjcgKSB7XG5cdFx0XHRcdGRpdkJvZHlTdHlsZS5oZWlnaHQgPSBfZm5TdHJpbmdUb0NzcyggdGFibGVFbC5vZmZzZXRIZWlnaHQrYmFyV2lkdGggKTtcblx0XHRcdH1cblx0XHR9XG5cdFxuXHRcdC8qIEZpbmFsbHkgc2V0IHRoZSB3aWR0aCdzIG9mIHRoZSBoZWFkZXIgYW5kIGZvb3RlciB0YWJsZXMgKi9cblx0XHR2YXIgaU91dGVyV2lkdGggPSB0YWJsZS5vdXRlcldpZHRoKCk7XG5cdFx0ZGl2SGVhZGVyVGFibGVbMF0uc3R5bGUud2lkdGggPSBfZm5TdHJpbmdUb0NzcyggaU91dGVyV2lkdGggKTtcblx0XHRkaXZIZWFkZXJJbm5lclN0eWxlLndpZHRoID0gX2ZuU3RyaW5nVG9Dc3MoIGlPdXRlcldpZHRoICk7XG5cdFxuXHRcdC8vIEZpZ3VyZSBvdXQgaWYgdGhlcmUgYXJlIHNjcm9sbGJhciBwcmVzZW50IC0gaWYgc28gdGhlbiB3ZSBuZWVkIGEgdGhlIGhlYWRlciBhbmQgZm9vdGVyIHRvXG5cdFx0Ly8gcHJvdmlkZSBhIGJpdCBtb3JlIHNwYWNlIHRvIGFsbG93IFwib3ZlcmZsb3dcIiBzY3JvbGxpbmcgKGkuZS4gcGFzdCB0aGUgc2Nyb2xsYmFyKVxuXHRcdHZhciBiU2Nyb2xsaW5nID0gdGFibGUuaGVpZ2h0KCkgPiBkaXZCb2R5RWwuY2xpZW50SGVpZ2h0IHx8IGRpdkJvZHkuY3NzKCdvdmVyZmxvdy15JykgPT0gXCJzY3JvbGxcIjtcblx0XHR2YXIgcGFkZGluZyA9ICdwYWRkaW5nJyArIChicm93c2VyLmJTY3JvbGxiYXJMZWZ0ID8gJ0xlZnQnIDogJ1JpZ2h0JyApO1xuXHRcdGRpdkhlYWRlcklubmVyU3R5bGVbIHBhZGRpbmcgXSA9IGJTY3JvbGxpbmcgPyBiYXJXaWR0aCtcInB4XCIgOiBcIjBweFwiO1xuXHRcblx0XHRpZiAoIGZvb3RlciApIHtcblx0XHRcdGRpdkZvb3RlclRhYmxlWzBdLnN0eWxlLndpZHRoID0gX2ZuU3RyaW5nVG9Dc3MoIGlPdXRlcldpZHRoICk7XG5cdFx0XHRkaXZGb290ZXJJbm5lclswXS5zdHlsZS53aWR0aCA9IF9mblN0cmluZ1RvQ3NzKCBpT3V0ZXJXaWR0aCApO1xuXHRcdFx0ZGl2Rm9vdGVySW5uZXJbMF0uc3R5bGVbcGFkZGluZ10gPSBiU2Nyb2xsaW5nID8gYmFyV2lkdGgrXCJweFwiIDogXCIwcHhcIjtcblx0XHR9XG5cdFxuXHRcdC8vIENvcnJlY3QgRE9NIG9yZGVyaW5nIGZvciBjb2xncm91cCAtIGNvbWVzIGJlZm9yZSB0aGUgdGhlYWRcblx0XHR0YWJsZS5jaGlsZHJlbignY29sZ3JvdXAnKS5pbnNlcnRCZWZvcmUoIHRhYmxlLmNoaWxkcmVuKCd0aGVhZCcpICk7XG5cdFxuXHRcdC8qIEFkanVzdCB0aGUgcG9zaXRpb24gb2YgdGhlIGhlYWRlciBpbiBjYXNlIHdlIGxvb3NlIHRoZSB5LXNjcm9sbGJhciAqL1xuXHRcdGRpdkJvZHkudHJpZ2dlcignc2Nyb2xsJyk7XG5cdFxuXHRcdC8vIElmIHNvcnRpbmcgb3IgZmlsdGVyaW5nIGhhcyBvY2N1cnJlZCwganVtcCB0aGUgc2Nyb2xsaW5nIGJhY2sgdG8gdGhlIHRvcFxuXHRcdC8vIG9ubHkgaWYgd2UgYXJlbid0IGhvbGRpbmcgdGhlIHBvc2l0aW9uXG5cdFx0aWYgKCAoc2V0dGluZ3MuYlNvcnRlZCB8fCBzZXR0aW5ncy5iRmlsdGVyZWQpICYmICEgc2V0dGluZ3MuX2RyYXdIb2xkICkge1xuXHRcdFx0ZGl2Qm9keUVsLnNjcm9sbFRvcCA9IDA7XG5cdFx0fVxuXHR9XG5cdFxuXHRcblx0XG5cdC8qKlxuXHQgKiBBcHBseSBhIGdpdmVuIGZ1bmN0aW9uIHRvIHRoZSBkaXNwbGF5IGNoaWxkIG5vZGVzIG9mIGFuIGVsZW1lbnQgYXJyYXkgKHR5cGljYWxseVxuXHQgKiBURCBjaGlsZHJlbiBvZiBUUiByb3dzXG5cdCAqICBAcGFyYW0ge2Z1bmN0aW9ufSBmbiBNZXRob2QgdG8gYXBwbHkgdG8gdGhlIG9iamVjdHNcblx0ICogIEBwYXJhbSBhcnJheSB7bm9kZXN9IGFuMSBMaXN0IG9mIGVsZW1lbnRzIHRvIGxvb2sgdGhyb3VnaCBmb3IgZGlzcGxheSBjaGlsZHJlblxuXHQgKiAgQHBhcmFtIGFycmF5IHtub2Rlc30gYW4yIEFub3RoZXIgbGlzdCAoaWRlbnRpY2FsIHN0cnVjdHVyZSB0byB0aGUgZmlyc3QpIC0gb3B0aW9uYWxcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuQXBwbHlUb0NoaWxkcmVuKCBmbiwgYW4xLCBhbjIgKVxuXHR7XG5cdFx0dmFyIGluZGV4PTAsIGk9MCwgaUxlbj1hbjEubGVuZ3RoO1xuXHRcdHZhciBuTm9kZTEsIG5Ob2RlMjtcblx0XG5cdFx0d2hpbGUgKCBpIDwgaUxlbiApIHtcblx0XHRcdG5Ob2RlMSA9IGFuMVtpXS5maXJzdENoaWxkO1xuXHRcdFx0bk5vZGUyID0gYW4yID8gYW4yW2ldLmZpcnN0Q2hpbGQgOiBudWxsO1xuXHRcblx0XHRcdHdoaWxlICggbk5vZGUxICkge1xuXHRcdFx0XHRpZiAoIG5Ob2RlMS5ub2RlVHlwZSA9PT0gMSApIHtcblx0XHRcdFx0XHRpZiAoIGFuMiApIHtcblx0XHRcdFx0XHRcdGZuKCBuTm9kZTEsIG5Ob2RlMiwgaW5kZXggKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRmbiggbk5vZGUxLCBpbmRleCApO1xuXHRcdFx0XHRcdH1cblx0XG5cdFx0XHRcdFx0aW5kZXgrKztcblx0XHRcdFx0fVxuXHRcblx0XHRcdFx0bk5vZGUxID0gbk5vZGUxLm5leHRTaWJsaW5nO1xuXHRcdFx0XHRuTm9kZTIgPSBhbjIgPyBuTm9kZTIubmV4dFNpYmxpbmcgOiBudWxsO1xuXHRcdFx0fVxuXHRcblx0XHRcdGkrKztcblx0XHR9XG5cdH1cblx0XG5cdFxuXHRcblx0dmFyIF9fcmVfaHRtbF9yZW1vdmUgPSAvPC4qPz4vZztcblx0XG5cdFxuXHQvKipcblx0ICogQ2FsY3VsYXRlIHRoZSB3aWR0aCBvZiBjb2x1bW5zIGZvciB0aGUgdGFibGVcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuQ2FsY3VsYXRlQ29sdW1uV2lkdGhzICggb1NldHRpbmdzIClcblx0e1xuXHRcdHZhclxuXHRcdFx0dGFibGUgPSBvU2V0dGluZ3MublRhYmxlLFxuXHRcdFx0Y29sdW1ucyA9IG9TZXR0aW5ncy5hb0NvbHVtbnMsXG5cdFx0XHRzY3JvbGwgPSBvU2V0dGluZ3Mub1Njcm9sbCxcblx0XHRcdHNjcm9sbFkgPSBzY3JvbGwuc1ksXG5cdFx0XHRzY3JvbGxYID0gc2Nyb2xsLnNYLFxuXHRcdFx0c2Nyb2xsWElubmVyID0gc2Nyb2xsLnNYSW5uZXIsXG5cdFx0XHRjb2x1bW5Db3VudCA9IGNvbHVtbnMubGVuZ3RoLFxuXHRcdFx0dmlzaWJsZUNvbHVtbnMgPSBfZm5HZXRDb2x1bW5zKCBvU2V0dGluZ3MsICdiVmlzaWJsZScgKSxcblx0XHRcdGhlYWRlckNlbGxzID0gJCgndGgnLCBvU2V0dGluZ3MublRIZWFkKSxcblx0XHRcdHRhYmxlV2lkdGhBdHRyID0gdGFibGUuZ2V0QXR0cmlidXRlKCd3aWR0aCcpLCAvLyBmcm9tIERPTSBlbGVtZW50XG5cdFx0XHR0YWJsZUNvbnRhaW5lciA9IHRhYmxlLnBhcmVudE5vZGUsXG5cdFx0XHR1c2VySW5wdXRzID0gZmFsc2UsXG5cdFx0XHRpLCBjb2x1bW4sIGNvbHVtbklkeCwgd2lkdGgsIG91dGVyV2lkdGgsXG5cdFx0XHRicm93c2VyID0gb1NldHRpbmdzLm9Ccm93c2VyLFxuXHRcdFx0aWU2NyA9IGJyb3dzZXIuYlNjcm9sbE92ZXJzaXplO1xuXHRcblx0XHR2YXIgc3R5bGVXaWR0aCA9IHRhYmxlLnN0eWxlLndpZHRoO1xuXHRcdGlmICggc3R5bGVXaWR0aCAmJiBzdHlsZVdpZHRoLmluZGV4T2YoJyUnKSAhPT0gLTEgKSB7XG5cdFx0XHR0YWJsZVdpZHRoQXR0ciA9IHN0eWxlV2lkdGg7XG5cdFx0fVxuXHRcblx0XHQvKiBDb252ZXJ0IGFueSB1c2VyIGlucHV0IHNpemVzIGludG8gcGl4ZWwgc2l6ZXMgKi9cblx0XHRmb3IgKCBpPTAgOyBpPHZpc2libGVDb2x1bW5zLmxlbmd0aCA7IGkrKyApIHtcblx0XHRcdGNvbHVtbiA9IGNvbHVtbnNbIHZpc2libGVDb2x1bW5zW2ldIF07XG5cdFxuXHRcdFx0aWYgKCBjb2x1bW4uc1dpZHRoICE9PSBudWxsICkge1xuXHRcdFx0XHRjb2x1bW4uc1dpZHRoID0gX2ZuQ29udmVydFRvV2lkdGgoIGNvbHVtbi5zV2lkdGhPcmlnLCB0YWJsZUNvbnRhaW5lciApO1xuXHRcblx0XHRcdFx0dXNlcklucHV0cyA9IHRydWU7XG5cdFx0XHR9XG5cdFx0fVxuXHRcblx0XHQvKiBJZiB0aGUgbnVtYmVyIG9mIGNvbHVtbnMgaW4gdGhlIERPTSBlcXVhbHMgdGhlIG51bWJlciB0aGF0IHdlIGhhdmUgdG9cblx0XHQgKiBwcm9jZXNzIGluIERhdGFUYWJsZXMsIHRoZW4gd2UgY2FuIHVzZSB0aGUgb2Zmc2V0cyB0aGF0IGFyZSBjcmVhdGVkIGJ5XG5cdFx0ICogdGhlIHdlYi0gYnJvd3Nlci4gTm8gY3VzdG9tIHNpemVzIGNhbiBiZSBzZXQgaW4gb3JkZXIgZm9yIHRoaXMgdG8gaGFwcGVuLFxuXHRcdCAqIG5vciBzY3JvbGxpbmcgdXNlZFxuXHRcdCAqL1xuXHRcdGlmICggaWU2NyB8fCAhIHVzZXJJbnB1dHMgJiYgISBzY3JvbGxYICYmICEgc2Nyb2xsWSAmJlxuXHRcdCAgICAgY29sdW1uQ291bnQgPT0gX2ZuVmlzYmxlQ29sdW1ucyggb1NldHRpbmdzICkgJiZcblx0XHQgICAgIGNvbHVtbkNvdW50ID09IGhlYWRlckNlbGxzLmxlbmd0aFxuXHRcdCkge1xuXHRcdFx0Zm9yICggaT0wIDsgaTxjb2x1bW5Db3VudCA7IGkrKyApIHtcblx0XHRcdFx0dmFyIGNvbElkeCA9IF9mblZpc2libGVUb0NvbHVtbkluZGV4KCBvU2V0dGluZ3MsIGkgKTtcblx0XG5cdFx0XHRcdGlmICggY29sSWR4ICE9PSBudWxsICkge1xuXHRcdFx0XHRcdGNvbHVtbnNbIGNvbElkeCBdLnNXaWR0aCA9IF9mblN0cmluZ1RvQ3NzKCBoZWFkZXJDZWxscy5lcShpKS53aWR0aCgpICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdFx0ZWxzZVxuXHRcdHtcblx0XHRcdC8vIE90aGVyd2lzZSBjb25zdHJ1Y3QgYSBzaW5nbGUgcm93LCB3b3JzdCBjYXNlLCB0YWJsZSB3aXRoIHRoZSB3aWRlc3Rcblx0XHRcdC8vIG5vZGUgaW4gdGhlIGRhdGEsIGFzc2lnbiBhbnkgdXNlciBkZWZpbmVkIHdpZHRocywgdGhlbiBpbnNlcnQgaXQgaW50b1xuXHRcdFx0Ly8gdGhlIERPTSBhbmQgYWxsb3cgdGhlIGJyb3dzZXIgdG8gZG8gYWxsIHRoZSBoYXJkIHdvcmsgb2YgY2FsY3VsYXRpbmdcblx0XHRcdC8vIHRhYmxlIHdpZHRoc1xuXHRcdFx0dmFyIHRtcFRhYmxlID0gJCh0YWJsZSkuY2xvbmUoKSAvLyBkb24ndCB1c2UgY2xvbmVOb2RlIC0gSUU4IHdpbGwgcmVtb3ZlIGV2ZW50cyBvbiB0aGUgbWFpbiB0YWJsZVxuXHRcdFx0XHQuY3NzKCAndmlzaWJpbGl0eScsICdoaWRkZW4nIClcblx0XHRcdFx0LnJlbW92ZUF0dHIoICdpZCcgKTtcblx0XG5cdFx0XHQvLyBDbGVhbiB1cCB0aGUgdGFibGUgYm9keVxuXHRcdFx0dG1wVGFibGUuZmluZCgndGJvZHkgdHInKS5yZW1vdmUoKTtcblx0XHRcdHZhciB0ciA9ICQoJzx0ci8+JykuYXBwZW5kVG8oIHRtcFRhYmxlLmZpbmQoJ3Rib2R5JykgKTtcblx0XG5cdFx0XHQvLyBDbG9uZSB0aGUgdGFibGUgaGVhZGVyIGFuZCBmb290ZXIgLSB3ZSBjYW4ndCB1c2UgdGhlIGhlYWRlciAvIGZvb3RlclxuXHRcdFx0Ly8gZnJvbSB0aGUgY2xvbmVkIHRhYmxlLCBzaW5jZSBpZiBzY3JvbGxpbmcgaXMgYWN0aXZlLCB0aGUgdGFibGUnc1xuXHRcdFx0Ly8gcmVhbCBoZWFkZXIgYW5kIGZvb3RlciBhcmUgY29udGFpbmVkIGluIGRpZmZlcmVudCB0YWJsZSB0YWdzXG5cdFx0XHR0bXBUYWJsZS5maW5kKCd0aGVhZCwgdGZvb3QnKS5yZW1vdmUoKTtcblx0XHRcdHRtcFRhYmxlXG5cdFx0XHRcdC5hcHBlbmQoICQob1NldHRpbmdzLm5USGVhZCkuY2xvbmUoKSApXG5cdFx0XHRcdC5hcHBlbmQoICQob1NldHRpbmdzLm5URm9vdCkuY2xvbmUoKSApO1xuXHRcblx0XHRcdC8vIFJlbW92ZSBhbnkgYXNzaWduZWQgd2lkdGhzIGZyb20gdGhlIGZvb3RlciAoZnJvbSBzY3JvbGxpbmcpXG5cdFx0XHR0bXBUYWJsZS5maW5kKCd0Zm9vdCB0aCwgdGZvb3QgdGQnKS5jc3MoJ3dpZHRoJywgJycpO1xuXHRcblx0XHRcdC8vIEFwcGx5IGN1c3RvbSBzaXppbmcgdG8gdGhlIGNsb25lZCBoZWFkZXJcblx0XHRcdGhlYWRlckNlbGxzID0gX2ZuR2V0VW5pcXVlVGhzKCBvU2V0dGluZ3MsIHRtcFRhYmxlLmZpbmQoJ3RoZWFkJylbMF0gKTtcblx0XG5cdFx0XHRmb3IgKCBpPTAgOyBpPHZpc2libGVDb2x1bW5zLmxlbmd0aCA7IGkrKyApIHtcblx0XHRcdFx0Y29sdW1uID0gY29sdW1uc1sgdmlzaWJsZUNvbHVtbnNbaV0gXTtcblx0XG5cdFx0XHRcdGhlYWRlckNlbGxzW2ldLnN0eWxlLndpZHRoID0gY29sdW1uLnNXaWR0aE9yaWcgIT09IG51bGwgJiYgY29sdW1uLnNXaWR0aE9yaWcgIT09ICcnID9cblx0XHRcdFx0XHRfZm5TdHJpbmdUb0NzcyggY29sdW1uLnNXaWR0aE9yaWcgKSA6XG5cdFx0XHRcdFx0Jyc7XG5cdFxuXHRcdFx0XHQvLyBGb3Igc2Nyb2xsWCB3ZSBuZWVkIHRvIGZvcmNlIHRoZSBjb2x1bW4gd2lkdGggb3RoZXJ3aXNlIHRoZVxuXHRcdFx0XHQvLyBicm93c2VyIHdpbGwgY29sbGFwc2UgaXQuIElmIHRoaXMgd2lkdGggaXMgc21hbGxlciB0aGFuIHRoZVxuXHRcdFx0XHQvLyB3aWR0aCB0aGUgY29sdW1uIHJlcXVpcmVzLCB0aGVuIGl0IHdpbGwgaGF2ZSBubyBlZmZlY3Rcblx0XHRcdFx0aWYgKCBjb2x1bW4uc1dpZHRoT3JpZyAmJiBzY3JvbGxYICkge1xuXHRcdFx0XHRcdCQoIGhlYWRlckNlbGxzW2ldICkuYXBwZW5kKCAkKCc8ZGl2Lz4nKS5jc3MoIHtcblx0XHRcdFx0XHRcdHdpZHRoOiBjb2x1bW4uc1dpZHRoT3JpZyxcblx0XHRcdFx0XHRcdG1hcmdpbjogMCxcblx0XHRcdFx0XHRcdHBhZGRpbmc6IDAsXG5cdFx0XHRcdFx0XHRib3JkZXI6IDAsXG5cdFx0XHRcdFx0XHRoZWlnaHQ6IDFcblx0XHRcdFx0XHR9ICkgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcblx0XHRcdC8vIEZpbmQgdGhlIHdpZGVzdCBjZWxsIGZvciBlYWNoIGNvbHVtbiBhbmQgcHV0IGl0IGludG8gdGhlIHRhYmxlXG5cdFx0XHRpZiAoIG9TZXR0aW5ncy5hb0RhdGEubGVuZ3RoICkge1xuXHRcdFx0XHRmb3IgKCBpPTAgOyBpPHZpc2libGVDb2x1bW5zLmxlbmd0aCA7IGkrKyApIHtcblx0XHRcdFx0XHRjb2x1bW5JZHggPSB2aXNpYmxlQ29sdW1uc1tpXTtcblx0XHRcdFx0XHRjb2x1bW4gPSBjb2x1bW5zWyBjb2x1bW5JZHggXTtcblx0XG5cdFx0XHRcdFx0JCggX2ZuR2V0V2lkZXN0Tm9kZSggb1NldHRpbmdzLCBjb2x1bW5JZHggKSApXG5cdFx0XHRcdFx0XHQuY2xvbmUoIGZhbHNlIClcblx0XHRcdFx0XHRcdC5hcHBlbmQoIGNvbHVtbi5zQ29udGVudFBhZGRpbmcgKVxuXHRcdFx0XHRcdFx0LmFwcGVuZFRvKCB0ciApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFxuXHRcdFx0Ly8gVGlkeSB0aGUgdGVtcG9yYXJ5IHRhYmxlIC0gcmVtb3ZlIG5hbWUgYXR0cmlidXRlcyBzbyB0aGVyZSBhcmVuJ3Rcblx0XHRcdC8vIGR1cGxpY2F0ZWQgaW4gdGhlIGRvbSAocmFkaW8gZWxlbWVudHMgZm9yIGV4YW1wbGUpXG5cdFx0XHQkKCdbbmFtZV0nLCB0bXBUYWJsZSkucmVtb3ZlQXR0cignbmFtZScpO1xuXHRcblx0XHRcdC8vIFRhYmxlIGhhcyBiZWVuIGJ1aWx0LCBhdHRhY2ggdG8gdGhlIGRvY3VtZW50IHNvIHdlIGNhbiB3b3JrIHdpdGggaXQuXG5cdFx0XHQvLyBBIGhvbGRpbmcgZWxlbWVudCBpcyB1c2VkLCBwb3NpdGlvbmVkIGF0IHRoZSB0b3Agb2YgdGhlIGNvbnRhaW5lclxuXHRcdFx0Ly8gd2l0aCBtaW5pbWFsIGhlaWdodCwgc28gaXQgaGFzIG5vIGVmZmVjdCBvbiBpZiB0aGUgY29udGFpbmVyIHNjcm9sbHNcblx0XHRcdC8vIG9yIG5vdC4gT3RoZXJ3aXNlIGl0IG1pZ2h0IHRyaWdnZXIgc2Nyb2xsaW5nIHdoZW4gaXQgYWN0dWFsbHkgaXNuJ3Rcblx0XHRcdC8vIG5lZWRlZFxuXHRcdFx0dmFyIGhvbGRlciA9ICQoJzxkaXYvPicpLmNzcyggc2Nyb2xsWCB8fCBzY3JvbGxZID9cblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRwb3NpdGlvbjogJ2Fic29sdXRlJyxcblx0XHRcdFx0XHRcdHRvcDogMCxcblx0XHRcdFx0XHRcdGxlZnQ6IDAsXG5cdFx0XHRcdFx0XHRoZWlnaHQ6IDEsXG5cdFx0XHRcdFx0XHRyaWdodDogMCxcblx0XHRcdFx0XHRcdG92ZXJmbG93OiAnaGlkZGVuJ1xuXHRcdFx0XHRcdH0gOlxuXHRcdFx0XHRcdHt9XG5cdFx0XHRcdClcblx0XHRcdFx0LmFwcGVuZCggdG1wVGFibGUgKVxuXHRcdFx0XHQuYXBwZW5kVG8oIHRhYmxlQ29udGFpbmVyICk7XG5cdFxuXHRcdFx0Ly8gV2hlbiBzY3JvbGxpbmcgKFggb3IgWSkgd2Ugd2FudCB0byBzZXQgdGhlIHdpZHRoIG9mIHRoZSB0YWJsZSBhcyBcblx0XHRcdC8vIGFwcHJvcHJpYXRlLiBIb3dldmVyLCB3aGVuIG5vdCBzY3JvbGxpbmcgbGVhdmUgdGhlIHRhYmxlIHdpZHRoIGFzIGl0XG5cdFx0XHQvLyBpcy4gVGhpcyByZXN1bHRzIGluIHNsaWdodGx5IGRpZmZlcmVudCwgYnV0IEkgdGhpbmsgY29ycmVjdCBiZWhhdmlvdXJcblx0XHRcdGlmICggc2Nyb2xsWCAmJiBzY3JvbGxYSW5uZXIgKSB7XG5cdFx0XHRcdHRtcFRhYmxlLndpZHRoKCBzY3JvbGxYSW5uZXIgKTtcblx0XHRcdH1cblx0XHRcdGVsc2UgaWYgKCBzY3JvbGxYICkge1xuXHRcdFx0XHR0bXBUYWJsZS5jc3MoICd3aWR0aCcsICdhdXRvJyApO1xuXHRcdFx0XHR0bXBUYWJsZS5yZW1vdmVBdHRyKCd3aWR0aCcpO1xuXHRcblx0XHRcdFx0Ly8gSWYgdGhlcmUgaXMgbm8gd2lkdGggYXR0cmlidXRlIG9yIHN0eWxlLCB0aGVuIGFsbG93IHRoZSB0YWJsZSB0b1xuXHRcdFx0XHQvLyBjb2xsYXBzZVxuXHRcdFx0XHRpZiAoIHRtcFRhYmxlLndpZHRoKCkgPCB0YWJsZUNvbnRhaW5lci5jbGllbnRXaWR0aCAmJiB0YWJsZVdpZHRoQXR0ciApIHtcblx0XHRcdFx0XHR0bXBUYWJsZS53aWR0aCggdGFibGVDb250YWluZXIuY2xpZW50V2lkdGggKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0ZWxzZSBpZiAoIHNjcm9sbFkgKSB7XG5cdFx0XHRcdHRtcFRhYmxlLndpZHRoKCB0YWJsZUNvbnRhaW5lci5jbGllbnRXaWR0aCApO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSBpZiAoIHRhYmxlV2lkdGhBdHRyICkge1xuXHRcdFx0XHR0bXBUYWJsZS53aWR0aCggdGFibGVXaWR0aEF0dHIgKTtcblx0XHRcdH1cblx0XG5cdFx0XHQvLyBHZXQgdGhlIHdpZHRoIG9mIGVhY2ggY29sdW1uIGluIHRoZSBjb25zdHJ1Y3RlZCB0YWJsZSAtIHdlIG5lZWQgdG9cblx0XHRcdC8vIGtub3cgdGhlIGlubmVyIHdpZHRoIChzbyBpdCBjYW4gYmUgYXNzaWduZWQgdG8gdGhlIG90aGVyIHRhYmxlJ3Ncblx0XHRcdC8vIGNlbGxzKSBhbmQgdGhlIG91dGVyIHdpZHRoIHNvIHdlIGNhbiBjYWxjdWxhdGUgdGhlIGZ1bGwgd2lkdGggb2YgdGhlXG5cdFx0XHQvLyB0YWJsZS4gVGhpcyBpcyBzYWZlIHNpbmNlIERhdGFUYWJsZXMgcmVxdWlyZXMgYSB1bmlxdWUgY2VsbCBmb3IgZWFjaFxuXHRcdFx0Ly8gY29sdW1uLCBidXQgaWYgZXZlciBhIGhlYWRlciBjYW4gc3BhbiBtdWx0aXBsZSBjb2x1bW5zLCB0aGlzIHdpbGxcblx0XHRcdC8vIG5lZWQgdG8gYmUgbW9kaWZpZWQuXG5cdFx0XHR2YXIgdG90YWwgPSAwO1xuXHRcdFx0Zm9yICggaT0wIDsgaTx2aXNpYmxlQ29sdW1ucy5sZW5ndGggOyBpKysgKSB7XG5cdFx0XHRcdHZhciBjZWxsID0gJChoZWFkZXJDZWxsc1tpXSk7XG5cdFx0XHRcdHZhciBib3JkZXIgPSBjZWxsLm91dGVyV2lkdGgoKSAtIGNlbGwud2lkdGgoKTtcblx0XG5cdFx0XHRcdC8vIFVzZSBnZXRCb3VuZGluZy4uLiB3aGVyZSBwb3NzaWJsZSAobm90IElFOC0pIGJlY2F1c2UgaXQgY2FuIGdpdmVcblx0XHRcdFx0Ly8gc3ViLXBpeGVsIGFjY3VyYWN5LCB3aGljaCB3ZSB0aGVuIHdhbnQgdG8gcm91bmQgdXAhXG5cdFx0XHRcdHZhciBib3VuZGluZyA9IGJyb3dzZXIuYkJvdW5kaW5nID9cblx0XHRcdFx0XHRNYXRoLmNlaWwoIGhlYWRlckNlbGxzW2ldLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLndpZHRoICkgOlxuXHRcdFx0XHRcdGNlbGwub3V0ZXJXaWR0aCgpO1xuXHRcblx0XHRcdFx0Ly8gVG90YWwgaXMgdHJhY2tlZCB0byByZW1vdmUgYW55IHN1Yi1waXhlbCBlcnJvcnMgYXMgdGhlIG91dGVyV2lkdGhcblx0XHRcdFx0Ly8gb2YgdGhlIHRhYmxlIG1pZ2h0IG5vdCBlcXVhbCB0aGUgdG90YWwgZ2l2ZW4gaGVyZSAoSUUhKS5cblx0XHRcdFx0dG90YWwgKz0gYm91bmRpbmc7XG5cdFxuXHRcdFx0XHQvLyBXaWR0aCBmb3IgZWFjaCBjb2x1bW4gdG8gdXNlXG5cdFx0XHRcdGNvbHVtbnNbIHZpc2libGVDb2x1bW5zW2ldIF0uc1dpZHRoID0gX2ZuU3RyaW5nVG9Dc3MoIGJvdW5kaW5nIC0gYm9yZGVyICk7XG5cdFx0XHR9XG5cdFxuXHRcdFx0dGFibGUuc3R5bGUud2lkdGggPSBfZm5TdHJpbmdUb0NzcyggdG90YWwgKTtcblx0XG5cdFx0XHQvLyBGaW5pc2hlZCB3aXRoIHRoZSB0YWJsZSAtIGRpdGNoIGl0XG5cdFx0XHRob2xkZXIucmVtb3ZlKCk7XG5cdFx0fVxuXHRcblx0XHQvLyBJZiB0aGVyZSBpcyBhIHdpZHRoIGF0dHIsIHdlIHdhbnQgdG8gYXR0YWNoIGFuIGV2ZW50IGxpc3RlbmVyIHdoaWNoXG5cdFx0Ly8gYWxsb3dzIHRoZSB0YWJsZSBzaXppbmcgdG8gYXV0b21hdGljYWxseSBhZGp1c3Qgd2hlbiB0aGUgd2luZG93IGlzXG5cdFx0Ly8gcmVzaXplZC4gVXNlIHRoZSB3aWR0aCBhdHRyIHJhdGhlciB0aGFuIENTUywgc2luY2Ugd2UgY2FuJ3Qga25vdyBpZiB0aGVcblx0XHQvLyBDU1MgaXMgYSByZWxhdGl2ZSB2YWx1ZSBvciBhYnNvbHV0ZSAtIERPTSByZWFkIGlzIGFsd2F5cyBweC5cblx0XHRpZiAoIHRhYmxlV2lkdGhBdHRyICkge1xuXHRcdFx0dGFibGUuc3R5bGUud2lkdGggPSBfZm5TdHJpbmdUb0NzcyggdGFibGVXaWR0aEF0dHIgKTtcblx0XHR9XG5cdFxuXHRcdGlmICggKHRhYmxlV2lkdGhBdHRyIHx8IHNjcm9sbFgpICYmICEgb1NldHRpbmdzLl9yZXN6RXZ0ICkge1xuXHRcdFx0dmFyIGJpbmRSZXNpemUgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdCQod2luZG93KS5vbigncmVzaXplLkRULScrb1NldHRpbmdzLnNJbnN0YW5jZSwgX2ZuVGhyb3R0bGUoIGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRfZm5BZGp1c3RDb2x1bW5TaXppbmcoIG9TZXR0aW5ncyApO1xuXHRcdFx0XHR9ICkgKTtcblx0XHRcdH07XG5cdFxuXHRcdFx0Ly8gSUU2Lzcgd2lsbCBjcmFzaCBpZiB3ZSBiaW5kIGEgcmVzaXplIGV2ZW50IGhhbmRsZXIgb24gcGFnZSBsb2FkLlxuXHRcdFx0Ly8gVG8gYmUgcmVtb3ZlZCBpbiAxLjExIHdoaWNoIGRyb3BzIElFNi83IHN1cHBvcnRcblx0XHRcdGlmICggaWU2NyApIHtcblx0XHRcdFx0c2V0VGltZW91dCggYmluZFJlc2l6ZSwgMTAwMCApO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSB7XG5cdFx0XHRcdGJpbmRSZXNpemUoKTtcblx0XHRcdH1cblx0XG5cdFx0XHRvU2V0dGluZ3MuX3Jlc3pFdnQgPSB0cnVlO1xuXHRcdH1cblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBUaHJvdHRsZSB0aGUgY2FsbHMgdG8gYSBmdW5jdGlvbi4gQXJndW1lbnRzIGFuZCBjb250ZXh0IGFyZSBtYWludGFpbmVkIGZvclxuXHQgKiB0aGUgdGhyb3R0bGVkIGZ1bmN0aW9uXG5cdCAqICBAcGFyYW0ge2Z1bmN0aW9ufSBmbiBGdW5jdGlvbiB0byBiZSBjYWxsZWRcblx0ICogIEBwYXJhbSB7aW50fSBbZnJlcT0yMDBdIGNhbGwgZnJlcXVlbmN5IGluIG1TXG5cdCAqICBAcmV0dXJucyB7ZnVuY3Rpb259IHdyYXBwZWQgZnVuY3Rpb25cblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0dmFyIF9mblRocm90dGxlID0gRGF0YVRhYmxlLnV0aWwudGhyb3R0bGU7XG5cdFxuXHRcblx0LyoqXG5cdCAqIENvbnZlcnQgYSBDU1MgdW5pdCB3aWR0aCB0byBwaXhlbHMgKGUuZy4gMmVtKVxuXHQgKiAgQHBhcmFtIHtzdHJpbmd9IHdpZHRoIHdpZHRoIHRvIGJlIGNvbnZlcnRlZFxuXHQgKiAgQHBhcmFtIHtub2RlfSBwYXJlbnQgcGFyZW50IHRvIGdldCB0aGUgd2l0aCBmb3IgKHJlcXVpcmVkIGZvciByZWxhdGl2ZSB3aWR0aHMpIC0gb3B0aW9uYWxcblx0ICogIEByZXR1cm5zIHtpbnR9IHdpZHRoIGluIHBpeGVsc1xuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5Db252ZXJ0VG9XaWR0aCAoIHdpZHRoLCBwYXJlbnQgKVxuXHR7XG5cdFx0aWYgKCAhIHdpZHRoICkge1xuXHRcdFx0cmV0dXJuIDA7XG5cdFx0fVxuXHRcblx0XHR2YXIgbiA9ICQoJzxkaXYvPicpXG5cdFx0XHQuY3NzKCAnd2lkdGgnLCBfZm5TdHJpbmdUb0Nzcyggd2lkdGggKSApXG5cdFx0XHQuYXBwZW5kVG8oIHBhcmVudCB8fCBkb2N1bWVudC5ib2R5ICk7XG5cdFxuXHRcdHZhciB2YWwgPSBuWzBdLm9mZnNldFdpZHRoO1xuXHRcdG4ucmVtb3ZlKCk7XG5cdFxuXHRcdHJldHVybiB2YWw7XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogR2V0IHRoZSB3aWRlc3Qgbm9kZVxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IHNldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAcGFyYW0ge2ludH0gY29sSWR4IGNvbHVtbiBvZiBpbnRlcmVzdFxuXHQgKiAgQHJldHVybnMge25vZGV9IHdpZGVzdCB0YWJsZSBub2RlXG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mbkdldFdpZGVzdE5vZGUoIHNldHRpbmdzLCBjb2xJZHggKVxuXHR7XG5cdFx0dmFyIGlkeCA9IF9mbkdldE1heExlblN0cmluZyggc2V0dGluZ3MsIGNvbElkeCApO1xuXHRcdGlmICggaWR4IDwgMCApIHtcblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH1cblx0XG5cdFx0dmFyIGRhdGEgPSBzZXR0aW5ncy5hb0RhdGFbIGlkeCBdO1xuXHRcdHJldHVybiAhIGRhdGEublRyID8gLy8gTWlnaHQgbm90IGhhdmUgYmVlbiBjcmVhdGVkIHdoZW4gZGVmZXJyZWQgcmVuZGVyaW5nXG5cdFx0XHQkKCc8dGQvPicpLmh0bWwoIF9mbkdldENlbGxEYXRhKCBzZXR0aW5ncywgaWR4LCBjb2xJZHgsICdkaXNwbGF5JyApIClbMF0gOlxuXHRcdFx0ZGF0YS5hbkNlbGxzWyBjb2xJZHggXTtcblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBHZXQgdGhlIG1heGltdW0gc3RybGVuIGZvciBlYWNoIGRhdGEgY29sdW1uXG5cdCAqICBAcGFyYW0ge29iamVjdH0gc2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBwYXJhbSB7aW50fSBjb2xJZHggY29sdW1uIG9mIGludGVyZXN0XG5cdCAqICBAcmV0dXJucyB7c3RyaW5nfSBtYXggc3RyaW5nIGxlbmd0aCBmb3IgZWFjaCBjb2x1bW5cblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuR2V0TWF4TGVuU3RyaW5nKCBzZXR0aW5ncywgY29sSWR4IClcblx0e1xuXHRcdHZhciBzLCBtYXg9LTEsIG1heElkeCA9IC0xO1xuXHRcblx0XHRmb3IgKCB2YXIgaT0wLCBpZW49c2V0dGluZ3MuYW9EYXRhLmxlbmd0aCA7IGk8aWVuIDsgaSsrICkge1xuXHRcdFx0cyA9IF9mbkdldENlbGxEYXRhKCBzZXR0aW5ncywgaSwgY29sSWR4LCAnZGlzcGxheScgKSsnJztcblx0XHRcdHMgPSBzLnJlcGxhY2UoIF9fcmVfaHRtbF9yZW1vdmUsICcnICk7XG5cdFx0XHRzID0gcy5yZXBsYWNlKCAvJm5ic3A7L2csICcgJyApO1xuXHRcblx0XHRcdGlmICggcy5sZW5ndGggPiBtYXggKSB7XG5cdFx0XHRcdG1heCA9IHMubGVuZ3RoO1xuXHRcdFx0XHRtYXhJZHggPSBpO1xuXHRcdFx0fVxuXHRcdH1cblx0XG5cdFx0cmV0dXJuIG1heElkeDtcblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBBcHBlbmQgYSBDU1MgdW5pdCAob25seSBpZiByZXF1aXJlZCkgdG8gYSBzdHJpbmdcblx0ICogIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSB0byBjc3MtaWZ5XG5cdCAqICBAcmV0dXJucyB7c3RyaW5nfSB2YWx1ZSB3aXRoIGNzcyB1bml0XG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mblN0cmluZ1RvQ3NzKCBzIClcblx0e1xuXHRcdGlmICggcyA9PT0gbnVsbCApIHtcblx0XHRcdHJldHVybiAnMHB4Jztcblx0XHR9XG5cdFxuXHRcdGlmICggdHlwZW9mIHMgPT0gJ251bWJlcicgKSB7XG5cdFx0XHRyZXR1cm4gcyA8IDAgP1xuXHRcdFx0XHQnMHB4JyA6XG5cdFx0XHRcdHMrJ3B4Jztcblx0XHR9XG5cdFxuXHRcdC8vIENoZWNrIGl0IGhhcyBhIHVuaXQgY2hhcmFjdGVyIGFscmVhZHlcblx0XHRyZXR1cm4gcy5tYXRjaCgvXFxkJC8pID9cblx0XHRcdHMrJ3B4JyA6XG5cdFx0XHRzO1xuXHR9XG5cdFxuXHRcblx0XG5cdGZ1bmN0aW9uIF9mblNvcnRGbGF0dGVuICggc2V0dGluZ3MgKVxuXHR7XG5cdFx0dmFyXG5cdFx0XHRpLCBpTGVuLCBrLCBrTGVuLFxuXHRcdFx0YVNvcnQgPSBbXSxcblx0XHRcdGFpT3JpZyA9IFtdLFxuXHRcdFx0YW9Db2x1bW5zID0gc2V0dGluZ3MuYW9Db2x1bW5zLFxuXHRcdFx0YURhdGFTb3J0LCBpQ29sLCBzVHlwZSwgc3JjQ29sLFxuXHRcdFx0Zml4ZWQgPSBzZXR0aW5ncy5hYVNvcnRpbmdGaXhlZCxcblx0XHRcdGZpeGVkT2JqID0gJC5pc1BsYWluT2JqZWN0KCBmaXhlZCApLFxuXHRcdFx0bmVzdGVkU29ydCA9IFtdLFxuXHRcdFx0YWRkID0gZnVuY3Rpb24gKCBhICkge1xuXHRcdFx0XHRpZiAoIGEubGVuZ3RoICYmICEgQXJyYXkuaXNBcnJheSggYVswXSApICkge1xuXHRcdFx0XHRcdC8vIDFEIGFycmF5XG5cdFx0XHRcdFx0bmVzdGVkU29ydC5wdXNoKCBhICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0Ly8gMkQgYXJyYXlcblx0XHRcdFx0XHQkLm1lcmdlKCBuZXN0ZWRTb3J0LCBhICk7XG5cdFx0XHRcdH1cblx0XHRcdH07XG5cdFxuXHRcdC8vIEJ1aWxkIHRoZSBzb3J0IGFycmF5LCB3aXRoIHByZS1maXggYW5kIHBvc3QtZml4IG9wdGlvbnMgaWYgdGhleSBoYXZlIGJlZW5cblx0XHQvLyBzcGVjaWZpZWRcblx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIGZpeGVkICkgKSB7XG5cdFx0XHRhZGQoIGZpeGVkICk7XG5cdFx0fVxuXHRcblx0XHRpZiAoIGZpeGVkT2JqICYmIGZpeGVkLnByZSApIHtcblx0XHRcdGFkZCggZml4ZWQucHJlICk7XG5cdFx0fVxuXHRcblx0XHRhZGQoIHNldHRpbmdzLmFhU29ydGluZyApO1xuXHRcblx0XHRpZiAoZml4ZWRPYmogJiYgZml4ZWQucG9zdCApIHtcblx0XHRcdGFkZCggZml4ZWQucG9zdCApO1xuXHRcdH1cblx0XG5cdFx0Zm9yICggaT0wIDsgaTxuZXN0ZWRTb3J0Lmxlbmd0aCA7IGkrKyApXG5cdFx0e1xuXHRcdFx0c3JjQ29sID0gbmVzdGVkU29ydFtpXVswXTtcblx0XHRcdGFEYXRhU29ydCA9IGFvQ29sdW1uc1sgc3JjQ29sIF0uYURhdGFTb3J0O1xuXHRcblx0XHRcdGZvciAoIGs9MCwga0xlbj1hRGF0YVNvcnQubGVuZ3RoIDsgazxrTGVuIDsgaysrIClcblx0XHRcdHtcblx0XHRcdFx0aUNvbCA9IGFEYXRhU29ydFtrXTtcblx0XHRcdFx0c1R5cGUgPSBhb0NvbHVtbnNbIGlDb2wgXS5zVHlwZSB8fCAnc3RyaW5nJztcblx0XG5cdFx0XHRcdGlmICggbmVzdGVkU29ydFtpXS5faWR4ID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0bmVzdGVkU29ydFtpXS5faWR4ID0gJC5pbkFycmF5KCBuZXN0ZWRTb3J0W2ldWzFdLCBhb0NvbHVtbnNbaUNvbF0uYXNTb3J0aW5nICk7XG5cdFx0XHRcdH1cblx0XG5cdFx0XHRcdGFTb3J0LnB1c2goIHtcblx0XHRcdFx0XHRzcmM6ICAgICAgIHNyY0NvbCxcblx0XHRcdFx0XHRjb2w6ICAgICAgIGlDb2wsXG5cdFx0XHRcdFx0ZGlyOiAgICAgICBuZXN0ZWRTb3J0W2ldWzFdLFxuXHRcdFx0XHRcdGluZGV4OiAgICAgbmVzdGVkU29ydFtpXS5faWR4LFxuXHRcdFx0XHRcdHR5cGU6ICAgICAgc1R5cGUsXG5cdFx0XHRcdFx0Zm9ybWF0dGVyOiBEYXRhVGFibGUuZXh0LnR5cGUub3JkZXJbIHNUeXBlK1wiLXByZVwiIF1cblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXHRcdH1cblx0XG5cdFx0cmV0dXJuIGFTb3J0O1xuXHR9XG5cdFxuXHQvKipcblx0ICogQ2hhbmdlIHRoZSBvcmRlciBvZiB0aGUgdGFibGVcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKiAgQHRvZG8gVGhpcyByZWFsbHkgbmVlZHMgc3BsaXQgdXAhXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5Tb3J0ICggb1NldHRpbmdzIClcblx0e1xuXHRcdHZhclxuXHRcdFx0aSwgaWVuLCBpTGVuLCBqLCBqTGVuLCBrLCBrTGVuLFxuXHRcdFx0c0RhdGFUeXBlLCBuVGgsXG5cdFx0XHRhaU9yaWcgPSBbXSxcblx0XHRcdG9FeHRTb3J0ID0gRGF0YVRhYmxlLmV4dC50eXBlLm9yZGVyLFxuXHRcdFx0YW9EYXRhID0gb1NldHRpbmdzLmFvRGF0YSxcblx0XHRcdGFvQ29sdW1ucyA9IG9TZXR0aW5ncy5hb0NvbHVtbnMsXG5cdFx0XHRhRGF0YVNvcnQsIGRhdGEsIGlDb2wsIHNUeXBlLCBvU29ydCxcblx0XHRcdGZvcm1hdHRlcnMgPSAwLFxuXHRcdFx0c29ydENvbCxcblx0XHRcdGRpc3BsYXlNYXN0ZXIgPSBvU2V0dGluZ3MuYWlEaXNwbGF5TWFzdGVyLFxuXHRcdFx0YVNvcnQ7XG5cdFxuXHRcdC8vIFJlc29sdmUgYW55IGNvbHVtbiB0eXBlcyB0aGF0IGFyZSB1bmtub3duIGR1ZSB0byBhZGRpdGlvbiBvciBpbnZhbGlkYXRpb25cblx0XHQvLyBAdG9kbyBDYW4gdGhpcyBiZSBtb3ZlZCBpbnRvIGEgJ2RhdGEtcmVhZHknIGhhbmRsZXIgd2hpY2ggaXMgY2FsbGVkIHdoZW5cblx0XHQvLyAgIGRhdGEgaXMgZ29pbmcgdG8gYmUgdXNlZCBpbiB0aGUgdGFibGU/XG5cdFx0X2ZuQ29sdW1uVHlwZXMoIG9TZXR0aW5ncyApO1xuXHRcblx0XHRhU29ydCA9IF9mblNvcnRGbGF0dGVuKCBvU2V0dGluZ3MgKTtcblx0XG5cdFx0Zm9yICggaT0wLCBpZW49YVNvcnQubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRzb3J0Q29sID0gYVNvcnRbaV07XG5cdFxuXHRcdFx0Ly8gVHJhY2sgaWYgd2UgY2FuIHVzZSB0aGUgZmFzdCBzb3J0IGFsZ29yaXRobVxuXHRcdFx0aWYgKCBzb3J0Q29sLmZvcm1hdHRlciApIHtcblx0XHRcdFx0Zm9ybWF0dGVycysrO1xuXHRcdFx0fVxuXHRcblx0XHRcdC8vIExvYWQgdGhlIGRhdGEgbmVlZGVkIGZvciB0aGUgc29ydCwgZm9yIGVhY2ggY2VsbFxuXHRcdFx0X2ZuU29ydERhdGEoIG9TZXR0aW5ncywgc29ydENvbC5jb2wgKTtcblx0XHR9XG5cdFxuXHRcdC8qIE5vIHNvcnRpbmcgcmVxdWlyZWQgaWYgc2VydmVyLXNpZGUgb3Igbm8gc29ydGluZyBhcnJheSAqL1xuXHRcdGlmICggX2ZuRGF0YVNvdXJjZSggb1NldHRpbmdzICkgIT0gJ3NzcCcgJiYgYVNvcnQubGVuZ3RoICE9PSAwIClcblx0XHR7XG5cdFx0XHQvLyBDcmVhdGUgYSB2YWx1ZSAtIGtleSBhcnJheSBvZiB0aGUgY3VycmVudCByb3cgcG9zaXRpb25zIHN1Y2ggdGhhdCB3ZSBjYW4gdXNlIHRoZWlyXG5cdFx0XHQvLyBjdXJyZW50IHBvc2l0aW9uIGR1cmluZyB0aGUgc29ydCwgaWYgdmFsdWVzIG1hdGNoLCBpbiBvcmRlciB0byBwZXJmb3JtIHN0YWJsZSBzb3J0aW5nXG5cdFx0XHRmb3IgKCBpPTAsIGlMZW49ZGlzcGxheU1hc3Rlci5sZW5ndGggOyBpPGlMZW4gOyBpKysgKSB7XG5cdFx0XHRcdGFpT3JpZ1sgZGlzcGxheU1hc3RlcltpXSBdID0gaTtcblx0XHRcdH1cblx0XG5cdFx0XHQvKiBEbyB0aGUgc29ydCAtIGhlcmUgd2Ugd2FudCBtdWx0aS1jb2x1bW4gc29ydGluZyBiYXNlZCBvbiBhIGdpdmVuIGRhdGEgc291cmNlIChjb2x1bW4pXG5cdFx0XHQgKiBhbmQgc29ydGluZyBmdW5jdGlvbiAoZnJvbSBvU29ydCkgaW4gYSBjZXJ0YWluIGRpcmVjdGlvbi4gSXQncyByZWFzb25hYmx5IGNvbXBsZXggdG9cblx0XHRcdCAqIGZvbGxvdyBvbiBpdCdzIG93biwgYnV0IHRoaXMgaXMgd2hhdCB3ZSB3YW50IChleGFtcGxlIHR3byBjb2x1bW4gc29ydGluZyk6XG5cdFx0XHQgKiAgZm5Mb2NhbFNvcnRpbmcgPSBmdW5jdGlvbihhLGIpe1xuXHRcdFx0ICogICAgdmFyIGlUZXN0O1xuXHRcdFx0ICogICAgaVRlc3QgPSBvU29ydFsnc3RyaW5nLWFzYyddKCdkYXRhMTEnLCAnZGF0YTEyJyk7XG5cdFx0XHQgKiAgICAgIGlmIChpVGVzdCAhPT0gMClcblx0XHRcdCAqICAgICAgICByZXR1cm4gaVRlc3Q7XG5cdFx0XHQgKiAgICBpVGVzdCA9IG9Tb3J0WydudW1lcmljLWRlc2MnXSgnZGF0YTIxJywgJ2RhdGEyMicpO1xuXHRcdFx0ICogICAgaWYgKGlUZXN0ICE9PSAwKVxuXHRcdFx0ICogICAgICByZXR1cm4gaVRlc3Q7XG5cdFx0XHQgKiAgICByZXR1cm4gb1NvcnRbJ251bWVyaWMtYXNjJ10oIGFpT3JpZ1thXSwgYWlPcmlnW2JdICk7XG5cdFx0XHQgKiAgfVxuXHRcdFx0ICogQmFzaWNhbGx5IHdlIGhhdmUgYSB0ZXN0IGZvciBlYWNoIHNvcnRpbmcgY29sdW1uLCBpZiB0aGUgZGF0YSBpbiB0aGF0IGNvbHVtbiBpcyBlcXVhbCxcblx0XHRcdCAqIHRlc3QgdGhlIG5leHQgY29sdW1uLiBJZiBhbGwgY29sdW1ucyBtYXRjaCwgdGhlbiB3ZSB1c2UgYSBudW1lcmljIHNvcnQgb24gdGhlIHJvd1xuXHRcdFx0ICogcG9zaXRpb25zIGluIHRoZSBvcmlnaW5hbCBkYXRhIGFycmF5IHRvIHByb3ZpZGUgYSBzdGFibGUgc29ydC5cblx0XHRcdCAqXG5cdFx0XHQgKiBOb3RlIC0gSSBrbm93IGl0IHNlZW1zIGV4Y2Vzc2l2ZSB0byBoYXZlIHR3byBzb3J0aW5nIG1ldGhvZHMsIGJ1dCB0aGUgZmlyc3QgaXMgYXJvdW5kXG5cdFx0XHQgKiAxNSUgZmFzdGVyLCBzbyB0aGUgc2Vjb25kIGlzIG9ubHkgbWFpbnRhaW5lZCBmb3IgYmFja3dhcmRzIGNvbXBhdGliaWxpdHkgd2l0aCBzb3J0aW5nXG5cdFx0XHQgKiBtZXRob2RzIHdoaWNoIGRvIG5vdCBoYXZlIGEgcHJlLXNvcnQgZm9ybWF0dGluZyBmdW5jdGlvbi5cblx0XHRcdCAqL1xuXHRcdFx0aWYgKCBmb3JtYXR0ZXJzID09PSBhU29ydC5sZW5ndGggKSB7XG5cdFx0XHRcdC8vIEFsbCBzb3J0IHR5cGVzIGhhdmUgZm9ybWF0dGluZyBmdW5jdGlvbnNcblx0XHRcdFx0ZGlzcGxheU1hc3Rlci5zb3J0KCBmdW5jdGlvbiAoIGEsIGIgKSB7XG5cdFx0XHRcdFx0dmFyXG5cdFx0XHRcdFx0XHR4LCB5LCBrLCB0ZXN0LCBzb3J0LFxuXHRcdFx0XHRcdFx0bGVuPWFTb3J0Lmxlbmd0aCxcblx0XHRcdFx0XHRcdGRhdGFBID0gYW9EYXRhW2FdLl9hU29ydERhdGEsXG5cdFx0XHRcdFx0XHRkYXRhQiA9IGFvRGF0YVtiXS5fYVNvcnREYXRhO1xuXHRcblx0XHRcdFx0XHRmb3IgKCBrPTAgOyBrPGxlbiA7IGsrKyApIHtcblx0XHRcdFx0XHRcdHNvcnQgPSBhU29ydFtrXTtcblx0XG5cdFx0XHRcdFx0XHR4ID0gZGF0YUFbIHNvcnQuY29sIF07XG5cdFx0XHRcdFx0XHR5ID0gZGF0YUJbIHNvcnQuY29sIF07XG5cdFxuXHRcdFx0XHRcdFx0dGVzdCA9IHg8eSA/IC0xIDogeD55ID8gMSA6IDA7XG5cdFx0XHRcdFx0XHRpZiAoIHRlc3QgIT09IDAgKSB7XG5cdFx0XHRcdFx0XHRcdHJldHVybiBzb3J0LmRpciA9PT0gJ2FzYycgPyB0ZXN0IDogLXRlc3Q7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcblx0XHRcdFx0XHR4ID0gYWlPcmlnW2FdO1xuXHRcdFx0XHRcdHkgPSBhaU9yaWdbYl07XG5cdFx0XHRcdFx0cmV0dXJuIHg8eSA/IC0xIDogeD55ID8gMSA6IDA7XG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHRcdGVsc2Uge1xuXHRcdFx0XHQvLyBEZXByZWNpYXRlZCAtIHJlbW92ZSBpbiAxLjExIChwcm92aWRpbmcgYSBwbHVnLWluIG9wdGlvbilcblx0XHRcdFx0Ly8gTm90IGFsbCBzb3J0IHR5cGVzIGhhdmUgZm9ybWF0dGluZyBtZXRob2RzLCBzbyB3ZSBoYXZlIHRvIGNhbGwgdGhlaXIgc29ydGluZ1xuXHRcdFx0XHQvLyBtZXRob2RzLlxuXHRcdFx0XHRkaXNwbGF5TWFzdGVyLnNvcnQoIGZ1bmN0aW9uICggYSwgYiApIHtcblx0XHRcdFx0XHR2YXJcblx0XHRcdFx0XHRcdHgsIHksIGssIGwsIHRlc3QsIHNvcnQsIGZuLFxuXHRcdFx0XHRcdFx0bGVuPWFTb3J0Lmxlbmd0aCxcblx0XHRcdFx0XHRcdGRhdGFBID0gYW9EYXRhW2FdLl9hU29ydERhdGEsXG5cdFx0XHRcdFx0XHRkYXRhQiA9IGFvRGF0YVtiXS5fYVNvcnREYXRhO1xuXHRcblx0XHRcdFx0XHRmb3IgKCBrPTAgOyBrPGxlbiA7IGsrKyApIHtcblx0XHRcdFx0XHRcdHNvcnQgPSBhU29ydFtrXTtcblx0XG5cdFx0XHRcdFx0XHR4ID0gZGF0YUFbIHNvcnQuY29sIF07XG5cdFx0XHRcdFx0XHR5ID0gZGF0YUJbIHNvcnQuY29sIF07XG5cdFxuXHRcdFx0XHRcdFx0Zm4gPSBvRXh0U29ydFsgc29ydC50eXBlK1wiLVwiK3NvcnQuZGlyIF0gfHwgb0V4dFNvcnRbIFwic3RyaW5nLVwiK3NvcnQuZGlyIF07XG5cdFx0XHRcdFx0XHR0ZXN0ID0gZm4oIHgsIHkgKTtcblx0XHRcdFx0XHRcdGlmICggdGVzdCAhPT0gMCApIHtcblx0XHRcdFx0XHRcdFx0cmV0dXJuIHRlc3Q7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcblx0XHRcdFx0XHR4ID0gYWlPcmlnW2FdO1xuXHRcdFx0XHRcdHkgPSBhaU9yaWdbYl07XG5cdFx0XHRcdFx0cmV0dXJuIHg8eSA/IC0xIDogeD55ID8gMSA6IDA7XG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHR9XG5cdFxuXHRcdC8qIFRlbGwgdGhlIGRyYXcgZnVuY3Rpb24gdGhhdCB3ZSBoYXZlIHNvcnRlZCB0aGUgZGF0YSAqL1xuXHRcdG9TZXR0aW5ncy5iU29ydGVkID0gdHJ1ZTtcblx0fVxuXHRcblx0XG5cdGZ1bmN0aW9uIF9mblNvcnRBcmlhICggc2V0dGluZ3MgKVxuXHR7XG5cdFx0dmFyIGxhYmVsO1xuXHRcdHZhciBuZXh0U29ydDtcblx0XHR2YXIgY29sdW1ucyA9IHNldHRpbmdzLmFvQ29sdW1ucztcblx0XHR2YXIgYVNvcnQgPSBfZm5Tb3J0RmxhdHRlbiggc2V0dGluZ3MgKTtcblx0XHR2YXIgb0FyaWEgPSBzZXR0aW5ncy5vTGFuZ3VhZ2Uub0FyaWE7XG5cdFxuXHRcdC8vIEFSSUEgYXR0cmlidXRlcyAtIG5lZWQgdG8gbG9vcCBhbGwgY29sdW1ucywgdG8gdXBkYXRlIGFsbCAocmVtb3Zpbmcgb2xkXG5cdFx0Ly8gYXR0cmlidXRlcyBhcyBuZWVkZWQpXG5cdFx0Zm9yICggdmFyIGk9MCwgaUxlbj1jb2x1bW5zLmxlbmd0aCA7IGk8aUxlbiA7IGkrKyApXG5cdFx0e1xuXHRcdFx0dmFyIGNvbCA9IGNvbHVtbnNbaV07XG5cdFx0XHR2YXIgYXNTb3J0aW5nID0gY29sLmFzU29ydGluZztcblx0XHRcdHZhciBzVGl0bGUgPSBjb2wuYXJpYVRpdGxlIHx8IGNvbC5zVGl0bGUucmVwbGFjZSggLzwuKj8+L2csIFwiXCIgKTtcblx0XHRcdHZhciB0aCA9IGNvbC5uVGg7XG5cdFxuXHRcdFx0Ly8gSUU3IGlzIHRocm93aW5nIGFuIGVycm9yIHdoZW4gc2V0dGluZyB0aGVzZSBwcm9wZXJ0aWVzIHdpdGggalF1ZXJ5J3Ncblx0XHRcdC8vIGF0dHIoKSBhbmQgcmVtb3ZlQXR0cigpIG1ldGhvZHMuLi5cblx0XHRcdHRoLnJlbW92ZUF0dHJpYnV0ZSgnYXJpYS1zb3J0Jyk7XG5cdFxuXHRcdFx0LyogSW4gQVJJQSBvbmx5IHRoZSBmaXJzdCBzb3J0aW5nIGNvbHVtbiBjYW4gYmUgbWFya2VkIGFzIHNvcnRpbmcgLSBubyBtdWx0aS1zb3J0IG9wdGlvbiAqL1xuXHRcdFx0aWYgKCBjb2wuYlNvcnRhYmxlICkge1xuXHRcdFx0XHRpZiAoIGFTb3J0Lmxlbmd0aCA+IDAgJiYgYVNvcnRbMF0uY29sID09IGkgKSB7XG5cdFx0XHRcdFx0dGguc2V0QXR0cmlidXRlKCdhcmlhLXNvcnQnLCBhU29ydFswXS5kaXI9PVwiYXNjXCIgPyBcImFzY2VuZGluZ1wiIDogXCJkZXNjZW5kaW5nXCIgKTtcblx0XHRcdFx0XHRuZXh0U29ydCA9IGFzU29ydGluZ1sgYVNvcnRbMF0uaW5kZXgrMSBdIHx8IGFzU29ydGluZ1swXTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRuZXh0U29ydCA9IGFzU29ydGluZ1swXTtcblx0XHRcdFx0fVxuXHRcblx0XHRcdFx0bGFiZWwgPSBzVGl0bGUgKyAoIG5leHRTb3J0ID09PSBcImFzY1wiID9cblx0XHRcdFx0XHRvQXJpYS5zU29ydEFzY2VuZGluZyA6XG5cdFx0XHRcdFx0b0FyaWEuc1NvcnREZXNjZW5kaW5nXG5cdFx0XHRcdCk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0bGFiZWwgPSBzVGl0bGU7XG5cdFx0XHR9XG5cdFxuXHRcdFx0dGguc2V0QXR0cmlidXRlKCdhcmlhLWxhYmVsJywgbGFiZWwpO1xuXHRcdH1cblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBGdW5jdGlvbiB0byBydW4gb24gdXNlciBzb3J0IHJlcXVlc3Rcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHBhcmFtIHtub2RlfSBhdHRhY2hUbyBub2RlIHRvIGF0dGFjaCB0aGUgaGFuZGxlciB0b1xuXHQgKiAgQHBhcmFtIHtpbnR9IGNvbElkeCBjb2x1bW4gc29ydGluZyBpbmRleFxuXHQgKiAgQHBhcmFtIHtib29sZWFufSBbYXBwZW5kPWZhbHNlXSBBcHBlbmQgdGhlIHJlcXVlc3RlZCBzb3J0IHRvIHRoZSBleGlzdGluZ1xuXHQgKiAgICBzb3J0IGlmIHRydWUgKGkuZS4gbXVsdGktY29sdW1uIHNvcnQpXG5cdCAqICBAcGFyYW0ge2Z1bmN0aW9ufSBbY2FsbGJhY2tdIGNhbGxiYWNrIGZ1bmN0aW9uXG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mblNvcnRMaXN0ZW5lciAoIHNldHRpbmdzLCBjb2xJZHgsIGFwcGVuZCwgY2FsbGJhY2sgKVxuXHR7XG5cdFx0dmFyIGNvbCA9IHNldHRpbmdzLmFvQ29sdW1uc1sgY29sSWR4IF07XG5cdFx0dmFyIHNvcnRpbmcgPSBzZXR0aW5ncy5hYVNvcnRpbmc7XG5cdFx0dmFyIGFzU29ydGluZyA9IGNvbC5hc1NvcnRpbmc7XG5cdFx0dmFyIG5leHRTb3J0SWR4O1xuXHRcdHZhciBuZXh0ID0gZnVuY3Rpb24gKCBhLCBvdmVyZmxvdyApIHtcblx0XHRcdHZhciBpZHggPSBhLl9pZHg7XG5cdFx0XHRpZiAoIGlkeCA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRpZHggPSAkLmluQXJyYXkoIGFbMV0sIGFzU29ydGluZyApO1xuXHRcdFx0fVxuXHRcblx0XHRcdHJldHVybiBpZHgrMSA8IGFzU29ydGluZy5sZW5ndGggP1xuXHRcdFx0XHRpZHgrMSA6XG5cdFx0XHRcdG92ZXJmbG93ID9cblx0XHRcdFx0XHRudWxsIDpcblx0XHRcdFx0XHQwO1xuXHRcdH07XG5cdFxuXHRcdC8vIENvbnZlcnQgdG8gMkQgYXJyYXkgaWYgbmVlZGVkXG5cdFx0aWYgKCB0eXBlb2Ygc29ydGluZ1swXSA9PT0gJ251bWJlcicgKSB7XG5cdFx0XHRzb3J0aW5nID0gc2V0dGluZ3MuYWFTb3J0aW5nID0gWyBzb3J0aW5nIF07XG5cdFx0fVxuXHRcblx0XHQvLyBJZiBhcHBlbmRpbmcgdGhlIHNvcnQgdGhlbiB3ZSBhcmUgbXVsdGktY29sdW1uIHNvcnRpbmdcblx0XHRpZiAoIGFwcGVuZCAmJiBzZXR0aW5ncy5vRmVhdHVyZXMuYlNvcnRNdWx0aSApIHtcblx0XHRcdC8vIEFyZSB3ZSBhbHJlYWR5IGRvaW5nIHNvbWUga2luZCBvZiBzb3J0IG9uIHRoaXMgY29sdW1uP1xuXHRcdFx0dmFyIHNvcnRJZHggPSAkLmluQXJyYXkoIGNvbElkeCwgX3BsdWNrKHNvcnRpbmcsICcwJykgKTtcblx0XG5cdFx0XHRpZiAoIHNvcnRJZHggIT09IC0xICkge1xuXHRcdFx0XHQvLyBZZXMsIG1vZGlmeSB0aGUgc29ydFxuXHRcdFx0XHRuZXh0U29ydElkeCA9IG5leHQoIHNvcnRpbmdbc29ydElkeF0sIHRydWUgKTtcblx0XG5cdFx0XHRcdGlmICggbmV4dFNvcnRJZHggPT09IG51bGwgJiYgc29ydGluZy5sZW5ndGggPT09IDEgKSB7XG5cdFx0XHRcdFx0bmV4dFNvcnRJZHggPSAwOyAvLyBjYW4ndCByZW1vdmUgc29ydGluZyBjb21wbGV0ZWx5XG5cdFx0XHRcdH1cblx0XG5cdFx0XHRcdGlmICggbmV4dFNvcnRJZHggPT09IG51bGwgKSB7XG5cdFx0XHRcdFx0c29ydGluZy5zcGxpY2UoIHNvcnRJZHgsIDEgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRzb3J0aW5nW3NvcnRJZHhdWzFdID0gYXNTb3J0aW5nWyBuZXh0U29ydElkeCBdO1xuXHRcdFx0XHRcdHNvcnRpbmdbc29ydElkeF0uX2lkeCA9IG5leHRTb3J0SWR4O1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0Ly8gTm8gc29ydCBvbiB0aGlzIGNvbHVtbiB5ZXRcblx0XHRcdFx0c29ydGluZy5wdXNoKCBbIGNvbElkeCwgYXNTb3J0aW5nWzBdLCAwIF0gKTtcblx0XHRcdFx0c29ydGluZ1tzb3J0aW5nLmxlbmd0aC0xXS5faWR4ID0gMDtcblx0XHRcdH1cblx0XHR9XG5cdFx0ZWxzZSBpZiAoIHNvcnRpbmcubGVuZ3RoICYmIHNvcnRpbmdbMF1bMF0gPT0gY29sSWR4ICkge1xuXHRcdFx0Ly8gU2luZ2xlIGNvbHVtbiAtIGFscmVhZHkgc29ydGluZyBvbiB0aGlzIGNvbHVtbiwgbW9kaWZ5IHRoZSBzb3J0XG5cdFx0XHRuZXh0U29ydElkeCA9IG5leHQoIHNvcnRpbmdbMF0gKTtcblx0XG5cdFx0XHRzb3J0aW5nLmxlbmd0aCA9IDE7XG5cdFx0XHRzb3J0aW5nWzBdWzFdID0gYXNTb3J0aW5nWyBuZXh0U29ydElkeCBdO1xuXHRcdFx0c29ydGluZ1swXS5faWR4ID0gbmV4dFNvcnRJZHg7XG5cdFx0fVxuXHRcdGVsc2Uge1xuXHRcdFx0Ly8gU2luZ2xlIGNvbHVtbiAtIHNvcnQgb25seSBvbiB0aGlzIGNvbHVtblxuXHRcdFx0c29ydGluZy5sZW5ndGggPSAwO1xuXHRcdFx0c29ydGluZy5wdXNoKCBbIGNvbElkeCwgYXNTb3J0aW5nWzBdIF0gKTtcblx0XHRcdHNvcnRpbmdbMF0uX2lkeCA9IDA7XG5cdFx0fVxuXHRcblx0XHQvLyBSdW4gdGhlIHNvcnQgYnkgY2FsbGluZyBhIGZ1bGwgcmVkcmF3XG5cdFx0X2ZuUmVEcmF3KCBzZXR0aW5ncyApO1xuXHRcblx0XHQvLyBjYWxsYmFjayB1c2VkIGZvciBhc3luYyB1c2VyIGludGVyYWN0aW9uXG5cdFx0aWYgKCB0eXBlb2YgY2FsbGJhY2sgPT0gJ2Z1bmN0aW9uJyApIHtcblx0XHRcdGNhbGxiYWNrKCBzZXR0aW5ncyApO1xuXHRcdH1cblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBBdHRhY2ggYSBzb3J0IGhhbmRsZXIgKGNsaWNrKSB0byBhIG5vZGVcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHBhcmFtIHtub2RlfSBhdHRhY2hUbyBub2RlIHRvIGF0dGFjaCB0aGUgaGFuZGxlciB0b1xuXHQgKiAgQHBhcmFtIHtpbnR9IGNvbElkeCBjb2x1bW4gc29ydGluZyBpbmRleFxuXHQgKiAgQHBhcmFtIHtmdW5jdGlvbn0gW2NhbGxiYWNrXSBjYWxsYmFjayBmdW5jdGlvblxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5Tb3J0QXR0YWNoTGlzdGVuZXIgKCBzZXR0aW5ncywgYXR0YWNoVG8sIGNvbElkeCwgY2FsbGJhY2sgKVxuXHR7XG5cdFx0dmFyIGNvbCA9IHNldHRpbmdzLmFvQ29sdW1uc1sgY29sSWR4IF07XG5cdFxuXHRcdF9mbkJpbmRBY3Rpb24oIGF0dGFjaFRvLCB7fSwgZnVuY3Rpb24gKGUpIHtcblx0XHRcdC8qIElmIHRoZSBjb2x1bW4gaXMgbm90IHNvcnRhYmxlIC0gZG9uJ3QgdG8gYW55dGhpbmcgKi9cblx0XHRcdGlmICggY29sLmJTb3J0YWJsZSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblx0XG5cdFx0XHQvLyBJZiBwcm9jZXNzaW5nIGlzIGVuYWJsZWQgdXNlIGEgdGltZW91dCB0byBhbGxvdyB0aGUgcHJvY2Vzc2luZ1xuXHRcdFx0Ly8gZGlzcGxheSB0byBiZSBzaG93biAtIG90aGVyd2lzZSB0byBpdCBzeW5jaHJvbm91c2x5XG5cdFx0XHRpZiAoIHNldHRpbmdzLm9GZWF0dXJlcy5iUHJvY2Vzc2luZyApIHtcblx0XHRcdFx0X2ZuUHJvY2Vzc2luZ0Rpc3BsYXkoIHNldHRpbmdzLCB0cnVlICk7XG5cdFxuXHRcdFx0XHRzZXRUaW1lb3V0KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRfZm5Tb3J0TGlzdGVuZXIoIHNldHRpbmdzLCBjb2xJZHgsIGUuc2hpZnRLZXksIGNhbGxiYWNrICk7XG5cdFxuXHRcdFx0XHRcdC8vIEluIHNlcnZlci1zaWRlIHByb2Nlc3NpbmcsIHRoZSBkcmF3IGNhbGxiYWNrIHdpbGwgcmVtb3ZlIHRoZVxuXHRcdFx0XHRcdC8vIHByb2Nlc3NpbmcgZGlzcGxheVxuXHRcdFx0XHRcdGlmICggX2ZuRGF0YVNvdXJjZSggc2V0dGluZ3MgKSAhPT0gJ3NzcCcgKSB7XG5cdFx0XHRcdFx0XHRfZm5Qcm9jZXNzaW5nRGlzcGxheSggc2V0dGluZ3MsIGZhbHNlICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9LCAwICk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0X2ZuU29ydExpc3RlbmVyKCBzZXR0aW5ncywgY29sSWR4LCBlLnNoaWZ0S2V5LCBjYWxsYmFjayApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBTZXQgdGhlIHNvcnRpbmcgY2xhc3NlcyBvbiB0YWJsZSdzIGJvZHksIE5vdGU6IGl0IGlzIHNhZmUgdG8gY2FsbCB0aGlzIGZ1bmN0aW9uXG5cdCAqIHdoZW4gYlNvcnQgYW5kIGJTb3J0Q2xhc3NlcyBhcmUgZmFsc2Vcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuU29ydGluZ0NsYXNzZXMoIHNldHRpbmdzIClcblx0e1xuXHRcdHZhciBvbGRTb3J0ID0gc2V0dGluZ3MuYUxhc3RTb3J0O1xuXHRcdHZhciBzb3J0Q2xhc3MgPSBzZXR0aW5ncy5vQ2xhc3Nlcy5zU29ydENvbHVtbjtcblx0XHR2YXIgc29ydCA9IF9mblNvcnRGbGF0dGVuKCBzZXR0aW5ncyApO1xuXHRcdHZhciBmZWF0dXJlcyA9IHNldHRpbmdzLm9GZWF0dXJlcztcblx0XHR2YXIgaSwgaWVuLCBjb2xJZHg7XG5cdFxuXHRcdGlmICggZmVhdHVyZXMuYlNvcnQgJiYgZmVhdHVyZXMuYlNvcnRDbGFzc2VzICkge1xuXHRcdFx0Ly8gUmVtb3ZlIG9sZCBzb3J0aW5nIGNsYXNzZXNcblx0XHRcdGZvciAoIGk9MCwgaWVuPW9sZFNvcnQubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRcdGNvbElkeCA9IG9sZFNvcnRbaV0uc3JjO1xuXHRcblx0XHRcdFx0Ly8gUmVtb3ZlIGNvbHVtbiBzb3J0aW5nXG5cdFx0XHRcdCQoIF9wbHVjayggc2V0dGluZ3MuYW9EYXRhLCAnYW5DZWxscycsIGNvbElkeCApIClcblx0XHRcdFx0XHQucmVtb3ZlQ2xhc3MoIHNvcnRDbGFzcyArIChpPDIgPyBpKzEgOiAzKSApO1xuXHRcdFx0fVxuXHRcblx0XHRcdC8vIEFkZCBuZXcgY29sdW1uIHNvcnRpbmdcblx0XHRcdGZvciAoIGk9MCwgaWVuPXNvcnQubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRcdGNvbElkeCA9IHNvcnRbaV0uc3JjO1xuXHRcblx0XHRcdFx0JCggX3BsdWNrKCBzZXR0aW5ncy5hb0RhdGEsICdhbkNlbGxzJywgY29sSWR4ICkgKVxuXHRcdFx0XHRcdC5hZGRDbGFzcyggc29ydENsYXNzICsgKGk8MiA/IGkrMSA6IDMpICk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcblx0XHRzZXR0aW5ncy5hTGFzdFNvcnQgPSBzb3J0O1xuXHR9XG5cdFxuXHRcblx0Ly8gR2V0IHRoZSBkYXRhIHRvIHNvcnQgYSBjb2x1bW4sIGJlIGl0IGZyb20gY2FjaGUsIGZyZXNoIChwb3B1bGF0aW5nIHRoZVxuXHQvLyBjYWNoZSksIG9yIGZyb20gYSBzb3J0IGZvcm1hdHRlclxuXHRmdW5jdGlvbiBfZm5Tb3J0RGF0YSggc2V0dGluZ3MsIGlkeCApXG5cdHtcblx0XHQvLyBDdXN0b20gc29ydGluZyBmdW5jdGlvbiAtIHByb3ZpZGVkIGJ5IHRoZSBzb3J0IGRhdGEgdHlwZVxuXHRcdHZhciBjb2x1bW4gPSBzZXR0aW5ncy5hb0NvbHVtbnNbIGlkeCBdO1xuXHRcdHZhciBjdXN0b21Tb3J0ID0gRGF0YVRhYmxlLmV4dC5vcmRlclsgY29sdW1uLnNTb3J0RGF0YVR5cGUgXTtcblx0XHR2YXIgY3VzdG9tRGF0YTtcblx0XG5cdFx0aWYgKCBjdXN0b21Tb3J0ICkge1xuXHRcdFx0Y3VzdG9tRGF0YSA9IGN1c3RvbVNvcnQuY2FsbCggc2V0dGluZ3Mub0luc3RhbmNlLCBzZXR0aW5ncywgaWR4LFxuXHRcdFx0XHRfZm5Db2x1bW5JbmRleFRvVmlzaWJsZSggc2V0dGluZ3MsIGlkeCApXG5cdFx0XHQpO1xuXHRcdH1cblx0XG5cdFx0Ly8gVXNlIC8gcG9wdWxhdGUgY2FjaGVcblx0XHR2YXIgcm93LCBjZWxsRGF0YTtcblx0XHR2YXIgZm9ybWF0dGVyID0gRGF0YVRhYmxlLmV4dC50eXBlLm9yZGVyWyBjb2x1bW4uc1R5cGUrXCItcHJlXCIgXTtcblx0XG5cdFx0Zm9yICggdmFyIGk9MCwgaWVuPXNldHRpbmdzLmFvRGF0YS5sZW5ndGggOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdHJvdyA9IHNldHRpbmdzLmFvRGF0YVtpXTtcblx0XG5cdFx0XHRpZiAoICEgcm93Ll9hU29ydERhdGEgKSB7XG5cdFx0XHRcdHJvdy5fYVNvcnREYXRhID0gW107XG5cdFx0XHR9XG5cdFxuXHRcdFx0aWYgKCAhIHJvdy5fYVNvcnREYXRhW2lkeF0gfHwgY3VzdG9tU29ydCApIHtcblx0XHRcdFx0Y2VsbERhdGEgPSBjdXN0b21Tb3J0ID9cblx0XHRcdFx0XHRjdXN0b21EYXRhW2ldIDogLy8gSWYgdGhlcmUgd2FzIGEgY3VzdG9tIHNvcnQgZnVuY3Rpb24sIHVzZSBkYXRhIGZyb20gdGhlcmVcblx0XHRcdFx0XHRfZm5HZXRDZWxsRGF0YSggc2V0dGluZ3MsIGksIGlkeCwgJ3NvcnQnICk7XG5cdFxuXHRcdFx0XHRyb3cuX2FTb3J0RGF0YVsgaWR4IF0gPSBmb3JtYXR0ZXIgP1xuXHRcdFx0XHRcdGZvcm1hdHRlciggY2VsbERhdGEgKSA6XG5cdFx0XHRcdFx0Y2VsbERhdGE7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cdFxuXHRcblx0XG5cdC8qKlxuXHQgKiBTYXZlIHRoZSBzdGF0ZSBvZiBhIHRhYmxlXG5cdCAqICBAcGFyYW0ge29iamVjdH0gb1NldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mblNhdmVTdGF0ZSAoIHNldHRpbmdzIClcblx0e1xuXHRcdGlmIChzZXR0aW5ncy5fYkxvYWRpbmdTdGF0ZSkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XG5cdFx0LyogU3RvcmUgdGhlIGludGVyZXN0aW5nIHZhcmlhYmxlcyAqL1xuXHRcdHZhciBzdGF0ZSA9IHtcblx0XHRcdHRpbWU6ICAgICtuZXcgRGF0ZSgpLFxuXHRcdFx0c3RhcnQ6ICAgc2V0dGluZ3MuX2lEaXNwbGF5U3RhcnQsXG5cdFx0XHRsZW5ndGg6ICBzZXR0aW5ncy5faURpc3BsYXlMZW5ndGgsXG5cdFx0XHRvcmRlcjogICAkLmV4dGVuZCggdHJ1ZSwgW10sIHNldHRpbmdzLmFhU29ydGluZyApLFxuXHRcdFx0c2VhcmNoOiAgX2ZuU2VhcmNoVG9DYW1lbCggc2V0dGluZ3Mub1ByZXZpb3VzU2VhcmNoICksXG5cdFx0XHRjb2x1bW5zOiAkLm1hcCggc2V0dGluZ3MuYW9Db2x1bW5zLCBmdW5jdGlvbiAoIGNvbCwgaSApIHtcblx0XHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0XHR2aXNpYmxlOiBjb2wuYlZpc2libGUsXG5cdFx0XHRcdFx0c2VhcmNoOiBfZm5TZWFyY2hUb0NhbWVsKCBzZXR0aW5ncy5hb1ByZVNlYXJjaENvbHNbaV0gKVxuXHRcdFx0XHR9O1xuXHRcdFx0fSApXG5cdFx0fTtcblx0XG5cdFx0c2V0dGluZ3Mub1NhdmVkU3RhdGUgPSBzdGF0ZTtcblx0XHRfZm5DYWxsYmFja0ZpcmUoIHNldHRpbmdzLCBcImFvU3RhdGVTYXZlUGFyYW1zXCIsICdzdGF0ZVNhdmVQYXJhbXMnLCBbc2V0dGluZ3MsIHN0YXRlXSApO1xuXHRcdFxuXHRcdGlmICggc2V0dGluZ3Mub0ZlYXR1cmVzLmJTdGF0ZVNhdmUgJiYgIXNldHRpbmdzLmJEZXN0cm95aW5nIClcblx0XHR7XG5cdFx0XHRzZXR0aW5ncy5mblN0YXRlU2F2ZUNhbGxiYWNrLmNhbGwoIHNldHRpbmdzLm9JbnN0YW5jZSwgc2V0dGluZ3MsIHN0YXRlICk7XG5cdFx0fVx0XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogQXR0ZW1wdCB0byBsb2FkIGEgc2F2ZWQgdGFibGUgc3RhdGVcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvU2V0dGluZ3MgZGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvSW5pdCBEYXRhVGFibGVzIGluaXQgb2JqZWN0IHNvIHdlIGNhbiBvdmVycmlkZSBzZXR0aW5nc1xuXHQgKiAgQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2sgQ2FsbGJhY2sgdG8gZXhlY3V0ZSB3aGVuIHRoZSBzdGF0ZSBoYXMgYmVlbiBsb2FkZWRcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuTG9hZFN0YXRlICggc2V0dGluZ3MsIG9Jbml0LCBjYWxsYmFjayApXG5cdHtcblx0XHRpZiAoICEgc2V0dGluZ3Mub0ZlYXR1cmVzLmJTdGF0ZVNhdmUgKSB7XG5cdFx0XHRjYWxsYmFjaygpO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XG5cdFx0dmFyIGxvYWRlZCA9IGZ1bmN0aW9uKHN0YXRlKSB7XG5cdFx0XHRfZm5JbXBsZW1lbnRTdGF0ZShzZXR0aW5ncywgc3RhdGUsIGNhbGxiYWNrKTtcblx0XHR9XG5cdFxuXHRcdHZhciBzdGF0ZSA9IHNldHRpbmdzLmZuU3RhdGVMb2FkQ2FsbGJhY2suY2FsbCggc2V0dGluZ3Mub0luc3RhbmNlLCBzZXR0aW5ncywgbG9hZGVkICk7XG5cdFxuXHRcdGlmICggc3RhdGUgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdF9mbkltcGxlbWVudFN0YXRlKCBzZXR0aW5ncywgc3RhdGUsIGNhbGxiYWNrICk7XG5cdFx0fVxuXHRcdC8vIG90aGVyd2lzZSwgd2FpdCBmb3IgdGhlIGxvYWRlZCBjYWxsYmFjayB0byBiZSBleGVjdXRlZFxuXHRcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fVxuXHRcblx0ZnVuY3Rpb24gX2ZuSW1wbGVtZW50U3RhdGUgKCBzZXR0aW5ncywgcywgY2FsbGJhY2spIHtcblx0XHR2YXIgaSwgaWVuO1xuXHRcdHZhciBjb2x1bW5zID0gc2V0dGluZ3MuYW9Db2x1bW5zO1xuXHRcdHNldHRpbmdzLl9iTG9hZGluZ1N0YXRlID0gdHJ1ZTtcblx0XG5cdFx0Ly8gV2hlbiBTdGF0ZVJlc3RvcmUgd2FzIGludHJvZHVjZWQgdGhlIHN0YXRlIGNvdWxkIG5vdyBiZSBpbXBsZW1lbnRlZCBhdCBhbnkgdGltZVxuXHRcdC8vIE5vdCBqdXN0IGluaXRpYWxpc2F0aW9uLiBUbyBkbyB0aGlzIGFuIGFwaSBpbnN0YW5jZSBpcyByZXF1aXJlZCBpbiBzb21lIHBsYWNlc1xuXHRcdHZhciBhcGkgPSBzZXR0aW5ncy5fYkluaXRDb21wbGV0ZSA/IG5ldyBEYXRhVGFibGUuQXBpKHNldHRpbmdzKSA6IG51bGw7XG5cdFxuXHRcdGlmICggISBzIHx8ICEgcy50aW1lICkge1xuXHRcdFx0c2V0dGluZ3MuX2JMb2FkaW5nU3RhdGUgPSBmYWxzZTtcblx0XHRcdGNhbGxiYWNrKCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcblx0XHQvLyBBbGxvdyBjdXN0b20gYW5kIHBsdWctaW4gbWFuaXB1bGF0aW9uIGZ1bmN0aW9ucyB0byBhbHRlciB0aGUgc2F2ZWQgZGF0YSBzZXQgYW5kXG5cdFx0Ly8gY2FuY2VsbGluZyBvZiBsb2FkaW5nIGJ5IHJldHVybmluZyBmYWxzZVxuXHRcdHZhciBhYlN0YXRlTG9hZCA9IF9mbkNhbGxiYWNrRmlyZSggc2V0dGluZ3MsICdhb1N0YXRlTG9hZFBhcmFtcycsICdzdGF0ZUxvYWRQYXJhbXMnLCBbc2V0dGluZ3MsIHNdICk7XG5cdFx0aWYgKCAkLmluQXJyYXkoIGZhbHNlLCBhYlN0YXRlTG9hZCApICE9PSAtMSApIHtcblx0XHRcdHNldHRpbmdzLl9iTG9hZGluZ1N0YXRlID0gZmFsc2U7XG5cdFx0XHRjYWxsYmFjaygpO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XG5cdFx0Ly8gUmVqZWN0IG9sZCBkYXRhXG5cdFx0dmFyIGR1cmF0aW9uID0gc2V0dGluZ3MuaVN0YXRlRHVyYXRpb247XG5cdFx0aWYgKCBkdXJhdGlvbiA+IDAgJiYgcy50aW1lIDwgK25ldyBEYXRlKCkgLSAoZHVyYXRpb24qMTAwMCkgKSB7XG5cdFx0XHRzZXR0aW5ncy5fYkxvYWRpbmdTdGF0ZSA9IGZhbHNlO1xuXHRcdFx0Y2FsbGJhY2soKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFxuXHRcdC8vIE51bWJlciBvZiBjb2x1bW5zIGhhdmUgY2hhbmdlZCAtIGFsbCBiZXRzIGFyZSBvZmYsIG5vIHJlc3RvcmUgb2Ygc2V0dGluZ3Ncblx0XHRpZiAoIHMuY29sdW1ucyAmJiBjb2x1bW5zLmxlbmd0aCAhPT0gcy5jb2x1bW5zLmxlbmd0aCApIHtcblx0XHRcdHNldHRpbmdzLl9iTG9hZGluZ1N0YXRlID0gZmFsc2U7XG5cdFx0XHRjYWxsYmFjaygpO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XG5cdFx0Ly8gU3RvcmUgdGhlIHNhdmVkIHN0YXRlIHNvIGl0IG1pZ2h0IGJlIGFjY2Vzc2VkIGF0IGFueSB0aW1lXG5cdFx0c2V0dGluZ3Mub0xvYWRlZFN0YXRlID0gJC5leHRlbmQoIHRydWUsIHt9LCBzICk7XG5cdFxuXHRcdC8vIFJlc3RvcmUga2V5IGZlYXR1cmVzIC0gdG9kbyAtIGZvciAxLjExIHRoaXMgbmVlZHMgdG8gYmUgZG9uZSBieVxuXHRcdC8vIHN1YnNjcmliZWQgZXZlbnRzXG5cdFx0aWYgKCBzLnN0YXJ0ICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRzZXR0aW5ncy5faURpc3BsYXlTdGFydCAgICA9IHMuc3RhcnQ7XG5cdFx0XHRpZihhcGkgPT09IG51bGwpIHtcblx0XHRcdFx0c2V0dGluZ3MuaUluaXREaXNwbGF5U3RhcnQgPSBzLnN0YXJ0O1xuXHRcdFx0fVxuXHRcdH1cblx0XHRpZiAoIHMubGVuZ3RoICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRzZXR0aW5ncy5faURpc3BsYXlMZW5ndGggICA9IHMubGVuZ3RoO1xuXHRcdH1cblx0XG5cdFx0Ly8gT3JkZXJcblx0XHRpZiAoIHMub3JkZXIgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHNldHRpbmdzLmFhU29ydGluZyA9IFtdO1xuXHRcdFx0JC5lYWNoKCBzLm9yZGVyLCBmdW5jdGlvbiAoIGksIGNvbCApIHtcblx0XHRcdFx0c2V0dGluZ3MuYWFTb3J0aW5nLnB1c2goIGNvbFswXSA+PSBjb2x1bW5zLmxlbmd0aCA/XG5cdFx0XHRcdFx0WyAwLCBjb2xbMV0gXSA6XG5cdFx0XHRcdFx0Y29sXG5cdFx0XHRcdCk7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXHRcblx0XHQvLyBTZWFyY2hcblx0XHRpZiAoIHMuc2VhcmNoICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHQkLmV4dGVuZCggc2V0dGluZ3Mub1ByZXZpb3VzU2VhcmNoLCBfZm5TZWFyY2hUb0h1bmcoIHMuc2VhcmNoICkgKTtcblx0XHR9XG5cdFxuXHRcdC8vIENvbHVtbnNcblx0XHRpZiAoIHMuY29sdW1ucyApIHtcblx0XHRcdGZvciAoIGk9MCwgaWVuPXMuY29sdW1ucy5sZW5ndGggOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdFx0dmFyIGNvbCA9IHMuY29sdW1uc1tpXTtcblx0XG5cdFx0XHRcdC8vIFZpc2liaWxpdHlcblx0XHRcdFx0aWYgKCBjb2wudmlzaWJsZSAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdC8vIElmIHRoZSBhcGkgaXMgZGVmaW5lZCwgdGhlIHRhYmxlIGhhcyBiZWVuIGluaXRpYWxpc2VkIHNvIHdlIG5lZWQgdG8gdXNlIGl0IHJhdGhlciB0aGFuIGludGVybmFsIHNldHRpbmdzXG5cdFx0XHRcdFx0aWYgKGFwaSkge1xuXHRcdFx0XHRcdFx0Ly8gRG9uJ3QgcmVkcmF3IHRoZSBjb2x1bW5zIG9uIGV2ZXJ5IGl0ZXJhdGlvbiBvZiB0aGlzIGxvb3AsIHdlIHdpbGwgZG8gdGhpcyBhdCB0aGUgZW5kIGluc3RlYWRcblx0XHRcdFx0XHRcdGFwaS5jb2x1bW4oaSkudmlzaWJsZShjb2wudmlzaWJsZSwgZmFsc2UpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRcdGNvbHVtbnNbaV0uYlZpc2libGUgPSBjb2wudmlzaWJsZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XG5cdFx0XHRcdC8vIFNlYXJjaFxuXHRcdFx0XHRpZiAoIGNvbC5zZWFyY2ggIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0XHQkLmV4dGVuZCggc2V0dGluZ3MuYW9QcmVTZWFyY2hDb2xzW2ldLCBfZm5TZWFyY2hUb0h1bmcoIGNvbC5zZWFyY2ggKSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRcblx0XHRcdC8vIElmIHRoZSBhcGkgaXMgZGVmaW5lZCB0aGVuIHdlIG5lZWQgdG8gYWRqdXN0IHRoZSBjb2x1bW5zIG9uY2UgdGhlIHZpc2liaWxpdHkgaGFzIGJlZW4gY2hhbmdlZFxuXHRcdFx0aWYgKGFwaSkge1xuXHRcdFx0XHRhcGkuY29sdW1ucy5hZGp1c3QoKTtcblx0XHRcdH1cblx0XHR9XG5cdFxuXHRcdHNldHRpbmdzLl9iTG9hZGluZ1N0YXRlID0gZmFsc2U7XG5cdFx0X2ZuQ2FsbGJhY2tGaXJlKCBzZXR0aW5ncywgJ2FvU3RhdGVMb2FkZWQnLCAnc3RhdGVMb2FkZWQnLCBbc2V0dGluZ3MsIHNdICk7XG5cdFx0Y2FsbGJhY2soKTtcblx0fTtcblx0XG5cdFxuXHQvKipcblx0ICogUmV0dXJuIHRoZSBzZXR0aW5ncyBvYmplY3QgZm9yIGEgcGFydGljdWxhciB0YWJsZVxuXHQgKiAgQHBhcmFtIHtub2RlfSB0YWJsZSB0YWJsZSB3ZSBhcmUgdXNpbmcgYXMgYSBkYXRhVGFibGVcblx0ICogIEByZXR1cm5zIHtvYmplY3R9IFNldHRpbmdzIG9iamVjdCAtIG9yIG51bGwgaWYgbm90IGZvdW5kXG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mblNldHRpbmdzRnJvbU5vZGUgKCB0YWJsZSApXG5cdHtcblx0XHR2YXIgc2V0dGluZ3MgPSBEYXRhVGFibGUuc2V0dGluZ3M7XG5cdFx0dmFyIGlkeCA9ICQuaW5BcnJheSggdGFibGUsIF9wbHVjayggc2V0dGluZ3MsICduVGFibGUnICkgKTtcblx0XG5cdFx0cmV0dXJuIGlkeCAhPT0gLTEgP1xuXHRcdFx0c2V0dGluZ3NbIGlkeCBdIDpcblx0XHRcdG51bGw7XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogTG9nIGFuIGVycm9yIG1lc3NhZ2Vcblx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBkYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgQHBhcmFtIHtpbnR9IGxldmVsIGxvZyBlcnJvciBtZXNzYWdlcywgb3IgZGlzcGxheSB0aGVtIHRvIHRoZSB1c2VyXG5cdCAqICBAcGFyYW0ge3N0cmluZ30gbXNnIGVycm9yIG1lc3NhZ2Vcblx0ICogIEBwYXJhbSB7aW50fSB0biBUZWNobmljYWwgbm90ZSBpZCB0byBnZXQgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgZXJyb3IuXG5cdCAqICBAbWVtYmVyb2YgRGF0YVRhYmxlI29BcGlcblx0ICovXG5cdGZ1bmN0aW9uIF9mbkxvZyggc2V0dGluZ3MsIGxldmVsLCBtc2csIHRuIClcblx0e1xuXHRcdG1zZyA9ICdEYXRhVGFibGVzIHdhcm5pbmc6ICcrXG5cdFx0XHQoc2V0dGluZ3MgPyAndGFibGUgaWQ9JytzZXR0aW5ncy5zVGFibGVJZCsnIC0gJyA6ICcnKSttc2c7XG5cdFxuXHRcdGlmICggdG4gKSB7XG5cdFx0XHRtc2cgKz0gJy4gRm9yIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgdGhpcyBlcnJvciwgcGxlYXNlIHNlZSAnK1xuXHRcdFx0J2h0dHA6Ly9kYXRhdGFibGVzLm5ldC90bi8nK3RuO1xuXHRcdH1cblx0XG5cdFx0aWYgKCAhIGxldmVsICApIHtcblx0XHRcdC8vIEJhY2t3YXJkcyBjb21wYXRpYmlsaXR5IHByZSAxLjEwXG5cdFx0XHR2YXIgZXh0ID0gRGF0YVRhYmxlLmV4dDtcblx0XHRcdHZhciB0eXBlID0gZXh0LnNFcnJNb2RlIHx8IGV4dC5lcnJNb2RlO1xuXHRcblx0XHRcdGlmICggc2V0dGluZ3MgKSB7XG5cdFx0XHRcdF9mbkNhbGxiYWNrRmlyZSggc2V0dGluZ3MsIG51bGwsICdlcnJvcicsIFsgc2V0dGluZ3MsIHRuLCBtc2cgXSApO1xuXHRcdFx0fVxuXHRcblx0XHRcdGlmICggdHlwZSA9PSAnYWxlcnQnICkge1xuXHRcdFx0XHRhbGVydCggbXNnICk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIGlmICggdHlwZSA9PSAndGhyb3cnICkge1xuXHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IobXNnKTtcblx0XHRcdH1cblx0XHRcdGVsc2UgaWYgKCB0eXBlb2YgdHlwZSA9PSAnZnVuY3Rpb24nICkge1xuXHRcdFx0XHR0eXBlKCBzZXR0aW5ncywgdG4sIG1zZyApO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRlbHNlIGlmICggd2luZG93LmNvbnNvbGUgJiYgY29uc29sZS5sb2cgKSB7XG5cdFx0XHRjb25zb2xlLmxvZyggbXNnICk7XG5cdFx0fVxuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIFNlZSBpZiBhIHByb3BlcnR5IGlzIGRlZmluZWQgb24gb25lIG9iamVjdCwgaWYgc28gYXNzaWduIGl0IHRvIHRoZSBvdGhlciBvYmplY3Rcblx0ICogIEBwYXJhbSB7b2JqZWN0fSByZXQgdGFyZ2V0IG9iamVjdFxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IHNyYyBzb3VyY2Ugb2JqZWN0XG5cdCAqICBAcGFyYW0ge3N0cmluZ30gbmFtZSBwcm9wZXJ0eVxuXHQgKiAgQHBhcmFtIHtzdHJpbmd9IFttYXBwZWROYW1lXSBuYW1lIHRvIG1hcCB0b28gLSBvcHRpb25hbCwgbmFtZSB1c2VkIGlmIG5vdCBnaXZlblxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5NYXAoIHJldCwgc3JjLCBuYW1lLCBtYXBwZWROYW1lIClcblx0e1xuXHRcdGlmICggQXJyYXkuaXNBcnJheSggbmFtZSApICkge1xuXHRcdFx0JC5lYWNoKCBuYW1lLCBmdW5jdGlvbiAoaSwgdmFsKSB7XG5cdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggdmFsICkgKSB7XG5cdFx0XHRcdFx0X2ZuTWFwKCByZXQsIHNyYywgdmFsWzBdLCB2YWxbMV0gKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRfZm5NYXAoIHJldCwgc3JjLCB2YWwgKTtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFxuXHRcdGlmICggbWFwcGVkTmFtZSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0bWFwcGVkTmFtZSA9IG5hbWU7XG5cdFx0fVxuXHRcblx0XHRpZiAoIHNyY1tuYW1lXSAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0cmV0W21hcHBlZE5hbWVdID0gc3JjW25hbWVdO1xuXHRcdH1cblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBFeHRlbmQgb2JqZWN0cyAtIHZlcnkgc2ltaWxhciB0byBqUXVlcnkuZXh0ZW5kLCBidXQgZGVlcCBjb3B5IG9iamVjdHMsIGFuZFxuXHQgKiBzaGFsbG93IGNvcHkgYXJyYXlzLiBUaGUgcmVhc29uIHdlIG5lZWQgdG8gZG8gdGhpcywgaXMgdGhhdCB3ZSBkb24ndCB3YW50IHRvXG5cdCAqIGRlZXAgY29weSBhcnJheSBpbml0IHZhbHVlcyAoc3VjaCBhcyBhYVNvcnRpbmcpIHNpbmNlIHRoZSBkZXYgd291bGRuJ3QgYmVcblx0ICogYWJsZSB0byBvdmVycmlkZSB0aGVtLCBidXQgd2UgZG8gd2FudCB0byBkZWVwIGNvcHkgYXJyYXlzLlxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IG91dCBPYmplY3QgdG8gZXh0ZW5kXG5cdCAqICBAcGFyYW0ge29iamVjdH0gZXh0ZW5kZXIgT2JqZWN0IGZyb20gd2hpY2ggdGhlIHByb3BlcnRpZXMgd2lsbCBiZSBhcHBsaWVkIHRvXG5cdCAqICAgICAgb3V0XG5cdCAqICBAcGFyYW0ge2Jvb2xlYW59IGJyZWFrUmVmcyBJZiB0cnVlLCB0aGVuIGFycmF5cyB3aWxsIGJlIHNsaWNlZCB0byB0YWtlIGFuXG5cdCAqICAgICAgaW5kZXBlbmRlbnQgY29weSB3aXRoIHRoZSBleGNlcHRpb24gb2YgdGhlIGBkYXRhYCBvciBgYWFEYXRhYCBwYXJhbWV0ZXJzXG5cdCAqICAgICAgaWYgdGhleSBhcmUgcHJlc2VudC4gVGhpcyBpcyBzbyB5b3UgY2FuIHBhc3MgaW4gYSBjb2xsZWN0aW9uIHRvXG5cdCAqICAgICAgRGF0YVRhYmxlcyBhbmQgaGF2ZSB0aGF0IHVzZWQgYXMgeW91ciBkYXRhIHNvdXJjZSB3aXRob3V0IGJyZWFraW5nIHRoZVxuXHQgKiAgICAgIHJlZmVyZW5jZXNcblx0ICogIEByZXR1cm5zIHtvYmplY3R9IG91dCBSZWZlcmVuY2UsIGp1c3QgZm9yIGNvbnZlbmllbmNlIC0gb3V0ID09PSB0aGUgcmV0dXJuLlxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqICBAdG9kbyBUaGlzIGRvZXNuJ3QgdGFrZSBhY2NvdW50IG9mIGFycmF5cyBpbnNpZGUgdGhlIGRlZXAgY29waWVkIG9iamVjdHMuXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5FeHRlbmQoIG91dCwgZXh0ZW5kZXIsIGJyZWFrUmVmcyApXG5cdHtcblx0XHR2YXIgdmFsO1xuXHRcblx0XHRmb3IgKCB2YXIgcHJvcCBpbiBleHRlbmRlciApIHtcblx0XHRcdGlmICggZXh0ZW5kZXIuaGFzT3duUHJvcGVydHkocHJvcCkgKSB7XG5cdFx0XHRcdHZhbCA9IGV4dGVuZGVyW3Byb3BdO1xuXHRcblx0XHRcdFx0aWYgKCAkLmlzUGxhaW5PYmplY3QoIHZhbCApICkge1xuXHRcdFx0XHRcdGlmICggISAkLmlzUGxhaW5PYmplY3QoIG91dFtwcm9wXSApICkge1xuXHRcdFx0XHRcdFx0b3V0W3Byb3BdID0ge307XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdCQuZXh0ZW5kKCB0cnVlLCBvdXRbcHJvcF0sIHZhbCApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGVsc2UgaWYgKCBicmVha1JlZnMgJiYgcHJvcCAhPT0gJ2RhdGEnICYmIHByb3AgIT09ICdhYURhdGEnICYmIEFycmF5LmlzQXJyYXkodmFsKSApIHtcblx0XHRcdFx0XHRvdXRbcHJvcF0gPSB2YWwuc2xpY2UoKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRvdXRbcHJvcF0gPSB2YWw7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdFxuXHRcdHJldHVybiBvdXQ7XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogQmluZCBhbiBldmVudCBoYW5kZXJzIHRvIGFsbG93IGEgY2xpY2sgb3IgcmV0dXJuIGtleSB0byBhY3RpdmF0ZSB0aGUgY2FsbGJhY2suXG5cdCAqIFRoaXMgaXMgZ29vZCBmb3IgYWNjZXNzaWJpbGl0eSBzaW5jZSBhIHJldHVybiBvbiB0aGUga2V5Ym9hcmQgd2lsbCBoYXZlIHRoZVxuXHQgKiBzYW1lIGVmZmVjdCBhcyBhIGNsaWNrLCBpZiB0aGUgZWxlbWVudCBoYXMgZm9jdXMuXG5cdCAqICBAcGFyYW0ge2VsZW1lbnR9IG4gRWxlbWVudCB0byBiaW5kIHRoZSBhY3Rpb24gdG9cblx0ICogIEBwYXJhbSB7b2JqZWN0fSBvRGF0YSBEYXRhIG9iamVjdCB0byBwYXNzIHRvIHRoZSB0cmlnZ2VyZWQgZnVuY3Rpb25cblx0ICogIEBwYXJhbSB7ZnVuY3Rpb259IGZuIENhbGxiYWNrIGZ1bmN0aW9uIGZvciB3aGVuIHRoZSBldmVudCBpcyB0cmlnZ2VyZWRcblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjb0FwaVxuXHQgKi9cblx0ZnVuY3Rpb24gX2ZuQmluZEFjdGlvbiggbiwgb0RhdGEsIGZuIClcblx0e1xuXHRcdCQobilcblx0XHRcdC5vbiggJ2NsaWNrLkRUJywgb0RhdGEsIGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdFx0JChuKS50cmlnZ2VyKCdibHVyJyk7IC8vIFJlbW92ZSBmb2N1cyBvdXRsaW5lIGZvciBtb3VzZSB1c2Vyc1xuXHRcdFx0XHRcdGZuKGUpO1xuXHRcdFx0XHR9IClcblx0XHRcdC5vbiggJ2tleXByZXNzLkRUJywgb0RhdGEsIGZ1bmN0aW9uIChlKXtcblx0XHRcdFx0XHRpZiAoIGUud2hpY2ggPT09IDEzICkge1xuXHRcdFx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdFx0Zm4oZSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IClcblx0XHRcdC5vbiggJ3NlbGVjdHN0YXJ0LkRUJywgZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdC8qIFRha2UgdGhlIGJydXRhbCBhcHByb2FjaCB0byBjYW5jZWxsaW5nIHRleHQgc2VsZWN0aW9uICovXG5cdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHR9ICk7XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogUmVnaXN0ZXIgYSBjYWxsYmFjayBmdW5jdGlvbi4gRWFzaWx5IGFsbG93cyBhIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGFkZGVkIHRvXG5cdCAqIGFuIGFycmF5IHN0b3JlIG9mIGNhbGxiYWNrIGZ1bmN0aW9ucyB0aGF0IGNhbiB0aGVuIGFsbCBiZSBjYWxsZWQgdG9nZXRoZXIuXG5cdCAqICBAcGFyYW0ge29iamVjdH0gb1NldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAcGFyYW0ge3N0cmluZ30gc1N0b3JlIE5hbWUgb2YgdGhlIGFycmF5IHN0b3JhZ2UgZm9yIHRoZSBjYWxsYmFja3MgaW4gb1NldHRpbmdzXG5cdCAqICBAcGFyYW0ge2Z1bmN0aW9ufSBmbiBGdW5jdGlvbiB0byBiZSBjYWxsZWQgYmFja1xuXHQgKiAgQHBhcmFtIHtzdHJpbmd9IHNOYW1lIElkZW50aWZ5aW5nIG5hbWUgZm9yIHRoZSBjYWxsYmFjayAoaS5lLiBhIGxhYmVsKVxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5DYWxsYmFja1JlZyggb1NldHRpbmdzLCBzU3RvcmUsIGZuLCBzTmFtZSApXG5cdHtcblx0XHRpZiAoIGZuIClcblx0XHR7XG5cdFx0XHRvU2V0dGluZ3Nbc1N0b3JlXS5wdXNoKCB7XG5cdFx0XHRcdFwiZm5cIjogZm4sXG5cdFx0XHRcdFwic05hbWVcIjogc05hbWVcblx0XHRcdH0gKTtcblx0XHR9XG5cdH1cblx0XG5cdFxuXHQvKipcblx0ICogRmlyZSBjYWxsYmFjayBmdW5jdGlvbnMgYW5kIHRyaWdnZXIgZXZlbnRzLiBOb3RlIHRoYXQgdGhlIGxvb3Agb3ZlciB0aGVcblx0ICogY2FsbGJhY2sgYXJyYXkgc3RvcmUgaXMgZG9uZSBiYWNrd2FyZHMhIEZ1cnRoZXIgbm90ZSB0aGF0IHlvdSBkbyBub3Qgd2FudCB0b1xuXHQgKiBmaXJlIG9mZiB0cmlnZ2VycyBpbiB0aW1lIHNlbnNpdGl2ZSBhcHBsaWNhdGlvbnMgKGZvciBleGFtcGxlIGNlbGwgY3JlYXRpb24pXG5cdCAqIGFzIGl0cyBzbG93LlxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IHNldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAcGFyYW0ge3N0cmluZ30gY2FsbGJhY2tBcnIgTmFtZSBvZiB0aGUgYXJyYXkgc3RvcmFnZSBmb3IgdGhlIGNhbGxiYWNrcyBpblxuXHQgKiAgICAgIG9TZXR0aW5nc1xuXHQgKiAgQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZSBOYW1lIG9mIHRoZSBqUXVlcnkgY3VzdG9tIGV2ZW50IHRvIHRyaWdnZXIuIElmXG5cdCAqICAgICAgbnVsbCBubyB0cmlnZ2VyIGlzIGZpcmVkXG5cdCAqICBAcGFyYW0ge2FycmF5fSBhcmdzIEFycmF5IG9mIGFyZ3VtZW50cyB0byBwYXNzIHRvIHRoZSBjYWxsYmFjayBmdW5jdGlvbiAvXG5cdCAqICAgICAgdHJpZ2dlclxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5DYWxsYmFja0ZpcmUoIHNldHRpbmdzLCBjYWxsYmFja0FyciwgZXZlbnROYW1lLCBhcmdzIClcblx0e1xuXHRcdHZhciByZXQgPSBbXTtcblx0XG5cdFx0aWYgKCBjYWxsYmFja0FyciApIHtcblx0XHRcdHJldCA9ICQubWFwKCBzZXR0aW5nc1tjYWxsYmFja0Fycl0uc2xpY2UoKS5yZXZlcnNlKCksIGZ1bmN0aW9uICh2YWwsIGkpIHtcblx0XHRcdFx0cmV0dXJuIHZhbC5mbi5hcHBseSggc2V0dGluZ3Mub0luc3RhbmNlLCBhcmdzICk7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXHRcblx0XHRpZiAoIGV2ZW50TmFtZSAhPT0gbnVsbCApIHtcblx0XHRcdHZhciBlID0gJC5FdmVudCggZXZlbnROYW1lKycuZHQnICk7XG5cdFxuXHRcdFx0JChzZXR0aW5ncy5uVGFibGUpLnRyaWdnZXIoIGUsIGFyZ3MgKTtcblx0XG5cdFx0XHRyZXQucHVzaCggZS5yZXN1bHQgKTtcblx0XHR9XG5cdFxuXHRcdHJldHVybiByZXQ7XG5cdH1cblx0XG5cdFxuXHRmdW5jdGlvbiBfZm5MZW5ndGhPdmVyZmxvdyAoIHNldHRpbmdzIClcblx0e1xuXHRcdHZhclxuXHRcdFx0c3RhcnQgPSBzZXR0aW5ncy5faURpc3BsYXlTdGFydCxcblx0XHRcdGVuZCA9IHNldHRpbmdzLmZuRGlzcGxheUVuZCgpLFxuXHRcdFx0bGVuID0gc2V0dGluZ3MuX2lEaXNwbGF5TGVuZ3RoO1xuXHRcblx0XHQvKiBJZiB3ZSBoYXZlIHNwYWNlIHRvIHNob3cgZXh0cmEgcm93cyAoYmFja2luZyB1cCBmcm9tIHRoZSBlbmQgcG9pbnQgLSB0aGVuIGRvIHNvICovXG5cdFx0aWYgKCBzdGFydCA+PSBlbmQgKVxuXHRcdHtcblx0XHRcdHN0YXJ0ID0gZW5kIC0gbGVuO1xuXHRcdH1cblx0XG5cdFx0Ly8gS2VlcCB0aGUgc3RhcnQgcmVjb3JkIG9uIHRoZSBjdXJyZW50IHBhZ2Vcblx0XHRzdGFydCAtPSAoc3RhcnQgJSBsZW4pO1xuXHRcblx0XHRpZiAoIGxlbiA9PT0gLTEgfHwgc3RhcnQgPCAwIClcblx0XHR7XG5cdFx0XHRzdGFydCA9IDA7XG5cdFx0fVxuXHRcblx0XHRzZXR0aW5ncy5faURpc3BsYXlTdGFydCA9IHN0YXJ0O1xuXHR9XG5cdFxuXHRcblx0ZnVuY3Rpb24gX2ZuUmVuZGVyZXIoIHNldHRpbmdzLCB0eXBlIClcblx0e1xuXHRcdHZhciByZW5kZXJlciA9IHNldHRpbmdzLnJlbmRlcmVyO1xuXHRcdHZhciBob3N0ID0gRGF0YVRhYmxlLmV4dC5yZW5kZXJlclt0eXBlXTtcblx0XG5cdFx0aWYgKCAkLmlzUGxhaW5PYmplY3QoIHJlbmRlcmVyICkgJiYgcmVuZGVyZXJbdHlwZV0gKSB7XG5cdFx0XHQvLyBTcGVjaWZpYyByZW5kZXJlciBmb3IgdGhpcyB0eXBlLiBJZiBhdmFpbGFibGUgdXNlIGl0LCBvdGhlcndpc2UgdXNlXG5cdFx0XHQvLyB0aGUgZGVmYXVsdC5cblx0XHRcdHJldHVybiBob3N0W3JlbmRlcmVyW3R5cGVdXSB8fCBob3N0Ll87XG5cdFx0fVxuXHRcdGVsc2UgaWYgKCB0eXBlb2YgcmVuZGVyZXIgPT09ICdzdHJpbmcnICkge1xuXHRcdFx0Ly8gQ29tbW9uIHJlbmRlcmVyIC0gaWYgdGhlcmUgaXMgb25lIGF2YWlsYWJsZSBmb3IgdGhpcyB0eXBlIHVzZSBpdCxcblx0XHRcdC8vIG90aGVyd2lzZSB1c2UgdGhlIGRlZmF1bHRcblx0XHRcdHJldHVybiBob3N0W3JlbmRlcmVyXSB8fCBob3N0Ll87XG5cdFx0fVxuXHRcblx0XHQvLyBVc2UgdGhlIGRlZmF1bHRcblx0XHRyZXR1cm4gaG9zdC5fO1xuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIERldGVjdCB0aGUgZGF0YSBzb3VyY2UgYmVpbmcgdXNlZCBmb3IgdGhlIHRhYmxlLiBVc2VkIHRvIHNpbXBsaWZ5IHRoZSBjb2RlXG5cdCAqIGEgbGl0dGxlIChhamF4KSBhbmQgdG8gbWFrZSBpdCBjb21wcmVzcyBhIGxpdHRsZSBzbWFsbGVyLlxuXHQgKlxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IHNldHRpbmdzIGRhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdCAqICBAcmV0dXJucyB7c3RyaW5nfSBEYXRhIHNvdXJjZVxuXHQgKiAgQG1lbWJlcm9mIERhdGFUYWJsZSNvQXBpXG5cdCAqL1xuXHRmdW5jdGlvbiBfZm5EYXRhU291cmNlICggc2V0dGluZ3MgKVxuXHR7XG5cdFx0aWYgKCBzZXR0aW5ncy5vRmVhdHVyZXMuYlNlcnZlclNpZGUgKSB7XG5cdFx0XHRyZXR1cm4gJ3NzcCc7XG5cdFx0fVxuXHRcdGVsc2UgaWYgKCBzZXR0aW5ncy5hamF4IHx8IHNldHRpbmdzLnNBamF4U291cmNlICkge1xuXHRcdFx0cmV0dXJuICdhamF4Jztcblx0XHR9XG5cdFx0cmV0dXJuICdkb20nO1xuXHR9XG5cdFxuXG5cdFxuXHRcblx0LyoqXG5cdCAqIENvbXB1dGVkIHN0cnVjdHVyZSBvZiB0aGUgRGF0YVRhYmxlcyBBUEksIGRlZmluZWQgYnkgdGhlIG9wdGlvbnMgcGFzc2VkIHRvXG5cdCAqIGBEYXRhVGFibGUuQXBpLnJlZ2lzdGVyKClgIHdoZW4gYnVpbGRpbmcgdGhlIEFQSS5cblx0ICpcblx0ICogVGhlIHN0cnVjdHVyZSBpcyBidWlsdCBpbiBvcmRlciB0byBzcGVlZCBjcmVhdGlvbiBhbmQgZXh0ZW5zaW9uIG9mIHRoZSBBcGlcblx0ICogb2JqZWN0cyBzaW5jZSB0aGUgZXh0ZW5zaW9ucyBhcmUgZWZmZWN0aXZlbHkgcHJlLXBhcnNlZC5cblx0ICpcblx0ICogVGhlIGFycmF5IGlzIGFuIGFycmF5IG9mIG9iamVjdHMgd2l0aCB0aGUgZm9sbG93aW5nIHN0cnVjdHVyZSwgd2hlcmUgdGhpc1xuXHQgKiBiYXNlIGFycmF5IHJlcHJlc2VudHMgdGhlIEFwaSBwcm90b3R5cGUgYmFzZTpcblx0ICpcblx0ICogICAgIFtcblx0ICogICAgICAge1xuXHQgKiAgICAgICAgIG5hbWU6ICAgICAgJ2RhdGEnICAgICAgICAgICAgICAgIC0tIHN0cmluZyAgIC0gUHJvcGVydHkgbmFtZVxuXHQgKiAgICAgICAgIHZhbDogICAgICAgZnVuY3Rpb24gKCkge30sICAgICAgIC0tIGZ1bmN0aW9uIC0gQXBpIG1ldGhvZCAob3IgdW5kZWZpbmVkIGlmIGp1c3QgYW4gb2JqZWN0XG5cdCAqICAgICAgICAgbWV0aG9kRXh0OiBbIC4uLiBdLCAgICAgICAgICAgICAgLS0gYXJyYXkgICAgLSBBcnJheSBvZiBBcGkgb2JqZWN0IGRlZmluaXRpb25zIHRvIGV4dGVuZCB0aGUgbWV0aG9kIHJlc3VsdFxuXHQgKiAgICAgICAgIHByb3BFeHQ6ICAgWyAuLi4gXSAgICAgICAgICAgICAgIC0tIGFycmF5ICAgIC0gQXJyYXkgb2YgQXBpIG9iamVjdCBkZWZpbml0aW9ucyB0byBleHRlbmQgdGhlIHByb3BlcnR5XG5cdCAqICAgICAgIH0sXG5cdCAqICAgICAgIHtcblx0ICogICAgICAgICBuYW1lOiAgICAgJ3Jvdydcblx0ICogICAgICAgICB2YWw6ICAgICAgIHt9LFxuXHQgKiAgICAgICAgIG1ldGhvZEV4dDogWyAuLi4gXSxcblx0ICogICAgICAgICBwcm9wRXh0OiAgIFtcblx0ICogICAgICAgICAgIHtcblx0ICogICAgICAgICAgICAgbmFtZTogICAgICAnZGF0YSdcblx0ICogICAgICAgICAgICAgdmFsOiAgICAgICBmdW5jdGlvbiAoKSB7fSxcblx0ICogICAgICAgICAgICAgbWV0aG9kRXh0OiBbIC4uLiBdLFxuXHQgKiAgICAgICAgICAgICBwcm9wRXh0OiAgIFsgLi4uIF1cblx0ICogICAgICAgICAgIH0sXG5cdCAqICAgICAgICAgICAuLi5cblx0ICogICAgICAgICBdXG5cdCAqICAgICAgIH1cblx0ICogICAgIF1cblx0ICpcblx0ICogQHR5cGUge0FycmF5fVxuXHQgKiBAaWdub3JlXG5cdCAqL1xuXHR2YXIgX19hcGlTdHJ1Y3QgPSBbXTtcblx0XG5cdFxuXHQvKipcblx0ICogYEFycmF5LnByb3RvdHlwZWAgcmVmZXJlbmNlLlxuXHQgKlxuXHQgKiBAdHlwZSBvYmplY3Rcblx0ICogQGlnbm9yZVxuXHQgKi9cblx0dmFyIF9fYXJyYXlQcm90byA9IEFycmF5LnByb3RvdHlwZTtcblx0XG5cdFxuXHQvKipcblx0ICogQWJzdHJhY3Rpb24gZm9yIGBjb250ZXh0YCBwYXJhbWV0ZXIgb2YgdGhlIGBBcGlgIGNvbnN0cnVjdG9yIHRvIGFsbG93IGl0IHRvXG5cdCAqIHRha2Ugc2V2ZXJhbCBkaWZmZXJlbnQgZm9ybXMgZm9yIGVhc2Ugb2YgdXNlLlxuXHQgKlxuXHQgKiBFYWNoIG9mIHRoZSBpbnB1dCBwYXJhbWV0ZXIgdHlwZXMgd2lsbCBiZSBjb252ZXJ0ZWQgdG8gYSBEYXRhVGFibGVzIHNldHRpbmdzXG5cdCAqIG9iamVjdCB3aGVyZSBwb3NzaWJsZS5cblx0ICpcblx0ICogQHBhcmFtICB7c3RyaW5nfG5vZGV8alF1ZXJ5fG9iamVjdH0gbWl4ZWQgRGF0YVRhYmxlIGlkZW50aWZpZXIuIENhbiBiZSBvbmVcblx0ICogICBvZjpcblx0ICpcblx0ICogICAqIGBzdHJpbmdgIC0galF1ZXJ5IHNlbGVjdG9yLiBBbnkgRGF0YVRhYmxlcycgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yXG5cdCAqICAgICB3aXRoIGJlIGZvdW5kIGFuZCB1c2VkLlxuXHQgKiAgICogYG5vZGVgIC0gYFRBQkxFYCBub2RlIHdoaWNoIGhhcyBhbHJlYWR5IGJlZW4gZm9ybWVkIGludG8gYSBEYXRhVGFibGUuXG5cdCAqICAgKiBgalF1ZXJ5YCAtIEEgalF1ZXJ5IG9iamVjdCBvZiBgVEFCTEVgIG5vZGVzLlxuXHQgKiAgICogYG9iamVjdGAgLSBEYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiAgICogYERhdGFUYWJsZXMuQXBpYCAtIEFQSSBpbnN0YW5jZVxuXHQgKiBAcmV0dXJuIHthcnJheXxudWxsfSBNYXRjaGluZyBEYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdHMuIGBudWxsYCBvclxuXHQgKiAgIGB1bmRlZmluZWRgIGlzIHJldHVybmVkIGlmIG5vIG1hdGNoaW5nIERhdGFUYWJsZSBpcyBmb3VuZC5cblx0ICogQGlnbm9yZVxuXHQgKi9cblx0dmFyIF90b1NldHRpbmdzID0gZnVuY3Rpb24gKCBtaXhlZCApXG5cdHtcblx0XHR2YXIgaWR4LCBqcTtcblx0XHR2YXIgc2V0dGluZ3MgPSBEYXRhVGFibGUuc2V0dGluZ3M7XG5cdFx0dmFyIHRhYmxlcyA9ICQubWFwKCBzZXR0aW5ncywgZnVuY3Rpb24gKGVsLCBpKSB7XG5cdFx0XHRyZXR1cm4gZWwublRhYmxlO1xuXHRcdH0gKTtcblx0XG5cdFx0aWYgKCAhIG1peGVkICkge1xuXHRcdFx0cmV0dXJuIFtdO1xuXHRcdH1cblx0XHRlbHNlIGlmICggbWl4ZWQublRhYmxlICYmIG1peGVkLm9BcGkgKSB7XG5cdFx0XHQvLyBEYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHRcdFx0cmV0dXJuIFsgbWl4ZWQgXTtcblx0XHR9XG5cdFx0ZWxzZSBpZiAoIG1peGVkLm5vZGVOYW1lICYmIG1peGVkLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09ICd0YWJsZScgKSB7XG5cdFx0XHQvLyBUYWJsZSBub2RlXG5cdFx0XHRpZHggPSAkLmluQXJyYXkoIG1peGVkLCB0YWJsZXMgKTtcblx0XHRcdHJldHVybiBpZHggIT09IC0xID8gWyBzZXR0aW5nc1tpZHhdIF0gOiBudWxsO1xuXHRcdH1cblx0XHRlbHNlIGlmICggbWl4ZWQgJiYgdHlwZW9mIG1peGVkLnNldHRpbmdzID09PSAnZnVuY3Rpb24nICkge1xuXHRcdFx0cmV0dXJuIG1peGVkLnNldHRpbmdzKCkudG9BcnJheSgpO1xuXHRcdH1cblx0XHRlbHNlIGlmICggdHlwZW9mIG1peGVkID09PSAnc3RyaW5nJyApIHtcblx0XHRcdC8vIGpRdWVyeSBzZWxlY3RvclxuXHRcdFx0anEgPSAkKG1peGVkKTtcblx0XHR9XG5cdFx0ZWxzZSBpZiAoIG1peGVkIGluc3RhbmNlb2YgJCApIHtcblx0XHRcdC8vIGpRdWVyeSBvYmplY3QgKGFsc28gRGF0YVRhYmxlcyBpbnN0YW5jZSlcblx0XHRcdGpxID0gbWl4ZWQ7XG5cdFx0fVxuXHRcblx0XHRpZiAoIGpxICkge1xuXHRcdFx0cmV0dXJuIGpxLm1hcCggZnVuY3Rpb24oaSkge1xuXHRcdFx0XHRpZHggPSAkLmluQXJyYXkoIHRoaXMsIHRhYmxlcyApO1xuXHRcdFx0XHRyZXR1cm4gaWR4ICE9PSAtMSA/IHNldHRpbmdzW2lkeF0gOiBudWxsO1xuXHRcdFx0fSApLnRvQXJyYXkoKTtcblx0XHR9XG5cdH07XG5cdFxuXHRcblx0LyoqXG5cdCAqIERhdGFUYWJsZXMgQVBJIGNsYXNzIC0gdXNlZCB0byBjb250cm9sIGFuZCBpbnRlcmZhY2Ugd2l0aCAgb25lIG9yIG1vcmVcblx0ICogRGF0YVRhYmxlcyBlbmhhbmNlZCB0YWJsZXMuXG5cdCAqXG5cdCAqIFRoZSBBUEkgY2xhc3MgaXMgaGVhdmlseSBiYXNlZCBvbiBqUXVlcnksIHByZXNlbnRpbmcgYSBjaGFpbmFibGUgaW50ZXJmYWNlXG5cdCAqIHRoYXQgeW91IGNhbiB1c2UgdG8gaW50ZXJhY3Qgd2l0aCB0YWJsZXMuIEVhY2ggaW5zdGFuY2Ugb2YgdGhlIEFQSSBjbGFzcyBoYXNcblx0ICogYSBcImNvbnRleHRcIiAtIGkuZS4gdGhlIHRhYmxlcyB0aGF0IGl0IHdpbGwgb3BlcmF0ZSBvbi4gVGhpcyBjb3VsZCBiZSBhIHNpbmdsZVxuXHQgKiB0YWJsZSwgYWxsIHRhYmxlcyBvbiBhIHBhZ2Ugb3IgYSBzdWItc2V0IHRoZXJlb2YuXG5cdCAqXG5cdCAqIEFkZGl0aW9uYWxseSB0aGUgQVBJIGlzIGRlc2lnbmVkIHRvIGFsbG93IHlvdSB0byBlYXNpbHkgd29yayB3aXRoIHRoZSBkYXRhIGluXG5cdCAqIHRoZSB0YWJsZXMsIHJldHJpZXZpbmcgYW5kIG1hbmlwdWxhdGluZyBpdCBhcyByZXF1aXJlZC4gVGhpcyBpcyBkb25lIGJ5XG5cdCAqIHByZXNlbnRpbmcgdGhlIEFQSSBjbGFzcyBhcyBhbiBhcnJheSBsaWtlIGludGVyZmFjZS4gVGhlIGNvbnRlbnRzIG9mIHRoZVxuXHQgKiBhcnJheSBkZXBlbmQgdXBvbiB0aGUgYWN0aW9ucyByZXF1ZXN0ZWQgYnkgZWFjaCBtZXRob2QgKGZvciBleGFtcGxlXG5cdCAqIGByb3dzKCkubm9kZXMoKWAgd2lsbCByZXR1cm4gYW4gYXJyYXkgb2Ygbm9kZXMsIHdoaWxlIGByb3dzKCkuZGF0YSgpYCB3aWxsXG5cdCAqIHJldHVybiBhbiBhcnJheSBvZiBvYmplY3RzIG9yIGFycmF5cyBkZXBlbmRpbmcgdXBvbiB5b3VyIHRhYmxlJ3Ncblx0ICogY29uZmlndXJhdGlvbikuIFRoZSBBUEkgb2JqZWN0IGhhcyBhIG51bWJlciBvZiBhcnJheSBsaWtlIG1ldGhvZHMgKGBwdXNoYCxcblx0ICogYHBvcGAsIGByZXZlcnNlYCBldGMpIGFzIHdlbGwgYXMgYWRkaXRpb25hbCBoZWxwZXIgbWV0aG9kcyAoYGVhY2hgLCBgcGx1Y2tgLFxuXHQgKiBgdW5pcXVlYCBldGMpIHRvIGFzc2lzdCB5b3VyIHdvcmtpbmcgd2l0aCB0aGUgZGF0YSBoZWxkIGluIGEgdGFibGUuXG5cdCAqXG5cdCAqIE1vc3QgbWV0aG9kcyAodGhvc2Ugd2hpY2ggcmV0dXJuIGFuIEFwaSBpbnN0YW5jZSkgYXJlIGNoYWluYWJsZSwgd2hpY2ggbWVhbnNcblx0ICogdGhlIHJldHVybiBmcm9tIGEgbWV0aG9kIGNhbGwgYWxzbyBoYXMgYWxsIG9mIHRoZSBtZXRob2RzIGF2YWlsYWJsZSB0aGF0IHRoZVxuXHQgKiB0b3AgbGV2ZWwgb2JqZWN0IGhhZC4gRm9yIGV4YW1wbGUsIHRoZXNlIHR3byBjYWxscyBhcmUgZXF1aXZhbGVudDpcblx0ICpcblx0ICogICAgIC8vIE5vdCBjaGFpbmVkXG5cdCAqICAgICBhcGkucm93LmFkZCggey4uLn0gKTtcblx0ICogICAgIGFwaS5kcmF3KCk7XG5cdCAqXG5cdCAqICAgICAvLyBDaGFpbmVkXG5cdCAqICAgICBhcGkucm93LmFkZCggey4uLn0gKS5kcmF3KCk7XG5cdCAqXG5cdCAqIEBjbGFzcyBEYXRhVGFibGUuQXBpXG5cdCAqIEBwYXJhbSB7YXJyYXl8b2JqZWN0fHN0cmluZ3xqUXVlcnl9IGNvbnRleHQgRGF0YVRhYmxlIGlkZW50aWZpZXIuIFRoaXMgaXNcblx0ICogICB1c2VkIHRvIGRlZmluZSB3aGljaCBEYXRhVGFibGVzIGVuaGFuY2VkIHRhYmxlcyB0aGlzIEFQSSB3aWxsIG9wZXJhdGUgb24uXG5cdCAqICAgQ2FuIGJlIG9uZSBvZjpcblx0ICpcblx0ICogICAqIGBzdHJpbmdgIC0galF1ZXJ5IHNlbGVjdG9yLiBBbnkgRGF0YVRhYmxlcycgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yXG5cdCAqICAgICB3aXRoIGJlIGZvdW5kIGFuZCB1c2VkLlxuXHQgKiAgICogYG5vZGVgIC0gYFRBQkxFYCBub2RlIHdoaWNoIGhhcyBhbHJlYWR5IGJlZW4gZm9ybWVkIGludG8gYSBEYXRhVGFibGUuXG5cdCAqICAgKiBgalF1ZXJ5YCAtIEEgalF1ZXJ5IG9iamVjdCBvZiBgVEFCTEVgIG5vZGVzLlxuXHQgKiAgICogYG9iamVjdGAgLSBEYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHQgKiBAcGFyYW0ge2FycmF5fSBbZGF0YV0gRGF0YSB0byBpbml0aWFsaXNlIHRoZSBBcGkgaW5zdGFuY2Ugd2l0aC5cblx0ICpcblx0ICogQGV4YW1wbGVcblx0ICogICAvLyBEaXJlY3QgaW5pdGlhbGlzYXRpb24gZHVyaW5nIERhdGFUYWJsZXMgY29uc3RydWN0aW9uXG5cdCAqICAgdmFyIGFwaSA9ICQoJyNleGFtcGxlJykuRGF0YVRhYmxlKCk7XG5cdCAqXG5cdCAqIEBleGFtcGxlXG5cdCAqICAgLy8gSW5pdGlhbGlzYXRpb24gdXNpbmcgYSBEYXRhVGFibGVzIGpRdWVyeSBvYmplY3Rcblx0ICogICB2YXIgYXBpID0gJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoKS5hcGkoKTtcblx0ICpcblx0ICogQGV4YW1wbGVcblx0ICogICAvLyBJbml0aWFsaXNhdGlvbiBhcyBhIGNvbnN0cnVjdG9yXG5cdCAqICAgdmFyIGFwaSA9IG5ldyAkLmZuLkRhdGFUYWJsZS5BcGkoICd0YWJsZS5kYXRhVGFibGUnICk7XG5cdCAqL1xuXHRfQXBpID0gZnVuY3Rpb24gKCBjb250ZXh0LCBkYXRhIClcblx0e1xuXHRcdGlmICggISAodGhpcyBpbnN0YW5jZW9mIF9BcGkpICkge1xuXHRcdFx0cmV0dXJuIG5ldyBfQXBpKCBjb250ZXh0LCBkYXRhICk7XG5cdFx0fVxuXHRcblx0XHR2YXIgc2V0dGluZ3MgPSBbXTtcblx0XHR2YXIgY3R4U2V0dGluZ3MgPSBmdW5jdGlvbiAoIG8gKSB7XG5cdFx0XHR2YXIgYSA9IF90b1NldHRpbmdzKCBvICk7XG5cdFx0XHRpZiAoIGEgKSB7XG5cdFx0XHRcdHNldHRpbmdzLnB1c2guYXBwbHkoIHNldHRpbmdzLCBhICk7XG5cdFx0XHR9XG5cdFx0fTtcblx0XG5cdFx0aWYgKCBBcnJheS5pc0FycmF5KCBjb250ZXh0ICkgKSB7XG5cdFx0XHRmb3IgKCB2YXIgaT0wLCBpZW49Y29udGV4dC5sZW5ndGggOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdFx0Y3R4U2V0dGluZ3MoIGNvbnRleHRbaV0gKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0ZWxzZSB7XG5cdFx0XHRjdHhTZXR0aW5ncyggY29udGV4dCApO1xuXHRcdH1cblx0XG5cdFx0Ly8gUmVtb3ZlIGR1cGxpY2F0ZXNcblx0XHR0aGlzLmNvbnRleHQgPSBfdW5pcXVlKCBzZXR0aW5ncyApO1xuXHRcblx0XHQvLyBJbml0aWFsIGRhdGFcblx0XHRpZiAoIGRhdGEgKSB7XG5cdFx0XHQkLm1lcmdlKCB0aGlzLCBkYXRhICk7XG5cdFx0fVxuXHRcblx0XHQvLyBzZWxlY3RvclxuXHRcdHRoaXMuc2VsZWN0b3IgPSB7XG5cdFx0XHRyb3dzOiBudWxsLFxuXHRcdFx0Y29sczogbnVsbCxcblx0XHRcdG9wdHM6IG51bGxcblx0XHR9O1xuXHRcblx0XHRfQXBpLmV4dGVuZCggdGhpcywgdGhpcywgX19hcGlTdHJ1Y3QgKTtcblx0fTtcblx0XG5cdERhdGFUYWJsZS5BcGkgPSBfQXBpO1xuXHRcblx0Ly8gRG9uJ3QgZGVzdHJveSB0aGUgZXhpc3RpbmcgcHJvdG90eXBlLCBqdXN0IGV4dGVuZCBpdC4gUmVxdWlyZWQgZm9yIGpRdWVyeSAyJ3Ncblx0Ly8gaXNQbGFpbk9iamVjdC5cblx0JC5leHRlbmQoIF9BcGkucHJvdG90eXBlLCB7XG5cdFx0YW55OiBmdW5jdGlvbiAoKVxuXHRcdHtcblx0XHRcdHJldHVybiB0aGlzLmNvdW50KCkgIT09IDA7XG5cdFx0fSxcblx0XG5cdFxuXHRcdGNvbmNhdDogIF9fYXJyYXlQcm90by5jb25jYXQsXG5cdFxuXHRcblx0XHRjb250ZXh0OiBbXSwgLy8gYXJyYXkgb2YgdGFibGUgc2V0dGluZ3Mgb2JqZWN0c1xuXHRcblx0XG5cdFx0Y291bnQ6IGZ1bmN0aW9uICgpXG5cdFx0e1xuXHRcdFx0cmV0dXJuIHRoaXMuZmxhdHRlbigpLmxlbmd0aDtcblx0XHR9LFxuXHRcblx0XG5cdFx0ZWFjaDogZnVuY3Rpb24gKCBmbiApXG5cdFx0e1xuXHRcdFx0Zm9yICggdmFyIGk9MCwgaWVuPXRoaXMubGVuZ3RoIDsgaTxpZW47IGkrKyApIHtcblx0XHRcdFx0Zm4uY2FsbCggdGhpcywgdGhpc1tpXSwgaSwgdGhpcyApO1xuXHRcdFx0fVxuXHRcblx0XHRcdHJldHVybiB0aGlzO1xuXHRcdH0sXG5cdFxuXHRcblx0XHRlcTogZnVuY3Rpb24gKCBpZHggKVxuXHRcdHtcblx0XHRcdHZhciBjdHggPSB0aGlzLmNvbnRleHQ7XG5cdFxuXHRcdFx0cmV0dXJuIGN0eC5sZW5ndGggPiBpZHggP1xuXHRcdFx0XHRuZXcgX0FwaSggY3R4W2lkeF0sIHRoaXNbaWR4XSApIDpcblx0XHRcdFx0bnVsbDtcblx0XHR9LFxuXHRcblx0XG5cdFx0ZmlsdGVyOiBmdW5jdGlvbiAoIGZuIClcblx0XHR7XG5cdFx0XHR2YXIgYSA9IFtdO1xuXHRcblx0XHRcdGlmICggX19hcnJheVByb3RvLmZpbHRlciApIHtcblx0XHRcdFx0YSA9IF9fYXJyYXlQcm90by5maWx0ZXIuY2FsbCggdGhpcywgZm4sIHRoaXMgKTtcblx0XHRcdH1cblx0XHRcdGVsc2Uge1xuXHRcdFx0XHQvLyBDb21wYXRpYmlsaXR5IGZvciBicm93c2VycyB3aXRob3V0IEVNQ0EtMjUyLTUgKEpTIDEuNilcblx0XHRcdFx0Zm9yICggdmFyIGk9MCwgaWVuPXRoaXMubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRcdFx0aWYgKCBmbi5jYWxsKCB0aGlzLCB0aGlzW2ldLCBpLCB0aGlzICkgKSB7XG5cdFx0XHRcdFx0XHRhLnB1c2goIHRoaXNbaV0gKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XG5cdFx0XHRyZXR1cm4gbmV3IF9BcGkoIHRoaXMuY29udGV4dCwgYSApO1xuXHRcdH0sXG5cdFxuXHRcblx0XHRmbGF0dGVuOiBmdW5jdGlvbiAoKVxuXHRcdHtcblx0XHRcdHZhciBhID0gW107XG5cdFx0XHRyZXR1cm4gbmV3IF9BcGkoIHRoaXMuY29udGV4dCwgYS5jb25jYXQuYXBwbHkoIGEsIHRoaXMudG9BcnJheSgpICkgKTtcblx0XHR9LFxuXHRcblx0XG5cdFx0am9pbjogICAgX19hcnJheVByb3RvLmpvaW4sXG5cdFxuXHRcblx0XHRpbmRleE9mOiBfX2FycmF5UHJvdG8uaW5kZXhPZiB8fCBmdW5jdGlvbiAob2JqLCBzdGFydClcblx0XHR7XG5cdFx0XHRmb3IgKCB2YXIgaT0oc3RhcnQgfHwgMCksIGllbj10aGlzLmxlbmd0aCA7IGk8aWVuIDsgaSsrICkge1xuXHRcdFx0XHRpZiAoIHRoaXNbaV0gPT09IG9iaiApIHtcblx0XHRcdFx0XHRyZXR1cm4gaTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIC0xO1xuXHRcdH0sXG5cdFxuXHRcdGl0ZXJhdG9yOiBmdW5jdGlvbiAoIGZsYXR0ZW4sIHR5cGUsIGZuLCBhbHdheXNOZXcgKSB7XG5cdFx0XHR2YXJcblx0XHRcdFx0YSA9IFtdLCByZXQsXG5cdFx0XHRcdGksIGllbiwgaiwgamVuLFxuXHRcdFx0XHRjb250ZXh0ID0gdGhpcy5jb250ZXh0LFxuXHRcdFx0XHRyb3dzLCBpdGVtcywgaXRlbSxcblx0XHRcdFx0c2VsZWN0b3IgPSB0aGlzLnNlbGVjdG9yO1xuXHRcblx0XHRcdC8vIEFyZ3VtZW50IHNoaWZ0aW5nXG5cdFx0XHRpZiAoIHR5cGVvZiBmbGF0dGVuID09PSAnc3RyaW5nJyApIHtcblx0XHRcdFx0YWx3YXlzTmV3ID0gZm47XG5cdFx0XHRcdGZuID0gdHlwZTtcblx0XHRcdFx0dHlwZSA9IGZsYXR0ZW47XG5cdFx0XHRcdGZsYXR0ZW4gPSBmYWxzZTtcblx0XHRcdH1cblx0XG5cdFx0XHRmb3IgKCBpPTAsIGllbj1jb250ZXh0Lmxlbmd0aCA7IGk8aWVuIDsgaSsrICkge1xuXHRcdFx0XHR2YXIgYXBpSW5zdCA9IG5ldyBfQXBpKCBjb250ZXh0W2ldICk7XG5cdFxuXHRcdFx0XHRpZiAoIHR5cGUgPT09ICd0YWJsZScgKSB7XG5cdFx0XHRcdFx0cmV0ID0gZm4uY2FsbCggYXBpSW5zdCwgY29udGV4dFtpXSwgaSApO1xuXHRcblx0XHRcdFx0XHRpZiAoIHJldCAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdFx0YS5wdXNoKCByZXQgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSBpZiAoIHR5cGUgPT09ICdjb2x1bW5zJyB8fCB0eXBlID09PSAncm93cycgKSB7XG5cdFx0XHRcdFx0Ly8gdGhpcyBoYXMgc2FtZSBsZW5ndGggYXMgY29udGV4dCAtIG9uZSBlbnRyeSBmb3IgZWFjaCB0YWJsZVxuXHRcdFx0XHRcdHJldCA9IGZuLmNhbGwoIGFwaUluc3QsIGNvbnRleHRbaV0sIHRoaXNbaV0sIGkgKTtcblx0XG5cdFx0XHRcdFx0aWYgKCByZXQgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0XHRcdGEucHVzaCggcmV0ICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdGVsc2UgaWYgKCB0eXBlID09PSAnY29sdW1uJyB8fCB0eXBlID09PSAnY29sdW1uLXJvd3MnIHx8IHR5cGUgPT09ICdyb3cnIHx8IHR5cGUgPT09ICdjZWxsJyApIHtcblx0XHRcdFx0XHQvLyBjb2x1bW5zIGFuZCByb3dzIHNoYXJlIHRoZSBzYW1lIHN0cnVjdHVyZS5cblx0XHRcdFx0XHQvLyAndGhpcycgaXMgYW4gYXJyYXkgb2YgY29sdW1uIGluZGV4ZXMgZm9yIGVhY2ggY29udGV4dFxuXHRcdFx0XHRcdGl0ZW1zID0gdGhpc1tpXTtcblx0XG5cdFx0XHRcdFx0aWYgKCB0eXBlID09PSAnY29sdW1uLXJvd3MnICkge1xuXHRcdFx0XHRcdFx0cm93cyA9IF9zZWxlY3Rvcl9yb3dfaW5kZXhlcyggY29udGV4dFtpXSwgc2VsZWN0b3Iub3B0cyApO1xuXHRcdFx0XHRcdH1cblx0XG5cdFx0XHRcdFx0Zm9yICggaj0wLCBqZW49aXRlbXMubGVuZ3RoIDsgajxqZW4gOyBqKysgKSB7XG5cdFx0XHRcdFx0XHRpdGVtID0gaXRlbXNbal07XG5cdFxuXHRcdFx0XHRcdFx0aWYgKCB0eXBlID09PSAnY2VsbCcgKSB7XG5cdFx0XHRcdFx0XHRcdHJldCA9IGZuLmNhbGwoIGFwaUluc3QsIGNvbnRleHRbaV0sIGl0ZW0ucm93LCBpdGVtLmNvbHVtbiwgaSwgaiApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRcdHJldCA9IGZuLmNhbGwoIGFwaUluc3QsIGNvbnRleHRbaV0sIGl0ZW0sIGksIGosIHJvd3MgKTtcblx0XHRcdFx0XHRcdH1cblx0XG5cdFx0XHRcdFx0XHRpZiAoIHJldCAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdFx0XHRhLnB1c2goIHJldCApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcblx0XHRcdGlmICggYS5sZW5ndGggfHwgYWx3YXlzTmV3ICkge1xuXHRcdFx0XHR2YXIgYXBpID0gbmV3IF9BcGkoIGNvbnRleHQsIGZsYXR0ZW4gPyBhLmNvbmNhdC5hcHBseSggW10sIGEgKSA6IGEgKTtcblx0XHRcdFx0dmFyIGFwaVNlbGVjdG9yID0gYXBpLnNlbGVjdG9yO1xuXHRcdFx0XHRhcGlTZWxlY3Rvci5yb3dzID0gc2VsZWN0b3Iucm93cztcblx0XHRcdFx0YXBpU2VsZWN0b3IuY29scyA9IHNlbGVjdG9yLmNvbHM7XG5cdFx0XHRcdGFwaVNlbGVjdG9yLm9wdHMgPSBzZWxlY3Rvci5vcHRzO1xuXHRcdFx0XHRyZXR1cm4gYXBpO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0fSxcblx0XG5cdFxuXHRcdGxhc3RJbmRleE9mOiBfX2FycmF5UHJvdG8ubGFzdEluZGV4T2YgfHwgZnVuY3Rpb24gKG9iaiwgc3RhcnQpXG5cdFx0e1xuXHRcdFx0Ly8gQml0IGNoZWVreS4uLlxuXHRcdFx0cmV0dXJuIHRoaXMuaW5kZXhPZi5hcHBseSggdGhpcy50b0FycmF5LnJldmVyc2UoKSwgYXJndW1lbnRzICk7XG5cdFx0fSxcblx0XG5cdFxuXHRcdGxlbmd0aDogIDAsXG5cdFxuXHRcblx0XHRtYXA6IGZ1bmN0aW9uICggZm4gKVxuXHRcdHtcblx0XHRcdHZhciBhID0gW107XG5cdFxuXHRcdFx0aWYgKCBfX2FycmF5UHJvdG8ubWFwICkge1xuXHRcdFx0XHRhID0gX19hcnJheVByb3RvLm1hcC5jYWxsKCB0aGlzLCBmbiwgdGhpcyApO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSB7XG5cdFx0XHRcdC8vIENvbXBhdGliaWxpdHkgZm9yIGJyb3dzZXJzIHdpdGhvdXQgRU1DQS0yNTItNSAoSlMgMS42KVxuXHRcdFx0XHRmb3IgKCB2YXIgaT0wLCBpZW49dGhpcy5sZW5ndGggOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdFx0XHRhLnB1c2goIGZuLmNhbGwoIHRoaXMsIHRoaXNbaV0sIGkgKSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFxuXHRcdFx0cmV0dXJuIG5ldyBfQXBpKCB0aGlzLmNvbnRleHQsIGEgKTtcblx0XHR9LFxuXHRcblx0XG5cdFx0cGx1Y2s6IGZ1bmN0aW9uICggcHJvcCApXG5cdFx0e1xuXHRcdFx0cmV0dXJuIHRoaXMubWFwKCBmdW5jdGlvbiAoIGVsICkge1xuXHRcdFx0XHRyZXR1cm4gZWxbIHByb3AgXTtcblx0XHRcdH0gKTtcblx0XHR9LFxuXHRcblx0XHRwb3A6ICAgICBfX2FycmF5UHJvdG8ucG9wLFxuXHRcblx0XG5cdFx0cHVzaDogICAgX19hcnJheVByb3RvLnB1c2gsXG5cdFxuXHRcblx0XHQvLyBEb2VzIG5vdCByZXR1cm4gYW4gQVBJIGluc3RhbmNlXG5cdFx0cmVkdWNlOiBfX2FycmF5UHJvdG8ucmVkdWNlIHx8IGZ1bmN0aW9uICggZm4sIGluaXQgKVxuXHRcdHtcblx0XHRcdHJldHVybiBfZm5SZWR1Y2UoIHRoaXMsIGZuLCBpbml0LCAwLCB0aGlzLmxlbmd0aCwgMSApO1xuXHRcdH0sXG5cdFxuXHRcblx0XHRyZWR1Y2VSaWdodDogX19hcnJheVByb3RvLnJlZHVjZVJpZ2h0IHx8IGZ1bmN0aW9uICggZm4sIGluaXQgKVxuXHRcdHtcblx0XHRcdHJldHVybiBfZm5SZWR1Y2UoIHRoaXMsIGZuLCBpbml0LCB0aGlzLmxlbmd0aC0xLCAtMSwgLTEgKTtcblx0XHR9LFxuXHRcblx0XG5cdFx0cmV2ZXJzZTogX19hcnJheVByb3RvLnJldmVyc2UsXG5cdFxuXHRcblx0XHQvLyBPYmplY3Qgd2l0aCByb3dzLCBjb2x1bW5zIGFuZCBvcHRzXG5cdFx0c2VsZWN0b3I6IG51bGwsXG5cdFxuXHRcblx0XHRzaGlmdDogICBfX2FycmF5UHJvdG8uc2hpZnQsXG5cdFxuXHRcblx0XHRzbGljZTogZnVuY3Rpb24gKCkge1xuXHRcdFx0cmV0dXJuIG5ldyBfQXBpKCB0aGlzLmNvbnRleHQsIHRoaXMgKTtcblx0XHR9LFxuXHRcblx0XG5cdFx0c29ydDogICAgX19hcnJheVByb3RvLnNvcnQsIC8vID8gbmFtZSAtIG9yZGVyP1xuXHRcblx0XG5cdFx0c3BsaWNlOiAgX19hcnJheVByb3RvLnNwbGljZSxcblx0XG5cdFxuXHRcdHRvQXJyYXk6IGZ1bmN0aW9uICgpXG5cdFx0e1xuXHRcdFx0cmV0dXJuIF9fYXJyYXlQcm90by5zbGljZS5jYWxsKCB0aGlzICk7XG5cdFx0fSxcblx0XG5cdFxuXHRcdHRvJDogZnVuY3Rpb24gKClcblx0XHR7XG5cdFx0XHRyZXR1cm4gJCggdGhpcyApO1xuXHRcdH0sXG5cdFxuXHRcblx0XHR0b0pRdWVyeTogZnVuY3Rpb24gKClcblx0XHR7XG5cdFx0XHRyZXR1cm4gJCggdGhpcyApO1xuXHRcdH0sXG5cdFxuXHRcblx0XHR1bmlxdWU6IGZ1bmN0aW9uICgpXG5cdFx0e1xuXHRcdFx0cmV0dXJuIG5ldyBfQXBpKCB0aGlzLmNvbnRleHQsIF91bmlxdWUodGhpcykgKTtcblx0XHR9LFxuXHRcblx0XG5cdFx0dW5zaGlmdDogX19hcnJheVByb3RvLnVuc2hpZnRcblx0fSApO1xuXHRcblx0XG5cdF9BcGkuZXh0ZW5kID0gZnVuY3Rpb24gKCBzY29wZSwgb2JqLCBleHQgKVxuXHR7XG5cdFx0Ly8gT25seSBleHRlbmQgQVBJIGluc3RhbmNlcyBhbmQgc3RhdGljIHByb3BlcnRpZXMgb2YgdGhlIEFQSVxuXHRcdGlmICggISBleHQubGVuZ3RoIHx8ICEgb2JqIHx8ICggISAob2JqIGluc3RhbmNlb2YgX0FwaSkgJiYgISBvYmouX19kdF93cmFwcGVyICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcblx0XHR2YXJcblx0XHRcdGksIGllbixcblx0XHRcdHN0cnVjdCxcblx0XHRcdG1ldGhvZFNjb3BpbmcgPSBmdW5jdGlvbiAoIHNjb3BlLCBmbiwgc3RydWMgKSB7XG5cdFx0XHRcdHJldHVybiBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0dmFyIHJldCA9IGZuLmFwcGx5KCBzY29wZSwgYXJndW1lbnRzICk7XG5cdFxuXHRcdFx0XHRcdC8vIE1ldGhvZCBleHRlbnNpb25cblx0XHRcdFx0XHRfQXBpLmV4dGVuZCggcmV0LCByZXQsIHN0cnVjLm1ldGhvZEV4dCApO1xuXHRcdFx0XHRcdHJldHVybiByZXQ7XG5cdFx0XHRcdH07XG5cdFx0XHR9O1xuXHRcblx0XHRmb3IgKCBpPTAsIGllbj1leHQubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRzdHJ1Y3QgPSBleHRbaV07XG5cdFxuXHRcdFx0Ly8gVmFsdWVcblx0XHRcdG9ialsgc3RydWN0Lm5hbWUgXSA9IHN0cnVjdC50eXBlID09PSAnZnVuY3Rpb24nID9cblx0XHRcdFx0bWV0aG9kU2NvcGluZyggc2NvcGUsIHN0cnVjdC52YWwsIHN0cnVjdCApIDpcblx0XHRcdFx0c3RydWN0LnR5cGUgPT09ICdvYmplY3QnID9cblx0XHRcdFx0XHR7fSA6XG5cdFx0XHRcdFx0c3RydWN0LnZhbDtcblx0XG5cdFx0XHRvYmpbIHN0cnVjdC5uYW1lIF0uX19kdF93cmFwcGVyID0gdHJ1ZTtcblx0XG5cdFx0XHQvLyBQcm9wZXJ0eSBleHRlbnNpb25cblx0XHRcdF9BcGkuZXh0ZW5kKCBzY29wZSwgb2JqWyBzdHJ1Y3QubmFtZSBdLCBzdHJ1Y3QucHJvcEV4dCApO1xuXHRcdH1cblx0fTtcblx0XG5cdFxuXHQvLyBAdG9kbyAtIElzIHRoZXJlIG5lZWQgZm9yIGFuIGF1Z21lbnQgZnVuY3Rpb24/XG5cdC8vIF9BcGkuYXVnbWVudCA9IGZ1bmN0aW9uICggaW5zdCwgbmFtZSApXG5cdC8vIHtcblx0Ly8gXHQvLyBGaW5kIHNyYyBvYmplY3QgaW4gdGhlIHN0cnVjdHVyZSBmcm9tIHRoZSBuYW1lXG5cdC8vIFx0dmFyIHBhcnRzID0gbmFtZS5zcGxpdCgnLicpO1xuXHRcblx0Ly8gXHRfQXBpLmV4dGVuZCggaW5zdCwgb2JqICk7XG5cdC8vIH07XG5cdFxuXHRcblx0Ly8gICAgIFtcblx0Ly8gICAgICAge1xuXHQvLyAgICAgICAgIG5hbWU6ICAgICAgJ2RhdGEnICAgICAgICAgICAgICAgIC0tIHN0cmluZyAgIC0gUHJvcGVydHkgbmFtZVxuXHQvLyAgICAgICAgIHZhbDogICAgICAgZnVuY3Rpb24gKCkge30sICAgICAgIC0tIGZ1bmN0aW9uIC0gQXBpIG1ldGhvZCAob3IgdW5kZWZpbmVkIGlmIGp1c3QgYW4gb2JqZWN0XG5cdC8vICAgICAgICAgbWV0aG9kRXh0OiBbIC4uLiBdLCAgICAgICAgICAgICAgLS0gYXJyYXkgICAgLSBBcnJheSBvZiBBcGkgb2JqZWN0IGRlZmluaXRpb25zIHRvIGV4dGVuZCB0aGUgbWV0aG9kIHJlc3VsdFxuXHQvLyAgICAgICAgIHByb3BFeHQ6ICAgWyAuLi4gXSAgICAgICAgICAgICAgIC0tIGFycmF5ICAgIC0gQXJyYXkgb2YgQXBpIG9iamVjdCBkZWZpbml0aW9ucyB0byBleHRlbmQgdGhlIHByb3BlcnR5XG5cdC8vICAgICAgIH0sXG5cdC8vICAgICAgIHtcblx0Ly8gICAgICAgICBuYW1lOiAgICAgJ3Jvdydcblx0Ly8gICAgICAgICB2YWw6ICAgICAgIHt9LFxuXHQvLyAgICAgICAgIG1ldGhvZEV4dDogWyAuLi4gXSxcblx0Ly8gICAgICAgICBwcm9wRXh0OiAgIFtcblx0Ly8gICAgICAgICAgIHtcblx0Ly8gICAgICAgICAgICAgbmFtZTogICAgICAnZGF0YSdcblx0Ly8gICAgICAgICAgICAgdmFsOiAgICAgICBmdW5jdGlvbiAoKSB7fSxcblx0Ly8gICAgICAgICAgICAgbWV0aG9kRXh0OiBbIC4uLiBdLFxuXHQvLyAgICAgICAgICAgICBwcm9wRXh0OiAgIFsgLi4uIF1cblx0Ly8gICAgICAgICAgIH0sXG5cdC8vICAgICAgICAgICAuLi5cblx0Ly8gICAgICAgICBdXG5cdC8vICAgICAgIH1cblx0Ly8gICAgIF1cblx0XG5cdF9BcGkucmVnaXN0ZXIgPSBfYXBpX3JlZ2lzdGVyID0gZnVuY3Rpb24gKCBuYW1lLCB2YWwgKVxuXHR7XG5cdFx0aWYgKCBBcnJheS5pc0FycmF5KCBuYW1lICkgKSB7XG5cdFx0XHRmb3IgKCB2YXIgaj0wLCBqZW49bmFtZS5sZW5ndGggOyBqPGplbiA7IGorKyApIHtcblx0XHRcdFx0X0FwaS5yZWdpc3RlciggbmFtZVtqXSwgdmFsICk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcblx0XHR2YXJcblx0XHRcdGksIGllbixcblx0XHRcdGhlaXIgPSBuYW1lLnNwbGl0KCcuJyksXG5cdFx0XHRzdHJ1Y3QgPSBfX2FwaVN0cnVjdCxcblx0XHRcdGtleSwgbWV0aG9kO1xuXHRcblx0XHR2YXIgZmluZCA9IGZ1bmN0aW9uICggc3JjLCBuYW1lICkge1xuXHRcdFx0Zm9yICggdmFyIGk9MCwgaWVuPXNyYy5sZW5ndGggOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdFx0aWYgKCBzcmNbaV0ubmFtZSA9PT0gbmFtZSApIHtcblx0XHRcdFx0XHRyZXR1cm4gc3JjW2ldO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gbnVsbDtcblx0XHR9O1xuXHRcblx0XHRmb3IgKCBpPTAsIGllbj1oZWlyLmxlbmd0aCA7IGk8aWVuIDsgaSsrICkge1xuXHRcdFx0bWV0aG9kID0gaGVpcltpXS5pbmRleE9mKCcoKScpICE9PSAtMTtcblx0XHRcdGtleSA9IG1ldGhvZCA/XG5cdFx0XHRcdGhlaXJbaV0ucmVwbGFjZSgnKCknLCAnJykgOlxuXHRcdFx0XHRoZWlyW2ldO1xuXHRcblx0XHRcdHZhciBzcmMgPSBmaW5kKCBzdHJ1Y3QsIGtleSApO1xuXHRcdFx0aWYgKCAhIHNyYyApIHtcblx0XHRcdFx0c3JjID0ge1xuXHRcdFx0XHRcdG5hbWU6ICAgICAga2V5LFxuXHRcdFx0XHRcdHZhbDogICAgICAge30sXG5cdFx0XHRcdFx0bWV0aG9kRXh0OiBbXSxcblx0XHRcdFx0XHRwcm9wRXh0OiAgIFtdLFxuXHRcdFx0XHRcdHR5cGU6ICAgICAgJ29iamVjdCdcblx0XHRcdFx0fTtcblx0XHRcdFx0c3RydWN0LnB1c2goIHNyYyApO1xuXHRcdFx0fVxuXHRcblx0XHRcdGlmICggaSA9PT0gaWVuLTEgKSB7XG5cdFx0XHRcdHNyYy52YWwgPSB2YWw7XG5cdFx0XHRcdHNyYy50eXBlID0gdHlwZW9mIHZhbCA9PT0gJ2Z1bmN0aW9uJyA/XG5cdFx0XHRcdFx0J2Z1bmN0aW9uJyA6XG5cdFx0XHRcdFx0JC5pc1BsYWluT2JqZWN0KCB2YWwgKSA/XG5cdFx0XHRcdFx0XHQnb2JqZWN0JyA6XG5cdFx0XHRcdFx0XHQnb3RoZXInO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSB7XG5cdFx0XHRcdHN0cnVjdCA9IG1ldGhvZCA/XG5cdFx0XHRcdFx0c3JjLm1ldGhvZEV4dCA6XG5cdFx0XHRcdFx0c3JjLnByb3BFeHQ7XG5cdFx0XHR9XG5cdFx0fVxuXHR9O1xuXHRcblx0X0FwaS5yZWdpc3RlclBsdXJhbCA9IF9hcGlfcmVnaXN0ZXJQbHVyYWwgPSBmdW5jdGlvbiAoIHBsdXJhbE5hbWUsIHNpbmd1bGFyTmFtZSwgdmFsICkge1xuXHRcdF9BcGkucmVnaXN0ZXIoIHBsdXJhbE5hbWUsIHZhbCApO1xuXHRcblx0XHRfQXBpLnJlZ2lzdGVyKCBzaW5ndWxhck5hbWUsIGZ1bmN0aW9uICgpIHtcblx0XHRcdHZhciByZXQgPSB2YWwuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcblx0XHRcdGlmICggcmV0ID09PSB0aGlzICkge1xuXHRcdFx0XHQvLyBSZXR1cm5lZCBpdGVtIGlzIHRoZSBBUEkgaW5zdGFuY2UgdGhhdCB3YXMgcGFzc2VkIGluLCByZXR1cm4gaXRcblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIGlmICggcmV0IGluc3RhbmNlb2YgX0FwaSApIHtcblx0XHRcdFx0Ly8gTmV3IEFQSSBpbnN0YW5jZSByZXR1cm5lZCwgd2FudCB0aGUgdmFsdWUgZnJvbSB0aGUgZmlyc3QgaXRlbVxuXHRcdFx0XHQvLyBpbiB0aGUgcmV0dXJuZWQgYXJyYXkgZm9yIHRoZSBzaW5ndWxhciByZXN1bHQuXG5cdFx0XHRcdHJldHVybiByZXQubGVuZ3RoID9cblx0XHRcdFx0XHRBcnJheS5pc0FycmF5KCByZXRbMF0gKSA/XG5cdFx0XHRcdFx0XHRuZXcgX0FwaSggcmV0LmNvbnRleHQsIHJldFswXSApIDogLy8gQXJyYXkgcmVzdWx0cyBhcmUgJ2VuaGFuY2VkJ1xuXHRcdFx0XHRcdFx0cmV0WzBdIDpcblx0XHRcdFx0XHR1bmRlZmluZWQ7XG5cdFx0XHR9XG5cdFxuXHRcdFx0Ly8gTm9uLUFQSSByZXR1cm4gLSBqdXN0IGZpcmUgaXQgYmFja1xuXHRcdFx0cmV0dXJuIHJldDtcblx0XHR9ICk7XG5cdH07XG5cdFxuXHRcblx0LyoqXG5cdCAqIFNlbGVjdG9yIGZvciBIVE1MIHRhYmxlcy4gQXBwbHkgdGhlIGdpdmVuIHNlbGVjdG9yIHRvIHRoZSBnaXZlIGFycmF5IG9mXG5cdCAqIERhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0cy5cblx0ICpcblx0ICogQHBhcmFtIHtzdHJpbmd8aW50ZWdlcn0gW3NlbGVjdG9yXSBqUXVlcnkgc2VsZWN0b3Igc3RyaW5nIG9yIGludGVnZXJcblx0ICogQHBhcmFtICB7YXJyYXl9IEFycmF5IG9mIERhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0cyB0byBiZSBmaWx0ZXJlZFxuXHQgKiBAcmV0dXJuIHthcnJheX1cblx0ICogQGlnbm9yZVxuXHQgKi9cblx0dmFyIF9fdGFibGVfc2VsZWN0b3IgPSBmdW5jdGlvbiAoIHNlbGVjdG9yLCBhIClcblx0e1xuXHRcdGlmICggQXJyYXkuaXNBcnJheShzZWxlY3RvcikgKSB7XG5cdFx0XHRyZXR1cm4gJC5tYXAoIHNlbGVjdG9yLCBmdW5jdGlvbiAoaXRlbSkge1xuXHRcdFx0XHRyZXR1cm4gX190YWJsZV9zZWxlY3RvcihpdGVtLCBhKTtcblx0XHRcdH0gKTtcblx0XHR9XG5cdFxuXHRcdC8vIEludGVnZXIgaXMgdXNlZCB0byBwaWNrIG91dCBhIHRhYmxlIGJ5IGluZGV4XG5cdFx0aWYgKCB0eXBlb2Ygc2VsZWN0b3IgPT09ICdudW1iZXInICkge1xuXHRcdFx0cmV0dXJuIFsgYVsgc2VsZWN0b3IgXSBdO1xuXHRcdH1cblx0XG5cdFx0Ly8gUGVyZm9ybSBhIGpRdWVyeSBzZWxlY3RvciBvbiB0aGUgdGFibGUgbm9kZXNcblx0XHR2YXIgbm9kZXMgPSAkLm1hcCggYSwgZnVuY3Rpb24gKGVsLCBpKSB7XG5cdFx0XHRyZXR1cm4gZWwublRhYmxlO1xuXHRcdH0gKTtcblx0XG5cdFx0cmV0dXJuICQobm9kZXMpXG5cdFx0XHQuZmlsdGVyKCBzZWxlY3RvciApXG5cdFx0XHQubWFwKCBmdW5jdGlvbiAoaSkge1xuXHRcdFx0XHQvLyBOZWVkIHRvIHRyYW5zbGF0ZSBiYWNrIGZyb20gdGhlIHRhYmxlIG5vZGUgdG8gdGhlIHNldHRpbmdzXG5cdFx0XHRcdHZhciBpZHggPSAkLmluQXJyYXkoIHRoaXMsIG5vZGVzICk7XG5cdFx0XHRcdHJldHVybiBhWyBpZHggXTtcblx0XHRcdH0gKVxuXHRcdFx0LnRvQXJyYXkoKTtcblx0fTtcblx0XG5cdFxuXHRcblx0LyoqXG5cdCAqIENvbnRleHQgc2VsZWN0b3IgZm9yIHRoZSBBUEkncyBjb250ZXh0IChpLmUuIHRoZSB0YWJsZXMgdGhlIEFQSSBpbnN0YW5jZVxuXHQgKiByZWZlcnMgdG8uXG5cdCAqXG5cdCAqIEBuYW1lICAgIERhdGFUYWJsZS5BcGkjdGFibGVzXG5cdCAqIEBwYXJhbSB7c3RyaW5nfGludGVnZXJ9IFtzZWxlY3Rvcl0gU2VsZWN0b3IgdG8gcGljayB3aGljaCB0YWJsZXMgdGhlIGl0ZXJhdG9yXG5cdCAqICAgc2hvdWxkIG9wZXJhdGUgb24uIElmIG5vdCBnaXZlbiwgYWxsIHRhYmxlcyBpbiB0aGUgY3VycmVudCBjb250ZXh0IGFyZVxuXHQgKiAgIHVzZWQuIFRoaXMgY2FuIGJlIGdpdmVuIGFzIGEgalF1ZXJ5IHNlbGVjdG9yIChmb3IgZXhhbXBsZSBgJzpndCgwKSdgKSB0b1xuXHQgKiAgIHNlbGVjdCBtdWx0aXBsZSB0YWJsZXMgb3IgYXMgYW4gaW50ZWdlciB0byBzZWxlY3QgYSBzaW5nbGUgdGFibGUuXG5cdCAqIEByZXR1cm5zIHtEYXRhVGFibGUuQXBpfSBSZXR1cm5zIGEgbmV3IEFQSSBpbnN0YW5jZSBpZiBhIHNlbGVjdG9yIGlzIGdpdmVuLlxuXHQgKi9cblx0X2FwaV9yZWdpc3RlciggJ3RhYmxlcygpJywgZnVuY3Rpb24gKCBzZWxlY3RvciApIHtcblx0XHQvLyBBIG5ldyBpbnN0YW5jZSBpcyBjcmVhdGVkIGlmIHRoZXJlIHdhcyBhIHNlbGVjdG9yIHNwZWNpZmllZFxuXHRcdHJldHVybiBzZWxlY3RvciAhPT0gdW5kZWZpbmVkICYmIHNlbGVjdG9yICE9PSBudWxsID9cblx0XHRcdG5ldyBfQXBpKCBfX3RhYmxlX3NlbGVjdG9yKCBzZWxlY3RvciwgdGhpcy5jb250ZXh0ICkgKSA6XG5cdFx0XHR0aGlzO1xuXHR9ICk7XG5cdFxuXHRcblx0X2FwaV9yZWdpc3RlciggJ3RhYmxlKCknLCBmdW5jdGlvbiAoIHNlbGVjdG9yICkge1xuXHRcdHZhciB0YWJsZXMgPSB0aGlzLnRhYmxlcyggc2VsZWN0b3IgKTtcblx0XHR2YXIgY3R4ID0gdGFibGVzLmNvbnRleHQ7XG5cdFxuXHRcdC8vIFRydW5jYXRlIHRvIHRoZSBmaXJzdCBtYXRjaGVkIHRhYmxlXG5cdFx0cmV0dXJuIGN0eC5sZW5ndGggP1xuXHRcdFx0bmV3IF9BcGkoIGN0eFswXSApIDpcblx0XHRcdHRhYmxlcztcblx0fSApO1xuXHRcblx0XG5cdF9hcGlfcmVnaXN0ZXJQbHVyYWwoICd0YWJsZXMoKS5ub2RlcygpJywgJ3RhYmxlKCkubm9kZSgpJyAsIGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ3RhYmxlJywgZnVuY3Rpb24gKCBjdHggKSB7XG5cdFx0XHRyZXR1cm4gY3R4Lm5UYWJsZTtcblx0XHR9LCAxICk7XG5cdH0gKTtcblx0XG5cdFxuXHRfYXBpX3JlZ2lzdGVyUGx1cmFsKCAndGFibGVzKCkuYm9keSgpJywgJ3RhYmxlKCkuYm9keSgpJyAsIGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ3RhYmxlJywgZnVuY3Rpb24gKCBjdHggKSB7XG5cdFx0XHRyZXR1cm4gY3R4Lm5UQm9keTtcblx0XHR9LCAxICk7XG5cdH0gKTtcblx0XG5cdFxuXHRfYXBpX3JlZ2lzdGVyUGx1cmFsKCAndGFibGVzKCkuaGVhZGVyKCknLCAndGFibGUoKS5oZWFkZXIoKScgLCBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuaXRlcmF0b3IoICd0YWJsZScsIGZ1bmN0aW9uICggY3R4ICkge1xuXHRcdFx0cmV0dXJuIGN0eC5uVEhlYWQ7XG5cdFx0fSwgMSApO1xuXHR9ICk7XG5cdFxuXHRcblx0X2FwaV9yZWdpc3RlclBsdXJhbCggJ3RhYmxlcygpLmZvb3RlcigpJywgJ3RhYmxlKCkuZm9vdGVyKCknICwgZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAndGFibGUnLCBmdW5jdGlvbiAoIGN0eCApIHtcblx0XHRcdHJldHVybiBjdHgublRGb290O1xuXHRcdH0sIDEgKTtcblx0fSApO1xuXHRcblx0XG5cdF9hcGlfcmVnaXN0ZXJQbHVyYWwoICd0YWJsZXMoKS5jb250YWluZXJzKCknLCAndGFibGUoKS5jb250YWluZXIoKScgLCBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuaXRlcmF0b3IoICd0YWJsZScsIGZ1bmN0aW9uICggY3R4ICkge1xuXHRcdFx0cmV0dXJuIGN0eC5uVGFibGVXcmFwcGVyO1xuXHRcdH0sIDEgKTtcblx0fSApO1xuXHRcblx0XG5cdFxuXHQvKipcblx0ICogUmVkcmF3IHRoZSB0YWJsZXMgaW4gdGhlIGN1cnJlbnQgY29udGV4dC5cblx0ICovXG5cdF9hcGlfcmVnaXN0ZXIoICdkcmF3KCknLCBmdW5jdGlvbiAoIHBhZ2luZyApIHtcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ3RhYmxlJywgZnVuY3Rpb24gKCBzZXR0aW5ncyApIHtcblx0XHRcdGlmICggcGFnaW5nID09PSAncGFnZScgKSB7XG5cdFx0XHRcdF9mbkRyYXcoIHNldHRpbmdzICk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0aWYgKCB0eXBlb2YgcGFnaW5nID09PSAnc3RyaW5nJyApIHtcblx0XHRcdFx0XHRwYWdpbmcgPSBwYWdpbmcgPT09ICdmdWxsLWhvbGQnID9cblx0XHRcdFx0XHRcdGZhbHNlIDpcblx0XHRcdFx0XHRcdHRydWU7XG5cdFx0XHRcdH1cblx0XG5cdFx0XHRcdF9mblJlRHJhdyggc2V0dGluZ3MsIHBhZ2luZz09PWZhbHNlICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9ICk7XG5cdFxuXHRcblx0XG5cdC8qKlxuXHQgKiBHZXQgdGhlIGN1cnJlbnQgcGFnZSBpbmRleC5cblx0ICpcblx0ICogQHJldHVybiB7aW50ZWdlcn0gQ3VycmVudCBwYWdlIGluZGV4ICh6ZXJvIGJhc2VkKVxuXHQgKi8vKipcblx0ICogU2V0IHRoZSBjdXJyZW50IHBhZ2UuXG5cdCAqXG5cdCAqIE5vdGUgdGhhdCBpZiB5b3UgYXR0ZW1wdCB0byBzaG93IGEgcGFnZSB3aGljaCBkb2VzIG5vdCBleGlzdCwgRGF0YVRhYmxlcyB3aWxsXG5cdCAqIG5vdCB0aHJvdyBhbiBlcnJvciwgYnV0IHJhdGhlciByZXNldCB0aGUgcGFnaW5nLlxuXHQgKlxuXHQgKiBAcGFyYW0ge2ludGVnZXJ8c3RyaW5nfSBhY3Rpb24gVGhlIHBhZ2luZyBhY3Rpb24gdG8gdGFrZS4gVGhpcyBjYW4gYmUgb25lIG9mOlxuXHQgKiAgKiBgaW50ZWdlcmAgLSBUaGUgcGFnZSBpbmRleCB0byBqdW1wIHRvXG5cdCAqICAqIGBzdHJpbmdgIC0gQW4gYWN0aW9uIHRvIHRha2U6XG5cdCAqICAgICogYGZpcnN0YCAtIEp1bXAgdG8gZmlyc3QgcGFnZS5cblx0ICogICAgKiBgbmV4dGAgLSBKdW1wIHRvIHRoZSBuZXh0IHBhZ2Vcblx0ICogICAgKiBgcHJldmlvdXNgIC0gSnVtcCB0byBwcmV2aW91cyBwYWdlXG5cdCAqICAgICogYGxhc3RgIC0gSnVtcCB0byB0aGUgbGFzdCBwYWdlLlxuXHQgKiBAcmV0dXJucyB7RGF0YVRhYmxlcy5BcGl9IHRoaXNcblx0ICovXG5cdF9hcGlfcmVnaXN0ZXIoICdwYWdlKCknLCBmdW5jdGlvbiAoIGFjdGlvbiApIHtcblx0XHRpZiAoIGFjdGlvbiA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0cmV0dXJuIHRoaXMucGFnZS5pbmZvKCkucGFnZTsgLy8gbm90IGFuIGV4cGVuc2l2ZSBjYWxsXG5cdFx0fVxuXHRcblx0XHQvLyBlbHNlLCBoYXZlIGFuIGFjdGlvbiB0byB0YWtlIG9uIGFsbCB0YWJsZXNcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ3RhYmxlJywgZnVuY3Rpb24gKCBzZXR0aW5ncyApIHtcblx0XHRcdF9mblBhZ2VDaGFuZ2UoIHNldHRpbmdzLCBhY3Rpb24gKTtcblx0XHR9ICk7XG5cdH0gKTtcblx0XG5cdFxuXHQvKipcblx0ICogUGFnaW5nIGluZm9ybWF0aW9uIGZvciB0aGUgZmlyc3QgdGFibGUgaW4gdGhlIGN1cnJlbnQgY29udGV4dC5cblx0ICpcblx0ICogSWYgeW91IHJlcXVpcmUgcGFnaW5nIGluZm9ybWF0aW9uIGZvciBhbm90aGVyIHRhYmxlLCB1c2UgdGhlIGB0YWJsZSgpYCBtZXRob2Rcblx0ICogd2l0aCBhIHN1aXRhYmxlIHNlbGVjdG9yLlxuXHQgKlxuXHQgKiBAcmV0dXJuIHtvYmplY3R9IE9iamVjdCB3aXRoIHRoZSBmb2xsb3dpbmcgcHJvcGVydGllcyBzZXQ6XG5cdCAqICAqIGBwYWdlYCAtIEN1cnJlbnQgcGFnZSBpbmRleCAoemVybyBiYXNlZCAtIGkuZS4gdGhlIGZpcnN0IHBhZ2UgaXMgYDBgKVxuXHQgKiAgKiBgcGFnZXNgIC0gVG90YWwgbnVtYmVyIG9mIHBhZ2VzXG5cdCAqICAqIGBzdGFydGAgLSBEaXNwbGF5IGluZGV4IGZvciB0aGUgZmlyc3QgcmVjb3JkIHNob3duIG9uIHRoZSBjdXJyZW50IHBhZ2Vcblx0ICogICogYGVuZGAgLSBEaXNwbGF5IGluZGV4IGZvciB0aGUgbGFzdCByZWNvcmQgc2hvd24gb24gdGhlIGN1cnJlbnQgcGFnZVxuXHQgKiAgKiBgbGVuZ3RoYCAtIERpc3BsYXkgbGVuZ3RoIChudW1iZXIgb2YgcmVjb3JkcykuIE5vdGUgdGhhdCBnZW5lcmFsbHkgYHN0YXJ0XG5cdCAqICAgICsgbGVuZ3RoID0gZW5kYCwgYnV0IHRoaXMgaXMgbm90IGFsd2F5cyB0cnVlLCBmb3IgZXhhbXBsZSBpZiB0aGVyZSBhcmVcblx0ICogICAgb25seSAyIHJlY29yZHMgdG8gc2hvdyBvbiB0aGUgZmluYWwgcGFnZSwgd2l0aCBhIGxlbmd0aCBvZiAxMC5cblx0ICogICogYHJlY29yZHNUb3RhbGAgLSBGdWxsIGRhdGEgc2V0IGxlbmd0aFxuXHQgKiAgKiBgcmVjb3Jkc0Rpc3BsYXlgIC0gRGF0YSBzZXQgbGVuZ3RoIG9uY2UgdGhlIGN1cnJlbnQgZmlsdGVyaW5nIGNyaXRlcmlvblxuXHQgKiAgICBhcmUgYXBwbGllZC5cblx0ICovXG5cdF9hcGlfcmVnaXN0ZXIoICdwYWdlLmluZm8oKScsIGZ1bmN0aW9uICggYWN0aW9uICkge1xuXHRcdGlmICggdGhpcy5jb250ZXh0Lmxlbmd0aCA9PT0gMCApIHtcblx0XHRcdHJldHVybiB1bmRlZmluZWQ7XG5cdFx0fVxuXHRcblx0XHR2YXJcblx0XHRcdHNldHRpbmdzICAgPSB0aGlzLmNvbnRleHRbMF0sXG5cdFx0XHRzdGFydCAgICAgID0gc2V0dGluZ3MuX2lEaXNwbGF5U3RhcnQsXG5cdFx0XHRsZW4gICAgICAgID0gc2V0dGluZ3Mub0ZlYXR1cmVzLmJQYWdpbmF0ZSA/IHNldHRpbmdzLl9pRGlzcGxheUxlbmd0aCA6IC0xLFxuXHRcdFx0dmlzUmVjb3JkcyA9IHNldHRpbmdzLmZuUmVjb3Jkc0Rpc3BsYXkoKSxcblx0XHRcdGFsbCAgICAgICAgPSBsZW4gPT09IC0xO1xuXHRcblx0XHRyZXR1cm4ge1xuXHRcdFx0XCJwYWdlXCI6ICAgICAgICAgICBhbGwgPyAwIDogTWF0aC5mbG9vciggc3RhcnQgLyBsZW4gKSxcblx0XHRcdFwicGFnZXNcIjogICAgICAgICAgYWxsID8gMSA6IE1hdGguY2VpbCggdmlzUmVjb3JkcyAvIGxlbiApLFxuXHRcdFx0XCJzdGFydFwiOiAgICAgICAgICBzdGFydCxcblx0XHRcdFwiZW5kXCI6ICAgICAgICAgICAgc2V0dGluZ3MuZm5EaXNwbGF5RW5kKCksXG5cdFx0XHRcImxlbmd0aFwiOiAgICAgICAgIGxlbixcblx0XHRcdFwicmVjb3Jkc1RvdGFsXCI6ICAgc2V0dGluZ3MuZm5SZWNvcmRzVG90YWwoKSxcblx0XHRcdFwicmVjb3Jkc0Rpc3BsYXlcIjogdmlzUmVjb3Jkcyxcblx0XHRcdFwic2VydmVyU2lkZVwiOiAgICAgX2ZuRGF0YVNvdXJjZSggc2V0dGluZ3MgKSA9PT0gJ3NzcCdcblx0XHR9O1xuXHR9ICk7XG5cdFxuXHRcblx0LyoqXG5cdCAqIEdldCB0aGUgY3VycmVudCBwYWdlIGxlbmd0aC5cblx0ICpcblx0ICogQHJldHVybiB7aW50ZWdlcn0gQ3VycmVudCBwYWdlIGxlbmd0aC4gTm90ZSBgLTFgIGluZGljYXRlcyB0aGF0IGFsbCByZWNvcmRzXG5cdCAqICAgYXJlIHRvIGJlIHNob3duLlxuXHQgKi8vKipcblx0ICogU2V0IHRoZSBjdXJyZW50IHBhZ2UgbGVuZ3RoLlxuXHQgKlxuXHQgKiBAcGFyYW0ge2ludGVnZXJ9IFBhZ2UgbGVuZ3RoIHRvIHNldC4gVXNlIGAtMWAgdG8gc2hvdyBhbGwgcmVjb3Jkcy5cblx0ICogQHJldHVybnMge0RhdGFUYWJsZXMuQXBpfSB0aGlzXG5cdCAqL1xuXHRfYXBpX3JlZ2lzdGVyKCAncGFnZS5sZW4oKScsIGZ1bmN0aW9uICggbGVuICkge1xuXHRcdC8vIE5vdGUgdGhhdCB3ZSBjYW4ndCBjYWxsIHRoaXMgZnVuY3Rpb24gJ2xlbmd0aCgpJyBiZWNhdXNlIGBsZW5ndGhgXG5cdFx0Ly8gaXMgYSBKYXZhc2NyaXB0IHByb3BlcnR5IG9mIGZ1bmN0aW9ucyB3aGljaCBkZWZpbmVzIGhvdyBtYW55IGFyZ3VtZW50c1xuXHRcdC8vIHRoZSBmdW5jdGlvbiBleHBlY3RzLlxuXHRcdGlmICggbGVuID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5jb250ZXh0Lmxlbmd0aCAhPT0gMCA/XG5cdFx0XHRcdHRoaXMuY29udGV4dFswXS5faURpc3BsYXlMZW5ndGggOlxuXHRcdFx0XHR1bmRlZmluZWQ7XG5cdFx0fVxuXHRcblx0XHQvLyBlbHNlLCBzZXQgdGhlIHBhZ2UgbGVuZ3RoXG5cdFx0cmV0dXJuIHRoaXMuaXRlcmF0b3IoICd0YWJsZScsIGZ1bmN0aW9uICggc2V0dGluZ3MgKSB7XG5cdFx0XHRfZm5MZW5ndGhDaGFuZ2UoIHNldHRpbmdzLCBsZW4gKTtcblx0XHR9ICk7XG5cdH0gKTtcblx0XG5cdFxuXHRcblx0dmFyIF9fcmVsb2FkID0gZnVuY3Rpb24gKCBzZXR0aW5ncywgaG9sZFBvc2l0aW9uLCBjYWxsYmFjayApIHtcblx0XHQvLyBVc2UgdGhlIGRyYXcgZXZlbnQgdG8gdHJpZ2dlciBhIGNhbGxiYWNrXG5cdFx0aWYgKCBjYWxsYmFjayApIHtcblx0XHRcdHZhciBhcGkgPSBuZXcgX0FwaSggc2V0dGluZ3MgKTtcblx0XG5cdFx0XHRhcGkub25lKCAnZHJhdycsIGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0Y2FsbGJhY2soIGFwaS5hamF4Lmpzb24oKSApO1xuXHRcdFx0fSApO1xuXHRcdH1cblx0XG5cdFx0aWYgKCBfZm5EYXRhU291cmNlKCBzZXR0aW5ncyApID09ICdzc3AnICkge1xuXHRcdFx0X2ZuUmVEcmF3KCBzZXR0aW5ncywgaG9sZFBvc2l0aW9uICk7XG5cdFx0fVxuXHRcdGVsc2Uge1xuXHRcdFx0X2ZuUHJvY2Vzc2luZ0Rpc3BsYXkoIHNldHRpbmdzLCB0cnVlICk7XG5cdFxuXHRcdFx0Ly8gQ2FuY2VsIGFuIGV4aXN0aW5nIHJlcXVlc3Rcblx0XHRcdHZhciB4aHIgPSBzZXR0aW5ncy5qcVhIUjtcblx0XHRcdGlmICggeGhyICYmIHhoci5yZWFkeVN0YXRlICE9PSA0ICkge1xuXHRcdFx0XHR4aHIuYWJvcnQoKTtcblx0XHRcdH1cblx0XG5cdFx0XHQvLyBUcmlnZ2VyIHhoclxuXHRcdFx0X2ZuQnVpbGRBamF4KCBzZXR0aW5ncywgW10sIGZ1bmN0aW9uKCBqc29uICkge1xuXHRcdFx0XHRfZm5DbGVhclRhYmxlKCBzZXR0aW5ncyApO1xuXHRcblx0XHRcdFx0dmFyIGRhdGEgPSBfZm5BamF4RGF0YVNyYyggc2V0dGluZ3MsIGpzb24gKTtcblx0XHRcdFx0Zm9yICggdmFyIGk9MCwgaWVuPWRhdGEubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRcdFx0X2ZuQWRkRGF0YSggc2V0dGluZ3MsIGRhdGFbaV0gKTtcblx0XHRcdFx0fVxuXHRcblx0XHRcdFx0X2ZuUmVEcmF3KCBzZXR0aW5ncywgaG9sZFBvc2l0aW9uICk7XG5cdFx0XHRcdF9mblByb2Nlc3NpbmdEaXNwbGF5KCBzZXR0aW5ncywgZmFsc2UgKTtcblx0XHRcdH0gKTtcblx0XHR9XG5cdH07XG5cdFxuXHRcblx0LyoqXG5cdCAqIEdldCB0aGUgSlNPTiByZXNwb25zZSBmcm9tIHRoZSBsYXN0IEFqYXggcmVxdWVzdCB0aGF0IERhdGFUYWJsZXMgbWFkZSB0byB0aGVcblx0ICogc2VydmVyLiBOb3RlIHRoYXQgdGhpcyByZXR1cm5zIHRoZSBKU09OIGZyb20gdGhlIGZpcnN0IHRhYmxlIGluIHRoZSBjdXJyZW50XG5cdCAqIGNvbnRleHQuXG5cdCAqXG5cdCAqIEByZXR1cm4ge29iamVjdH0gSlNPTiByZWNlaXZlZCBmcm9tIHRoZSBzZXJ2ZXIuXG5cdCAqL1xuXHRfYXBpX3JlZ2lzdGVyKCAnYWpheC5qc29uKCknLCBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGN0eCA9IHRoaXMuY29udGV4dDtcblx0XG5cdFx0aWYgKCBjdHgubGVuZ3RoID4gMCApIHtcblx0XHRcdHJldHVybiBjdHhbMF0uanNvbjtcblx0XHR9XG5cdFxuXHRcdC8vIGVsc2UgcmV0dXJuIHVuZGVmaW5lZDtcblx0fSApO1xuXHRcblx0XG5cdC8qKlxuXHQgKiBHZXQgdGhlIGRhdGEgc3VibWl0dGVkIGluIHRoZSBsYXN0IEFqYXggcmVxdWVzdFxuXHQgKi9cblx0X2FwaV9yZWdpc3RlciggJ2FqYXgucGFyYW1zKCknLCBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGN0eCA9IHRoaXMuY29udGV4dDtcblx0XG5cdFx0aWYgKCBjdHgubGVuZ3RoID4gMCApIHtcblx0XHRcdHJldHVybiBjdHhbMF0ub0FqYXhEYXRhO1xuXHRcdH1cblx0XG5cdFx0Ly8gZWxzZSByZXR1cm4gdW5kZWZpbmVkO1xuXHR9ICk7XG5cdFxuXHRcblx0LyoqXG5cdCAqIFJlbG9hZCB0YWJsZXMgZnJvbSB0aGUgQWpheCBkYXRhIHNvdXJjZS4gTm90ZSB0aGF0IHRoaXMgZnVuY3Rpb24gd2lsbFxuXHQgKiBhdXRvbWF0aWNhbGx5IHJlLWRyYXcgdGhlIHRhYmxlIHdoZW4gdGhlIHJlbW90ZSBkYXRhIGhhcyBiZWVuIGxvYWRlZC5cblx0ICpcblx0ICogQHBhcmFtIHtib29sZWFufSBbcmVzZXQ9dHJ1ZV0gUmVzZXQgKGRlZmF1bHQpIG9yIGhvbGQgdGhlIGN1cnJlbnQgcGFnaW5nXG5cdCAqICAgcG9zaXRpb24uIEEgZnVsbCByZS1zb3J0IGFuZCByZS1maWx0ZXIgaXMgcGVyZm9ybWVkIHdoZW4gdGhpcyBtZXRob2QgaXNcblx0ICogICBjYWxsZWQsIHdoaWNoIGlzIHdoeSB0aGUgcGFnaW5hdGlvbiByZXNldCBpcyB0aGUgZGVmYXVsdCBhY3Rpb24uXG5cdCAqIEByZXR1cm5zIHtEYXRhVGFibGVzLkFwaX0gdGhpc1xuXHQgKi9cblx0X2FwaV9yZWdpc3RlciggJ2FqYXgucmVsb2FkKCknLCBmdW5jdGlvbiAoIGNhbGxiYWNrLCByZXNldFBhZ2luZyApIHtcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ3RhYmxlJywgZnVuY3Rpb24gKHNldHRpbmdzKSB7XG5cdFx0XHRfX3JlbG9hZCggc2V0dGluZ3MsIHJlc2V0UGFnaW5nPT09ZmFsc2UsIGNhbGxiYWNrICk7XG5cdFx0fSApO1xuXHR9ICk7XG5cdFxuXHRcblx0LyoqXG5cdCAqIEdldCB0aGUgY3VycmVudCBBamF4IFVSTC4gTm90ZSB0aGF0IHRoaXMgcmV0dXJucyB0aGUgVVJMIGZyb20gdGhlIGZpcnN0XG5cdCAqIHRhYmxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQuXG5cdCAqXG5cdCAqIEByZXR1cm4ge3N0cmluZ30gQ3VycmVudCBBamF4IHNvdXJjZSBVUkxcblx0ICovLyoqXG5cdCAqIFNldCB0aGUgQWpheCBVUkwuIE5vdGUgdGhhdCB0aGlzIHdpbGwgc2V0IHRoZSBVUkwgZm9yIGFsbCB0YWJsZXMgaW4gdGhlXG5cdCAqIGN1cnJlbnQgY29udGV4dC5cblx0ICpcblx0ICogQHBhcmFtIHtzdHJpbmd9IHVybCBVUkwgdG8gc2V0LlxuXHQgKiBAcmV0dXJucyB7RGF0YVRhYmxlcy5BcGl9IHRoaXNcblx0ICovXG5cdF9hcGlfcmVnaXN0ZXIoICdhamF4LnVybCgpJywgZnVuY3Rpb24gKCB1cmwgKSB7XG5cdFx0dmFyIGN0eCA9IHRoaXMuY29udGV4dDtcblx0XG5cdFx0aWYgKCB1cmwgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdC8vIGdldFxuXHRcdFx0aWYgKCBjdHgubGVuZ3RoID09PSAwICkge1xuXHRcdFx0XHRyZXR1cm4gdW5kZWZpbmVkO1xuXHRcdFx0fVxuXHRcdFx0Y3R4ID0gY3R4WzBdO1xuXHRcblx0XHRcdHJldHVybiBjdHguYWpheCA/XG5cdFx0XHRcdCQuaXNQbGFpbk9iamVjdCggY3R4LmFqYXggKSA/XG5cdFx0XHRcdFx0Y3R4LmFqYXgudXJsIDpcblx0XHRcdFx0XHRjdHguYWpheCA6XG5cdFx0XHRcdGN0eC5zQWpheFNvdXJjZTtcblx0XHR9XG5cdFxuXHRcdC8vIHNldFxuXHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAndGFibGUnLCBmdW5jdGlvbiAoIHNldHRpbmdzICkge1xuXHRcdFx0aWYgKCAkLmlzUGxhaW5PYmplY3QoIHNldHRpbmdzLmFqYXggKSApIHtcblx0XHRcdFx0c2V0dGluZ3MuYWpheC51cmwgPSB1cmw7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0c2V0dGluZ3MuYWpheCA9IHVybDtcblx0XHRcdH1cblx0XHRcdC8vIE5vIG5lZWQgdG8gY29uc2lkZXIgc0FqYXhTb3VyY2UgaGVyZSBzaW5jZSBEYXRhVGFibGVzIGdpdmVzIHByaW9yaXR5XG5cdFx0XHQvLyB0byBgYWpheGAgb3ZlciBgc0FqYXhTb3VyY2VgLiBTbyBzZXR0aW5nIGBhamF4YCBoZXJlLCByZW5kZXJzIGFueVxuXHRcdFx0Ly8gdmFsdWUgb2YgYHNBamF4U291cmNlYCByZWR1bmRhbnQuXG5cdFx0fSApO1xuXHR9ICk7XG5cdFxuXHRcblx0LyoqXG5cdCAqIExvYWQgZGF0YSBmcm9tIHRoZSBuZXdseSBzZXQgQWpheCBVUkwuIE5vdGUgdGhhdCB0aGlzIG1ldGhvZCBpcyBvbmx5XG5cdCAqIGF2YWlsYWJsZSB3aGVuIGBhamF4LnVybCgpYCBpcyB1c2VkIHRvIHNldCBhIFVSTC4gQWRkaXRpb25hbGx5LCB0aGlzIG1ldGhvZFxuXHQgKiBoYXMgdGhlIHNhbWUgZWZmZWN0IGFzIGNhbGxpbmcgYGFqYXgucmVsb2FkKClgIGJ1dCBpcyBwcm92aWRlZCBmb3Jcblx0ICogY29udmVuaWVuY2Ugd2hlbiBzZXR0aW5nIGEgbmV3IFVSTC4gTGlrZSBgYWpheC5yZWxvYWQoKWAgaXQgd2lsbFxuXHQgKiBhdXRvbWF0aWNhbGx5IHJlZHJhdyB0aGUgdGFibGUgb25jZSB0aGUgcmVtb3RlIGRhdGEgaGFzIGJlZW4gbG9hZGVkLlxuXHQgKlxuXHQgKiBAcmV0dXJucyB7RGF0YVRhYmxlcy5BcGl9IHRoaXNcblx0ICovXG5cdF9hcGlfcmVnaXN0ZXIoICdhamF4LnVybCgpLmxvYWQoKScsIGZ1bmN0aW9uICggY2FsbGJhY2ssIHJlc2V0UGFnaW5nICkge1xuXHRcdC8vIFNhbWUgYXMgYSByZWxvYWQsIGJ1dCBtYWtlcyBzZW5zZSB0byBwcmVzZW50IGl0IGZvciBlYXN5IGFjY2VzcyBhZnRlciBhXG5cdFx0Ly8gdXJsIGNoYW5nZVxuXHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAndGFibGUnLCBmdW5jdGlvbiAoIGN0eCApIHtcblx0XHRcdF9fcmVsb2FkKCBjdHgsIHJlc2V0UGFnaW5nPT09ZmFsc2UsIGNhbGxiYWNrICk7XG5cdFx0fSApO1xuXHR9ICk7XG5cdFxuXHRcblx0XG5cdFxuXHR2YXIgX3NlbGVjdG9yX3J1biA9IGZ1bmN0aW9uICggdHlwZSwgc2VsZWN0b3IsIHNlbGVjdEZuLCBzZXR0aW5ncywgb3B0cyApXG5cdHtcblx0XHR2YXJcblx0XHRcdG91dCA9IFtdLCByZXMsXG5cdFx0XHRhLCBpLCBpZW4sIGosIGplbixcblx0XHRcdHNlbGVjdG9yVHlwZSA9IHR5cGVvZiBzZWxlY3Rvcjtcblx0XG5cdFx0Ly8gQ2FuJ3QganVzdCBjaGVjayBmb3IgaXNBcnJheSBoZXJlLCBhcyBhbiBBUEkgb3IgalF1ZXJ5IGluc3RhbmNlIG1pZ2h0IGJlXG5cdFx0Ly8gZ2l2ZW4gd2l0aCB0aGVpciBhcnJheSBsaWtlIGxvb2tcblx0XHRpZiAoICEgc2VsZWN0b3IgfHwgc2VsZWN0b3JUeXBlID09PSAnc3RyaW5nJyB8fCBzZWxlY3RvclR5cGUgPT09ICdmdW5jdGlvbicgfHwgc2VsZWN0b3IubGVuZ3RoID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRzZWxlY3RvciA9IFsgc2VsZWN0b3IgXTtcblx0XHR9XG5cdFxuXHRcdGZvciAoIGk9MCwgaWVuPXNlbGVjdG9yLmxlbmd0aCA7IGk8aWVuIDsgaSsrICkge1xuXHRcdFx0Ly8gT25seSBzcGxpdCBvbiBzaW1wbGUgc3RyaW5ncyAtIGNvbXBsZXggZXhwcmVzc2lvbnMgd2lsbCBiZSBqUXVlcnkgc2VsZWN0b3JzXG5cdFx0XHRhID0gc2VsZWN0b3JbaV0gJiYgc2VsZWN0b3JbaV0uc3BsaXQgJiYgISBzZWxlY3RvcltpXS5tYXRjaCgvW1xcW1xcKDpdLykgP1xuXHRcdFx0XHRzZWxlY3RvcltpXS5zcGxpdCgnLCcpIDpcblx0XHRcdFx0WyBzZWxlY3RvcltpXSBdO1xuXHRcblx0XHRcdGZvciAoIGo9MCwgamVuPWEubGVuZ3RoIDsgajxqZW4gOyBqKysgKSB7XG5cdFx0XHRcdHJlcyA9IHNlbGVjdEZuKCB0eXBlb2YgYVtqXSA9PT0gJ3N0cmluZycgPyAoYVtqXSkudHJpbSgpIDogYVtqXSApO1xuXHRcblx0XHRcdFx0aWYgKCByZXMgJiYgcmVzLmxlbmd0aCApIHtcblx0XHRcdFx0XHRvdXQgPSBvdXQuY29uY2F0KCByZXMgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XG5cdFx0Ly8gc2VsZWN0b3IgZXh0ZW5zaW9uc1xuXHRcdHZhciBleHQgPSBfZXh0LnNlbGVjdG9yWyB0eXBlIF07XG5cdFx0aWYgKCBleHQubGVuZ3RoICkge1xuXHRcdFx0Zm9yICggaT0wLCBpZW49ZXh0Lmxlbmd0aCA7IGk8aWVuIDsgaSsrICkge1xuXHRcdFx0XHRvdXQgPSBleHRbaV0oIHNldHRpbmdzLCBvcHRzLCBvdXQgKTtcblx0XHRcdH1cblx0XHR9XG5cdFxuXHRcdHJldHVybiBfdW5pcXVlKCBvdXQgKTtcblx0fTtcblx0XG5cdFxuXHR2YXIgX3NlbGVjdG9yX29wdHMgPSBmdW5jdGlvbiAoIG9wdHMgKVxuXHR7XG5cdFx0aWYgKCAhIG9wdHMgKSB7XG5cdFx0XHRvcHRzID0ge307XG5cdFx0fVxuXHRcblx0XHQvLyBCYWNrd2FyZHMgY29tcGF0aWJpbGl0eSBmb3IgMS45LSB3aGljaCB1c2VkIHRoZSB0ZXJtaW5vbG9neSBmaWx0ZXIgcmF0aGVyXG5cdFx0Ly8gdGhhbiBzZWFyY2hcblx0XHRpZiAoIG9wdHMuZmlsdGVyICYmIG9wdHMuc2VhcmNoID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRvcHRzLnNlYXJjaCA9IG9wdHMuZmlsdGVyO1xuXHRcdH1cblx0XG5cdFx0cmV0dXJuICQuZXh0ZW5kKCB7XG5cdFx0XHRzZWFyY2g6ICdub25lJyxcblx0XHRcdG9yZGVyOiAnY3VycmVudCcsXG5cdFx0XHRwYWdlOiAnYWxsJ1xuXHRcdH0sIG9wdHMgKTtcblx0fTtcblx0XG5cdFxuXHR2YXIgX3NlbGVjdG9yX2ZpcnN0ID0gZnVuY3Rpb24gKCBpbnN0IClcblx0e1xuXHRcdC8vIFJlZHVjZSB0aGUgQVBJIGluc3RhbmNlIHRvIHRoZSBmaXJzdCBpdGVtIGZvdW5kXG5cdFx0Zm9yICggdmFyIGk9MCwgaWVuPWluc3QubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRpZiAoIGluc3RbaV0ubGVuZ3RoID4gMCApIHtcblx0XHRcdFx0Ly8gQXNzaWduIHRoZSBmaXJzdCBlbGVtZW50IHRvIHRoZSBmaXJzdCBpdGVtIGluIHRoZSBpbnN0YW5jZVxuXHRcdFx0XHQvLyBhbmQgdHJ1bmNhdGUgdGhlIGluc3RhbmNlIGFuZCBjb250ZXh0XG5cdFx0XHRcdGluc3RbMF0gPSBpbnN0W2ldO1xuXHRcdFx0XHRpbnN0WzBdLmxlbmd0aCA9IDE7XG5cdFx0XHRcdGluc3QubGVuZ3RoID0gMTtcblx0XHRcdFx0aW5zdC5jb250ZXh0ID0gWyBpbnN0LmNvbnRleHRbaV0gXTtcblx0XG5cdFx0XHRcdHJldHVybiBpbnN0O1xuXHRcdFx0fVxuXHRcdH1cblx0XG5cdFx0Ly8gTm90IGZvdW5kIC0gcmV0dXJuIGFuIGVtcHR5IGluc3RhbmNlXG5cdFx0aW5zdC5sZW5ndGggPSAwO1xuXHRcdHJldHVybiBpbnN0O1xuXHR9O1xuXHRcblx0XG5cdHZhciBfc2VsZWN0b3Jfcm93X2luZGV4ZXMgPSBmdW5jdGlvbiAoIHNldHRpbmdzLCBvcHRzIClcblx0e1xuXHRcdHZhclxuXHRcdFx0aSwgaWVuLCB0bXAsIGE9W10sXG5cdFx0XHRkaXNwbGF5RmlsdGVyZWQgPSBzZXR0aW5ncy5haURpc3BsYXksXG5cdFx0XHRkaXNwbGF5TWFzdGVyID0gc2V0dGluZ3MuYWlEaXNwbGF5TWFzdGVyO1xuXHRcblx0XHR2YXJcblx0XHRcdHNlYXJjaCA9IG9wdHMuc2VhcmNoLCAgLy8gbm9uZSwgYXBwbGllZCwgcmVtb3ZlZFxuXHRcdFx0b3JkZXIgID0gb3B0cy5vcmRlciwgICAvLyBhcHBsaWVkLCBjdXJyZW50LCBpbmRleCAob3JpZ2luYWwgLSBjb21wYXRpYmlsaXR5IHdpdGggMS45KVxuXHRcdFx0cGFnZSAgID0gb3B0cy5wYWdlOyAgICAvLyBhbGwsIGN1cnJlbnRcblx0XG5cdFx0aWYgKCBfZm5EYXRhU291cmNlKCBzZXR0aW5ncyApID09ICdzc3AnICkge1xuXHRcdFx0Ly8gSW4gc2VydmVyLXNpZGUgcHJvY2Vzc2luZyBtb2RlLCBtb3N0IG9wdGlvbnMgYXJlIGlycmVsZXZhbnQgc2luY2Vcblx0XHRcdC8vIHJvd3Mgbm90IHNob3duIGRvbid0IGV4aXN0IGFuZCB0aGUgaW5kZXggb3JkZXIgaXMgdGhlIGFwcGxpZWQgb3JkZXJcblx0XHRcdC8vIFJlbW92ZWQgaXMgYSBzcGVjaWFsIGNhc2UgLSBmb3IgY29uc2lzdGVuY3kganVzdCByZXR1cm4gYW4gZW1wdHlcblx0XHRcdC8vIGFycmF5XG5cdFx0XHRyZXR1cm4gc2VhcmNoID09PSAncmVtb3ZlZCcgP1xuXHRcdFx0XHRbXSA6XG5cdFx0XHRcdF9yYW5nZSggMCwgZGlzcGxheU1hc3Rlci5sZW5ndGggKTtcblx0XHR9XG5cdFx0ZWxzZSBpZiAoIHBhZ2UgPT0gJ2N1cnJlbnQnICkge1xuXHRcdFx0Ly8gQ3VycmVudCBwYWdlIGltcGxpZXMgdGhhdCBvcmRlcj1jdXJyZW50IGFuZCBmaWx0ZXI9YXBwbGllZCwgc2luY2UgaXQgaXNcblx0XHRcdC8vIGZhaXJseSBzZW5zZWxlc3Mgb3RoZXJ3aXNlLCByZWdhcmRsZXNzIG9mIHdoYXQgb3JkZXIgYW5kIHNlYXJjaCBhY3R1YWxseVxuXHRcdFx0Ly8gYXJlXG5cdFx0XHRmb3IgKCBpPXNldHRpbmdzLl9pRGlzcGxheVN0YXJ0LCBpZW49c2V0dGluZ3MuZm5EaXNwbGF5RW5kKCkgOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdFx0YS5wdXNoKCBkaXNwbGF5RmlsdGVyZWRbaV0gKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0ZWxzZSBpZiAoIG9yZGVyID09ICdjdXJyZW50JyB8fCBvcmRlciA9PSAnYXBwbGllZCcgKSB7XG5cdFx0XHRpZiAoIHNlYXJjaCA9PSAnbm9uZScpIHtcblx0XHRcdFx0YSA9IGRpc3BsYXlNYXN0ZXIuc2xpY2UoKTtcblx0XHRcdH1cblx0XHRcdGVsc2UgaWYgKCBzZWFyY2ggPT0gJ2FwcGxpZWQnICkge1xuXHRcdFx0XHRhID0gZGlzcGxheUZpbHRlcmVkLnNsaWNlKCk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIGlmICggc2VhcmNoID09ICdyZW1vdmVkJyApIHtcblx0XHRcdFx0Ly8gTyhuK20pIHNvbHV0aW9uIGJ5IGNyZWF0aW5nIGEgaGFzaCBtYXBcblx0XHRcdFx0dmFyIGRpc3BsYXlGaWx0ZXJlZE1hcCA9IHt9O1xuXHRcblx0XHRcdFx0Zm9yICggdmFyIGk9MCwgaWVuPWRpc3BsYXlGaWx0ZXJlZC5sZW5ndGggOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdFx0XHRkaXNwbGF5RmlsdGVyZWRNYXBbZGlzcGxheUZpbHRlcmVkW2ldXSA9IG51bGw7XG5cdFx0XHRcdH1cblx0XG5cdFx0XHRcdGEgPSAkLm1hcCggZGlzcGxheU1hc3RlciwgZnVuY3Rpb24gKGVsKSB7XG5cdFx0XHRcdFx0cmV0dXJuICEgZGlzcGxheUZpbHRlcmVkTWFwLmhhc093blByb3BlcnR5KGVsKSA/XG5cdFx0XHRcdFx0XHRlbCA6XG5cdFx0XHRcdFx0XHRudWxsO1xuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGVsc2UgaWYgKCBvcmRlciA9PSAnaW5kZXgnIHx8IG9yZGVyID09ICdvcmlnaW5hbCcgKSB7XG5cdFx0XHRmb3IgKCBpPTAsIGllbj1zZXR0aW5ncy5hb0RhdGEubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRcdGlmICggc2VhcmNoID09ICdub25lJyApIHtcblx0XHRcdFx0XHRhLnB1c2goIGkgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHsgLy8gYXBwbGllZCB8IHJlbW92ZWRcblx0XHRcdFx0XHR0bXAgPSAkLmluQXJyYXkoIGksIGRpc3BsYXlGaWx0ZXJlZCApO1xuXHRcblx0XHRcdFx0XHRpZiAoKHRtcCA9PT0gLTEgJiYgc2VhcmNoID09ICdyZW1vdmVkJykgfHxcblx0XHRcdFx0XHRcdCh0bXAgPj0gMCAgICYmIHNlYXJjaCA9PSAnYXBwbGllZCcpIClcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRhLnB1c2goIGkgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdFxuXHRcdHJldHVybiBhO1xuXHR9O1xuXHRcblx0XG5cdC8qICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKlxuXHQgKiBSb3dzXG5cdCAqXG5cdCAqIHt9ICAgICAgICAgIC0gbm8gc2VsZWN0b3IgLSB1c2UgYWxsIGF2YWlsYWJsZSByb3dzXG5cdCAqIHtpbnRlZ2VyfSAgIC0gcm93IGFvRGF0YSBpbmRleFxuXHQgKiB7bm9kZX0gICAgICAtIFRSIG5vZGVcblx0ICoge3N0cmluZ30gICAgLSBqUXVlcnkgc2VsZWN0b3IgdG8gYXBwbHkgdG8gdGhlIFRSIGVsZW1lbnRzXG5cdCAqIHthcnJheX0gICAgIC0galF1ZXJ5IGFycmF5IG9mIG5vZGVzLCBvciBzaW1wbHkgYW4gYXJyYXkgb2YgVFIgbm9kZXNcblx0ICpcblx0ICovXG5cdHZhciBfX3Jvd19zZWxlY3RvciA9IGZ1bmN0aW9uICggc2V0dGluZ3MsIHNlbGVjdG9yLCBvcHRzIClcblx0e1xuXHRcdHZhciByb3dzO1xuXHRcdHZhciBydW4gPSBmdW5jdGlvbiAoIHNlbCApIHtcblx0XHRcdHZhciBzZWxJbnQgPSBfaW50VmFsKCBzZWwgKTtcblx0XHRcdHZhciBpLCBpZW47XG5cdFx0XHR2YXIgYW9EYXRhID0gc2V0dGluZ3MuYW9EYXRhO1xuXHRcblx0XHRcdC8vIFNob3J0IGN1dCAtIHNlbGVjdG9yIGlzIGEgbnVtYmVyIGFuZCBubyBvcHRpb25zIHByb3ZpZGVkIChkZWZhdWx0IGlzXG5cdFx0XHQvLyBhbGwgcmVjb3Jkcywgc28gbm8gbmVlZCB0byBjaGVjayBpZiB0aGUgaW5kZXggaXMgaW4gdGhlcmUsIHNpbmNlIGl0XG5cdFx0XHQvLyBtdXN0IGJlIC0gZGV2IGVycm9yIGlmIHRoZSBpbmRleCBkb2Vzbid0IGV4aXN0KS5cblx0XHRcdGlmICggc2VsSW50ICE9PSBudWxsICYmICEgb3B0cyApIHtcblx0XHRcdFx0cmV0dXJuIFsgc2VsSW50IF07XG5cdFx0XHR9XG5cdFxuXHRcdFx0aWYgKCAhIHJvd3MgKSB7XG5cdFx0XHRcdHJvd3MgPSBfc2VsZWN0b3Jfcm93X2luZGV4ZXMoIHNldHRpbmdzLCBvcHRzICk7XG5cdFx0XHR9XG5cdFxuXHRcdFx0aWYgKCBzZWxJbnQgIT09IG51bGwgJiYgJC5pbkFycmF5KCBzZWxJbnQsIHJvd3MgKSAhPT0gLTEgKSB7XG5cdFx0XHRcdC8vIFNlbGVjdG9yIC0gaW50ZWdlclxuXHRcdFx0XHRyZXR1cm4gWyBzZWxJbnQgXTtcblx0XHRcdH1cblx0XHRcdGVsc2UgaWYgKCBzZWwgPT09IG51bGwgfHwgc2VsID09PSB1bmRlZmluZWQgfHwgc2VsID09PSAnJyApIHtcblx0XHRcdFx0Ly8gU2VsZWN0b3IgLSBub25lXG5cdFx0XHRcdHJldHVybiByb3dzO1xuXHRcdFx0fVxuXHRcblx0XHRcdC8vIFNlbGVjdG9yIC0gZnVuY3Rpb25cblx0XHRcdGlmICggdHlwZW9mIHNlbCA9PT0gJ2Z1bmN0aW9uJyApIHtcblx0XHRcdFx0cmV0dXJuICQubWFwKCByb3dzLCBmdW5jdGlvbiAoaWR4KSB7XG5cdFx0XHRcdFx0dmFyIHJvdyA9IGFvRGF0YVsgaWR4IF07XG5cdFx0XHRcdFx0cmV0dXJuIHNlbCggaWR4LCByb3cuX2FEYXRhLCByb3cublRyICkgPyBpZHggOiBudWxsO1xuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cdFxuXHRcdFx0Ly8gU2VsZWN0b3IgLSBub2RlXG5cdFx0XHRpZiAoIHNlbC5ub2RlTmFtZSApIHtcblx0XHRcdFx0dmFyIHJvd0lkeCA9IHNlbC5fRFRfUm93SW5kZXg7ICAvLyBQcm9wZXJ0eSBhZGRlZCBieSBEVCBmb3IgZmFzdCBsb29rdXBcblx0XHRcdFx0dmFyIGNlbGxJZHggPSBzZWwuX0RUX0NlbGxJbmRleDtcblx0XG5cdFx0XHRcdGlmICggcm93SWR4ICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0Ly8gTWFrZSBzdXJlIHRoYXQgdGhlIHJvdyBpcyBhY3R1YWxseSBzdGlsbCBwcmVzZW50IGluIHRoZSB0YWJsZVxuXHRcdFx0XHRcdHJldHVybiBhb0RhdGFbIHJvd0lkeCBdICYmIGFvRGF0YVsgcm93SWR4IF0ublRyID09PSBzZWwgP1xuXHRcdFx0XHRcdFx0WyByb3dJZHggXSA6XG5cdFx0XHRcdFx0XHRbXTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIGlmICggY2VsbElkeCApIHtcblx0XHRcdFx0XHRyZXR1cm4gYW9EYXRhWyBjZWxsSWR4LnJvdyBdICYmIGFvRGF0YVsgY2VsbElkeC5yb3cgXS5uVHIgPT09IHNlbC5wYXJlbnROb2RlID9cblx0XHRcdFx0XHRcdFsgY2VsbElkeC5yb3cgXSA6XG5cdFx0XHRcdFx0XHRbXTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHR2YXIgaG9zdCA9ICQoc2VsKS5jbG9zZXN0KCcqW2RhdGEtZHQtcm93XScpO1xuXHRcdFx0XHRcdHJldHVybiBob3N0Lmxlbmd0aCA/XG5cdFx0XHRcdFx0XHRbIGhvc3QuZGF0YSgnZHQtcm93JykgXSA6XG5cdFx0XHRcdFx0XHRbXTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcblx0XHRcdC8vIElEIHNlbGVjdG9yLiBXYW50IHRvIGFsd2F5cyBiZSBhYmxlIHRvIHNlbGVjdCByb3dzIGJ5IGlkLCByZWdhcmRsZXNzXG5cdFx0XHQvLyBvZiBpZiB0aGUgdHIgZWxlbWVudCBoYXMgYmVlbiBjcmVhdGVkIG9yIG5vdCwgc28gY2FuJ3QgcmVseSB1cG9uXG5cdFx0XHQvLyBqUXVlcnkgaGVyZSAtIGhlbmNlIGEgY3VzdG9tIGltcGxlbWVudGF0aW9uLiBUaGlzIGRvZXMgbm90IG1hdGNoXG5cdFx0XHQvLyBTaXp6bGUncyBmYXN0IHNlbGVjdG9yIG9yIEhUTUw0IC0gaW4gSFRNTDUgdGhlIElEIGNhbiBiZSBhbnl0aGluZyxcblx0XHRcdC8vIGJ1dCB0byBzZWxlY3QgaXQgdXNpbmcgYSBDU1Mgc2VsZWN0b3IgZW5naW5lIChsaWtlIFNpenpsZSBvclxuXHRcdFx0Ly8gcXVlcnlTZWxlY3QpIGl0IHdvdWxkIG5lZWQgdG8gbmVlZCB0byBiZSBlc2NhcGVkIGZvciBzb21lIGNoYXJhY3RlcnMuXG5cdFx0XHQvLyBEYXRhVGFibGVzIHNpbXBsaWZpZXMgdGhpcyBmb3Igcm93IHNlbGVjdG9ycyBzaW5jZSB5b3UgY2FuIHNlbGVjdFxuXHRcdFx0Ly8gb25seSBhIHJvdy4gQSAjIGluZGljYXRlcyBhbiBpZCBhbnkgYW55dGhpbmcgdGhhdCBmb2xsb3dzIGlzIHRoZSBpZCAtXG5cdFx0XHQvLyB1bmVzY2FwZWQuXG5cdFx0XHRpZiAoIHR5cGVvZiBzZWwgPT09ICdzdHJpbmcnICYmIHNlbC5jaGFyQXQoMCkgPT09ICcjJyApIHtcblx0XHRcdFx0Ly8gZ2V0IHJvdyBpbmRleCBmcm9tIGlkXG5cdFx0XHRcdHZhciByb3dPYmogPSBzZXR0aW5ncy5hSWRzWyBzZWwucmVwbGFjZSggL14jLywgJycgKSBdO1xuXHRcdFx0XHRpZiAoIHJvd09iaiAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdHJldHVybiBbIHJvd09iai5pZHggXTtcblx0XHRcdFx0fVxuXHRcblx0XHRcdFx0Ly8gbmVlZCB0byBmYWxsIHRocm91Z2ggdG8galF1ZXJ5IGluIGNhc2UgdGhlcmUgaXMgRE9NIGlkIHRoYXRcblx0XHRcdFx0Ly8gbWF0Y2hlc1xuXHRcdFx0fVxuXHRcdFx0XG5cdFx0XHQvLyBHZXQgbm9kZXMgaW4gdGhlIG9yZGVyIGZyb20gdGhlIGByb3dzYCBhcnJheSB3aXRoIG51bGwgdmFsdWVzIHJlbW92ZWRcblx0XHRcdHZhciBub2RlcyA9IF9yZW1vdmVFbXB0eShcblx0XHRcdFx0X3BsdWNrX29yZGVyKCBzZXR0aW5ncy5hb0RhdGEsIHJvd3MsICduVHInIClcblx0XHRcdCk7XG5cdFxuXHRcdFx0Ly8gU2VsZWN0b3IgLSBqUXVlcnkgc2VsZWN0b3Igc3RyaW5nLCBhcnJheSBvZiBub2RlcyBvciBqUXVlcnkgb2JqZWN0L1xuXHRcdFx0Ly8gQXMgalF1ZXJ5J3MgLmZpbHRlcigpIGFsbG93cyBqUXVlcnkgb2JqZWN0cyB0byBiZSBwYXNzZWQgaW4gZmlsdGVyLFxuXHRcdFx0Ly8gaXQgYWxzbyBhbGxvd3MgYXJyYXlzLCBzbyB0aGlzIHdpbGwgY29wZSB3aXRoIGFsbCB0aHJlZSBvcHRpb25zXG5cdFx0XHRyZXR1cm4gJChub2Rlcylcblx0XHRcdFx0LmZpbHRlciggc2VsIClcblx0XHRcdFx0Lm1hcCggZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdHJldHVybiB0aGlzLl9EVF9Sb3dJbmRleDtcblx0XHRcdFx0fSApXG5cdFx0XHRcdC50b0FycmF5KCk7XG5cdFx0fTtcblx0XG5cdFx0cmV0dXJuIF9zZWxlY3Rvcl9ydW4oICdyb3cnLCBzZWxlY3RvciwgcnVuLCBzZXR0aW5ncywgb3B0cyApO1xuXHR9O1xuXHRcblx0XG5cdF9hcGlfcmVnaXN0ZXIoICdyb3dzKCknLCBmdW5jdGlvbiAoIHNlbGVjdG9yLCBvcHRzICkge1xuXHRcdC8vIGFyZ3VtZW50IHNoaWZ0aW5nXG5cdFx0aWYgKCBzZWxlY3RvciA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0c2VsZWN0b3IgPSAnJztcblx0XHR9XG5cdFx0ZWxzZSBpZiAoICQuaXNQbGFpbk9iamVjdCggc2VsZWN0b3IgKSApIHtcblx0XHRcdG9wdHMgPSBzZWxlY3Rvcjtcblx0XHRcdHNlbGVjdG9yID0gJyc7XG5cdFx0fVxuXHRcblx0XHRvcHRzID0gX3NlbGVjdG9yX29wdHMoIG9wdHMgKTtcblx0XG5cdFx0dmFyIGluc3QgPSB0aGlzLml0ZXJhdG9yKCAndGFibGUnLCBmdW5jdGlvbiAoIHNldHRpbmdzICkge1xuXHRcdFx0cmV0dXJuIF9fcm93X3NlbGVjdG9yKCBzZXR0aW5ncywgc2VsZWN0b3IsIG9wdHMgKTtcblx0XHR9LCAxICk7XG5cdFxuXHRcdC8vIFdhbnQgYXJndW1lbnQgc2hpZnRpbmcgaGVyZSBhbmQgaW4gX19yb3dfc2VsZWN0b3I/XG5cdFx0aW5zdC5zZWxlY3Rvci5yb3dzID0gc2VsZWN0b3I7XG5cdFx0aW5zdC5zZWxlY3Rvci5vcHRzID0gb3B0cztcblx0XG5cdFx0cmV0dXJuIGluc3Q7XG5cdH0gKTtcblx0XG5cdF9hcGlfcmVnaXN0ZXIoICdyb3dzKCkubm9kZXMoKScsIGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ3JvdycsIGZ1bmN0aW9uICggc2V0dGluZ3MsIHJvdyApIHtcblx0XHRcdHJldHVybiBzZXR0aW5ncy5hb0RhdGFbIHJvdyBdLm5UciB8fCB1bmRlZmluZWQ7XG5cdFx0fSwgMSApO1xuXHR9ICk7XG5cdFxuXHRfYXBpX3JlZ2lzdGVyKCAncm93cygpLmRhdGEoKScsIGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggdHJ1ZSwgJ3Jvd3MnLCBmdW5jdGlvbiAoIHNldHRpbmdzLCByb3dzICkge1xuXHRcdFx0cmV0dXJuIF9wbHVja19vcmRlciggc2V0dGluZ3MuYW9EYXRhLCByb3dzLCAnX2FEYXRhJyApO1xuXHRcdH0sIDEgKTtcblx0fSApO1xuXHRcblx0X2FwaV9yZWdpc3RlclBsdXJhbCggJ3Jvd3MoKS5jYWNoZSgpJywgJ3JvdygpLmNhY2hlKCknLCBmdW5jdGlvbiAoIHR5cGUgKSB7XG5cdFx0cmV0dXJuIHRoaXMuaXRlcmF0b3IoICdyb3cnLCBmdW5jdGlvbiAoIHNldHRpbmdzLCByb3cgKSB7XG5cdFx0XHR2YXIgciA9IHNldHRpbmdzLmFvRGF0YVsgcm93IF07XG5cdFx0XHRyZXR1cm4gdHlwZSA9PT0gJ3NlYXJjaCcgPyByLl9hRmlsdGVyRGF0YSA6IHIuX2FTb3J0RGF0YTtcblx0XHR9LCAxICk7XG5cdH0gKTtcblx0XG5cdF9hcGlfcmVnaXN0ZXJQbHVyYWwoICdyb3dzKCkuaW52YWxpZGF0ZSgpJywgJ3JvdygpLmludmFsaWRhdGUoKScsIGZ1bmN0aW9uICggc3JjICkge1xuXHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAncm93JywgZnVuY3Rpb24gKCBzZXR0aW5ncywgcm93ICkge1xuXHRcdFx0X2ZuSW52YWxpZGF0ZSggc2V0dGluZ3MsIHJvdywgc3JjICk7XG5cdFx0fSApO1xuXHR9ICk7XG5cdFxuXHRfYXBpX3JlZ2lzdGVyUGx1cmFsKCAncm93cygpLmluZGV4ZXMoKScsICdyb3coKS5pbmRleCgpJywgZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAncm93JywgZnVuY3Rpb24gKCBzZXR0aW5ncywgcm93ICkge1xuXHRcdFx0cmV0dXJuIHJvdztcblx0XHR9LCAxICk7XG5cdH0gKTtcblx0XG5cdF9hcGlfcmVnaXN0ZXJQbHVyYWwoICdyb3dzKCkuaWRzKCknLCAncm93KCkuaWQoKScsIGZ1bmN0aW9uICggaGFzaCApIHtcblx0XHR2YXIgYSA9IFtdO1xuXHRcdHZhciBjb250ZXh0ID0gdGhpcy5jb250ZXh0O1xuXHRcblx0XHQvLyBgaXRlcmF0b3JgIHdpbGwgZHJvcCB1bmRlZmluZWQgdmFsdWVzLCBidXQgaW4gdGhpcyBjYXNlIHdlIHdhbnQgdGhlbVxuXHRcdGZvciAoIHZhciBpPTAsIGllbj1jb250ZXh0Lmxlbmd0aCA7IGk8aWVuIDsgaSsrICkge1xuXHRcdFx0Zm9yICggdmFyIGo9MCwgamVuPXRoaXNbaV0ubGVuZ3RoIDsgajxqZW4gOyBqKysgKSB7XG5cdFx0XHRcdHZhciBpZCA9IGNvbnRleHRbaV0ucm93SWRGbiggY29udGV4dFtpXS5hb0RhdGFbIHRoaXNbaV1bal0gXS5fYURhdGEgKTtcblx0XHRcdFx0YS5wdXNoKCAoaGFzaCA9PT0gdHJ1ZSA/ICcjJyA6ICcnICkrIGlkICk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcblx0XHRyZXR1cm4gbmV3IF9BcGkoIGNvbnRleHQsIGEgKTtcblx0fSApO1xuXHRcblx0X2FwaV9yZWdpc3RlclBsdXJhbCggJ3Jvd3MoKS5yZW1vdmUoKScsICdyb3coKS5yZW1vdmUoKScsIGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cdFxuXHRcdHRoaXMuaXRlcmF0b3IoICdyb3cnLCBmdW5jdGlvbiAoIHNldHRpbmdzLCByb3csIHRoYXRJZHggKSB7XG5cdFx0XHR2YXIgZGF0YSA9IHNldHRpbmdzLmFvRGF0YTtcblx0XHRcdHZhciByb3dEYXRhID0gZGF0YVsgcm93IF07XG5cdFx0XHR2YXIgaSwgaWVuLCBqLCBqZW47XG5cdFx0XHR2YXIgbG9vcFJvdywgbG9vcENlbGxzO1xuXHRcblx0XHRcdGRhdGEuc3BsaWNlKCByb3csIDEgKTtcblx0XG5cdFx0XHQvLyBVcGRhdGUgdGhlIGNhY2hlZCBpbmRleGVzXG5cdFx0XHRmb3IgKCBpPTAsIGllbj1kYXRhLmxlbmd0aCA7IGk8aWVuIDsgaSsrICkge1xuXHRcdFx0XHRsb29wUm93ID0gZGF0YVtpXTtcblx0XHRcdFx0bG9vcENlbGxzID0gbG9vcFJvdy5hbkNlbGxzO1xuXHRcblx0XHRcdFx0Ly8gUm93c1xuXHRcdFx0XHRpZiAoIGxvb3BSb3cublRyICE9PSBudWxsICkge1xuXHRcdFx0XHRcdGxvb3BSb3cublRyLl9EVF9Sb3dJbmRleCA9IGk7XG5cdFx0XHRcdH1cblx0XG5cdFx0XHRcdC8vIENlbGxzXG5cdFx0XHRcdGlmICggbG9vcENlbGxzICE9PSBudWxsICkge1xuXHRcdFx0XHRcdGZvciAoIGo9MCwgamVuPWxvb3BDZWxscy5sZW5ndGggOyBqPGplbiA7IGorKyApIHtcblx0XHRcdFx0XHRcdGxvb3BDZWxsc1tqXS5fRFRfQ2VsbEluZGV4LnJvdyA9IGk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFxuXHRcdFx0Ly8gRGVsZXRlIGZyb20gdGhlIGRpc3BsYXkgYXJyYXlzXG5cdFx0XHRfZm5EZWxldGVJbmRleCggc2V0dGluZ3MuYWlEaXNwbGF5TWFzdGVyLCByb3cgKTtcblx0XHRcdF9mbkRlbGV0ZUluZGV4KCBzZXR0aW5ncy5haURpc3BsYXksIHJvdyApO1xuXHRcdFx0X2ZuRGVsZXRlSW5kZXgoIHRoYXRbIHRoYXRJZHggXSwgcm93LCBmYWxzZSApOyAvLyBtYWludGFpbiBsb2NhbCBpbmRleGVzXG5cdFxuXHRcdFx0Ly8gRm9yIHNlcnZlci1zaWRlIHByb2Nlc3NpbmcgdGFibGVzIC0gc3VidHJhY3QgdGhlIGRlbGV0ZWQgcm93IGZyb20gdGhlIGNvdW50XG5cdFx0XHRpZiAoIHNldHRpbmdzLl9pUmVjb3Jkc0Rpc3BsYXkgPiAwICkge1xuXHRcdFx0XHRzZXR0aW5ncy5faVJlY29yZHNEaXNwbGF5LS07XG5cdFx0XHR9XG5cdFxuXHRcdFx0Ly8gQ2hlY2sgZm9yIGFuICdvdmVyZmxvdycgdGhleSBjYXNlIGZvciBkaXNwbGF5aW5nIHRoZSB0YWJsZVxuXHRcdFx0X2ZuTGVuZ3RoT3ZlcmZsb3coIHNldHRpbmdzICk7XG5cdFxuXHRcdFx0Ly8gUmVtb3ZlIHRoZSByb3cncyBJRCByZWZlcmVuY2UgaWYgdGhlcmUgaXMgb25lXG5cdFx0XHR2YXIgaWQgPSBzZXR0aW5ncy5yb3dJZEZuKCByb3dEYXRhLl9hRGF0YSApO1xuXHRcdFx0aWYgKCBpZCAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRkZWxldGUgc2V0dGluZ3MuYUlkc1sgaWQgXTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdFxuXHRcdHRoaXMuaXRlcmF0b3IoICd0YWJsZScsIGZ1bmN0aW9uICggc2V0dGluZ3MgKSB7XG5cdFx0XHRmb3IgKCB2YXIgaT0wLCBpZW49c2V0dGluZ3MuYW9EYXRhLmxlbmd0aCA7IGk8aWVuIDsgaSsrICkge1xuXHRcdFx0XHRzZXR0aW5ncy5hb0RhdGFbaV0uaWR4ID0gaTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdFxuXHRcdHJldHVybiB0aGlzO1xuXHR9ICk7XG5cdFxuXHRcblx0X2FwaV9yZWdpc3RlciggJ3Jvd3MuYWRkKCknLCBmdW5jdGlvbiAoIHJvd3MgKSB7XG5cdFx0dmFyIG5ld1Jvd3MgPSB0aGlzLml0ZXJhdG9yKCAndGFibGUnLCBmdW5jdGlvbiAoIHNldHRpbmdzICkge1xuXHRcdFx0XHR2YXIgcm93LCBpLCBpZW47XG5cdFx0XHRcdHZhciBvdXQgPSBbXTtcblx0XG5cdFx0XHRcdGZvciAoIGk9MCwgaWVuPXJvd3MubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRcdFx0cm93ID0gcm93c1tpXTtcblx0XG5cdFx0XHRcdFx0aWYgKCByb3cubm9kZU5hbWUgJiYgcm93Lm5vZGVOYW1lLnRvVXBwZXJDYXNlKCkgPT09ICdUUicgKSB7XG5cdFx0XHRcdFx0XHRvdXQucHVzaCggX2ZuQWRkVHIoIHNldHRpbmdzLCByb3cgKVswXSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRcdG91dC5wdXNoKCBfZm5BZGREYXRhKCBzZXR0aW5ncywgcm93ICkgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XG5cdFx0XHRcdHJldHVybiBvdXQ7XG5cdFx0XHR9LCAxICk7XG5cdFxuXHRcdC8vIFJldHVybiBhbiBBcGkucm93cygpIGV4dGVuZGVkIGluc3RhbmNlLCBzbyByb3dzKCkubm9kZXMoKSBldGMgY2FuIGJlIHVzZWRcblx0XHR2YXIgbW9kUm93cyA9IHRoaXMucm93cyggLTEgKTtcblx0XHRtb2RSb3dzLnBvcCgpO1xuXHRcdCQubWVyZ2UoIG1vZFJvd3MsIG5ld1Jvd3MgKTtcblx0XG5cdFx0cmV0dXJuIG1vZFJvd3M7XG5cdH0gKTtcblx0XG5cdFxuXHRcblx0XG5cdFxuXHQvKipcblx0ICpcblx0ICovXG5cdF9hcGlfcmVnaXN0ZXIoICdyb3coKScsIGZ1bmN0aW9uICggc2VsZWN0b3IsIG9wdHMgKSB7XG5cdFx0cmV0dXJuIF9zZWxlY3Rvcl9maXJzdCggdGhpcy5yb3dzKCBzZWxlY3Rvciwgb3B0cyApICk7XG5cdH0gKTtcblx0XG5cdFxuXHRfYXBpX3JlZ2lzdGVyKCAncm93KCkuZGF0YSgpJywgZnVuY3Rpb24gKCBkYXRhICkge1xuXHRcdHZhciBjdHggPSB0aGlzLmNvbnRleHQ7XG5cdFxuXHRcdGlmICggZGF0YSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0Ly8gR2V0XG5cdFx0XHRyZXR1cm4gY3R4Lmxlbmd0aCAmJiB0aGlzLmxlbmd0aCA/XG5cdFx0XHRcdGN0eFswXS5hb0RhdGFbIHRoaXNbMF0gXS5fYURhdGEgOlxuXHRcdFx0XHR1bmRlZmluZWQ7XG5cdFx0fVxuXHRcblx0XHQvLyBTZXRcblx0XHR2YXIgcm93ID0gY3R4WzBdLmFvRGF0YVsgdGhpc1swXSBdO1xuXHRcdHJvdy5fYURhdGEgPSBkYXRhO1xuXHRcblx0XHQvLyBJZiB0aGUgRE9NIGhhcyBhbiBpZCwgYW5kIHRoZSBkYXRhIHNvdXJjZSBpcyBhbiBhcnJheVxuXHRcdGlmICggQXJyYXkuaXNBcnJheSggZGF0YSApICYmIHJvdy5uVHIgJiYgcm93Lm5Uci5pZCApIHtcblx0XHRcdF9mblNldE9iamVjdERhdGFGbiggY3R4WzBdLnJvd0lkICkoIGRhdGEsIHJvdy5uVHIuaWQgKTtcblx0XHR9XG5cdFxuXHRcdC8vIEF1dG9tYXRpY2FsbHkgaW52YWxpZGF0ZVxuXHRcdF9mbkludmFsaWRhdGUoIGN0eFswXSwgdGhpc1swXSwgJ2RhdGEnICk7XG5cdFxuXHRcdHJldHVybiB0aGlzO1xuXHR9ICk7XG5cdFxuXHRcblx0X2FwaV9yZWdpc3RlciggJ3JvdygpLm5vZGUoKScsIGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgY3R4ID0gdGhpcy5jb250ZXh0O1xuXHRcblx0XHRyZXR1cm4gY3R4Lmxlbmd0aCAmJiB0aGlzLmxlbmd0aCA/XG5cdFx0XHRjdHhbMF0uYW9EYXRhWyB0aGlzWzBdIF0ublRyIHx8IG51bGwgOlxuXHRcdFx0bnVsbDtcblx0fSApO1xuXHRcblx0XG5cdF9hcGlfcmVnaXN0ZXIoICdyb3cuYWRkKCknLCBmdW5jdGlvbiAoIHJvdyApIHtcblx0XHQvLyBBbGxvdyBhIGpRdWVyeSBvYmplY3QgdG8gYmUgcGFzc2VkIGluIC0gb25seSBhIHNpbmdsZSByb3cgaXMgYWRkZWQgZnJvbVxuXHRcdC8vIGl0IHRob3VnaCAtIHRoZSBmaXJzdCBlbGVtZW50IGluIHRoZSBzZXRcblx0XHRpZiAoIHJvdyBpbnN0YW5jZW9mICQgJiYgcm93Lmxlbmd0aCApIHtcblx0XHRcdHJvdyA9IHJvd1swXTtcblx0XHR9XG5cdFxuXHRcdHZhciByb3dzID0gdGhpcy5pdGVyYXRvciggJ3RhYmxlJywgZnVuY3Rpb24gKCBzZXR0aW5ncyApIHtcblx0XHRcdGlmICggcm93Lm5vZGVOYW1lICYmIHJvdy5ub2RlTmFtZS50b1VwcGVyQ2FzZSgpID09PSAnVFInICkge1xuXHRcdFx0XHRyZXR1cm4gX2ZuQWRkVHIoIHNldHRpbmdzLCByb3cgKVswXTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBfZm5BZGREYXRhKCBzZXR0aW5ncywgcm93ICk7XG5cdFx0fSApO1xuXHRcblx0XHQvLyBSZXR1cm4gYW4gQXBpLnJvd3MoKSBleHRlbmRlZCBpbnN0YW5jZSwgd2l0aCB0aGUgbmV3bHkgYWRkZWQgcm93IHNlbGVjdGVkXG5cdFx0cmV0dXJuIHRoaXMucm93KCByb3dzWzBdICk7XG5cdH0gKTtcblx0XG5cdFxuXHQkKGRvY3VtZW50KS5vbigncGx1Z2luLWluaXQuZHQnLCBmdW5jdGlvbiAoZSwgY29udGV4dCkge1xuXHRcdHZhciBhcGkgPSBuZXcgX0FwaSggY29udGV4dCApO1xuXHRcdGFwaS5vbiggJ3N0YXRlU2F2ZVBhcmFtcycsIGZ1bmN0aW9uICggZSwgc2V0dGluZ3MsIGRhdGEgKSB7XG5cdFx0XHR2YXIgaW5kZXhlcyA9IGFwaS5yb3dzKCkuaXRlcmF0b3IoICdyb3cnLCBmdW5jdGlvbiAoIHNldHRpbmdzLCBpZHggKSB7XG5cdFx0XHRcdHJldHVybiBzZXR0aW5ncy5hb0RhdGFbaWR4XS5fZGV0YWlsc1Nob3cgPyBpZHggOiB1bmRlZmluZWQ7XG5cdFx0XHR9KTtcblx0XG5cdFx0XHRkYXRhLmNoaWxkUm93cyA9IGFwaS5yb3dzKCBpbmRleGVzICkuaWRzKCB0cnVlICkudG9BcnJheSgpO1xuXHRcdH0pXG5cdFxuXHRcdHZhciBsb2FkZWQgPSBhcGkuc3RhdGUubG9hZGVkKCk7XG5cdFxuXHRcdGlmICggbG9hZGVkICYmIGxvYWRlZC5jaGlsZFJvd3MgKSB7XG5cdFx0XHRhcGkucm93cyggbG9hZGVkLmNoaWxkUm93cyApLmV2ZXJ5KCBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdF9mbkNhbGxiYWNrRmlyZSggY29udGV4dCwgbnVsbCwgJ3JlcXVlc3RDaGlsZCcsIFsgdGhpcyBdIClcblx0XHRcdH0pXG5cdFx0fVxuXHR9KVxuXHRcblx0dmFyIF9fZGV0YWlsc19hZGQgPSBmdW5jdGlvbiAoIGN0eCwgcm93LCBkYXRhLCBrbGFzcyApXG5cdHtcblx0XHQvLyBDb252ZXJ0IHRvIGFycmF5IG9mIFRSIGVsZW1lbnRzXG5cdFx0dmFyIHJvd3MgPSBbXTtcblx0XHR2YXIgYWRkUm93ID0gZnVuY3Rpb24gKCByLCBrICkge1xuXHRcdFx0Ly8gUmVjdXJzaW9uIHRvIGFsbG93IGZvciBhcnJheXMgb2YgalF1ZXJ5IG9iamVjdHNcblx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggciApIHx8IHIgaW5zdGFuY2VvZiAkICkge1xuXHRcdFx0XHRmb3IgKCB2YXIgaT0wLCBpZW49ci5sZW5ndGggOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdFx0XHRhZGRSb3coIHJbaV0sIGsgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cdFxuXHRcdFx0Ly8gSWYgd2UgZ2V0IGEgVFIgZWxlbWVudCwgdGhlbiBqdXN0IGFkZCBpdCBkaXJlY3RseSAtIHVwIHRvIHRoZSBkZXZcblx0XHRcdC8vIHRvIGFkZCB0aGUgY29ycmVjdCBudW1iZXIgb2YgY29sdW1ucyBldGNcblx0XHRcdGlmICggci5ub2RlTmFtZSAmJiByLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09ICd0cicgKSB7XG5cdFx0XHRcdHJvd3MucHVzaCggciApO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSB7XG5cdFx0XHRcdC8vIE90aGVyd2lzZSBjcmVhdGUgYSByb3cgd2l0aCBhIHdyYXBwZXJcblx0XHRcdFx0dmFyIGNyZWF0ZWQgPSAkKCc8dHI+PHRkPjwvdGQ+PC90cj4nKS5hZGRDbGFzcyggayApO1xuXHRcdFx0XHQkKCd0ZCcsIGNyZWF0ZWQpXG5cdFx0XHRcdFx0LmFkZENsYXNzKCBrIClcblx0XHRcdFx0XHQuaHRtbCggciApXG5cdFx0XHRcdFx0WzBdLmNvbFNwYW4gPSBfZm5WaXNibGVDb2x1bW5zKCBjdHggKTtcblx0XG5cdFx0XHRcdHJvd3MucHVzaCggY3JlYXRlZFswXSApO1xuXHRcdFx0fVxuXHRcdH07XG5cdFxuXHRcdGFkZFJvdyggZGF0YSwga2xhc3MgKTtcblx0XG5cdFx0aWYgKCByb3cuX2RldGFpbHMgKSB7XG5cdFx0XHRyb3cuX2RldGFpbHMuZGV0YWNoKCk7XG5cdFx0fVxuXHRcblx0XHRyb3cuX2RldGFpbHMgPSAkKHJvd3MpO1xuXHRcblx0XHQvLyBJZiB0aGUgY2hpbGRyZW4gd2VyZSBhbHJlYWR5IHNob3duLCB0aGF0IHN0YXRlIHNob3VsZCBiZSByZXRhaW5lZFxuXHRcdGlmICggcm93Ll9kZXRhaWxzU2hvdyApIHtcblx0XHRcdHJvdy5fZGV0YWlscy5pbnNlcnRBZnRlciggcm93Lm5UciApO1xuXHRcdH1cblx0fTtcblx0XG5cdFxuXHR2YXIgX19kZXRhaWxzX3JlbW92ZSA9IGZ1bmN0aW9uICggYXBpLCBpZHggKVxuXHR7XG5cdFx0dmFyIGN0eCA9IGFwaS5jb250ZXh0O1xuXHRcblx0XHRpZiAoIGN0eC5sZW5ndGggKSB7XG5cdFx0XHR2YXIgcm93ID0gY3R4WzBdLmFvRGF0YVsgaWR4ICE9PSB1bmRlZmluZWQgPyBpZHggOiBhcGlbMF0gXTtcblx0XG5cdFx0XHRpZiAoIHJvdyAmJiByb3cuX2RldGFpbHMgKSB7XG5cdFx0XHRcdHJvdy5fZGV0YWlscy5yZW1vdmUoKTtcblx0XG5cdFx0XHRcdHJvdy5fZGV0YWlsc1Nob3cgPSB1bmRlZmluZWQ7XG5cdFx0XHRcdHJvdy5fZGV0YWlscyA9IHVuZGVmaW5lZDtcblx0XHRcdFx0JCggcm93Lm5UciApLnJlbW92ZUNsYXNzKCAnZHQtaGFzQ2hpbGQnICk7XG5cdFx0XHRcdF9mblNhdmVTdGF0ZSggY3R4WzBdICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9O1xuXHRcblx0XG5cdHZhciBfX2RldGFpbHNfZGlzcGxheSA9IGZ1bmN0aW9uICggYXBpLCBzaG93ICkge1xuXHRcdHZhciBjdHggPSBhcGkuY29udGV4dDtcblx0XG5cdFx0aWYgKCBjdHgubGVuZ3RoICYmIGFwaS5sZW5ndGggKSB7XG5cdFx0XHR2YXIgcm93ID0gY3R4WzBdLmFvRGF0YVsgYXBpWzBdIF07XG5cdFxuXHRcdFx0aWYgKCByb3cuX2RldGFpbHMgKSB7XG5cdFx0XHRcdHJvdy5fZGV0YWlsc1Nob3cgPSBzaG93O1xuXHRcblx0XHRcdFx0aWYgKCBzaG93ICkge1xuXHRcdFx0XHRcdHJvdy5fZGV0YWlscy5pbnNlcnRBZnRlciggcm93Lm5UciApO1xuXHRcdFx0XHRcdCQoIHJvdy5uVHIgKS5hZGRDbGFzcyggJ2R0LWhhc0NoaWxkJyApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdHJvdy5fZGV0YWlscy5kZXRhY2goKTtcblx0XHRcdFx0XHQkKCByb3cublRyICkucmVtb3ZlQ2xhc3MoICdkdC1oYXNDaGlsZCcgKTtcblx0XHRcdFx0fVxuXHRcblx0XHRcdFx0X2ZuQ2FsbGJhY2tGaXJlKCBjdHhbMF0sIG51bGwsICdjaGlsZFJvdycsIFsgc2hvdywgYXBpLnJvdyggYXBpWzBdICkgXSApXG5cdFxuXHRcdFx0XHRfX2RldGFpbHNfZXZlbnRzKCBjdHhbMF0gKTtcblx0XHRcdFx0X2ZuU2F2ZVN0YXRlKCBjdHhbMF0gKTtcblx0XHRcdH1cblx0XHR9XG5cdH07XG5cdFxuXHRcblx0dmFyIF9fZGV0YWlsc19ldmVudHMgPSBmdW5jdGlvbiAoIHNldHRpbmdzIClcblx0e1xuXHRcdHZhciBhcGkgPSBuZXcgX0FwaSggc2V0dGluZ3MgKTtcblx0XHR2YXIgbmFtZXNwYWNlID0gJy5kdC5EVF9kZXRhaWxzJztcblx0XHR2YXIgZHJhd0V2ZW50ID0gJ2RyYXcnK25hbWVzcGFjZTtcblx0XHR2YXIgY29sdmlzRXZlbnQgPSAnY29sdW1uLXZpc2liaWxpdHknK25hbWVzcGFjZTtcblx0XHR2YXIgZGVzdHJveUV2ZW50ID0gJ2Rlc3Ryb3knK25hbWVzcGFjZTtcblx0XHR2YXIgZGF0YSA9IHNldHRpbmdzLmFvRGF0YTtcblx0XG5cdFx0YXBpLm9mZiggZHJhd0V2ZW50ICsnICcrIGNvbHZpc0V2ZW50ICsnICcrIGRlc3Ryb3lFdmVudCApO1xuXHRcblx0XHRpZiAoIF9wbHVjayggZGF0YSwgJ19kZXRhaWxzJyApLmxlbmd0aCA+IDAgKSB7XG5cdFx0XHQvLyBPbiBlYWNoIGRyYXcsIGluc2VydCB0aGUgcmVxdWlyZWQgZWxlbWVudHMgaW50byB0aGUgZG9jdW1lbnRcblx0XHRcdGFwaS5vbiggZHJhd0V2ZW50LCBmdW5jdGlvbiAoIGUsIGN0eCApIHtcblx0XHRcdFx0aWYgKCBzZXR0aW5ncyAhPT0gY3R4ICkge1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXHRcblx0XHRcdFx0YXBpLnJvd3MoIHtwYWdlOidjdXJyZW50J30gKS5lcSgwKS5lYWNoKCBmdW5jdGlvbiAoaWR4KSB7XG5cdFx0XHRcdFx0Ly8gSW50ZXJuYWwgZGF0YSBncmFiXG5cdFx0XHRcdFx0dmFyIHJvdyA9IGRhdGFbIGlkeCBdO1xuXHRcblx0XHRcdFx0XHRpZiAoIHJvdy5fZGV0YWlsc1Nob3cgKSB7XG5cdFx0XHRcdFx0XHRyb3cuX2RldGFpbHMuaW5zZXJ0QWZ0ZXIoIHJvdy5uVHIgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHRcdH0gKTtcblx0XG5cdFx0XHQvLyBDb2x1bW4gdmlzaWJpbGl0eSBjaGFuZ2UgLSB1cGRhdGUgdGhlIGNvbHNwYW5cblx0XHRcdGFwaS5vbiggY29sdmlzRXZlbnQsIGZ1bmN0aW9uICggZSwgY3R4LCBpZHgsIHZpcyApIHtcblx0XHRcdFx0aWYgKCBzZXR0aW5ncyAhPT0gY3R4ICkge1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXHRcblx0XHRcdFx0Ly8gVXBkYXRlIHRoZSBjb2xzcGFuIGZvciB0aGUgZGV0YWlscyByb3dzIChub3RlLCBvbmx5IGlmIGl0IGFscmVhZHkgaGFzXG5cdFx0XHRcdC8vIGEgY29sc3Bhbilcblx0XHRcdFx0dmFyIHJvdywgdmlzaWJsZSA9IF9mblZpc2JsZUNvbHVtbnMoIGN0eCApO1xuXHRcblx0XHRcdFx0Zm9yICggdmFyIGk9MCwgaWVuPWRhdGEubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRcdFx0cm93ID0gZGF0YVtpXTtcblx0XG5cdFx0XHRcdFx0aWYgKCByb3cuX2RldGFpbHMgKSB7XG5cdFx0XHRcdFx0XHRyb3cuX2RldGFpbHMuY2hpbGRyZW4oJ3RkW2NvbHNwYW5dJykuYXR0cignY29sc3BhbicsIHZpc2libGUgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0XG5cdFx0XHQvLyBUYWJsZSBkZXN0cm95ZWQgLSBudWtlIGFueSBjaGlsZCByb3dzXG5cdFx0XHRhcGkub24oIGRlc3Ryb3lFdmVudCwgZnVuY3Rpb24gKCBlLCBjdHggKSB7XG5cdFx0XHRcdGlmICggc2V0dGluZ3MgIT09IGN0eCApIHtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblx0XG5cdFx0XHRcdGZvciAoIHZhciBpPTAsIGllbj1kYXRhLmxlbmd0aCA7IGk8aWVuIDsgaSsrICkge1xuXHRcdFx0XHRcdGlmICggZGF0YVtpXS5fZGV0YWlscyApIHtcblx0XHRcdFx0XHRcdF9fZGV0YWlsc19yZW1vdmUoIGFwaSwgaSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcdH1cblx0fTtcblx0XG5cdC8vIFN0cmluZ3MgZm9yIHRoZSBtZXRob2QgbmFtZXMgdG8gaGVscCBtaW5pZmljYXRpb25cblx0dmFyIF9lbXAgPSAnJztcblx0dmFyIF9jaGlsZF9vYmogPSBfZW1wKydyb3coKS5jaGlsZCc7XG5cdHZhciBfY2hpbGRfbXRoID0gX2NoaWxkX29iaisnKCknO1xuXHRcblx0Ly8gZGF0YSBjYW4gYmU6XG5cdC8vICB0clxuXHQvLyAgc3RyaW5nXG5cdC8vICBqUXVlcnkgb3IgYXJyYXkgb2YgYW55IG9mIHRoZSBhYm92ZVxuXHRfYXBpX3JlZ2lzdGVyKCBfY2hpbGRfbXRoLCBmdW5jdGlvbiAoIGRhdGEsIGtsYXNzICkge1xuXHRcdHZhciBjdHggPSB0aGlzLmNvbnRleHQ7XG5cdFxuXHRcdGlmICggZGF0YSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0Ly8gZ2V0XG5cdFx0XHRyZXR1cm4gY3R4Lmxlbmd0aCAmJiB0aGlzLmxlbmd0aCA/XG5cdFx0XHRcdGN0eFswXS5hb0RhdGFbIHRoaXNbMF0gXS5fZGV0YWlscyA6XG5cdFx0XHRcdHVuZGVmaW5lZDtcblx0XHR9XG5cdFx0ZWxzZSBpZiAoIGRhdGEgPT09IHRydWUgKSB7XG5cdFx0XHQvLyBzaG93XG5cdFx0XHR0aGlzLmNoaWxkLnNob3coKTtcblx0XHR9XG5cdFx0ZWxzZSBpZiAoIGRhdGEgPT09IGZhbHNlICkge1xuXHRcdFx0Ly8gcmVtb3ZlXG5cdFx0XHRfX2RldGFpbHNfcmVtb3ZlKCB0aGlzICk7XG5cdFx0fVxuXHRcdGVsc2UgaWYgKCBjdHgubGVuZ3RoICYmIHRoaXMubGVuZ3RoICkge1xuXHRcdFx0Ly8gc2V0XG5cdFx0XHRfX2RldGFpbHNfYWRkKCBjdHhbMF0sIGN0eFswXS5hb0RhdGFbIHRoaXNbMF0gXSwgZGF0YSwga2xhc3MgKTtcblx0XHR9XG5cdFxuXHRcdHJldHVybiB0aGlzO1xuXHR9ICk7XG5cdFxuXHRcblx0X2FwaV9yZWdpc3RlciggW1xuXHRcdF9jaGlsZF9vYmorJy5zaG93KCknLFxuXHRcdF9jaGlsZF9tdGgrJy5zaG93KCknIC8vIG9ubHkgd2hlbiBgY2hpbGQoKWAgd2FzIGNhbGxlZCB3aXRoIHBhcmFtZXRlcnMgKHdpdGhvdXRcblx0XSwgZnVuY3Rpb24gKCBzaG93ICkgeyAgIC8vIGl0IHJldHVybnMgYW4gb2JqZWN0IGFuZCB0aGlzIG1ldGhvZCBpcyBub3QgZXhlY3V0ZWQpXG5cdFx0X19kZXRhaWxzX2Rpc3BsYXkoIHRoaXMsIHRydWUgKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fSApO1xuXHRcblx0XG5cdF9hcGlfcmVnaXN0ZXIoIFtcblx0XHRfY2hpbGRfb2JqKycuaGlkZSgpJyxcblx0XHRfY2hpbGRfbXRoKycuaGlkZSgpJyAvLyBvbmx5IHdoZW4gYGNoaWxkKClgIHdhcyBjYWxsZWQgd2l0aCBwYXJhbWV0ZXJzICh3aXRob3V0XG5cdF0sIGZ1bmN0aW9uICgpIHsgICAgICAgICAvLyBpdCByZXR1cm5zIGFuIG9iamVjdCBhbmQgdGhpcyBtZXRob2QgaXMgbm90IGV4ZWN1dGVkKVxuXHRcdF9fZGV0YWlsc19kaXNwbGF5KCB0aGlzLCBmYWxzZSApO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9ICk7XG5cdFxuXHRcblx0X2FwaV9yZWdpc3RlciggW1xuXHRcdF9jaGlsZF9vYmorJy5yZW1vdmUoKScsXG5cdFx0X2NoaWxkX210aCsnLnJlbW92ZSgpJyAvLyBvbmx5IHdoZW4gYGNoaWxkKClgIHdhcyBjYWxsZWQgd2l0aCBwYXJhbWV0ZXJzICh3aXRob3V0XG5cdF0sIGZ1bmN0aW9uICgpIHsgICAgICAgICAgIC8vIGl0IHJldHVybnMgYW4gb2JqZWN0IGFuZCB0aGlzIG1ldGhvZCBpcyBub3QgZXhlY3V0ZWQpXG5cdFx0X19kZXRhaWxzX3JlbW92ZSggdGhpcyApO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9ICk7XG5cdFxuXHRcblx0X2FwaV9yZWdpc3RlciggX2NoaWxkX29iaisnLmlzU2hvd24oKScsIGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgY3R4ID0gdGhpcy5jb250ZXh0O1xuXHRcblx0XHRpZiAoIGN0eC5sZW5ndGggJiYgdGhpcy5sZW5ndGggKSB7XG5cdFx0XHQvLyBfZGV0YWlsc1Nob3duIGFzIGZhbHNlIG9yIHVuZGVmaW5lZCB3aWxsIGZhbGwgdGhyb3VnaCB0byByZXR1cm4gZmFsc2Vcblx0XHRcdHJldHVybiBjdHhbMF0uYW9EYXRhWyB0aGlzWzBdIF0uX2RldGFpbHNTaG93IHx8IGZhbHNlO1xuXHRcdH1cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH0gKTtcblx0XG5cdFxuXHRcblx0LyogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqICogKiAqXG5cdCAqIENvbHVtbnNcblx0ICpcblx0ICoge2ludGVnZXJ9ICAgICAgICAgICAtIGNvbHVtbiBpbmRleCAoPj0wIGNvdW50IGZyb20gbGVmdCwgPDAgY291bnQgZnJvbSByaWdodClcblx0ICogXCJ7aW50ZWdlcn06dmlzSWR4XCIgIC0gdmlzaWJsZSBjb2x1bW4gaW5kZXggKGkuZS4gdHJhbnNsYXRlIHRvIGNvbHVtbiBpbmRleCkgICg+PTAgY291bnQgZnJvbSBsZWZ0LCA8MCBjb3VudCBmcm9tIHJpZ2h0KVxuXHQgKiBcIntpbnRlZ2VyfTp2aXNpYmxlXCIgLSBhbGlhcyBmb3Ige2ludGVnZXJ9OnZpc0lkeCAgKD49MCBjb3VudCBmcm9tIGxlZnQsIDwwIGNvdW50IGZyb20gcmlnaHQpXG5cdCAqIFwie3N0cmluZ306bmFtZVwiICAgICAtIGNvbHVtbiBuYW1lXG5cdCAqIFwie3N0cmluZ31cIiAgICAgICAgICAtIGpRdWVyeSBzZWxlY3RvciBvbiBjb2x1bW4gaGVhZGVyIG5vZGVzXG5cdCAqXG5cdCAqL1xuXHRcblx0Ly8gY2FuIGJlIGFuIGFycmF5IG9mIHRoZXNlIGl0ZW1zLCBjb21tYSBzZXBhcmF0ZWQgbGlzdCwgb3IgYW4gYXJyYXkgb2YgY29tbWFcblx0Ly8gc2VwYXJhdGVkIGxpc3RzXG5cdFxuXHR2YXIgX19yZV9jb2x1bW5fc2VsZWN0b3IgPSAvXihbXjpdKyk6KG5hbWV8dmlzSWR4fHZpc2libGUpJC87XG5cdFxuXHRcblx0Ly8gcjEgYW5kIHIyIGFyZSByZWR1bmRhbnQgLSBidXQgaXQgbWVhbnMgdGhhdCB0aGUgcGFyYW1ldGVycyBtYXRjaCBmb3IgdGhlXG5cdC8vIGl0ZXJhdG9yIGNhbGxiYWNrIGluIGNvbHVtbnMoKS5kYXRhKClcblx0dmFyIF9fY29sdW1uRGF0YSA9IGZ1bmN0aW9uICggc2V0dGluZ3MsIGNvbHVtbiwgcjEsIHIyLCByb3dzICkge1xuXHRcdHZhciBhID0gW107XG5cdFx0Zm9yICggdmFyIHJvdz0wLCBpZW49cm93cy5sZW5ndGggOyByb3c8aWVuIDsgcm93KysgKSB7XG5cdFx0XHRhLnB1c2goIF9mbkdldENlbGxEYXRhKCBzZXR0aW5ncywgcm93c1tyb3ddLCBjb2x1bW4gKSApO1xuXHRcdH1cblx0XHRyZXR1cm4gYTtcblx0fTtcblx0XG5cdFxuXHR2YXIgX19jb2x1bW5fc2VsZWN0b3IgPSBmdW5jdGlvbiAoIHNldHRpbmdzLCBzZWxlY3Rvciwgb3B0cyApXG5cdHtcblx0XHR2YXJcblx0XHRcdGNvbHVtbnMgPSBzZXR0aW5ncy5hb0NvbHVtbnMsXG5cdFx0XHRuYW1lcyA9IF9wbHVjayggY29sdW1ucywgJ3NOYW1lJyApLFxuXHRcdFx0bm9kZXMgPSBfcGx1Y2soIGNvbHVtbnMsICduVGgnICk7XG5cdFxuXHRcdHZhciBydW4gPSBmdW5jdGlvbiAoIHMgKSB7XG5cdFx0XHR2YXIgc2VsSW50ID0gX2ludFZhbCggcyApO1xuXHRcblx0XHRcdC8vIFNlbGVjdG9yIC0gYWxsXG5cdFx0XHRpZiAoIHMgPT09ICcnICkge1xuXHRcdFx0XHRyZXR1cm4gX3JhbmdlKCBjb2x1bW5zLmxlbmd0aCApO1xuXHRcdFx0fVxuXHRcblx0XHRcdC8vIFNlbGVjdG9yIC0gaW5kZXhcblx0XHRcdGlmICggc2VsSW50ICE9PSBudWxsICkge1xuXHRcdFx0XHRyZXR1cm4gWyBzZWxJbnQgPj0gMCA/XG5cdFx0XHRcdFx0c2VsSW50IDogLy8gQ291bnQgZnJvbSBsZWZ0XG5cdFx0XHRcdFx0Y29sdW1ucy5sZW5ndGggKyBzZWxJbnQgLy8gQ291bnQgZnJvbSByaWdodCAoKyBiZWNhdXNlIGl0cyBhIG5lZ2F0aXZlIHZhbHVlKVxuXHRcdFx0XHRdO1xuXHRcdFx0fVxuXHRcblx0XHRcdC8vIFNlbGVjdG9yID0gZnVuY3Rpb25cblx0XHRcdGlmICggdHlwZW9mIHMgPT09ICdmdW5jdGlvbicgKSB7XG5cdFx0XHRcdHZhciByb3dzID0gX3NlbGVjdG9yX3Jvd19pbmRleGVzKCBzZXR0aW5ncywgb3B0cyApO1xuXHRcblx0XHRcdFx0cmV0dXJuICQubWFwKCBjb2x1bW5zLCBmdW5jdGlvbiAoY29sLCBpZHgpIHtcblx0XHRcdFx0XHRyZXR1cm4gcyhcblx0XHRcdFx0XHRcdFx0aWR4LFxuXHRcdFx0XHRcdFx0XHRfX2NvbHVtbkRhdGEoIHNldHRpbmdzLCBpZHgsIDAsIDAsIHJvd3MgKSxcblx0XHRcdFx0XHRcdFx0bm9kZXNbIGlkeCBdXG5cdFx0XHRcdFx0XHQpID8gaWR4IDogbnVsbDtcblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXHRcblx0XHRcdC8vIGpRdWVyeSBvciBzdHJpbmcgc2VsZWN0b3Jcblx0XHRcdHZhciBtYXRjaCA9IHR5cGVvZiBzID09PSAnc3RyaW5nJyA/XG5cdFx0XHRcdHMubWF0Y2goIF9fcmVfY29sdW1uX3NlbGVjdG9yICkgOlxuXHRcdFx0XHQnJztcblx0XG5cdFx0XHRpZiAoIG1hdGNoICkge1xuXHRcdFx0XHRzd2l0Y2goIG1hdGNoWzJdICkge1xuXHRcdFx0XHRcdGNhc2UgJ3Zpc0lkeCc6XG5cdFx0XHRcdFx0Y2FzZSAndmlzaWJsZSc6XG5cdFx0XHRcdFx0XHR2YXIgaWR4ID0gcGFyc2VJbnQoIG1hdGNoWzFdLCAxMCApO1xuXHRcdFx0XHRcdFx0Ly8gVmlzaWJsZSBpbmRleCBnaXZlbiwgY29udmVydCB0byBjb2x1bW4gaW5kZXhcblx0XHRcdFx0XHRcdGlmICggaWR4IDwgMCApIHtcblx0XHRcdFx0XHRcdFx0Ly8gQ291bnRpbmcgZnJvbSB0aGUgcmlnaHRcblx0XHRcdFx0XHRcdFx0dmFyIHZpc0NvbHVtbnMgPSAkLm1hcCggY29sdW1ucywgZnVuY3Rpb24gKGNvbCxpKSB7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIGNvbC5iVmlzaWJsZSA/IGkgOiBudWxsO1xuXHRcdFx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdFx0XHRcdHJldHVybiBbIHZpc0NvbHVtbnNbIHZpc0NvbHVtbnMubGVuZ3RoICsgaWR4IF0gXTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdC8vIENvdW50aW5nIGZyb20gdGhlIGxlZnRcblx0XHRcdFx0XHRcdHJldHVybiBbIF9mblZpc2libGVUb0NvbHVtbkluZGV4KCBzZXR0aW5ncywgaWR4ICkgXTtcblx0XG5cdFx0XHRcdFx0Y2FzZSAnbmFtZSc6XG5cdFx0XHRcdFx0XHQvLyBtYXRjaCBieSBuYW1lLiBgbmFtZXNgIGlzIGNvbHVtbiBpbmRleCBjb21wbGV0ZSBhbmQgaW4gb3JkZXJcblx0XHRcdFx0XHRcdHJldHVybiAkLm1hcCggbmFtZXMsIGZ1bmN0aW9uIChuYW1lLCBpKSB7XG5cdFx0XHRcdFx0XHRcdHJldHVybiBuYW1lID09PSBtYXRjaFsxXSA/IGkgOiBudWxsO1xuXHRcdFx0XHRcdFx0fSApO1xuXHRcblx0XHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdFx0cmV0dXJuIFtdO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFxuXHRcdFx0Ly8gQ2VsbCBpbiB0aGUgdGFibGUgYm9keVxuXHRcdFx0aWYgKCBzLm5vZGVOYW1lICYmIHMuX0RUX0NlbGxJbmRleCApIHtcblx0XHRcdFx0cmV0dXJuIFsgcy5fRFRfQ2VsbEluZGV4LmNvbHVtbiBdO1xuXHRcdFx0fVxuXHRcblx0XHRcdC8vIGpRdWVyeSBzZWxlY3RvciBvbiB0aGUgVEggZWxlbWVudHMgZm9yIHRoZSBjb2x1bW5zXG5cdFx0XHR2YXIganFSZXN1bHQgPSAkKCBub2RlcyApXG5cdFx0XHRcdC5maWx0ZXIoIHMgKVxuXHRcdFx0XHQubWFwKCBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0cmV0dXJuICQuaW5BcnJheSggdGhpcywgbm9kZXMgKTsgLy8gYG5vZGVzYCBpcyBjb2x1bW4gaW5kZXggY29tcGxldGUgYW5kIGluIG9yZGVyXG5cdFx0XHRcdH0gKVxuXHRcdFx0XHQudG9BcnJheSgpO1xuXHRcblx0XHRcdGlmICgganFSZXN1bHQubGVuZ3RoIHx8ICEgcy5ub2RlTmFtZSApIHtcblx0XHRcdFx0cmV0dXJuIGpxUmVzdWx0O1xuXHRcdFx0fVxuXHRcblx0XHRcdC8vIE90aGVyd2lzZSBhIG5vZGUgd2hpY2ggbWlnaHQgaGF2ZSBhIGBkdC1jb2x1bW5gIGRhdGEgYXR0cmlidXRlLCBvciBiZVxuXHRcdFx0Ly8gYSBjaGlsZCBvciBzdWNoIGFuIGVsZW1lbnRcblx0XHRcdHZhciBob3N0ID0gJChzKS5jbG9zZXN0KCcqW2RhdGEtZHQtY29sdW1uXScpO1xuXHRcdFx0cmV0dXJuIGhvc3QubGVuZ3RoID9cblx0XHRcdFx0WyBob3N0LmRhdGEoJ2R0LWNvbHVtbicpIF0gOlxuXHRcdFx0XHRbXTtcblx0XHR9O1xuXHRcblx0XHRyZXR1cm4gX3NlbGVjdG9yX3J1biggJ2NvbHVtbicsIHNlbGVjdG9yLCBydW4sIHNldHRpbmdzLCBvcHRzICk7XG5cdH07XG5cdFxuXHRcblx0dmFyIF9fc2V0Q29sdW1uVmlzID0gZnVuY3Rpb24gKCBzZXR0aW5ncywgY29sdW1uLCB2aXMgKSB7XG5cdFx0dmFyXG5cdFx0XHRjb2xzID0gc2V0dGluZ3MuYW9Db2x1bW5zLFxuXHRcdFx0Y29sICA9IGNvbHNbIGNvbHVtbiBdLFxuXHRcdFx0ZGF0YSA9IHNldHRpbmdzLmFvRGF0YSxcblx0XHRcdHJvdywgY2VsbHMsIGksIGllbiwgdHI7XG5cdFxuXHRcdC8vIEdldFxuXHRcdGlmICggdmlzID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRyZXR1cm4gY29sLmJWaXNpYmxlO1xuXHRcdH1cblx0XG5cdFx0Ly8gU2V0XG5cdFx0Ly8gTm8gY2hhbmdlXG5cdFx0aWYgKCBjb2wuYlZpc2libGUgPT09IHZpcyApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFxuXHRcdGlmICggdmlzICkge1xuXHRcdFx0Ly8gSW5zZXJ0IGNvbHVtblxuXHRcdFx0Ly8gTmVlZCB0byBkZWNpZGUgaWYgd2Ugc2hvdWxkIHVzZSBhcHBlbmRDaGlsZCBvciBpbnNlcnRCZWZvcmVcblx0XHRcdHZhciBpbnNlcnRCZWZvcmUgPSAkLmluQXJyYXkoIHRydWUsIF9wbHVjayhjb2xzLCAnYlZpc2libGUnKSwgY29sdW1uKzEgKTtcblx0XG5cdFx0XHRmb3IgKCBpPTAsIGllbj1kYXRhLmxlbmd0aCA7IGk8aWVuIDsgaSsrICkge1xuXHRcdFx0XHR0ciA9IGRhdGFbaV0ublRyO1xuXHRcdFx0XHRjZWxscyA9IGRhdGFbaV0uYW5DZWxscztcblx0XG5cdFx0XHRcdGlmICggdHIgKSB7XG5cdFx0XHRcdFx0Ly8gaW5zZXJ0QmVmb3JlIGNhbiBhY3QgbGlrZSBhcHBlbmRDaGlsZCBpZiAybmQgYXJnIGlzIG51bGxcblx0XHRcdFx0XHR0ci5pbnNlcnRCZWZvcmUoIGNlbGxzWyBjb2x1bW4gXSwgY2VsbHNbIGluc2VydEJlZm9yZSBdIHx8IG51bGwgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XHRlbHNlIHtcblx0XHRcdC8vIFJlbW92ZSBjb2x1bW5cblx0XHRcdCQoIF9wbHVjayggc2V0dGluZ3MuYW9EYXRhLCAnYW5DZWxscycsIGNvbHVtbiApICkuZGV0YWNoKCk7XG5cdFx0fVxuXHRcblx0XHQvLyBDb21tb24gYWN0aW9uc1xuXHRcdGNvbC5iVmlzaWJsZSA9IHZpcztcblx0fTtcblx0XG5cdFxuXHRfYXBpX3JlZ2lzdGVyKCAnY29sdW1ucygpJywgZnVuY3Rpb24gKCBzZWxlY3Rvciwgb3B0cyApIHtcblx0XHQvLyBhcmd1bWVudCBzaGlmdGluZ1xuXHRcdGlmICggc2VsZWN0b3IgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHNlbGVjdG9yID0gJyc7XG5cdFx0fVxuXHRcdGVsc2UgaWYgKCAkLmlzUGxhaW5PYmplY3QoIHNlbGVjdG9yICkgKSB7XG5cdFx0XHRvcHRzID0gc2VsZWN0b3I7XG5cdFx0XHRzZWxlY3RvciA9ICcnO1xuXHRcdH1cblx0XG5cdFx0b3B0cyA9IF9zZWxlY3Rvcl9vcHRzKCBvcHRzICk7XG5cdFxuXHRcdHZhciBpbnN0ID0gdGhpcy5pdGVyYXRvciggJ3RhYmxlJywgZnVuY3Rpb24gKCBzZXR0aW5ncyApIHtcblx0XHRcdHJldHVybiBfX2NvbHVtbl9zZWxlY3Rvciggc2V0dGluZ3MsIHNlbGVjdG9yLCBvcHRzICk7XG5cdFx0fSwgMSApO1xuXHRcblx0XHQvLyBXYW50IGFyZ3VtZW50IHNoaWZ0aW5nIGhlcmUgYW5kIGluIF9yb3dfc2VsZWN0b3I/XG5cdFx0aW5zdC5zZWxlY3Rvci5jb2xzID0gc2VsZWN0b3I7XG5cdFx0aW5zdC5zZWxlY3Rvci5vcHRzID0gb3B0cztcblx0XG5cdFx0cmV0dXJuIGluc3Q7XG5cdH0gKTtcblx0XG5cdF9hcGlfcmVnaXN0ZXJQbHVyYWwoICdjb2x1bW5zKCkuaGVhZGVyKCknLCAnY29sdW1uKCkuaGVhZGVyKCknLCBmdW5jdGlvbiAoIHNlbGVjdG9yLCBvcHRzICkge1xuXHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAnY29sdW1uJywgZnVuY3Rpb24gKCBzZXR0aW5ncywgY29sdW1uICkge1xuXHRcdFx0cmV0dXJuIHNldHRpbmdzLmFvQ29sdW1uc1tjb2x1bW5dLm5UaDtcblx0XHR9LCAxICk7XG5cdH0gKTtcblx0XG5cdF9hcGlfcmVnaXN0ZXJQbHVyYWwoICdjb2x1bW5zKCkuZm9vdGVyKCknLCAnY29sdW1uKCkuZm9vdGVyKCknLCBmdW5jdGlvbiAoIHNlbGVjdG9yLCBvcHRzICkge1xuXHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAnY29sdW1uJywgZnVuY3Rpb24gKCBzZXR0aW5ncywgY29sdW1uICkge1xuXHRcdFx0cmV0dXJuIHNldHRpbmdzLmFvQ29sdW1uc1tjb2x1bW5dLm5UZjtcblx0XHR9LCAxICk7XG5cdH0gKTtcblx0XG5cdF9hcGlfcmVnaXN0ZXJQbHVyYWwoICdjb2x1bW5zKCkuZGF0YSgpJywgJ2NvbHVtbigpLmRhdGEoKScsIGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ2NvbHVtbi1yb3dzJywgX19jb2x1bW5EYXRhLCAxICk7XG5cdH0gKTtcblx0XG5cdF9hcGlfcmVnaXN0ZXJQbHVyYWwoICdjb2x1bW5zKCkuZGF0YVNyYygpJywgJ2NvbHVtbigpLmRhdGFTcmMoKScsIGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ2NvbHVtbicsIGZ1bmN0aW9uICggc2V0dGluZ3MsIGNvbHVtbiApIHtcblx0XHRcdHJldHVybiBzZXR0aW5ncy5hb0NvbHVtbnNbY29sdW1uXS5tRGF0YTtcblx0XHR9LCAxICk7XG5cdH0gKTtcblx0XG5cdF9hcGlfcmVnaXN0ZXJQbHVyYWwoICdjb2x1bW5zKCkuY2FjaGUoKScsICdjb2x1bW4oKS5jYWNoZSgpJywgZnVuY3Rpb24gKCB0eXBlICkge1xuXHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAnY29sdW1uLXJvd3MnLCBmdW5jdGlvbiAoIHNldHRpbmdzLCBjb2x1bW4sIGksIGosIHJvd3MgKSB7XG5cdFx0XHRyZXR1cm4gX3BsdWNrX29yZGVyKCBzZXR0aW5ncy5hb0RhdGEsIHJvd3MsXG5cdFx0XHRcdHR5cGUgPT09ICdzZWFyY2gnID8gJ19hRmlsdGVyRGF0YScgOiAnX2FTb3J0RGF0YScsIGNvbHVtblxuXHRcdFx0KTtcblx0XHR9LCAxICk7XG5cdH0gKTtcblx0XG5cdF9hcGlfcmVnaXN0ZXJQbHVyYWwoICdjb2x1bW5zKCkubm9kZXMoKScsICdjb2x1bW4oKS5ub2RlcygpJywgZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAnY29sdW1uLXJvd3MnLCBmdW5jdGlvbiAoIHNldHRpbmdzLCBjb2x1bW4sIGksIGosIHJvd3MgKSB7XG5cdFx0XHRyZXR1cm4gX3BsdWNrX29yZGVyKCBzZXR0aW5ncy5hb0RhdGEsIHJvd3MsICdhbkNlbGxzJywgY29sdW1uICkgO1xuXHRcdH0sIDEgKTtcblx0fSApO1xuXHRcblx0X2FwaV9yZWdpc3RlclBsdXJhbCggJ2NvbHVtbnMoKS52aXNpYmxlKCknLCAnY29sdW1uKCkudmlzaWJsZSgpJywgZnVuY3Rpb24gKCB2aXMsIGNhbGMgKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXHRcdHZhciByZXQgPSB0aGlzLml0ZXJhdG9yKCAnY29sdW1uJywgZnVuY3Rpb24gKCBzZXR0aW5ncywgY29sdW1uICkge1xuXHRcdFx0aWYgKCB2aXMgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0cmV0dXJuIHNldHRpbmdzLmFvQ29sdW1uc1sgY29sdW1uIF0uYlZpc2libGU7XG5cdFx0XHR9IC8vIGVsc2Vcblx0XHRcdF9fc2V0Q29sdW1uVmlzKCBzZXR0aW5ncywgY29sdW1uLCB2aXMgKTtcblx0XHR9ICk7XG5cdFxuXHRcdC8vIEdyb3VwIHRoZSBjb2x1bW4gdmlzaWJpbGl0eSBjaGFuZ2VzXG5cdFx0aWYgKCB2aXMgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHRoaXMuaXRlcmF0b3IoICd0YWJsZScsIGZ1bmN0aW9uICggc2V0dGluZ3MgKSB7XG5cdFx0XHRcdC8vIFJlZHJhdyB0aGUgaGVhZGVyIGFmdGVyIGNoYW5nZXNcblx0XHRcdFx0X2ZuRHJhd0hlYWQoIHNldHRpbmdzLCBzZXR0aW5ncy5hb0hlYWRlciApO1xuXHRcdFx0XHRfZm5EcmF3SGVhZCggc2V0dGluZ3MsIHNldHRpbmdzLmFvRm9vdGVyICk7XG5cdFx0XG5cdFx0XHRcdC8vIFVwZGF0ZSBjb2xzcGFuIGZvciBubyByZWNvcmRzIGRpc3BsYXkuIENoaWxkIHJvd3MgYW5kIGV4dGVuc2lvbnMgd2lsbCB1c2UgdGhlaXIgb3duXG5cdFx0XHRcdC8vIGxpc3RlbmVycyB0byBkbyB0aGlzIC0gb25seSBuZWVkIHRvIHVwZGF0ZSB0aGUgZW1wdHkgdGFibGUgaXRlbSBoZXJlXG5cdFx0XHRcdGlmICggISBzZXR0aW5ncy5haURpc3BsYXkubGVuZ3RoICkge1xuXHRcdFx0XHRcdCQoc2V0dGluZ3MublRCb2R5KS5maW5kKCd0ZFtjb2xzcGFuXScpLmF0dHIoJ2NvbHNwYW4nLCBfZm5WaXNibGVDb2x1bW5zKHNldHRpbmdzKSk7XG5cdFx0XHRcdH1cblx0XHRcblx0XHRcdFx0X2ZuU2F2ZVN0YXRlKCBzZXR0aW5ncyApO1xuXHRcblx0XHRcdFx0Ly8gU2Vjb25kIGxvb3Agb25jZSB0aGUgZmlyc3QgaXMgZG9uZSBmb3IgZXZlbnRzXG5cdFx0XHRcdHRoYXQuaXRlcmF0b3IoICdjb2x1bW4nLCBmdW5jdGlvbiAoIHNldHRpbmdzLCBjb2x1bW4gKSB7XG5cdFx0XHRcdFx0X2ZuQ2FsbGJhY2tGaXJlKCBzZXR0aW5ncywgbnVsbCwgJ2NvbHVtbi12aXNpYmlsaXR5JywgW3NldHRpbmdzLCBjb2x1bW4sIHZpcywgY2FsY10gKTtcblx0XHRcdFx0fSApO1xuXHRcblx0XHRcdFx0aWYgKCBjYWxjID09PSB1bmRlZmluZWQgfHwgY2FsYyApIHtcblx0XHRcdFx0XHR0aGF0LmNvbHVtbnMuYWRqdXN0KCk7XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdH1cblx0XG5cdFx0cmV0dXJuIHJldDtcblx0fSApO1xuXHRcblx0X2FwaV9yZWdpc3RlclBsdXJhbCggJ2NvbHVtbnMoKS5pbmRleGVzKCknLCAnY29sdW1uKCkuaW5kZXgoKScsIGZ1bmN0aW9uICggdHlwZSApIHtcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ2NvbHVtbicsIGZ1bmN0aW9uICggc2V0dGluZ3MsIGNvbHVtbiApIHtcblx0XHRcdHJldHVybiB0eXBlID09PSAndmlzaWJsZScgP1xuXHRcdFx0XHRfZm5Db2x1bW5JbmRleFRvVmlzaWJsZSggc2V0dGluZ3MsIGNvbHVtbiApIDpcblx0XHRcdFx0Y29sdW1uO1xuXHRcdH0sIDEgKTtcblx0fSApO1xuXHRcblx0X2FwaV9yZWdpc3RlciggJ2NvbHVtbnMuYWRqdXN0KCknLCBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuaXRlcmF0b3IoICd0YWJsZScsIGZ1bmN0aW9uICggc2V0dGluZ3MgKSB7XG5cdFx0XHRfZm5BZGp1c3RDb2x1bW5TaXppbmcoIHNldHRpbmdzICk7XG5cdFx0fSwgMSApO1xuXHR9ICk7XG5cdFxuXHRfYXBpX3JlZ2lzdGVyKCAnY29sdW1uLmluZGV4KCknLCBmdW5jdGlvbiAoIHR5cGUsIGlkeCApIHtcblx0XHRpZiAoIHRoaXMuY29udGV4dC5sZW5ndGggIT09IDAgKSB7XG5cdFx0XHR2YXIgY3R4ID0gdGhpcy5jb250ZXh0WzBdO1xuXHRcblx0XHRcdGlmICggdHlwZSA9PT0gJ2Zyb21WaXNpYmxlJyB8fCB0eXBlID09PSAndG9EYXRhJyApIHtcblx0XHRcdFx0cmV0dXJuIF9mblZpc2libGVUb0NvbHVtbkluZGV4KCBjdHgsIGlkeCApO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSBpZiAoIHR5cGUgPT09ICdmcm9tRGF0YScgfHwgdHlwZSA9PT0gJ3RvVmlzaWJsZScgKSB7XG5cdFx0XHRcdHJldHVybiBfZm5Db2x1bW5JbmRleFRvVmlzaWJsZSggY3R4LCBpZHggKTtcblx0XHRcdH1cblx0XHR9XG5cdH0gKTtcblx0XG5cdF9hcGlfcmVnaXN0ZXIoICdjb2x1bW4oKScsIGZ1bmN0aW9uICggc2VsZWN0b3IsIG9wdHMgKSB7XG5cdFx0cmV0dXJuIF9zZWxlY3Rvcl9maXJzdCggdGhpcy5jb2x1bW5zKCBzZWxlY3Rvciwgb3B0cyApICk7XG5cdH0gKTtcblx0XG5cdHZhciBfX2NlbGxfc2VsZWN0b3IgPSBmdW5jdGlvbiAoIHNldHRpbmdzLCBzZWxlY3Rvciwgb3B0cyApXG5cdHtcblx0XHR2YXIgZGF0YSA9IHNldHRpbmdzLmFvRGF0YTtcblx0XHR2YXIgcm93cyA9IF9zZWxlY3Rvcl9yb3dfaW5kZXhlcyggc2V0dGluZ3MsIG9wdHMgKTtcblx0XHR2YXIgY2VsbHMgPSBfcmVtb3ZlRW1wdHkoIF9wbHVja19vcmRlciggZGF0YSwgcm93cywgJ2FuQ2VsbHMnICkgKTtcblx0XHR2YXIgYWxsQ2VsbHMgPSAkKF9mbGF0dGVuKCBbXSwgY2VsbHMgKSk7XG5cdFx0dmFyIHJvdztcblx0XHR2YXIgY29sdW1ucyA9IHNldHRpbmdzLmFvQ29sdW1ucy5sZW5ndGg7XG5cdFx0dmFyIGEsIGksIGllbiwgaiwgbywgaG9zdDtcblx0XG5cdFx0dmFyIHJ1biA9IGZ1bmN0aW9uICggcyApIHtcblx0XHRcdHZhciBmblNlbGVjdG9yID0gdHlwZW9mIHMgPT09ICdmdW5jdGlvbic7XG5cdFxuXHRcdFx0aWYgKCBzID09PSBudWxsIHx8IHMgPT09IHVuZGVmaW5lZCB8fCBmblNlbGVjdG9yICkge1xuXHRcdFx0XHQvLyBBbGwgY2VsbHMgYW5kIGZ1bmN0aW9uIHNlbGVjdG9yc1xuXHRcdFx0XHRhID0gW107XG5cdFxuXHRcdFx0XHRmb3IgKCBpPTAsIGllbj1yb3dzLmxlbmd0aCA7IGk8aWVuIDsgaSsrICkge1xuXHRcdFx0XHRcdHJvdyA9IHJvd3NbaV07XG5cdFxuXHRcdFx0XHRcdGZvciAoIGo9MCA7IGo8Y29sdW1ucyA7IGorKyApIHtcblx0XHRcdFx0XHRcdG8gPSB7XG5cdFx0XHRcdFx0XHRcdHJvdzogcm93LFxuXHRcdFx0XHRcdFx0XHRjb2x1bW46IGpcblx0XHRcdFx0XHRcdH07XG5cdFxuXHRcdFx0XHRcdFx0aWYgKCBmblNlbGVjdG9yICkge1xuXHRcdFx0XHRcdFx0XHQvLyBTZWxlY3RvciAtIGZ1bmN0aW9uXG5cdFx0XHRcdFx0XHRcdGhvc3QgPSBkYXRhWyByb3cgXTtcblx0XG5cdFx0XHRcdFx0XHRcdGlmICggcyggbywgX2ZuR2V0Q2VsbERhdGEoc2V0dGluZ3MsIHJvdywgaiksIGhvc3QuYW5DZWxscyA/IGhvc3QuYW5DZWxsc1tqXSA6IG51bGwgKSApIHtcblx0XHRcdFx0XHRcdFx0XHRhLnB1c2goIG8gKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRcdC8vIFNlbGVjdG9yIC0gYWxsXG5cdFx0XHRcdFx0XHRcdGEucHVzaCggbyApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcblx0XHRcdFx0cmV0dXJuIGE7XG5cdFx0XHR9XG5cdFx0XHRcblx0XHRcdC8vIFNlbGVjdG9yIC0gaW5kZXhcblx0XHRcdGlmICggJC5pc1BsYWluT2JqZWN0KCBzICkgKSB7XG5cdFx0XHRcdC8vIFZhbGlkIGNlbGwgaW5kZXggYW5kIGl0cyBpbiB0aGUgYXJyYXkgb2Ygc2VsZWN0YWJsZSByb3dzXG5cdFx0XHRcdHJldHVybiBzLmNvbHVtbiAhPT0gdW5kZWZpbmVkICYmIHMucm93ICE9PSB1bmRlZmluZWQgJiYgJC5pbkFycmF5KCBzLnJvdywgcm93cyApICE9PSAtMSA/XG5cdFx0XHRcdFx0W3NdIDpcblx0XHRcdFx0XHRbXTtcblx0XHRcdH1cblx0XG5cdFx0XHQvLyBTZWxlY3RvciAtIGpRdWVyeSBmaWx0ZXJlZCBjZWxsc1xuXHRcdFx0dmFyIGpxUmVzdWx0ID0gYWxsQ2VsbHNcblx0XHRcdFx0LmZpbHRlciggcyApXG5cdFx0XHRcdC5tYXAoIGZ1bmN0aW9uIChpLCBlbCkge1xuXHRcdFx0XHRcdHJldHVybiB7IC8vIHVzZSBhIG5ldyBvYmplY3QsIGluIGNhc2Ugc29tZW9uZSBjaGFuZ2VzIHRoZSB2YWx1ZXNcblx0XHRcdFx0XHRcdHJvdzogICAgZWwuX0RUX0NlbGxJbmRleC5yb3csXG5cdFx0XHRcdFx0XHRjb2x1bW46IGVsLl9EVF9DZWxsSW5kZXguY29sdW1uXG5cdCBcdFx0XHRcdH07XG5cdFx0XHRcdH0gKVxuXHRcdFx0XHQudG9BcnJheSgpO1xuXHRcblx0XHRcdGlmICgganFSZXN1bHQubGVuZ3RoIHx8ICEgcy5ub2RlTmFtZSApIHtcblx0XHRcdFx0cmV0dXJuIGpxUmVzdWx0O1xuXHRcdFx0fVxuXHRcblx0XHRcdC8vIE90aGVyd2lzZSB0aGUgc2VsZWN0b3IgaXMgYSBub2RlLCBhbmQgdGhlcmUgaXMgb25lIGxhc3Qgb3B0aW9uIC0gdGhlXG5cdFx0XHQvLyBlbGVtZW50IG1pZ2h0IGJlIGEgY2hpbGQgb2YgYW4gZWxlbWVudCB3aGljaCBoYXMgZHQtcm93IGFuZCBkdC1jb2x1bW5cblx0XHRcdC8vIGRhdGEgYXR0cmlidXRlc1xuXHRcdFx0aG9zdCA9ICQocykuY2xvc2VzdCgnKltkYXRhLWR0LXJvd10nKTtcblx0XHRcdHJldHVybiBob3N0Lmxlbmd0aCA/XG5cdFx0XHRcdFsge1xuXHRcdFx0XHRcdHJvdzogaG9zdC5kYXRhKCdkdC1yb3cnKSxcblx0XHRcdFx0XHRjb2x1bW46IGhvc3QuZGF0YSgnZHQtY29sdW1uJylcblx0XHRcdFx0fSBdIDpcblx0XHRcdFx0W107XG5cdFx0fTtcblx0XG5cdFx0cmV0dXJuIF9zZWxlY3Rvcl9ydW4oICdjZWxsJywgc2VsZWN0b3IsIHJ1biwgc2V0dGluZ3MsIG9wdHMgKTtcblx0fTtcblx0XG5cdFxuXHRcblx0XG5cdF9hcGlfcmVnaXN0ZXIoICdjZWxscygpJywgZnVuY3Rpb24gKCByb3dTZWxlY3RvciwgY29sdW1uU2VsZWN0b3IsIG9wdHMgKSB7XG5cdFx0Ly8gQXJndW1lbnQgc2hpZnRpbmdcblx0XHRpZiAoICQuaXNQbGFpbk9iamVjdCggcm93U2VsZWN0b3IgKSApIHtcblx0XHRcdC8vIEluZGV4ZXNcblx0XHRcdGlmICggcm93U2VsZWN0b3Iucm93ID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdC8vIFNlbGVjdG9yIG9wdGlvbnMgaW4gZmlyc3QgcGFyYW1ldGVyXG5cdFx0XHRcdG9wdHMgPSByb3dTZWxlY3Rvcjtcblx0XHRcdFx0cm93U2VsZWN0b3IgPSBudWxsO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSB7XG5cdFx0XHRcdC8vIENlbGwgaW5kZXggb2JqZWN0cyBpbiBmaXJzdCBwYXJhbWV0ZXJcblx0XHRcdFx0b3B0cyA9IGNvbHVtblNlbGVjdG9yO1xuXHRcdFx0XHRjb2x1bW5TZWxlY3RvciA9IG51bGw7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGlmICggJC5pc1BsYWluT2JqZWN0KCBjb2x1bW5TZWxlY3RvciApICkge1xuXHRcdFx0b3B0cyA9IGNvbHVtblNlbGVjdG9yO1xuXHRcdFx0Y29sdW1uU2VsZWN0b3IgPSBudWxsO1xuXHRcdH1cblx0XG5cdFx0Ly8gQ2VsbCBzZWxlY3RvclxuXHRcdGlmICggY29sdW1uU2VsZWN0b3IgPT09IG51bGwgfHwgY29sdW1uU2VsZWN0b3IgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAndGFibGUnLCBmdW5jdGlvbiAoIHNldHRpbmdzICkge1xuXHRcdFx0XHRyZXR1cm4gX19jZWxsX3NlbGVjdG9yKCBzZXR0aW5ncywgcm93U2VsZWN0b3IsIF9zZWxlY3Rvcl9vcHRzKCBvcHRzICkgKTtcblx0XHRcdH0gKTtcblx0XHR9XG5cdFxuXHRcdC8vIFRoZSBkZWZhdWx0IGJ1aWx0IGluIG9wdGlvbnMgbmVlZCB0byBhcHBseSB0byByb3cgYW5kIGNvbHVtbnNcblx0XHR2YXIgaW50ZXJuYWxPcHRzID0gb3B0cyA/IHtcblx0XHRcdHBhZ2U6IG9wdHMucGFnZSxcblx0XHRcdG9yZGVyOiBvcHRzLm9yZGVyLFxuXHRcdFx0c2VhcmNoOiBvcHRzLnNlYXJjaFxuXHRcdH0gOiB7fTtcblx0XG5cdFx0Ly8gUm93ICsgY29sdW1uIHNlbGVjdG9yXG5cdFx0dmFyIGNvbHVtbnMgPSB0aGlzLmNvbHVtbnMoIGNvbHVtblNlbGVjdG9yLCBpbnRlcm5hbE9wdHMgKTtcblx0XHR2YXIgcm93cyA9IHRoaXMucm93cyggcm93U2VsZWN0b3IsIGludGVybmFsT3B0cyApO1xuXHRcdHZhciBpLCBpZW4sIGosIGplbjtcblx0XG5cdFx0dmFyIGNlbGxzTm9PcHRzID0gdGhpcy5pdGVyYXRvciggJ3RhYmxlJywgZnVuY3Rpb24gKCBzZXR0aW5ncywgaWR4ICkge1xuXHRcdFx0dmFyIGEgPSBbXTtcblx0XG5cdFx0XHRmb3IgKCBpPTAsIGllbj1yb3dzW2lkeF0ubGVuZ3RoIDsgaTxpZW4gOyBpKysgKSB7XG5cdFx0XHRcdGZvciAoIGo9MCwgamVuPWNvbHVtbnNbaWR4XS5sZW5ndGggOyBqPGplbiA7IGorKyApIHtcblx0XHRcdFx0XHRhLnB1c2goIHtcblx0XHRcdFx0XHRcdHJvdzogICAgcm93c1tpZHhdW2ldLFxuXHRcdFx0XHRcdFx0Y29sdW1uOiBjb2x1bW5zW2lkeF1bal1cblx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XG5cdFx0XHRyZXR1cm4gYTtcblx0XHR9LCAxICk7XG5cdFxuXHRcdC8vIFRoZXJlIGlzIGN1cnJlbnRseSBvbmx5IG9uZSBleHRlbnNpb24gd2hpY2ggdXNlcyBhIGNlbGwgc2VsZWN0b3IgZXh0ZW5zaW9uXG5cdFx0Ly8gSXQgaXMgYSBfbWFqb3JfIHBlcmZvcm1hbmNlIGRyYWcgdG8gcnVuIHRoaXMgaWYgaXQgaXNuJ3QgbmVlZGVkLCBzbyB0aGlzIGlzXG5cdFx0Ly8gYW4gZXh0ZW5zaW9uIHNwZWNpZmljIGNoZWNrIGF0IHRoZSBtb21lbnRcblx0XHR2YXIgY2VsbHMgPSBvcHRzICYmIG9wdHMuc2VsZWN0ZWQgP1xuXHRcdFx0dGhpcy5jZWxscyggY2VsbHNOb09wdHMsIG9wdHMgKSA6XG5cdFx0XHRjZWxsc05vT3B0cztcblx0XG5cdFx0JC5leHRlbmQoIGNlbGxzLnNlbGVjdG9yLCB7XG5cdFx0XHRjb2xzOiBjb2x1bW5TZWxlY3Rvcixcblx0XHRcdHJvd3M6IHJvd1NlbGVjdG9yLFxuXHRcdFx0b3B0czogb3B0c1xuXHRcdH0gKTtcblx0XG5cdFx0cmV0dXJuIGNlbGxzO1xuXHR9ICk7XG5cdFxuXHRcblx0X2FwaV9yZWdpc3RlclBsdXJhbCggJ2NlbGxzKCkubm9kZXMoKScsICdjZWxsKCkubm9kZSgpJywgZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAnY2VsbCcsIGZ1bmN0aW9uICggc2V0dGluZ3MsIHJvdywgY29sdW1uICkge1xuXHRcdFx0dmFyIGRhdGEgPSBzZXR0aW5ncy5hb0RhdGFbIHJvdyBdO1xuXHRcblx0XHRcdHJldHVybiBkYXRhICYmIGRhdGEuYW5DZWxscyA/XG5cdFx0XHRcdGRhdGEuYW5DZWxsc1sgY29sdW1uIF0gOlxuXHRcdFx0XHR1bmRlZmluZWQ7XG5cdFx0fSwgMSApO1xuXHR9ICk7XG5cdFxuXHRcblx0X2FwaV9yZWdpc3RlciggJ2NlbGxzKCkuZGF0YSgpJywgZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAnY2VsbCcsIGZ1bmN0aW9uICggc2V0dGluZ3MsIHJvdywgY29sdW1uICkge1xuXHRcdFx0cmV0dXJuIF9mbkdldENlbGxEYXRhKCBzZXR0aW5ncywgcm93LCBjb2x1bW4gKTtcblx0XHR9LCAxICk7XG5cdH0gKTtcblx0XG5cdFxuXHRfYXBpX3JlZ2lzdGVyUGx1cmFsKCAnY2VsbHMoKS5jYWNoZSgpJywgJ2NlbGwoKS5jYWNoZSgpJywgZnVuY3Rpb24gKCB0eXBlICkge1xuXHRcdHR5cGUgPSB0eXBlID09PSAnc2VhcmNoJyA/ICdfYUZpbHRlckRhdGEnIDogJ19hU29ydERhdGEnO1xuXHRcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ2NlbGwnLCBmdW5jdGlvbiAoIHNldHRpbmdzLCByb3csIGNvbHVtbiApIHtcblx0XHRcdHJldHVybiBzZXR0aW5ncy5hb0RhdGFbIHJvdyBdWyB0eXBlIF1bIGNvbHVtbiBdO1xuXHRcdH0sIDEgKTtcblx0fSApO1xuXHRcblx0XG5cdF9hcGlfcmVnaXN0ZXJQbHVyYWwoICdjZWxscygpLnJlbmRlcigpJywgJ2NlbGwoKS5yZW5kZXIoKScsIGZ1bmN0aW9uICggdHlwZSApIHtcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ2NlbGwnLCBmdW5jdGlvbiAoIHNldHRpbmdzLCByb3csIGNvbHVtbiApIHtcblx0XHRcdHJldHVybiBfZm5HZXRDZWxsRGF0YSggc2V0dGluZ3MsIHJvdywgY29sdW1uLCB0eXBlICk7XG5cdFx0fSwgMSApO1xuXHR9ICk7XG5cdFxuXHRcblx0X2FwaV9yZWdpc3RlclBsdXJhbCggJ2NlbGxzKCkuaW5kZXhlcygpJywgJ2NlbGwoKS5pbmRleCgpJywgZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAnY2VsbCcsIGZ1bmN0aW9uICggc2V0dGluZ3MsIHJvdywgY29sdW1uICkge1xuXHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0cm93OiByb3csXG5cdFx0XHRcdGNvbHVtbjogY29sdW1uLFxuXHRcdFx0XHRjb2x1bW5WaXNpYmxlOiBfZm5Db2x1bW5JbmRleFRvVmlzaWJsZSggc2V0dGluZ3MsIGNvbHVtbiApXG5cdFx0XHR9O1xuXHRcdH0sIDEgKTtcblx0fSApO1xuXHRcblx0XG5cdF9hcGlfcmVnaXN0ZXJQbHVyYWwoICdjZWxscygpLmludmFsaWRhdGUoKScsICdjZWxsKCkuaW52YWxpZGF0ZSgpJywgZnVuY3Rpb24gKCBzcmMgKSB7XG5cdFx0cmV0dXJuIHRoaXMuaXRlcmF0b3IoICdjZWxsJywgZnVuY3Rpb24gKCBzZXR0aW5ncywgcm93LCBjb2x1bW4gKSB7XG5cdFx0XHRfZm5JbnZhbGlkYXRlKCBzZXR0aW5ncywgcm93LCBzcmMsIGNvbHVtbiApO1xuXHRcdH0gKTtcblx0fSApO1xuXHRcblx0XG5cdFxuXHRfYXBpX3JlZ2lzdGVyKCAnY2VsbCgpJywgZnVuY3Rpb24gKCByb3dTZWxlY3RvciwgY29sdW1uU2VsZWN0b3IsIG9wdHMgKSB7XG5cdFx0cmV0dXJuIF9zZWxlY3Rvcl9maXJzdCggdGhpcy5jZWxscyggcm93U2VsZWN0b3IsIGNvbHVtblNlbGVjdG9yLCBvcHRzICkgKTtcblx0fSApO1xuXHRcblx0XG5cdF9hcGlfcmVnaXN0ZXIoICdjZWxsKCkuZGF0YSgpJywgZnVuY3Rpb24gKCBkYXRhICkge1xuXHRcdHZhciBjdHggPSB0aGlzLmNvbnRleHQ7XG5cdFx0dmFyIGNlbGwgPSB0aGlzWzBdO1xuXHRcblx0XHRpZiAoIGRhdGEgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdC8vIEdldFxuXHRcdFx0cmV0dXJuIGN0eC5sZW5ndGggJiYgY2VsbC5sZW5ndGggP1xuXHRcdFx0XHRfZm5HZXRDZWxsRGF0YSggY3R4WzBdLCBjZWxsWzBdLnJvdywgY2VsbFswXS5jb2x1bW4gKSA6XG5cdFx0XHRcdHVuZGVmaW5lZDtcblx0XHR9XG5cdFxuXHRcdC8vIFNldFxuXHRcdF9mblNldENlbGxEYXRhKCBjdHhbMF0sIGNlbGxbMF0ucm93LCBjZWxsWzBdLmNvbHVtbiwgZGF0YSApO1xuXHRcdF9mbkludmFsaWRhdGUoIGN0eFswXSwgY2VsbFswXS5yb3csICdkYXRhJywgY2VsbFswXS5jb2x1bW4gKTtcblx0XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0gKTtcblx0XG5cdFxuXHRcblx0LyoqXG5cdCAqIEdldCBjdXJyZW50IG9yZGVyaW5nIChzb3J0aW5nKSB0aGF0IGhhcyBiZWVuIGFwcGxpZWQgdG8gdGhlIHRhYmxlLlxuXHQgKlxuXHQgKiBAcmV0dXJucyB7YXJyYXl9IDJEIGFycmF5IGNvbnRhaW5pbmcgdGhlIHNvcnRpbmcgaW5mb3JtYXRpb24gZm9yIHRoZSBmaXJzdFxuXHQgKiAgIHRhYmxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQuIEVhY2ggZWxlbWVudCBpbiB0aGUgcGFyZW50IGFycmF5IHJlcHJlc2VudHNcblx0ICogICBhIGNvbHVtbiBiZWluZyBzb3J0ZWQgdXBvbiAoaS5lLiBtdWx0aS1zb3J0aW5nIHdpdGggdHdvIGNvbHVtbnMgd291bGQgaGF2ZVxuXHQgKiAgIDIgaW5uZXIgYXJyYXlzKS4gVGhlIGlubmVyIGFycmF5cyBtYXkgaGF2ZSAyIG9yIDMgZWxlbWVudHMuIFRoZSBmaXJzdCBpc1xuXHQgKiAgIHRoZSBjb2x1bW4gaW5kZXggdGhhdCB0aGUgc29ydGluZyBjb25kaXRpb24gYXBwbGllcyB0bywgdGhlIHNlY29uZCBpcyB0aGVcblx0ICogICBkaXJlY3Rpb24gb2YgdGhlIHNvcnQgKGBkZXNjYCBvciBgYXNjYCkgYW5kLCBvcHRpb25hbGx5LCB0aGUgdGhpcmQgaXMgdGhlXG5cdCAqICAgaW5kZXggb2YgdGhlIHNvcnRpbmcgb3JkZXIgZnJvbSB0aGUgYGNvbHVtbi5zb3J0aW5nYCBpbml0aWFsaXNhdGlvbiBhcnJheS5cblx0ICovLyoqXG5cdCAqIFNldCB0aGUgb3JkZXJpbmcgZm9yIHRoZSB0YWJsZS5cblx0ICpcblx0ICogQHBhcmFtIHtpbnRlZ2VyfSBvcmRlciBDb2x1bW4gaW5kZXggdG8gc29ydCB1cG9uLlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gZGlyZWN0aW9uIERpcmVjdGlvbiBvZiB0aGUgc29ydCB0byBiZSBhcHBsaWVkIChgYXNjYCBvciBgZGVzY2ApXG5cdCAqIEByZXR1cm5zIHtEYXRhVGFibGVzLkFwaX0gdGhpc1xuXHQgKi8vKipcblx0ICogU2V0IHRoZSBvcmRlcmluZyBmb3IgdGhlIHRhYmxlLlxuXHQgKlxuXHQgKiBAcGFyYW0ge2FycmF5fSBvcmRlciAxRCBhcnJheSBvZiBzb3J0aW5nIGluZm9ybWF0aW9uIHRvIGJlIGFwcGxpZWQuXG5cdCAqIEBwYXJhbSB7YXJyYXl9IFsuLi5dIE9wdGlvbmFsIGFkZGl0aW9uYWwgc29ydGluZyBjb25kaXRpb25zXG5cdCAqIEByZXR1cm5zIHtEYXRhVGFibGVzLkFwaX0gdGhpc1xuXHQgKi8vKipcblx0ICogU2V0IHRoZSBvcmRlcmluZyBmb3IgdGhlIHRhYmxlLlxuXHQgKlxuXHQgKiBAcGFyYW0ge2FycmF5fSBvcmRlciAyRCBhcnJheSBvZiBzb3J0aW5nIGluZm9ybWF0aW9uIHRvIGJlIGFwcGxpZWQuXG5cdCAqIEByZXR1cm5zIHtEYXRhVGFibGVzLkFwaX0gdGhpc1xuXHQgKi9cblx0X2FwaV9yZWdpc3RlciggJ29yZGVyKCknLCBmdW5jdGlvbiAoIG9yZGVyLCBkaXIgKSB7XG5cdFx0dmFyIGN0eCA9IHRoaXMuY29udGV4dDtcblx0XG5cdFx0aWYgKCBvcmRlciA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0Ly8gZ2V0XG5cdFx0XHRyZXR1cm4gY3R4Lmxlbmd0aCAhPT0gMCA/XG5cdFx0XHRcdGN0eFswXS5hYVNvcnRpbmcgOlxuXHRcdFx0XHR1bmRlZmluZWQ7XG5cdFx0fVxuXHRcblx0XHQvLyBzZXRcblx0XHRpZiAoIHR5cGVvZiBvcmRlciA9PT0gJ251bWJlcicgKSB7XG5cdFx0XHQvLyBTaW1wbGUgY29sdW1uIC8gZGlyZWN0aW9uIHBhc3NlZCBpblxuXHRcdFx0b3JkZXIgPSBbIFsgb3JkZXIsIGRpciBdIF07XG5cdFx0fVxuXHRcdGVsc2UgaWYgKCBvcmRlci5sZW5ndGggJiYgISBBcnJheS5pc0FycmF5KCBvcmRlclswXSApICkge1xuXHRcdFx0Ly8gQXJndW1lbnRzIHBhc3NlZCBpbiAobGlzdCBvZiAxRCBhcnJheXMpXG5cdFx0XHRvcmRlciA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKCBhcmd1bWVudHMgKTtcblx0XHR9XG5cdFx0Ly8gb3RoZXJ3aXNlIGEgMkQgYXJyYXkgd2FzIHBhc3NlZCBpblxuXHRcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ3RhYmxlJywgZnVuY3Rpb24gKCBzZXR0aW5ncyApIHtcblx0XHRcdHNldHRpbmdzLmFhU29ydGluZyA9IG9yZGVyLnNsaWNlKCk7XG5cdFx0fSApO1xuXHR9ICk7XG5cdFxuXHRcblx0LyoqXG5cdCAqIEF0dGFjaCBhIHNvcnQgbGlzdGVuZXIgdG8gYW4gZWxlbWVudCBmb3IgYSBnaXZlbiBjb2x1bW5cblx0ICpcblx0ICogQHBhcmFtIHtub2RlfGpRdWVyeXxzdHJpbmd9IG5vZGUgSWRlbnRpZmllciBmb3IgdGhlIGVsZW1lbnQocykgdG8gYXR0YWNoIHRoZVxuXHQgKiAgIGxpc3RlbmVyIHRvLiBUaGlzIGNhbiB0YWtlIHRoZSBmb3JtIG9mIGEgc2luZ2xlIERPTSBub2RlLCBhIGpRdWVyeVxuXHQgKiAgIGNvbGxlY3Rpb24gb2Ygbm9kZXMgb3IgYSBqUXVlcnkgc2VsZWN0b3Igd2hpY2ggd2lsbCBpZGVudGlmeSB0aGUgbm9kZShzKS5cblx0ICogQHBhcmFtIHtpbnRlZ2VyfSBjb2x1bW4gdGhlIGNvbHVtbiB0aGF0IGEgY2xpY2sgb24gdGhpcyBub2RlIHdpbGwgc29ydCBvblxuXHQgKiBAcGFyYW0ge2Z1bmN0aW9ufSBbY2FsbGJhY2tdIGNhbGxiYWNrIGZ1bmN0aW9uIHdoZW4gc29ydCBpcyBydW5cblx0ICogQHJldHVybnMge0RhdGFUYWJsZXMuQXBpfSB0aGlzXG5cdCAqL1xuXHRfYXBpX3JlZ2lzdGVyKCAnb3JkZXIubGlzdGVuZXIoKScsIGZ1bmN0aW9uICggbm9kZSwgY29sdW1uLCBjYWxsYmFjayApIHtcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ3RhYmxlJywgZnVuY3Rpb24gKCBzZXR0aW5ncyApIHtcblx0XHRcdF9mblNvcnRBdHRhY2hMaXN0ZW5lciggc2V0dGluZ3MsIG5vZGUsIGNvbHVtbiwgY2FsbGJhY2sgKTtcblx0XHR9ICk7XG5cdH0gKTtcblx0XG5cdFxuXHRfYXBpX3JlZ2lzdGVyKCAnb3JkZXIuZml4ZWQoKScsIGZ1bmN0aW9uICggc2V0ICkge1xuXHRcdGlmICggISBzZXQgKSB7XG5cdFx0XHR2YXIgY3R4ID0gdGhpcy5jb250ZXh0O1xuXHRcdFx0dmFyIGZpeGVkID0gY3R4Lmxlbmd0aCA/XG5cdFx0XHRcdGN0eFswXS5hYVNvcnRpbmdGaXhlZCA6XG5cdFx0XHRcdHVuZGVmaW5lZDtcblx0XG5cdFx0XHRyZXR1cm4gQXJyYXkuaXNBcnJheSggZml4ZWQgKSA/XG5cdFx0XHRcdHsgcHJlOiBmaXhlZCB9IDpcblx0XHRcdFx0Zml4ZWQ7XG5cdFx0fVxuXHRcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ3RhYmxlJywgZnVuY3Rpb24gKCBzZXR0aW5ncyApIHtcblx0XHRcdHNldHRpbmdzLmFhU29ydGluZ0ZpeGVkID0gJC5leHRlbmQoIHRydWUsIHt9LCBzZXQgKTtcblx0XHR9ICk7XG5cdH0gKTtcblx0XG5cdFxuXHQvLyBPcmRlciBieSB0aGUgc2VsZWN0ZWQgY29sdW1uKHMpXG5cdF9hcGlfcmVnaXN0ZXIoIFtcblx0XHQnY29sdW1ucygpLm9yZGVyKCknLFxuXHRcdCdjb2x1bW4oKS5vcmRlcigpJ1xuXHRdLCBmdW5jdGlvbiAoIGRpciApIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cdFxuXHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAndGFibGUnLCBmdW5jdGlvbiAoIHNldHRpbmdzLCBpICkge1xuXHRcdFx0dmFyIHNvcnQgPSBbXTtcblx0XG5cdFx0XHQkLmVhY2goIHRoYXRbaV0sIGZ1bmN0aW9uIChqLCBjb2wpIHtcblx0XHRcdFx0c29ydC5wdXNoKCBbIGNvbCwgZGlyIF0gKTtcblx0XHRcdH0gKTtcblx0XG5cdFx0XHRzZXR0aW5ncy5hYVNvcnRpbmcgPSBzb3J0O1xuXHRcdH0gKTtcblx0fSApO1xuXHRcblx0XG5cdFxuXHRfYXBpX3JlZ2lzdGVyKCAnc2VhcmNoKCknLCBmdW5jdGlvbiAoIGlucHV0LCByZWdleCwgc21hcnQsIGNhc2VJbnNlbiApIHtcblx0XHR2YXIgY3R4ID0gdGhpcy5jb250ZXh0O1xuXHRcblx0XHRpZiAoIGlucHV0ID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHQvLyBnZXRcblx0XHRcdHJldHVybiBjdHgubGVuZ3RoICE9PSAwID9cblx0XHRcdFx0Y3R4WzBdLm9QcmV2aW91c1NlYXJjaC5zU2VhcmNoIDpcblx0XHRcdFx0dW5kZWZpbmVkO1xuXHRcdH1cblx0XG5cdFx0Ly8gc2V0XG5cdFx0cmV0dXJuIHRoaXMuaXRlcmF0b3IoICd0YWJsZScsIGZ1bmN0aW9uICggc2V0dGluZ3MgKSB7XG5cdFx0XHRpZiAoICEgc2V0dGluZ3Mub0ZlYXR1cmVzLmJGaWx0ZXIgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblx0XG5cdFx0XHRfZm5GaWx0ZXJDb21wbGV0ZSggc2V0dGluZ3MsICQuZXh0ZW5kKCB7fSwgc2V0dGluZ3Mub1ByZXZpb3VzU2VhcmNoLCB7XG5cdFx0XHRcdFwic1NlYXJjaFwiOiBpbnB1dCtcIlwiLFxuXHRcdFx0XHRcImJSZWdleFwiOiAgcmVnZXggPT09IG51bGwgPyBmYWxzZSA6IHJlZ2V4LFxuXHRcdFx0XHRcImJTbWFydFwiOiAgc21hcnQgPT09IG51bGwgPyB0cnVlICA6IHNtYXJ0LFxuXHRcdFx0XHRcImJDYXNlSW5zZW5zaXRpdmVcIjogY2FzZUluc2VuID09PSBudWxsID8gdHJ1ZSA6IGNhc2VJbnNlblxuXHRcdFx0fSApLCAxICk7XG5cdFx0fSApO1xuXHR9ICk7XG5cdFxuXHRcblx0X2FwaV9yZWdpc3RlclBsdXJhbChcblx0XHQnY29sdW1ucygpLnNlYXJjaCgpJyxcblx0XHQnY29sdW1uKCkuc2VhcmNoKCknLFxuXHRcdGZ1bmN0aW9uICggaW5wdXQsIHJlZ2V4LCBzbWFydCwgY2FzZUluc2VuICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuaXRlcmF0b3IoICdjb2x1bW4nLCBmdW5jdGlvbiAoIHNldHRpbmdzLCBjb2x1bW4gKSB7XG5cdFx0XHRcdHZhciBwcmVTZWFyY2ggPSBzZXR0aW5ncy5hb1ByZVNlYXJjaENvbHM7XG5cdFxuXHRcdFx0XHRpZiAoIGlucHV0ID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0Ly8gZ2V0XG5cdFx0XHRcdFx0cmV0dXJuIHByZVNlYXJjaFsgY29sdW1uIF0uc1NlYXJjaDtcblx0XHRcdFx0fVxuXHRcblx0XHRcdFx0Ly8gc2V0XG5cdFx0XHRcdGlmICggISBzZXR0aW5ncy5vRmVhdHVyZXMuYkZpbHRlciApIHtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblx0XG5cdFx0XHRcdCQuZXh0ZW5kKCBwcmVTZWFyY2hbIGNvbHVtbiBdLCB7XG5cdFx0XHRcdFx0XCJzU2VhcmNoXCI6IGlucHV0K1wiXCIsXG5cdFx0XHRcdFx0XCJiUmVnZXhcIjogIHJlZ2V4ID09PSBudWxsID8gZmFsc2UgOiByZWdleCxcblx0XHRcdFx0XHRcImJTbWFydFwiOiAgc21hcnQgPT09IG51bGwgPyB0cnVlICA6IHNtYXJ0LFxuXHRcdFx0XHRcdFwiYkNhc2VJbnNlbnNpdGl2ZVwiOiBjYXNlSW5zZW4gPT09IG51bGwgPyB0cnVlIDogY2FzZUluc2VuXG5cdFx0XHRcdH0gKTtcblx0XG5cdFx0XHRcdF9mbkZpbHRlckNvbXBsZXRlKCBzZXR0aW5ncywgc2V0dGluZ3Mub1ByZXZpb3VzU2VhcmNoLCAxICk7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXHQpO1xuXHRcblx0Lypcblx0ICogU3RhdGUgQVBJIG1ldGhvZHNcblx0ICovXG5cdFxuXHRfYXBpX3JlZ2lzdGVyKCAnc3RhdGUoKScsIGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5jb250ZXh0Lmxlbmd0aCA/XG5cdFx0XHR0aGlzLmNvbnRleHRbMF0ub1NhdmVkU3RhdGUgOlxuXHRcdFx0bnVsbDtcblx0fSApO1xuXHRcblx0XG5cdF9hcGlfcmVnaXN0ZXIoICdzdGF0ZS5jbGVhcigpJywgZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAndGFibGUnLCBmdW5jdGlvbiAoIHNldHRpbmdzICkge1xuXHRcdFx0Ly8gU2F2ZSBhbiBlbXB0eSBvYmplY3Rcblx0XHRcdHNldHRpbmdzLmZuU3RhdGVTYXZlQ2FsbGJhY2suY2FsbCggc2V0dGluZ3Mub0luc3RhbmNlLCBzZXR0aW5ncywge30gKTtcblx0XHR9ICk7XG5cdH0gKTtcblx0XG5cdFxuXHRfYXBpX3JlZ2lzdGVyKCAnc3RhdGUubG9hZGVkKCknLCBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuY29udGV4dC5sZW5ndGggP1xuXHRcdFx0dGhpcy5jb250ZXh0WzBdLm9Mb2FkZWRTdGF0ZSA6XG5cdFx0XHRudWxsO1xuXHR9ICk7XG5cdFxuXHRcblx0X2FwaV9yZWdpc3RlciggJ3N0YXRlLnNhdmUoKScsIGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ3RhYmxlJywgZnVuY3Rpb24gKCBzZXR0aW5ncyApIHtcblx0XHRcdF9mblNhdmVTdGF0ZSggc2V0dGluZ3MgKTtcblx0XHR9ICk7XG5cdH0gKTtcblx0XG5cdFxuXHRcblx0LyoqXG5cdCAqIFByb3ZpZGUgYSBjb21tb24gbWV0aG9kIGZvciBwbHVnLWlucyB0byBjaGVjayB0aGUgdmVyc2lvbiBvZiBEYXRhVGFibGVzIGJlaW5nXG5cdCAqIHVzZWQsIGluIG9yZGVyIHRvIGVuc3VyZSBjb21wYXRpYmlsaXR5LlxuXHQgKlxuXHQgKiAgQHBhcmFtIHtzdHJpbmd9IHZlcnNpb24gVmVyc2lvbiBzdHJpbmcgdG8gY2hlY2sgZm9yLCBpbiB0aGUgZm9ybWF0IFwiWC5ZLlpcIi5cblx0ICogICAgTm90ZSB0aGF0IHRoZSBmb3JtYXRzIFwiWFwiIGFuZCBcIlguWVwiIGFyZSBhbHNvIGFjY2VwdGFibGUuXG5cdCAqICBAcmV0dXJucyB7Ym9vbGVhbn0gdHJ1ZSBpZiB0aGlzIHZlcnNpb24gb2YgRGF0YVRhYmxlcyBpcyBncmVhdGVyIG9yIGVxdWFsIHRvXG5cdCAqICAgIHRoZSByZXF1aXJlZCB2ZXJzaW9uLCBvciBmYWxzZSBpZiB0aGlzIHZlcnNpb24gb2YgRGF0YVRhbGVzIGlzIG5vdFxuXHQgKiAgICBzdWl0YWJsZVxuXHQgKiAgQHN0YXRpY1xuXHQgKiAgQGR0b3B0IEFQSS1TdGF0aWNcblx0ICpcblx0ICogIEBleGFtcGxlXG5cdCAqICAgIGFsZXJ0KCAkLmZuLmRhdGFUYWJsZS52ZXJzaW9uQ2hlY2soICcxLjkuMCcgKSApO1xuXHQgKi9cblx0RGF0YVRhYmxlLnZlcnNpb25DaGVjayA9IERhdGFUYWJsZS5mblZlcnNpb25DaGVjayA9IGZ1bmN0aW9uKCB2ZXJzaW9uIClcblx0e1xuXHRcdHZhciBhVGhpcyA9IERhdGFUYWJsZS52ZXJzaW9uLnNwbGl0KCcuJyk7XG5cdFx0dmFyIGFUaGF0ID0gdmVyc2lvbi5zcGxpdCgnLicpO1xuXHRcdHZhciBpVGhpcywgaVRoYXQ7XG5cdFxuXHRcdGZvciAoIHZhciBpPTAsIGlMZW49YVRoYXQubGVuZ3RoIDsgaTxpTGVuIDsgaSsrICkge1xuXHRcdFx0aVRoaXMgPSBwYXJzZUludCggYVRoaXNbaV0sIDEwICkgfHwgMDtcblx0XHRcdGlUaGF0ID0gcGFyc2VJbnQoIGFUaGF0W2ldLCAxMCApIHx8IDA7XG5cdFxuXHRcdFx0Ly8gUGFydHMgYXJlIHRoZSBzYW1lLCBrZWVwIGNvbXBhcmluZ1xuXHRcdFx0aWYgKGlUaGlzID09PSBpVGhhdCkge1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblx0XG5cdFx0XHQvLyBQYXJ0cyBhcmUgZGlmZmVyZW50LCByZXR1cm4gaW1tZWRpYXRlbHlcblx0XHRcdHJldHVybiBpVGhpcyA+IGlUaGF0O1xuXHRcdH1cblx0XG5cdFx0cmV0dXJuIHRydWU7XG5cdH07XG5cdFxuXHRcblx0LyoqXG5cdCAqIENoZWNrIGlmIGEgYDx0YWJsZT5gIG5vZGUgaXMgYSBEYXRhVGFibGUgdGFibGUgYWxyZWFkeSBvciBub3QuXG5cdCAqXG5cdCAqICBAcGFyYW0ge25vZGV8anF1ZXJ5fHN0cmluZ30gdGFibGUgVGFibGUgbm9kZSwgalF1ZXJ5IG9iamVjdCBvciBqUXVlcnlcblx0ICogICAgICBzZWxlY3RvciBmb3IgdGhlIHRhYmxlIHRvIHRlc3QuIE5vdGUgdGhhdCBpZiBtb3JlIHRoYW4gbW9yZSB0aGFuIG9uZVxuXHQgKiAgICAgIHRhYmxlIGlzIHBhc3NlZCBvbiwgb25seSB0aGUgZmlyc3Qgd2lsbCBiZSBjaGVja2VkXG5cdCAqICBAcmV0dXJucyB7Ym9vbGVhbn0gdHJ1ZSB0aGUgdGFibGUgZ2l2ZW4gaXMgYSBEYXRhVGFibGUsIG9yIGZhbHNlIG90aGVyd2lzZVxuXHQgKiAgQHN0YXRpY1xuXHQgKiAgQGR0b3B0IEFQSS1TdGF0aWNcblx0ICpcblx0ICogIEBleGFtcGxlXG5cdCAqICAgIGlmICggISAkLmZuLkRhdGFUYWJsZS5pc0RhdGFUYWJsZSggJyNleGFtcGxlJyApICkge1xuXHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCk7XG5cdCAqICAgIH1cblx0ICovXG5cdERhdGFUYWJsZS5pc0RhdGFUYWJsZSA9IERhdGFUYWJsZS5mbklzRGF0YVRhYmxlID0gZnVuY3Rpb24gKCB0YWJsZSApXG5cdHtcblx0XHR2YXIgdCA9ICQodGFibGUpLmdldCgwKTtcblx0XHR2YXIgaXMgPSBmYWxzZTtcblx0XG5cdFx0aWYgKCB0YWJsZSBpbnN0YW5jZW9mIERhdGFUYWJsZS5BcGkgKSB7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9XG5cdFxuXHRcdCQuZWFjaCggRGF0YVRhYmxlLnNldHRpbmdzLCBmdW5jdGlvbiAoaSwgbykge1xuXHRcdFx0dmFyIGhlYWQgPSBvLm5TY3JvbGxIZWFkID8gJCgndGFibGUnLCBvLm5TY3JvbGxIZWFkKVswXSA6IG51bGw7XG5cdFx0XHR2YXIgZm9vdCA9IG8ublNjcm9sbEZvb3QgPyAkKCd0YWJsZScsIG8ublNjcm9sbEZvb3QpWzBdIDogbnVsbDtcblx0XG5cdFx0XHRpZiAoIG8ublRhYmxlID09PSB0IHx8IGhlYWQgPT09IHQgfHwgZm9vdCA9PT0gdCApIHtcblx0XHRcdFx0aXMgPSB0cnVlO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0XG5cdFx0cmV0dXJuIGlzO1xuXHR9O1xuXHRcblx0XG5cdC8qKlxuXHQgKiBHZXQgYWxsIERhdGFUYWJsZSB0YWJsZXMgdGhhdCBoYXZlIGJlZW4gaW5pdGlhbGlzZWQgLSBvcHRpb25hbGx5IHlvdSBjYW5cblx0ICogc2VsZWN0IHRvIGdldCBvbmx5IGN1cnJlbnRseSB2aXNpYmxlIHRhYmxlcy5cblx0ICpcblx0ICogIEBwYXJhbSB7Ym9vbGVhbn0gW3Zpc2libGU9ZmFsc2VdIEZsYWcgdG8gaW5kaWNhdGUgaWYgeW91IHdhbnQgYWxsIChkZWZhdWx0KVxuXHQgKiAgICBvciB2aXNpYmxlIHRhYmxlcyBvbmx5LlxuXHQgKiAgQHJldHVybnMge2FycmF5fSBBcnJheSBvZiBgdGFibGVgIG5vZGVzIChub3QgRGF0YVRhYmxlIGluc3RhbmNlcykgd2hpY2ggYXJlXG5cdCAqICAgIERhdGFUYWJsZXNcblx0ICogIEBzdGF0aWNcblx0ICogIEBkdG9wdCBBUEktU3RhdGljXG5cdCAqXG5cdCAqICBAZXhhbXBsZVxuXHQgKiAgICAkLmVhY2goICQuZm4uZGF0YVRhYmxlLnRhYmxlcyh0cnVlKSwgZnVuY3Rpb24gKCkge1xuXHQgKiAgICAgICQodGFibGUpLkRhdGFUYWJsZSgpLmNvbHVtbnMuYWRqdXN0KCk7XG5cdCAqICAgIH0gKTtcblx0ICovXG5cdERhdGFUYWJsZS50YWJsZXMgPSBEYXRhVGFibGUuZm5UYWJsZXMgPSBmdW5jdGlvbiAoIHZpc2libGUgKVxuXHR7XG5cdFx0dmFyIGFwaSA9IGZhbHNlO1xuXHRcblx0XHRpZiAoICQuaXNQbGFpbk9iamVjdCggdmlzaWJsZSApICkge1xuXHRcdFx0YXBpID0gdmlzaWJsZS5hcGk7XG5cdFx0XHR2aXNpYmxlID0gdmlzaWJsZS52aXNpYmxlO1xuXHRcdH1cblx0XG5cdFx0dmFyIGEgPSAkLm1hcCggRGF0YVRhYmxlLnNldHRpbmdzLCBmdW5jdGlvbiAobykge1xuXHRcdFx0aWYgKCAhdmlzaWJsZSB8fCAodmlzaWJsZSAmJiAkKG8ublRhYmxlKS5pcygnOnZpc2libGUnKSkgKSB7XG5cdFx0XHRcdHJldHVybiBvLm5UYWJsZTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdFxuXHRcdHJldHVybiBhcGkgP1xuXHRcdFx0bmV3IF9BcGkoIGEgKSA6XG5cdFx0XHRhO1xuXHR9O1xuXHRcblx0XG5cdC8qKlxuXHQgKiBDb252ZXJ0IGZyb20gY2FtZWwgY2FzZSBwYXJhbWV0ZXJzIHRvIEh1bmdhcmlhbiBub3RhdGlvbi4gVGhpcyBpcyBtYWRlIHB1YmxpY1xuXHQgKiBmb3IgdGhlIGV4dGVuc2lvbnMgdG8gcHJvdmlkZSB0aGUgc2FtZSBhYmlsaXR5IGFzIERhdGFUYWJsZXMgY29yZSB0byBhY2NlcHRcblx0ICogZWl0aGVyIHRoZSAxLjkgc3R5bGUgSHVuZ2FyaWFuIG5vdGF0aW9uLCBvciB0aGUgMS4xMCsgc3R5bGUgY2FtZWxDYXNlXG5cdCAqIHBhcmFtZXRlcnMuXG5cdCAqXG5cdCAqICBAcGFyYW0ge29iamVjdH0gc3JjIFRoZSBtb2RlbCBvYmplY3Qgd2hpY2ggaG9sZHMgYWxsIHBhcmFtZXRlcnMgdGhhdCBjYW4gYmVcblx0ICogICAgbWFwcGVkLlxuXHQgKiAgQHBhcmFtIHtvYmplY3R9IHVzZXIgVGhlIG9iamVjdCB0byBjb252ZXJ0IGZyb20gY2FtZWwgY2FzZSB0byBIdW5nYXJpYW4uXG5cdCAqICBAcGFyYW0ge2Jvb2xlYW59IGZvcmNlIFdoZW4gc2V0IHRvIGB0cnVlYCwgcHJvcGVydGllcyB3aGljaCBhbHJlYWR5IGhhdmUgYVxuXHQgKiAgICBIdW5nYXJpYW4gdmFsdWUgaW4gdGhlIGB1c2VyYCBvYmplY3Qgd2lsbCBiZSBvdmVyd3JpdHRlbi4gT3RoZXJ3aXNlIHRoZXlcblx0ICogICAgd29uJ3QgYmUuXG5cdCAqL1xuXHREYXRhVGFibGUuY2FtZWxUb0h1bmdhcmlhbiA9IF9mbkNhbWVsVG9IdW5nYXJpYW47XG5cdFxuXHRcblx0XG5cdC8qKlxuXHQgKlxuXHQgKi9cblx0X2FwaV9yZWdpc3RlciggJyQoKScsIGZ1bmN0aW9uICggc2VsZWN0b3IsIG9wdHMgKSB7XG5cdFx0dmFyXG5cdFx0XHRyb3dzICAgPSB0aGlzLnJvd3MoIG9wdHMgKS5ub2RlcygpLCAvLyBHZXQgYWxsIHJvd3Ncblx0XHRcdGpxUm93cyA9ICQocm93cyk7XG5cdFxuXHRcdHJldHVybiAkKCBbXS5jb25jYXQoXG5cdFx0XHRqcVJvd3MuZmlsdGVyKCBzZWxlY3RvciApLnRvQXJyYXkoKSxcblx0XHRcdGpxUm93cy5maW5kKCBzZWxlY3RvciApLnRvQXJyYXkoKVxuXHRcdCkgKTtcblx0fSApO1xuXHRcblx0XG5cdC8vIGpRdWVyeSBmdW5jdGlvbnMgdG8gb3BlcmF0ZSBvbiB0aGUgdGFibGVzXG5cdCQuZWFjaCggWyAnb24nLCAnb25lJywgJ29mZicgXSwgZnVuY3Rpb24gKGksIGtleSkge1xuXHRcdF9hcGlfcmVnaXN0ZXIoIGtleSsnKCknLCBmdW5jdGlvbiAoIC8qIGV2ZW50LCBoYW5kbGVyICovICkge1xuXHRcdFx0dmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuXHRcblx0XHRcdC8vIEFkZCB0aGUgYGR0YCBuYW1lc3BhY2UgYXV0b21hdGljYWxseSBpZiBpdCBpc24ndCBhbHJlYWR5IHByZXNlbnRcblx0XHRcdGFyZ3NbMF0gPSAkLm1hcCggYXJnc1swXS5zcGxpdCggL1xccy8gKSwgZnVuY3Rpb24gKCBlICkge1xuXHRcdFx0XHRyZXR1cm4gISBlLm1hdGNoKC9cXC5kdFxcYi8pID9cblx0XHRcdFx0XHRlKycuZHQnIDpcblx0XHRcdFx0XHRlO1xuXHRcdFx0XHR9ICkuam9pbiggJyAnICk7XG5cdFxuXHRcdFx0dmFyIGluc3QgPSAkKCB0aGlzLnRhYmxlcygpLm5vZGVzKCkgKTtcblx0XHRcdGluc3Rba2V5XS5hcHBseSggaW5zdCwgYXJncyApO1xuXHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0fSApO1xuXHR9ICk7XG5cdFxuXHRcblx0X2FwaV9yZWdpc3RlciggJ2NsZWFyKCknLCBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuaXRlcmF0b3IoICd0YWJsZScsIGZ1bmN0aW9uICggc2V0dGluZ3MgKSB7XG5cdFx0XHRfZm5DbGVhclRhYmxlKCBzZXR0aW5ncyApO1xuXHRcdH0gKTtcblx0fSApO1xuXHRcblx0XG5cdF9hcGlfcmVnaXN0ZXIoICdzZXR0aW5ncygpJywgZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiBuZXcgX0FwaSggdGhpcy5jb250ZXh0LCB0aGlzLmNvbnRleHQgKTtcblx0fSApO1xuXHRcblx0XG5cdF9hcGlfcmVnaXN0ZXIoICdpbml0KCknLCBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGN0eCA9IHRoaXMuY29udGV4dDtcblx0XHRyZXR1cm4gY3R4Lmxlbmd0aCA/IGN0eFswXS5vSW5pdCA6IG51bGw7XG5cdH0gKTtcblx0XG5cdFxuXHRfYXBpX3JlZ2lzdGVyKCAnZGF0YSgpJywgZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLml0ZXJhdG9yKCAndGFibGUnLCBmdW5jdGlvbiAoIHNldHRpbmdzICkge1xuXHRcdFx0cmV0dXJuIF9wbHVjayggc2V0dGluZ3MuYW9EYXRhLCAnX2FEYXRhJyApO1xuXHRcdH0gKS5mbGF0dGVuKCk7XG5cdH0gKTtcblx0XG5cdFxuXHRfYXBpX3JlZ2lzdGVyKCAnZGVzdHJveSgpJywgZnVuY3Rpb24gKCByZW1vdmUgKSB7XG5cdFx0cmVtb3ZlID0gcmVtb3ZlIHx8IGZhbHNlO1xuXHRcblx0XHRyZXR1cm4gdGhpcy5pdGVyYXRvciggJ3RhYmxlJywgZnVuY3Rpb24gKCBzZXR0aW5ncyApIHtcblx0XHRcdHZhciBvcmlnICAgICAgPSBzZXR0aW5ncy5uVGFibGVXcmFwcGVyLnBhcmVudE5vZGU7XG5cdFx0XHR2YXIgY2xhc3NlcyAgID0gc2V0dGluZ3Mub0NsYXNzZXM7XG5cdFx0XHR2YXIgdGFibGUgICAgID0gc2V0dGluZ3MublRhYmxlO1xuXHRcdFx0dmFyIHRib2R5ICAgICA9IHNldHRpbmdzLm5UQm9keTtcblx0XHRcdHZhciB0aGVhZCAgICAgPSBzZXR0aW5ncy5uVEhlYWQ7XG5cdFx0XHR2YXIgdGZvb3QgICAgID0gc2V0dGluZ3MublRGb290O1xuXHRcdFx0dmFyIGpxVGFibGUgICA9ICQodGFibGUpO1xuXHRcdFx0dmFyIGpxVGJvZHkgICA9ICQodGJvZHkpO1xuXHRcdFx0dmFyIGpxV3JhcHBlciA9ICQoc2V0dGluZ3MublRhYmxlV3JhcHBlcik7XG5cdFx0XHR2YXIgcm93cyAgICAgID0gJC5tYXAoIHNldHRpbmdzLmFvRGF0YSwgZnVuY3Rpb24gKHIpIHsgcmV0dXJuIHIublRyOyB9ICk7XG5cdFx0XHR2YXIgaSwgaWVuO1xuXHRcblx0XHRcdC8vIEZsYWcgdG8gbm90ZSB0aGF0IHRoZSB0YWJsZSBpcyBjdXJyZW50bHkgYmVpbmcgZGVzdHJveWVkIC0gbm8gYWN0aW9uXG5cdFx0XHQvLyBzaG91bGQgYmUgdGFrZW5cblx0XHRcdHNldHRpbmdzLmJEZXN0cm95aW5nID0gdHJ1ZTtcblx0XG5cdFx0XHQvLyBGaXJlIG9mZiB0aGUgZGVzdHJveSBjYWxsYmFja3MgZm9yIHBsdWctaW5zIGV0Y1xuXHRcdFx0X2ZuQ2FsbGJhY2tGaXJlKCBzZXR0aW5ncywgXCJhb0Rlc3Ryb3lDYWxsYmFja1wiLCBcImRlc3Ryb3lcIiwgW3NldHRpbmdzXSApO1xuXHRcblx0XHRcdC8vIElmIG5vdCBiZWluZyByZW1vdmVkIGZyb20gdGhlIGRvY3VtZW50LCBtYWtlIGFsbCBjb2x1bW5zIHZpc2libGVcblx0XHRcdGlmICggISByZW1vdmUgKSB7XG5cdFx0XHRcdG5ldyBfQXBpKCBzZXR0aW5ncyApLmNvbHVtbnMoKS52aXNpYmxlKCB0cnVlICk7XG5cdFx0XHR9XG5cdFxuXHRcdFx0Ly8gQmxpdHogYWxsIGBEVGAgbmFtZXNwYWNlZCBldmVudHMgKHRoZXNlIGFyZSBpbnRlcm5hbCBldmVudHMsIHRoZVxuXHRcdFx0Ly8gbG93ZXJjYXNlLCBgZHRgIGV2ZW50cyBhcmUgdXNlciBzdWJzY3JpYmVkIGFuZCB0aGV5IGFyZSByZXNwb25zaWJsZVxuXHRcdFx0Ly8gZm9yIHJlbW92aW5nIHRoZW1cblx0XHRcdGpxV3JhcHBlci5vZmYoJy5EVCcpLmZpbmQoJzpub3QodGJvZHkgKiknKS5vZmYoJy5EVCcpO1xuXHRcdFx0JCh3aW5kb3cpLm9mZignLkRULScrc2V0dGluZ3Muc0luc3RhbmNlKTtcblx0XG5cdFx0XHQvLyBXaGVuIHNjcm9sbGluZyB3ZSBoYWQgdG8gYnJlYWsgdGhlIHRhYmxlIHVwIC0gcmVzdG9yZSBpdFxuXHRcdFx0aWYgKCB0YWJsZSAhPSB0aGVhZC5wYXJlbnROb2RlICkge1xuXHRcdFx0XHRqcVRhYmxlLmNoaWxkcmVuKCd0aGVhZCcpLmRldGFjaCgpO1xuXHRcdFx0XHRqcVRhYmxlLmFwcGVuZCggdGhlYWQgKTtcblx0XHRcdH1cblx0XG5cdFx0XHRpZiAoIHRmb290ICYmIHRhYmxlICE9IHRmb290LnBhcmVudE5vZGUgKSB7XG5cdFx0XHRcdGpxVGFibGUuY2hpbGRyZW4oJ3Rmb290JykuZGV0YWNoKCk7XG5cdFx0XHRcdGpxVGFibGUuYXBwZW5kKCB0Zm9vdCApO1xuXHRcdFx0fVxuXHRcblx0XHRcdHNldHRpbmdzLmFhU29ydGluZyA9IFtdO1xuXHRcdFx0c2V0dGluZ3MuYWFTb3J0aW5nRml4ZWQgPSBbXTtcblx0XHRcdF9mblNvcnRpbmdDbGFzc2VzKCBzZXR0aW5ncyApO1xuXHRcblx0XHRcdCQoIHJvd3MgKS5yZW1vdmVDbGFzcyggc2V0dGluZ3MuYXNTdHJpcGVDbGFzc2VzLmpvaW4oJyAnKSApO1xuXHRcblx0XHRcdCQoJ3RoLCB0ZCcsIHRoZWFkKS5yZW1vdmVDbGFzcyggY2xhc3Nlcy5zU29ydGFibGUrJyAnK1xuXHRcdFx0XHRjbGFzc2VzLnNTb3J0YWJsZUFzYysnICcrY2xhc3Nlcy5zU29ydGFibGVEZXNjKycgJytjbGFzc2VzLnNTb3J0YWJsZU5vbmVcblx0XHRcdCk7XG5cdFxuXHRcdFx0Ly8gQWRkIHRoZSBUUiBlbGVtZW50cyBiYWNrIGludG8gdGhlIHRhYmxlIGluIHRoZWlyIG9yaWdpbmFsIG9yZGVyXG5cdFx0XHRqcVRib2R5LmNoaWxkcmVuKCkuZGV0YWNoKCk7XG5cdFx0XHRqcVRib2R5LmFwcGVuZCggcm93cyApO1xuXHRcblx0XHRcdC8vIFJlbW92ZSB0aGUgRGF0YVRhYmxlcyBnZW5lcmF0ZWQgbm9kZXMsIGV2ZW50cyBhbmQgY2xhc3Nlc1xuXHRcdFx0dmFyIHJlbW92ZWRNZXRob2QgPSByZW1vdmUgPyAncmVtb3ZlJyA6ICdkZXRhY2gnO1xuXHRcdFx0anFUYWJsZVsgcmVtb3ZlZE1ldGhvZCBdKCk7XG5cdFx0XHRqcVdyYXBwZXJbIHJlbW92ZWRNZXRob2QgXSgpO1xuXHRcblx0XHRcdC8vIElmIHdlIG5lZWQgdG8gcmVhdHRhY2ggdGhlIHRhYmxlIHRvIHRoZSBkb2N1bWVudFxuXHRcdFx0aWYgKCAhIHJlbW92ZSAmJiBvcmlnICkge1xuXHRcdFx0XHQvLyBpbnNlcnRCZWZvcmUgYWN0cyBsaWtlIGFwcGVuZENoaWxkIGlmICFhcmdbMV1cblx0XHRcdFx0b3JpZy5pbnNlcnRCZWZvcmUoIHRhYmxlLCBzZXR0aW5ncy5uVGFibGVSZWluc2VydEJlZm9yZSApO1xuXHRcblx0XHRcdFx0Ly8gUmVzdG9yZSB0aGUgd2lkdGggb2YgdGhlIG9yaWdpbmFsIHRhYmxlIC0gd2FzIHJlYWQgZnJvbSB0aGUgc3R5bGUgcHJvcGVydHksXG5cdFx0XHRcdC8vIHNvIHdlIGNhbiByZXN0b3JlIGRpcmVjdGx5IHRvIHRoYXRcblx0XHRcdFx0anFUYWJsZVxuXHRcdFx0XHRcdC5jc3MoICd3aWR0aCcsIHNldHRpbmdzLnNEZXN0cm95V2lkdGggKVxuXHRcdFx0XHRcdC5yZW1vdmVDbGFzcyggY2xhc3Nlcy5zVGFibGUgKTtcblx0XG5cdFx0XHRcdC8vIElmIHRoZSB3ZXJlIG9yaWdpbmFsbHkgc3RyaXBlIGNsYXNzZXMgLSB0aGVuIHdlIGFkZCB0aGVtIGJhY2sgaGVyZS5cblx0XHRcdFx0Ly8gTm90ZSB0aGlzIGlzIG5vdCBmb29sIHByb29mIChmb3IgZXhhbXBsZSBpZiBub3QgYWxsIHJvd3MgaGFkIHN0cmlwZVxuXHRcdFx0XHQvLyBjbGFzc2VzIC0gYnV0IGl0J3MgYSBnb29kIGVmZm9ydCB3aXRob3V0IGdldHRpbmcgY2FycmllZCBhd2F5XG5cdFx0XHRcdGllbiA9IHNldHRpbmdzLmFzRGVzdHJveVN0cmlwZXMubGVuZ3RoO1xuXHRcblx0XHRcdFx0aWYgKCBpZW4gKSB7XG5cdFx0XHRcdFx0anFUYm9keS5jaGlsZHJlbigpLmVhY2goIGZ1bmN0aW9uIChpKSB7XG5cdFx0XHRcdFx0XHQkKHRoaXMpLmFkZENsYXNzKCBzZXR0aW5ncy5hc0Rlc3Ryb3lTdHJpcGVzW2kgJSBpZW5dICk7XG5cdFx0XHRcdFx0fSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFxuXHRcdFx0LyogUmVtb3ZlIHRoZSBzZXR0aW5ncyBvYmplY3QgZnJvbSB0aGUgc2V0dGluZ3MgYXJyYXkgKi9cblx0XHRcdHZhciBpZHggPSAkLmluQXJyYXkoIHNldHRpbmdzLCBEYXRhVGFibGUuc2V0dGluZ3MgKTtcblx0XHRcdGlmICggaWR4ICE9PSAtMSApIHtcblx0XHRcdFx0RGF0YVRhYmxlLnNldHRpbmdzLnNwbGljZSggaWR4LCAxICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9ICk7XG5cdFxuXHRcblx0Ly8gQWRkIHRoZSBgZXZlcnkoKWAgbWV0aG9kIGZvciByb3dzLCBjb2x1bW5zIGFuZCBjZWxscyBpbiBhIGNvbXBhY3QgZm9ybVxuXHQkLmVhY2goIFsgJ2NvbHVtbicsICdyb3cnLCAnY2VsbCcgXSwgZnVuY3Rpb24gKCBpLCB0eXBlICkge1xuXHRcdF9hcGlfcmVnaXN0ZXIoIHR5cGUrJ3MoKS5ldmVyeSgpJywgZnVuY3Rpb24gKCBmbiApIHtcblx0XHRcdHZhciBvcHRzID0gdGhpcy5zZWxlY3Rvci5vcHRzO1xuXHRcdFx0dmFyIGFwaSA9IHRoaXM7XG5cdFxuXHRcdFx0cmV0dXJuIHRoaXMuaXRlcmF0b3IoIHR5cGUsIGZ1bmN0aW9uICggc2V0dGluZ3MsIGFyZzEsIGFyZzIsIGFyZzMsIGFyZzQgKSB7XG5cdFx0XHRcdC8vIFJvd3MgYW5kIGNvbHVtbnM6XG5cdFx0XHRcdC8vICBhcmcxIC0gaW5kZXhcblx0XHRcdFx0Ly8gIGFyZzIgLSB0YWJsZSBjb3VudGVyXG5cdFx0XHRcdC8vICBhcmczIC0gbG9vcCBjb3VudGVyXG5cdFx0XHRcdC8vICBhcmc0IC0gdW5kZWZpbmVkXG5cdFx0XHRcdC8vIENlbGxzOlxuXHRcdFx0XHQvLyAgYXJnMSAtIHJvdyBpbmRleFxuXHRcdFx0XHQvLyAgYXJnMiAtIGNvbHVtbiBpbmRleFxuXHRcdFx0XHQvLyAgYXJnMyAtIHRhYmxlIGNvdW50ZXJcblx0XHRcdFx0Ly8gIGFyZzQgLSBsb29wIGNvdW50ZXJcblx0XHRcdFx0Zm4uY2FsbChcblx0XHRcdFx0XHRhcGlbIHR5cGUgXShcblx0XHRcdFx0XHRcdGFyZzEsXG5cdFx0XHRcdFx0XHR0eXBlPT09J2NlbGwnID8gYXJnMiA6IG9wdHMsXG5cdFx0XHRcdFx0XHR0eXBlPT09J2NlbGwnID8gb3B0cyA6IHVuZGVmaW5lZFxuXHRcdFx0XHRcdCksXG5cdFx0XHRcdFx0YXJnMSwgYXJnMiwgYXJnMywgYXJnNFxuXHRcdFx0XHQpO1xuXHRcdFx0fSApO1xuXHRcdH0gKTtcblx0fSApO1xuXHRcblx0XG5cdC8vIGkxOG4gbWV0aG9kIGZvciBleHRlbnNpb25zIHRvIGJlIGFibGUgdG8gdXNlIHRoZSBsYW5ndWFnZSBvYmplY3QgZnJvbSB0aGVcblx0Ly8gRGF0YVRhYmxlXG5cdF9hcGlfcmVnaXN0ZXIoICdpMThuKCknLCBmdW5jdGlvbiAoIHRva2VuLCBkZWYsIHBsdXJhbCApIHtcblx0XHR2YXIgY3R4ID0gdGhpcy5jb250ZXh0WzBdO1xuXHRcdHZhciByZXNvbHZlZCA9IF9mbkdldE9iamVjdERhdGFGbiggdG9rZW4gKSggY3R4Lm9MYW5ndWFnZSApO1xuXHRcblx0XHRpZiAoIHJlc29sdmVkID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRyZXNvbHZlZCA9IGRlZjtcblx0XHR9XG5cdFxuXHRcdGlmICggcGx1cmFsICE9PSB1bmRlZmluZWQgJiYgJC5pc1BsYWluT2JqZWN0KCByZXNvbHZlZCApICkge1xuXHRcdFx0cmVzb2x2ZWQgPSByZXNvbHZlZFsgcGx1cmFsIF0gIT09IHVuZGVmaW5lZCA/XG5cdFx0XHRcdHJlc29sdmVkWyBwbHVyYWwgXSA6XG5cdFx0XHRcdHJlc29sdmVkLl87XG5cdFx0fVxuXHRcblx0XHRyZXR1cm4gcmVzb2x2ZWQucmVwbGFjZSggJyVkJywgcGx1cmFsICk7IC8vIG5iOiBwbHVyYWwgbWlnaHQgYmUgdW5kZWZpbmVkLFxuXHR9ICk7XG5cdC8qKlxuXHQgKiBWZXJzaW9uIHN0cmluZyBmb3IgcGx1Zy1pbnMgdG8gY2hlY2sgY29tcGF0aWJpbGl0eS4gQWxsb3dlZCBmb3JtYXQgaXNcblx0ICogYGEuYi5jLWRgIHdoZXJlOiBhOmludCwgYjppbnQsIGM6aW50LCBkOnN0cmluZyhkZXZ8YmV0YXxhbHBoYSkuIGBkYCBpcyB1c2VkXG5cdCAqIG9ubHkgZm9yIG5vbi1yZWxlYXNlIGJ1aWxkcy4gU2VlIGh0dHA6Ly9zZW12ZXIub3JnLyBmb3IgbW9yZSBpbmZvcm1hdGlvbi5cblx0ICogIEBtZW1iZXJcblx0ICogIEB0eXBlIHN0cmluZ1xuXHQgKiAgQGRlZmF1bHQgVmVyc2lvbiBudW1iZXJcblx0ICovXG5cdERhdGFUYWJsZS52ZXJzaW9uID0gXCIxLjExLjNcIjtcblxuXHQvKipcblx0ICogUHJpdmF0ZSBkYXRhIHN0b3JlLCBjb250YWluaW5nIGFsbCBvZiB0aGUgc2V0dGluZ3Mgb2JqZWN0cyB0aGF0IGFyZVxuXHQgKiBjcmVhdGVkIGZvciB0aGUgdGFibGVzIG9uIGEgZ2l2ZW4gcGFnZS5cblx0ICpcblx0ICogTm90ZSB0aGF0IHRoZSBgRGF0YVRhYmxlLnNldHRpbmdzYCBvYmplY3QgaXMgYWxpYXNlZCB0b1xuXHQgKiBgalF1ZXJ5LmZuLmRhdGFUYWJsZUV4dGAgdGhyb3VnaCB3aGljaCBpdCBtYXkgYmUgYWNjZXNzZWQgYW5kXG5cdCAqIG1hbmlwdWxhdGVkLCBvciBgalF1ZXJ5LmZuLmRhdGFUYWJsZS5zZXR0aW5nc2AuXG5cdCAqICBAbWVtYmVyXG5cdCAqICBAdHlwZSBhcnJheVxuXHQgKiAgQGRlZmF1bHQgW11cblx0ICogIEBwcml2YXRlXG5cdCAqL1xuXHREYXRhVGFibGUuc2V0dGluZ3MgPSBbXTtcblxuXHQvKipcblx0ICogT2JqZWN0IG1vZGVscyBjb250YWluZXIsIGZvciB0aGUgdmFyaW91cyBtb2RlbHMgdGhhdCBEYXRhVGFibGVzIGhhc1xuXHQgKiBhdmFpbGFibGUgdG8gaXQuIFRoZXNlIG1vZGVscyBkZWZpbmUgdGhlIG9iamVjdHMgdGhhdCBhcmUgdXNlZCB0byBob2xkXG5cdCAqIHRoZSBhY3RpdmUgc3RhdGUgYW5kIGNvbmZpZ3VyYXRpb24gb2YgdGhlIHRhYmxlLlxuXHQgKiAgQG5hbWVzcGFjZVxuXHQgKi9cblx0RGF0YVRhYmxlLm1vZGVscyA9IHt9O1xuXHRcblx0XG5cdFxuXHQvKipcblx0ICogVGVtcGxhdGUgb2JqZWN0IGZvciB0aGUgd2F5IGluIHdoaWNoIERhdGFUYWJsZXMgaG9sZHMgaW5mb3JtYXRpb24gYWJvdXRcblx0ICogc2VhcmNoIGluZm9ybWF0aW9uIGZvciB0aGUgZ2xvYmFsIGZpbHRlciBhbmQgaW5kaXZpZHVhbCBjb2x1bW4gZmlsdGVycy5cblx0ICogIEBuYW1lc3BhY2Vcblx0ICovXG5cdERhdGFUYWJsZS5tb2RlbHMub1NlYXJjaCA9IHtcblx0XHQvKipcblx0XHQgKiBGbGFnIHRvIGluZGljYXRlIGlmIHRoZSBmaWx0ZXJpbmcgc2hvdWxkIGJlIGNhc2UgaW5zZW5zaXRpdmUgb3Igbm90XG5cdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHQgKiAgQGRlZmF1bHQgdHJ1ZVxuXHRcdCAqL1xuXHRcdFwiYkNhc2VJbnNlbnNpdGl2ZVwiOiB0cnVlLFxuXHRcblx0XHQvKipcblx0XHQgKiBBcHBsaWVkIHNlYXJjaCB0ZXJtXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqICBAZGVmYXVsdCA8aT5FbXB0eSBzdHJpbmc8L2k+XG5cdFx0ICovXG5cdFx0XCJzU2VhcmNoXCI6IFwiXCIsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIEZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIHNlYXJjaCB0ZXJtIHNob3VsZCBiZSBpbnRlcnByZXRlZCBhcyBhXG5cdFx0ICogcmVndWxhciBleHByZXNzaW9uICh0cnVlKSBvciBub3QgKGZhbHNlKSBhbmQgdGhlcmVmb3JlIGFuZCBzcGVjaWFsXG5cdFx0ICogcmVnZXggY2hhcmFjdGVycyBlc2NhcGVkLlxuXHRcdCAqICBAdHlwZSBib29sZWFuXG5cdFx0ICogIEBkZWZhdWx0IGZhbHNlXG5cdFx0ICovXG5cdFx0XCJiUmVnZXhcIjogZmFsc2UsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIEZsYWcgdG8gaW5kaWNhdGUgaWYgRGF0YVRhYmxlcyBpcyB0byB1c2UgaXRzIHNtYXJ0IGZpbHRlcmluZyBvciBub3QuXG5cdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHQgKiAgQGRlZmF1bHQgdHJ1ZVxuXHRcdCAqL1xuXHRcdFwiYlNtYXJ0XCI6IHRydWUsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIEZsYWcgdG8gaW5kaWNhdGUgaWYgRGF0YVRhYmxlcyBzaG91bGQgb25seSB0cmlnZ2VyIGEgc2VhcmNoIHdoZW5cblx0XHQgKiB0aGUgcmV0dXJuIGtleSBpcyBwcmVzc2VkLlxuXHRcdCAqICBAdHlwZSBib29sZWFuXG5cdFx0ICogIEBkZWZhdWx0IGZhbHNlXG5cdFx0ICovXG5cdFx0XCJyZXR1cm5cIjogZmFsc2Vcblx0fTtcblx0XG5cdFxuXHRcblx0XG5cdC8qKlxuXHQgKiBUZW1wbGF0ZSBvYmplY3QgZm9yIHRoZSB3YXkgaW4gd2hpY2ggRGF0YVRhYmxlcyBob2xkcyBpbmZvcm1hdGlvbiBhYm91dFxuXHQgKiBlYWNoIGluZGl2aWR1YWwgcm93LiBUaGlzIGlzIHRoZSBvYmplY3QgZm9ybWF0IHVzZWQgZm9yIHRoZSBzZXR0aW5nc1xuXHQgKiBhb0RhdGEgYXJyYXkuXG5cdCAqICBAbmFtZXNwYWNlXG5cdCAqL1xuXHREYXRhVGFibGUubW9kZWxzLm9Sb3cgPSB7XG5cdFx0LyoqXG5cdFx0ICogVFIgZWxlbWVudCBmb3IgdGhlIHJvd1xuXHRcdCAqICBAdHlwZSBub2RlXG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKi9cblx0XHRcIm5UclwiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBBcnJheSBvZiBURCBlbGVtZW50cyBmb3IgZWFjaCByb3cuIFRoaXMgaXMgbnVsbCB1bnRpbCB0aGUgcm93IGhhcyBiZWVuXG5cdFx0ICogY3JlYXRlZC5cblx0XHQgKiAgQHR5cGUgYXJyYXkgbm9kZXNcblx0XHQgKiAgQGRlZmF1bHQgW11cblx0XHQgKi9cblx0XHRcImFuQ2VsbHNcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogRGF0YSBvYmplY3QgZnJvbSB0aGUgb3JpZ2luYWwgZGF0YSBzb3VyY2UgZm9yIHRoZSByb3cuIFRoaXMgaXMgZWl0aGVyXG5cdFx0ICogYW4gYXJyYXkgaWYgdXNpbmcgdGhlIHRyYWRpdGlvbmFsIGZvcm0gb2YgRGF0YVRhYmxlcywgb3IgYW4gb2JqZWN0IGlmXG5cdFx0ICogdXNpbmcgbURhdGEgb3B0aW9ucy4gVGhlIGV4YWN0IHR5cGUgd2lsbCBkZXBlbmQgb24gdGhlIHBhc3NlZCBpblxuXHRcdCAqIGRhdGEgZnJvbSB0aGUgZGF0YSBzb3VyY2UsIG9yIHdpbGwgYmUgYW4gYXJyYXkgaWYgdXNpbmcgRE9NIGEgZGF0YVxuXHRcdCAqIHNvdXJjZS5cblx0XHQgKiAgQHR5cGUgYXJyYXl8b2JqZWN0XG5cdFx0ICogIEBkZWZhdWx0IFtdXG5cdFx0ICovXG5cdFx0XCJfYURhdGFcIjogW10sXG5cdFxuXHRcdC8qKlxuXHRcdCAqIFNvcnRpbmcgZGF0YSBjYWNoZSAtIHRoaXMgYXJyYXkgaXMgb3N0ZW5zaWJseSB0aGUgc2FtZSBsZW5ndGggYXMgdGhlXG5cdFx0ICogbnVtYmVyIG9mIGNvbHVtbnMgKGFsdGhvdWdoIGVhY2ggaW5kZXggaXMgZ2VuZXJhdGVkIG9ubHkgYXMgaXQgaXNcblx0XHQgKiBuZWVkZWQpLCBhbmQgaG9sZHMgdGhlIGRhdGEgdGhhdCBpcyB1c2VkIGZvciBzb3J0aW5nIGVhY2ggY29sdW1uIGluIHRoZVxuXHRcdCAqIHJvdy4gV2UgZG8gdGhpcyBjYWNoZSBnZW5lcmF0aW9uIGF0IHRoZSBzdGFydCBvZiB0aGUgc29ydCBpbiBvcmRlciB0aGF0XG5cdFx0ICogdGhlIGZvcm1hdHRpbmcgb2YgdGhlIHNvcnQgZGF0YSBuZWVkIGJlIGRvbmUgb25seSBvbmNlIGZvciBlYWNoIGNlbGxcblx0XHQgKiBwZXIgc29ydC4gVGhpcyBhcnJheSBzaG91bGQgbm90IGJlIHJlYWQgZnJvbSBvciB3cml0dGVuIHRvIGJ5IGFueXRoaW5nXG5cdFx0ICogb3RoZXIgdGhhbiB0aGUgbWFzdGVyIHNvcnRpbmcgbWV0aG9kcy5cblx0XHQgKiAgQHR5cGUgYXJyYXlcblx0XHQgKiAgQGRlZmF1bHQgbnVsbFxuXHRcdCAqICBAcHJpdmF0ZVxuXHRcdCAqL1xuXHRcdFwiX2FTb3J0RGF0YVwiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBQZXIgY2VsbCBmaWx0ZXJpbmcgZGF0YSBjYWNoZS4gQXMgcGVyIHRoZSBzb3J0IGRhdGEgY2FjaGUsIHVzZWQgdG9cblx0XHQgKiBpbmNyZWFzZSB0aGUgcGVyZm9ybWFuY2Ugb2YgdGhlIGZpbHRlcmluZyBpbiBEYXRhVGFibGVzXG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKiAgQHByaXZhdGVcblx0XHQgKi9cblx0XHRcIl9hRmlsdGVyRGF0YVwiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBGaWx0ZXJpbmcgZGF0YSBjYWNoZS4gVGhpcyBpcyB0aGUgc2FtZSBhcyB0aGUgY2VsbCBmaWx0ZXJpbmcgY2FjaGUsIGJ1dFxuXHRcdCAqIGluIHRoaXMgY2FzZSBhIHN0cmluZyByYXRoZXIgdGhhbiBhbiBhcnJheS4gVGhpcyBpcyBlYXNpbHkgY29tcHV0ZWQgd2l0aFxuXHRcdCAqIGEgam9pbiBvbiBgX2FGaWx0ZXJEYXRhYCwgYnV0IGlzIHByb3ZpZGVkIGFzIGEgY2FjaGUgc28gdGhlIGpvaW4gaXNuJ3Rcblx0XHQgKiBuZWVkZWQgb24gZXZlcnkgc2VhcmNoIChtZW1vcnkgdHJhZGVkIGZvciBwZXJmb3JtYW5jZSlcblx0XHQgKiAgQHR5cGUgYXJyYXlcblx0XHQgKiAgQGRlZmF1bHQgbnVsbFxuXHRcdCAqICBAcHJpdmF0ZVxuXHRcdCAqL1xuXHRcdFwiX3NGaWx0ZXJSb3dcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogQ2FjaGUgb2YgdGhlIGNsYXNzIG5hbWUgdGhhdCBEYXRhVGFibGVzIGhhcyBhcHBsaWVkIHRvIHRoZSByb3csIHNvIHdlXG5cdFx0ICogY2FuIHF1aWNrbHkgbG9vayBhdCB0aGlzIHZhcmlhYmxlIHJhdGhlciB0aGFuIG5lZWRpbmcgdG8gZG8gYSBET00gY2hlY2tcblx0XHQgKiBvbiBjbGFzc05hbWUgZm9yIHRoZSBuVHIgcHJvcGVydHkuXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqICBAZGVmYXVsdCA8aT5FbXB0eSBzdHJpbmc8L2k+XG5cdFx0ICogIEBwcml2YXRlXG5cdFx0ICovXG5cdFx0XCJfc1Jvd1N0cmlwZVwiOiBcIlwiLFxuXHRcblx0XHQvKipcblx0XHQgKiBEZW5vdGUgaWYgdGhlIG9yaWdpbmFsIGRhdGEgc291cmNlIHdhcyBmcm9tIHRoZSBET00sIG9yIHRoZSBkYXRhIHNvdXJjZVxuXHRcdCAqIG9iamVjdC4gVGhpcyBpcyB1c2VkIGZvciBpbnZhbGlkYXRpbmcgZGF0YSwgc28gRGF0YVRhYmxlcyBjYW5cblx0XHQgKiBhdXRvbWF0aWNhbGx5IHJlYWQgZGF0YSBmcm9tIHRoZSBvcmlnaW5hbCBzb3VyY2UsIHVubGVzcyB1bmluc3RydWN0ZWRcblx0XHQgKiBvdGhlcndpc2UuXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqICBAZGVmYXVsdCBudWxsXG5cdFx0ICogIEBwcml2YXRlXG5cdFx0ICovXG5cdFx0XCJzcmNcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogSW5kZXggaW4gdGhlIGFvRGF0YSBhcnJheS4gVGhpcyBzYXZlcyBhbiBpbmRleE9mIGxvb2t1cCB3aGVuIHdlIGhhdmUgdGhlXG5cdFx0ICogb2JqZWN0LCBidXQgd2FudCB0byBrbm93IHRoZSBpbmRleFxuXHRcdCAqICBAdHlwZSBpbnRlZ2VyXG5cdFx0ICogIEBkZWZhdWx0IC0xXG5cdFx0ICogIEBwcml2YXRlXG5cdFx0ICovXG5cdFx0XCJpZHhcIjogLTFcblx0fTtcblx0XG5cdFxuXHQvKipcblx0ICogVGVtcGxhdGUgb2JqZWN0IGZvciB0aGUgY29sdW1uIGluZm9ybWF0aW9uIG9iamVjdCBpbiBEYXRhVGFibGVzLiBUaGlzIG9iamVjdFxuXHQgKiBpcyBoZWxkIGluIHRoZSBzZXR0aW5ncyBhb0NvbHVtbnMgYXJyYXkgYW5kIGNvbnRhaW5zIGFsbCB0aGUgaW5mb3JtYXRpb24gdGhhdFxuXHQgKiBEYXRhVGFibGVzIG5lZWRzIGFib3V0IGVhY2ggaW5kaXZpZHVhbCBjb2x1bW4uXG5cdCAqXG5cdCAqIE5vdGUgdGhhdCB0aGlzIG9iamVjdCBpcyByZWxhdGVkIHRvIHtAbGluayBEYXRhVGFibGUuZGVmYXVsdHMuY29sdW1ufVxuXHQgKiBidXQgdGhpcyBvbmUgaXMgdGhlIGludGVybmFsIGRhdGEgc3RvcmUgZm9yIERhdGFUYWJsZXMncyBjYWNoZSBvZiBjb2x1bW5zLlxuXHQgKiBJdCBzaG91bGQgTk9UIGJlIG1hbmlwdWxhdGVkIG91dHNpZGUgb2YgRGF0YVRhYmxlcy4gQW55IGNvbmZpZ3VyYXRpb24gc2hvdWxkXG5cdCAqIGJlIGRvbmUgdGhyb3VnaCB0aGUgaW5pdGlhbGlzYXRpb24gb3B0aW9ucy5cblx0ICogIEBuYW1lc3BhY2Vcblx0ICovXG5cdERhdGFUYWJsZS5tb2RlbHMub0NvbHVtbiA9IHtcblx0XHQvKipcblx0XHQgKiBDb2x1bW4gaW5kZXguIFRoaXMgY291bGQgYmUgd29ya2VkIG91dCBvbi10aGUtZmx5IHdpdGggJC5pbkFycmF5LCBidXQgaXRcblx0XHQgKiBpcyBmYXN0ZXIgdG8ganVzdCBob2xkIGl0IGFzIGEgdmFyaWFibGVcblx0XHQgKiAgQHR5cGUgaW50ZWdlclxuXHRcdCAqICBAZGVmYXVsdCBudWxsXG5cdFx0ICovXG5cdFx0XCJpZHhcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogQSBsaXN0IG9mIHRoZSBjb2x1bW5zIHRoYXQgc29ydGluZyBzaG91bGQgb2NjdXIgb24gd2hlbiB0aGlzIGNvbHVtblxuXHRcdCAqIGlzIHNvcnRlZC4gVGhhdCB0aGlzIHByb3BlcnR5IGlzIGFuIGFycmF5IGFsbG93cyBtdWx0aS1jb2x1bW4gc29ydGluZ1xuXHRcdCAqIHRvIGJlIGRlZmluZWQgZm9yIGEgY29sdW1uIChmb3IgZXhhbXBsZSBmaXJzdCBuYW1lIC8gbGFzdCBuYW1lIGNvbHVtbnNcblx0XHQgKiB3b3VsZCBiZW5lZml0IGZyb20gdGhpcykuIFRoZSB2YWx1ZXMgYXJlIGludGVnZXJzIHBvaW50aW5nIHRvIHRoZVxuXHRcdCAqIGNvbHVtbnMgdG8gYmUgc29ydGVkIG9uICh0eXBpY2FsbHkgaXQgd2lsbCBiZSBhIHNpbmdsZSBpbnRlZ2VyIHBvaW50aW5nXG5cdFx0ICogYXQgaXRzZWxmLCBidXQgdGhhdCBkb2Vzbid0IG5lZWQgdG8gYmUgdGhlIGNhc2UpLlxuXHRcdCAqICBAdHlwZSBhcnJheVxuXHRcdCAqL1xuXHRcdFwiYURhdGFTb3J0XCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIERlZmluZSB0aGUgc29ydGluZyBkaXJlY3Rpb25zIHRoYXQgYXJlIGFwcGxpZWQgdG8gdGhlIGNvbHVtbiwgaW4gc2VxdWVuY2Vcblx0XHQgKiBhcyB0aGUgY29sdW1uIGlzIHJlcGVhdGVkbHkgc29ydGVkIHVwb24gLSBpLmUuIHRoZSBmaXJzdCB2YWx1ZSBpcyB1c2VkXG5cdFx0ICogYXMgdGhlIHNvcnRpbmcgZGlyZWN0aW9uIHdoZW4gdGhlIGNvbHVtbiBpZiBmaXJzdCBzb3J0ZWQgKGNsaWNrZWQgb24pLlxuXHRcdCAqIFNvcnQgaXQgYWdhaW4gKGNsaWNrIGFnYWluKSBhbmQgaXQgd2lsbCBtb3ZlIG9uIHRvIHRoZSBuZXh0IGluZGV4LlxuXHRcdCAqIFJlcGVhdCB1bnRpbCBsb29wLlxuXHRcdCAqICBAdHlwZSBhcnJheVxuXHRcdCAqL1xuXHRcdFwiYXNTb3J0aW5nXCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIEZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGNvbHVtbiBpcyBzZWFyY2hhYmxlLCBhbmQgdGh1cyBzaG91bGQgYmUgaW5jbHVkZWRcblx0XHQgKiBpbiB0aGUgZmlsdGVyaW5nIG9yIG5vdC5cblx0XHQgKiAgQHR5cGUgYm9vbGVhblxuXHRcdCAqL1xuXHRcdFwiYlNlYXJjaGFibGVcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogRmxhZyB0byBpbmRpY2F0ZSBpZiB0aGUgY29sdW1uIGlzIHNvcnRhYmxlIG9yIG5vdC5cblx0XHQgKiAgQHR5cGUgYm9vbGVhblxuXHRcdCAqL1xuXHRcdFwiYlNvcnRhYmxlXCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIEZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGNvbHVtbiBpcyBjdXJyZW50bHkgdmlzaWJsZSBpbiB0aGUgdGFibGUgb3Igbm90XG5cdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHQgKi9cblx0XHRcImJWaXNpYmxlXCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIFN0b3JlIGZvciBtYW51YWwgdHlwZSBhc3NpZ25tZW50IHVzaW5nIHRoZSBgY29sdW1uLnR5cGVgIG9wdGlvbi4gVGhpc1xuXHRcdCAqIGlzIGhlbGQgaW4gc3RvcmUgc28gd2UgY2FuIG1hbmlwdWxhdGUgdGhlIGNvbHVtbidzIGBzVHlwZWAgcHJvcGVydHkuXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqICBAZGVmYXVsdCBudWxsXG5cdFx0ICogIEBwcml2YXRlXG5cdFx0ICovXG5cdFx0XCJfc01hbnVhbFR5cGVcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogRmxhZyB0byBpbmRpY2F0ZSBpZiBIVE1MNSBkYXRhIGF0dHJpYnV0ZXMgc2hvdWxkIGJlIHVzZWQgYXMgdGhlIGRhdGFcblx0XHQgKiBzb3VyY2UgZm9yIGZpbHRlcmluZyBvciBzb3J0aW5nLiBUcnVlIGlzIGVpdGhlciBhcmUuXG5cdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHQgKiAgQGRlZmF1bHQgZmFsc2Vcblx0XHQgKiAgQHByaXZhdGVcblx0XHQgKi9cblx0XHRcIl9iQXR0clNyY1wiOiBmYWxzZSxcblx0XG5cdFx0LyoqXG5cdFx0ICogRGV2ZWxvcGVyIGRlZmluYWJsZSBmdW5jdGlvbiB0aGF0IGlzIGNhbGxlZCB3aGVuZXZlciBhIGNlbGwgaXMgY3JlYXRlZCAoQWpheCBzb3VyY2UsXG5cdFx0ICogZXRjKSBvciBwcm9jZXNzZWQgZm9yIGlucHV0IChET00gc291cmNlKS4gVGhpcyBjYW4gYmUgdXNlZCBhcyBhIGNvbXBsaW1lbnQgdG8gbVJlbmRlclxuXHRcdCAqIGFsbG93aW5nIHlvdSB0byBtb2RpZnkgdGhlIERPTSBlbGVtZW50IChhZGQgYmFja2dyb3VuZCBjb2xvdXIgZm9yIGV4YW1wbGUpIHdoZW4gdGhlXG5cdFx0ICogZWxlbWVudCBpcyBhdmFpbGFibGUuXG5cdFx0ICogIEB0eXBlIGZ1bmN0aW9uXG5cdFx0ICogIEBwYXJhbSB7ZWxlbWVudH0gblRkIFRoZSBURCBub2RlIHRoYXQgaGFzIGJlZW4gY3JlYXRlZFxuXHRcdCAqICBAcGFyYW0geyp9IHNEYXRhIFRoZSBEYXRhIGZvciB0aGUgY2VsbFxuXHRcdCAqICBAcGFyYW0ge2FycmF5fG9iamVjdH0gb0RhdGEgVGhlIGRhdGEgZm9yIHRoZSB3aG9sZSByb3dcblx0XHQgKiAgQHBhcmFtIHtpbnR9IGlSb3cgVGhlIHJvdyBpbmRleCBmb3IgdGhlIGFvRGF0YSBkYXRhIHN0b3JlXG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKi9cblx0XHRcImZuQ3JlYXRlZENlbGxcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogRnVuY3Rpb24gdG8gZ2V0IGRhdGEgZnJvbSBhIGNlbGwgaW4gYSBjb2x1bW4uIFlvdSBzaG91bGQgPGI+bmV2ZXI8L2I+XG5cdFx0ICogYWNjZXNzIGRhdGEgZGlyZWN0bHkgdGhyb3VnaCBfYURhdGEgaW50ZXJuYWxseSBpbiBEYXRhVGFibGVzIC0gYWx3YXlzIHVzZVxuXHRcdCAqIHRoZSBtZXRob2QgYXR0YWNoZWQgdG8gdGhpcyBwcm9wZXJ0eS4gSXQgYWxsb3dzIG1EYXRhIHRvIGZ1bmN0aW9uIGFzXG5cdFx0ICogcmVxdWlyZWQuIFRoaXMgZnVuY3Rpb24gaXMgYXV0b21hdGljYWxseSBhc3NpZ25lZCBieSB0aGUgY29sdW1uXG5cdFx0ICogaW5pdGlhbGlzYXRpb24gbWV0aG9kXG5cdFx0ICogIEB0eXBlIGZ1bmN0aW9uXG5cdFx0ICogIEBwYXJhbSB7YXJyYXl8b2JqZWN0fSBvRGF0YSBUaGUgZGF0YSBhcnJheS9vYmplY3QgZm9yIHRoZSBhcnJheVxuXHRcdCAqICAgIChpLmUuIGFvRGF0YVtdLl9hRGF0YSlcblx0XHQgKiAgQHBhcmFtIHtzdHJpbmd9IHNTcGVjaWZpYyBUaGUgc3BlY2lmaWMgZGF0YSB0eXBlIHlvdSB3YW50IHRvIGdldCAtXG5cdFx0ICogICAgJ2Rpc3BsYXknLCAndHlwZScgJ2ZpbHRlcicgJ3NvcnQnXG5cdFx0ICogIEByZXR1cm5zIHsqfSBUaGUgZGF0YSBmb3IgdGhlIGNlbGwgZnJvbSB0aGUgZ2l2ZW4gcm93J3MgZGF0YVxuXHRcdCAqICBAZGVmYXVsdCBudWxsXG5cdFx0ICovXG5cdFx0XCJmbkdldERhdGFcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogRnVuY3Rpb24gdG8gc2V0IGRhdGEgZm9yIGEgY2VsbCBpbiB0aGUgY29sdW1uLiBZb3Ugc2hvdWxkIDxiPm5ldmVyPC9iPlxuXHRcdCAqIHNldCB0aGUgZGF0YSBkaXJlY3RseSB0byBfYURhdGEgaW50ZXJuYWxseSBpbiBEYXRhVGFibGVzIC0gYWx3YXlzIHVzZVxuXHRcdCAqIHRoaXMgbWV0aG9kLiBJdCBhbGxvd3MgbURhdGEgdG8gZnVuY3Rpb24gYXMgcmVxdWlyZWQuIFRoaXMgZnVuY3Rpb25cblx0XHQgKiBpcyBhdXRvbWF0aWNhbGx5IGFzc2lnbmVkIGJ5IHRoZSBjb2x1bW4gaW5pdGlhbGlzYXRpb24gbWV0aG9kXG5cdFx0ICogIEB0eXBlIGZ1bmN0aW9uXG5cdFx0ICogIEBwYXJhbSB7YXJyYXl8b2JqZWN0fSBvRGF0YSBUaGUgZGF0YSBhcnJheS9vYmplY3QgZm9yIHRoZSBhcnJheVxuXHRcdCAqICAgIChpLmUuIGFvRGF0YVtdLl9hRGF0YSlcblx0XHQgKiAgQHBhcmFtIHsqfSBzVmFsdWUgVmFsdWUgdG8gc2V0XG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKi9cblx0XHRcImZuU2V0RGF0YVwiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBQcm9wZXJ0eSB0byByZWFkIHRoZSB2YWx1ZSBmb3IgdGhlIGNlbGxzIGluIHRoZSBjb2x1bW4gZnJvbSB0aGUgZGF0YVxuXHRcdCAqIHNvdXJjZSBhcnJheSAvIG9iamVjdC4gSWYgbnVsbCwgdGhlbiB0aGUgZGVmYXVsdCBjb250ZW50IGlzIHVzZWQsIGlmIGFcblx0XHQgKiBmdW5jdGlvbiBpcyBnaXZlbiB0aGVuIHRoZSByZXR1cm4gZnJvbSB0aGUgZnVuY3Rpb24gaXMgdXNlZC5cblx0XHQgKiAgQHR5cGUgZnVuY3Rpb258aW50fHN0cmluZ3xudWxsXG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKi9cblx0XHRcIm1EYXRhXCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIFBhcnRuZXIgcHJvcGVydHkgdG8gbURhdGEgd2hpY2ggaXMgdXNlZCAob25seSB3aGVuIGRlZmluZWQpIHRvIGdldFxuXHRcdCAqIHRoZSBkYXRhIC0gaS5lLiBpdCBpcyBiYXNpY2FsbHkgdGhlIHNhbWUgYXMgbURhdGEsIGJ1dCB3aXRob3V0IHRoZVxuXHRcdCAqICdzZXQnIG9wdGlvbiwgYW5kIGFsc28gdGhlIGRhdGEgZmVkIHRvIGl0IGlzIHRoZSByZXN1bHQgZnJvbSBtRGF0YS5cblx0XHQgKiBUaGlzIGlzIHRoZSByZW5kZXJpbmcgbWV0aG9kIHRvIG1hdGNoIHRoZSBkYXRhIG1ldGhvZCBvZiBtRGF0YS5cblx0XHQgKiAgQHR5cGUgZnVuY3Rpb258aW50fHN0cmluZ3xudWxsXG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKi9cblx0XHRcIm1SZW5kZXJcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogVW5pcXVlIGhlYWRlciBUSC9URCBlbGVtZW50IGZvciB0aGlzIGNvbHVtbiAtIHRoaXMgaXMgd2hhdCB0aGUgc29ydGluZ1xuXHRcdCAqIGxpc3RlbmVyIGlzIGF0dGFjaGVkIHRvIChpZiBzb3J0aW5nIGlzIGVuYWJsZWQuKVxuXHRcdCAqICBAdHlwZSBub2RlXG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKi9cblx0XHRcIm5UaFwiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBVbmlxdWUgZm9vdGVyIFRIL1REIGVsZW1lbnQgZm9yIHRoaXMgY29sdW1uIChpZiB0aGVyZSBpcyBvbmUpLiBOb3QgdXNlZFxuXHRcdCAqIGluIERhdGFUYWJsZXMgYXMgc3VjaCwgYnV0IGNhbiBiZSB1c2VkIGZvciBwbHVnLWlucyB0byByZWZlcmVuY2UgdGhlXG5cdFx0ICogZm9vdGVyIGZvciBlYWNoIGNvbHVtbi5cblx0XHQgKiAgQHR5cGUgbm9kZVxuXHRcdCAqICBAZGVmYXVsdCBudWxsXG5cdFx0ICovXG5cdFx0XCJuVGZcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogVGhlIGNsYXNzIHRvIGFwcGx5IHRvIGFsbCBURCBlbGVtZW50cyBpbiB0aGUgdGFibGUncyBUQk9EWSBmb3IgdGhlIGNvbHVtblxuXHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHQgKiAgQGRlZmF1bHQgbnVsbFxuXHRcdCAqL1xuXHRcdFwic0NsYXNzXCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIFdoZW4gRGF0YVRhYmxlcyBjYWxjdWxhdGVzIHRoZSBjb2x1bW4gd2lkdGhzIHRvIGFzc2lnbiB0byBlYWNoIGNvbHVtbixcblx0XHQgKiBpdCBmaW5kcyB0aGUgbG9uZ2VzdCBzdHJpbmcgaW4gZWFjaCBjb2x1bW4gYW5kIHRoZW4gY29uc3RydWN0cyBhXG5cdFx0ICogdGVtcG9yYXJ5IHRhYmxlIGFuZCByZWFkcyB0aGUgd2lkdGhzIGZyb20gdGhhdC4gVGhlIHByb2JsZW0gd2l0aCB0aGlzXG5cdFx0ICogaXMgdGhhdCBcIm1tbVwiIGlzIG11Y2ggd2lkZXIgdGhlbiBcImlpaWlcIiwgYnV0IHRoZSBsYXR0ZXIgaXMgYSBsb25nZXJcblx0XHQgKiBzdHJpbmcgLSB0aHVzIHRoZSBjYWxjdWxhdGlvbiBjYW4gZ28gd3JvbmcgKGRvaW5nIGl0IHByb3Blcmx5IGFuZCBwdXR0aW5nXG5cdFx0ICogaXQgaW50byBhbiBET00gb2JqZWN0IGFuZCBtZWFzdXJpbmcgdGhhdCBpcyBob3JyaWJseSghKSBzbG93KS4gVGh1cyBhc1xuXHRcdCAqIGEgXCJ3b3JrIGFyb3VuZFwiIHdlIHByb3ZpZGUgdGhpcyBvcHRpb24uIEl0IHdpbGwgYXBwZW5kIGl0cyB2YWx1ZSB0byB0aGVcblx0XHQgKiB0ZXh0IHRoYXQgaXMgZm91bmQgdG8gYmUgdGhlIGxvbmdlc3Qgc3RyaW5nIGZvciB0aGUgY29sdW1uIC0gaS5lLiBwYWRkaW5nLlxuXHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHQgKi9cblx0XHRcInNDb250ZW50UGFkZGluZ1wiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBBbGxvd3MgYSBkZWZhdWx0IHZhbHVlIHRvIGJlIGdpdmVuIGZvciBhIGNvbHVtbidzIGRhdGEsIGFuZCB3aWxsIGJlIHVzZWRcblx0XHQgKiB3aGVuZXZlciBhIG51bGwgZGF0YSBzb3VyY2UgaXMgZW5jb3VudGVyZWQgKHRoaXMgY2FuIGJlIGJlY2F1c2UgbURhdGFcblx0XHQgKiBpcyBzZXQgdG8gbnVsbCwgb3IgYmVjYXVzZSB0aGUgZGF0YSBzb3VyY2UgaXRzZWxmIGlzIG51bGwpLlxuXHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHQgKiAgQGRlZmF1bHQgbnVsbFxuXHRcdCAqL1xuXHRcdFwic0RlZmF1bHRDb250ZW50XCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIE5hbWUgZm9yIHRoZSBjb2x1bW4sIGFsbG93aW5nIHJlZmVyZW5jZSB0byB0aGUgY29sdW1uIGJ5IG5hbWUgYXMgd2VsbCBhc1xuXHRcdCAqIGJ5IGluZGV4IChuZWVkcyBhIGxvb2t1cCB0byB3b3JrIGJ5IG5hbWUpLlxuXHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHQgKi9cblx0XHRcInNOYW1lXCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIEN1c3RvbSBzb3J0aW5nIGRhdGEgdHlwZSAtIGRlZmluZXMgd2hpY2ggb2YgdGhlIGF2YWlsYWJsZSBwbHVnLWlucyBpblxuXHRcdCAqIGFmblNvcnREYXRhIHRoZSBjdXN0b20gc29ydGluZyB3aWxsIHVzZSAtIGlmIGFueSBpcyBkZWZpbmVkLlxuXHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHQgKiAgQGRlZmF1bHQgc3RkXG5cdFx0ICovXG5cdFx0XCJzU29ydERhdGFUeXBlXCI6ICdzdGQnLFxuXHRcblx0XHQvKipcblx0XHQgKiBDbGFzcyB0byBiZSBhcHBsaWVkIHRvIHRoZSBoZWFkZXIgZWxlbWVudCB3aGVuIHNvcnRpbmcgb24gdGhpcyBjb2x1bW5cblx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKi9cblx0XHRcInNTb3J0aW5nQ2xhc3NcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogQ2xhc3MgdG8gYmUgYXBwbGllZCB0byB0aGUgaGVhZGVyIGVsZW1lbnQgd2hlbiBzb3J0aW5nIG9uIHRoaXMgY29sdW1uIC1cblx0XHQgKiB3aGVuIGpRdWVyeSBVSSB0aGVtaW5nIGlzIHVzZWQuXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqICBAZGVmYXVsdCBudWxsXG5cdFx0ICovXG5cdFx0XCJzU29ydGluZ0NsYXNzSlVJXCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIFRpdGxlIG9mIHRoZSBjb2x1bW4gLSB3aGF0IGlzIHNlZW4gaW4gdGhlIFRIIGVsZW1lbnQgKG5UaCkuXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqL1xuXHRcdFwic1RpdGxlXCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIENvbHVtbiBzb3J0aW5nIGFuZCBmaWx0ZXJpbmcgdHlwZVxuXHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHQgKiAgQGRlZmF1bHQgbnVsbFxuXHRcdCAqL1xuXHRcdFwic1R5cGVcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogV2lkdGggb2YgdGhlIGNvbHVtblxuXHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHQgKiAgQGRlZmF1bHQgbnVsbFxuXHRcdCAqL1xuXHRcdFwic1dpZHRoXCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIFdpZHRoIG9mIHRoZSBjb2x1bW4gd2hlbiBpdCB3YXMgZmlyc3QgXCJlbmNvdW50ZXJlZFwiXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqICBAZGVmYXVsdCBudWxsXG5cdFx0ICovXG5cdFx0XCJzV2lkdGhPcmlnXCI6IG51bGxcblx0fTtcblx0XG5cdFxuXHQvKlxuXHQgKiBEZXZlbG9wZXIgbm90ZTogVGhlIHByb3BlcnRpZXMgb2YgdGhlIG9iamVjdCBiZWxvdyBhcmUgZ2l2ZW4gaW4gSHVuZ2FyaWFuXG5cdCAqIG5vdGF0aW9uLCB0aGF0IHdhcyB1c2VkIGFzIHRoZSBpbnRlcmZhY2UgZm9yIERhdGFUYWJsZXMgcHJpb3IgdG8gdjEuMTAsIGhvd2V2ZXJcblx0ICogZnJvbSB2MS4xMCBvbndhcmRzIHRoZSBwcmltYXJ5IGludGVyZmFjZSBpcyBjYW1lbCBjYXNlLiBJbiBvcmRlciB0byBhdm9pZFxuXHQgKiBicmVha2luZyBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eSB1dHRlcmx5IHdpdGggdGhpcyBjaGFuZ2UsIHRoZSBIdW5nYXJpYW5cblx0ICogdmVyc2lvbiBpcyBzdGlsbCwgaW50ZXJuYWxseSB0aGUgcHJpbWFyeSBpbnRlcmZhY2UsIGJ1dCBpcyBpcyBub3QgZG9jdW1lbnRlZFxuXHQgKiAtIGhlbmNlIHRoZSBAbmFtZSB0YWdzIGluIGVhY2ggZG9jIGNvbW1lbnQuIFRoaXMgYWxsb3dzIGEgSmF2YXNjcmlwdCBmdW5jdGlvblxuXHQgKiB0byBjcmVhdGUgYSBtYXAgZnJvbSBIdW5nYXJpYW4gbm90YXRpb24gdG8gY2FtZWwgY2FzZSAoZ29pbmcgdGhlIG90aGVyIGRpcmVjdGlvblxuXHQgKiB3b3VsZCByZXF1aXJlIGVhY2ggcHJvcGVydHkgdG8gYmUgbGlzdGVkLCB3aGljaCB3b3VsZCBhZGQgYXJvdW5kIDNLIHRvIHRoZSBzaXplXG5cdCAqIG9mIERhdGFUYWJsZXMsIHdoaWxlIHRoaXMgbWV0aG9kIGlzIGFib3V0IGEgMC41SyBoaXQpLlxuXHQgKlxuXHQgKiBVbHRpbWF0ZWx5IHRoaXMgZG9lcyBwYXZlIHRoZSB3YXkgZm9yIEh1bmdhcmlhbiBub3RhdGlvbiB0byBiZSBkcm9wcGVkXG5cdCAqIGNvbXBsZXRlbHksIGJ1dCB0aGF0IGlzIGEgbWFzc2l2ZSBhbW91bnQgb2Ygd29yayBhbmQgd2lsbCBicmVhayBjdXJyZW50XG5cdCAqIGluc3RhbGxzICh0aGVyZWZvcmUgaXMgb24taG9sZCB1bnRpbCB2MikuXG5cdCAqL1xuXHRcblx0LyoqXG5cdCAqIEluaXRpYWxpc2F0aW9uIG9wdGlvbnMgdGhhdCBjYW4gYmUgZ2l2ZW4gdG8gRGF0YVRhYmxlcyBhdCBpbml0aWFsaXNhdGlvblxuXHQgKiB0aW1lLlxuXHQgKiAgQG5hbWVzcGFjZVxuXHQgKi9cblx0RGF0YVRhYmxlLmRlZmF1bHRzID0ge1xuXHRcdC8qKlxuXHRcdCAqIEFuIGFycmF5IG9mIGRhdGEgdG8gdXNlIGZvciB0aGUgdGFibGUsIHBhc3NlZCBpbiBhdCBpbml0aWFsaXNhdGlvbiB3aGljaFxuXHRcdCAqIHdpbGwgYmUgdXNlZCBpbiBwcmVmZXJlbmNlIHRvIGFueSBkYXRhIHdoaWNoIGlzIGFscmVhZHkgaW4gdGhlIERPTS4gVGhpcyBpc1xuXHRcdCAqIHBhcnRpY3VsYXJseSB1c2VmdWwgZm9yIGNvbnN0cnVjdGluZyB0YWJsZXMgcHVyZWx5IGluIEphdmFzY3JpcHQsIGZvclxuXHRcdCAqIGV4YW1wbGUgd2l0aCBhIGN1c3RvbSBBamF4IGNhbGwuXG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgT3B0aW9uXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5kYXRhXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBVc2luZyBhIDJEIGFycmF5IGRhdGEgc291cmNlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uICgpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiZGF0YVwiOiBbXG5cdFx0ICogICAgICAgICAgWydUcmlkZW50JywgJ0ludGVybmV0IEV4cGxvcmVyIDQuMCcsICdXaW4gOTUrJywgNCwgJ1gnXSxcblx0XHQgKiAgICAgICAgICBbJ1RyaWRlbnQnLCAnSW50ZXJuZXQgRXhwbG9yZXIgNS4wJywgJ1dpbiA5NSsnLCA1LCAnQyddLFxuXHRcdCAqICAgICAgICBdLFxuXHRcdCAqICAgICAgICBcImNvbHVtbnNcIjogW1xuXHRcdCAqICAgICAgICAgIHsgXCJ0aXRsZVwiOiBcIkVuZ2luZVwiIH0sXG5cdFx0ICogICAgICAgICAgeyBcInRpdGxlXCI6IFwiQnJvd3NlclwiIH0sXG5cdFx0ICogICAgICAgICAgeyBcInRpdGxlXCI6IFwiUGxhdGZvcm1cIiB9LFxuXHRcdCAqICAgICAgICAgIHsgXCJ0aXRsZVwiOiBcIlZlcnNpb25cIiB9LFxuXHRcdCAqICAgICAgICAgIHsgXCJ0aXRsZVwiOiBcIkdyYWRlXCIgfVxuXHRcdCAqICAgICAgICBdXG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgLy8gVXNpbmcgYW4gYXJyYXkgb2Ygb2JqZWN0cyBhcyBhIGRhdGEgc291cmNlIChgZGF0YWApXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uICgpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiZGF0YVwiOiBbXG5cdFx0ICogICAgICAgICAge1xuXHRcdCAqICAgICAgICAgICAgXCJlbmdpbmVcIjogICBcIlRyaWRlbnRcIixcblx0XHQgKiAgICAgICAgICAgIFwiYnJvd3NlclwiOiAgXCJJbnRlcm5ldCBFeHBsb3JlciA0LjBcIixcblx0XHQgKiAgICAgICAgICAgIFwicGxhdGZvcm1cIjogXCJXaW4gOTUrXCIsXG5cdFx0ICogICAgICAgICAgICBcInZlcnNpb25cIjogIDQsXG5cdFx0ICogICAgICAgICAgICBcImdyYWRlXCI6ICAgIFwiWFwiXG5cdFx0ICogICAgICAgICAgfSxcblx0XHQgKiAgICAgICAgICB7XG5cdFx0ICogICAgICAgICAgICBcImVuZ2luZVwiOiAgIFwiVHJpZGVudFwiLFxuXHRcdCAqICAgICAgICAgICAgXCJicm93c2VyXCI6ICBcIkludGVybmV0IEV4cGxvcmVyIDUuMFwiLFxuXHRcdCAqICAgICAgICAgICAgXCJwbGF0Zm9ybVwiOiBcIldpbiA5NStcIixcblx0XHQgKiAgICAgICAgICAgIFwidmVyc2lvblwiOiAgNSxcblx0XHQgKiAgICAgICAgICAgIFwiZ3JhZGVcIjogICAgXCJDXCJcblx0XHQgKiAgICAgICAgICB9XG5cdFx0ICogICAgICAgIF0sXG5cdFx0ICogICAgICAgIFwiY29sdW1uc1wiOiBbXG5cdFx0ICogICAgICAgICAgeyBcInRpdGxlXCI6IFwiRW5naW5lXCIsICAgXCJkYXRhXCI6IFwiZW5naW5lXCIgfSxcblx0XHQgKiAgICAgICAgICB7IFwidGl0bGVcIjogXCJCcm93c2VyXCIsICBcImRhdGFcIjogXCJicm93c2VyXCIgfSxcblx0XHQgKiAgICAgICAgICB7IFwidGl0bGVcIjogXCJQbGF0Zm9ybVwiLCBcImRhdGFcIjogXCJwbGF0Zm9ybVwiIH0sXG5cdFx0ICogICAgICAgICAgeyBcInRpdGxlXCI6IFwiVmVyc2lvblwiLCAgXCJkYXRhXCI6IFwidmVyc2lvblwiIH0sXG5cdFx0ICogICAgICAgICAgeyBcInRpdGxlXCI6IFwiR3JhZGVcIiwgICAgXCJkYXRhXCI6IFwiZ3JhZGVcIiB9XG5cdFx0ICogICAgICAgIF1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJhYURhdGFcIjogbnVsbCxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIElmIG9yZGVyaW5nIGlzIGVuYWJsZWQsIHRoZW4gRGF0YVRhYmxlcyB3aWxsIHBlcmZvcm0gYSBmaXJzdCBwYXNzIHNvcnQgb25cblx0XHQgKiBpbml0aWFsaXNhdGlvbi4gWW91IGNhbiBkZWZpbmUgd2hpY2ggY29sdW1uKHMpIHRoZSBzb3J0IGlzIHBlcmZvcm1lZFxuXHRcdCAqIHVwb24sIGFuZCB0aGUgc29ydGluZyBkaXJlY3Rpb24sIHdpdGggdGhpcyB2YXJpYWJsZS4gVGhlIGBzb3J0aW5nYCBhcnJheVxuXHRcdCAqIHNob3VsZCBjb250YWluIGFuIGFycmF5IGZvciBlYWNoIGNvbHVtbiB0byBiZSBzb3J0ZWQgaW5pdGlhbGx5IGNvbnRhaW5pbmdcblx0XHQgKiB0aGUgY29sdW1uJ3MgaW5kZXggYW5kIGEgZGlyZWN0aW9uIHN0cmluZyAoJ2FzYycgb3IgJ2Rlc2MnKS5cblx0XHQgKiAgQHR5cGUgYXJyYXlcblx0XHQgKiAgQGRlZmF1bHQgW1swLCdhc2MnXV1cblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgT3B0aW9uXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5vcmRlclxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgLy8gU29ydCBieSAzcmQgY29sdW1uIGZpcnN0LCBhbmQgdGhlbiA0dGggY29sdW1uXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJvcmRlclwiOiBbWzIsJ2FzYyddLCBbMywnZGVzYyddXVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKlxuXHRcdCAqICAgIC8vIE5vIGluaXRpYWwgc29ydGluZ1xuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwib3JkZXJcIjogW11cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJhYVNvcnRpbmdcIjogW1swLCdhc2MnXV0sXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBUaGlzIHBhcmFtZXRlciBpcyBiYXNpY2FsbHkgaWRlbnRpY2FsIHRvIHRoZSBgc29ydGluZ2AgcGFyYW1ldGVyLCBidXRcblx0XHQgKiBjYW5ub3QgYmUgb3ZlcnJpZGRlbiBieSB1c2VyIGludGVyYWN0aW9uIHdpdGggdGhlIHRhYmxlLiBXaGF0IHRoaXMgbWVhbnNcblx0XHQgKiBpcyB0aGF0IHlvdSBjb3VsZCBoYXZlIGEgY29sdW1uICh2aXNpYmxlIG9yIGhpZGRlbikgd2hpY2ggdGhlIHNvcnRpbmdcblx0XHQgKiB3aWxsIGFsd2F5cyBiZSBmb3JjZWQgb24gZmlyc3QgLSBhbnkgc29ydGluZyBhZnRlciB0aGF0IChmcm9tIHRoZSB1c2VyKVxuXHRcdCAqIHdpbGwgdGhlbiBiZSBwZXJmb3JtZWQgYXMgcmVxdWlyZWQuIFRoaXMgY2FuIGJlIHVzZWZ1bCBmb3IgZ3JvdXBpbmcgcm93c1xuXHRcdCAqIHRvZ2V0aGVyLlxuXHRcdCAqICBAdHlwZSBhcnJheVxuXHRcdCAqICBAZGVmYXVsdCBudWxsXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IE9wdGlvblxuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMub3JkZXJGaXhlZFxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJvcmRlckZpeGVkXCI6IFtbMCwnYXNjJ11dXG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApXG5cdFx0ICovXG5cdFx0XCJhYVNvcnRpbmdGaXhlZFwiOiBbXSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIERhdGFUYWJsZXMgY2FuIGJlIGluc3RydWN0ZWQgdG8gbG9hZCBkYXRhIHRvIGRpc3BsYXkgaW4gdGhlIHRhYmxlIGZyb20gYVxuXHRcdCAqIEFqYXggc291cmNlLiBUaGlzIG9wdGlvbiBkZWZpbmVzIGhvdyB0aGF0IEFqYXggY2FsbCBpcyBtYWRlIGFuZCB3aGVyZSB0by5cblx0XHQgKlxuXHRcdCAqIFRoZSBgYWpheGAgcHJvcGVydHkgaGFzIHRocmVlIGRpZmZlcmVudCBtb2RlcyBvZiBvcGVyYXRpb24sIGRlcGVuZGluZyBvblxuXHRcdCAqIGhvdyBpdCBpcyBkZWZpbmVkLiBUaGVzZSBhcmU6XG5cdFx0ICpcblx0XHQgKiAqIGBzdHJpbmdgIC0gU2V0IHRoZSBVUkwgZnJvbSB3aGVyZSB0aGUgZGF0YSBzaG91bGQgYmUgbG9hZGVkIGZyb20uXG5cdFx0ICogKiBgb2JqZWN0YCAtIERlZmluZSBwcm9wZXJ0aWVzIGZvciBgalF1ZXJ5LmFqYXhgLlxuXHRcdCAqICogYGZ1bmN0aW9uYCAtIEN1c3RvbSBkYXRhIGdldCBmdW5jdGlvblxuXHRcdCAqXG5cdFx0ICogYHN0cmluZ2Bcblx0XHQgKiAtLS0tLS0tLVxuXHRcdCAqXG5cdFx0ICogQXMgYSBzdHJpbmcsIHRoZSBgYWpheGAgcHJvcGVydHkgc2ltcGx5IGRlZmluZXMgdGhlIFVSTCBmcm9tIHdoaWNoXG5cdFx0ICogRGF0YVRhYmxlcyB3aWxsIGxvYWQgZGF0YS5cblx0XHQgKlxuXHRcdCAqIGBvYmplY3RgXG5cdFx0ICogLS0tLS0tLS1cblx0XHQgKlxuXHRcdCAqIEFzIGFuIG9iamVjdCwgdGhlIHBhcmFtZXRlcnMgaW4gdGhlIG9iamVjdCBhcmUgcGFzc2VkIHRvXG5cdFx0ICogW2pRdWVyeS5hamF4XShodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvKSBhbGxvd2luZyBmaW5lIGNvbnRyb2xcblx0XHQgKiBvZiB0aGUgQWpheCByZXF1ZXN0LiBEYXRhVGFibGVzIGhhcyBhIG51bWJlciBvZiBkZWZhdWx0IHBhcmFtZXRlcnMgd2hpY2hcblx0XHQgKiB5b3UgY2FuIG92ZXJyaWRlIHVzaW5nIHRoaXMgb3B0aW9uLiBQbGVhc2UgcmVmZXIgdG8gdGhlIGpRdWVyeVxuXHRcdCAqIGRvY3VtZW50YXRpb24gZm9yIGEgZnVsbCBkZXNjcmlwdGlvbiBvZiB0aGUgb3B0aW9ucyBhdmFpbGFibGUsIGFsdGhvdWdoXG5cdFx0ICogdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzIHByb3ZpZGUgYWRkaXRpb25hbCBvcHRpb25zIGluIERhdGFUYWJsZXMgb3Jcblx0XHQgKiByZXF1aXJlIHNwZWNpYWwgY29uc2lkZXJhdGlvbjpcblx0XHQgKlxuXHRcdCAqICogYGRhdGFgIC0gQXMgd2l0aCBqUXVlcnksIGBkYXRhYCBjYW4gYmUgcHJvdmlkZWQgYXMgYW4gb2JqZWN0LCBidXQgaXRcblx0XHQgKiAgIGNhbiBhbHNvIGJlIHVzZWQgYXMgYSBmdW5jdGlvbiB0byBtYW5pcHVsYXRlIHRoZSBkYXRhIERhdGFUYWJsZXMgc2VuZHNcblx0XHQgKiAgIHRvIHRoZSBzZXJ2ZXIuIFRoZSBmdW5jdGlvbiB0YWtlcyBhIHNpbmdsZSBwYXJhbWV0ZXIsIGFuIG9iamVjdCBvZlxuXHRcdCAqICAgcGFyYW1ldGVycyB3aXRoIHRoZSB2YWx1ZXMgdGhhdCBEYXRhVGFibGVzIGhhcyByZWFkaWVkIGZvciBzZW5kaW5nLiBBblxuXHRcdCAqICAgb2JqZWN0IG1heSBiZSByZXR1cm5lZCB3aGljaCB3aWxsIGJlIG1lcmdlZCBpbnRvIHRoZSBEYXRhVGFibGVzXG5cdFx0ICogICBkZWZhdWx0cywgb3IgeW91IGNhbiBhZGQgdGhlIGl0ZW1zIHRvIHRoZSBvYmplY3QgdGhhdCB3YXMgcGFzc2VkIGluIGFuZFxuXHRcdCAqICAgbm90IHJldHVybiBhbnl0aGluZyBmcm9tIHRoZSBmdW5jdGlvbi4gVGhpcyBzdXBlcnNlZGVzIGBmblNlcnZlclBhcmFtc2Bcblx0XHQgKiAgIGZyb20gRGF0YVRhYmxlcyAxLjktLlxuXHRcdCAqXG5cdFx0ICogKiBgZGF0YVNyY2AgLSBCeSBkZWZhdWx0IERhdGFUYWJsZXMgd2lsbCBsb29rIGZvciB0aGUgcHJvcGVydHkgYGRhdGFgIChvclxuXHRcdCAqICAgYGFhRGF0YWAgZm9yIGNvbXBhdGliaWxpdHkgd2l0aCBEYXRhVGFibGVzIDEuOS0pIHdoZW4gb2J0YWluaW5nIGRhdGFcblx0XHQgKiAgIGZyb20gYW4gQWpheCBzb3VyY2Ugb3IgZm9yIHNlcnZlci1zaWRlIHByb2Nlc3NpbmcgLSB0aGlzIHBhcmFtZXRlclxuXHRcdCAqICAgYWxsb3dzIHRoYXQgcHJvcGVydHkgdG8gYmUgY2hhbmdlZC4gWW91IGNhbiB1c2UgSmF2YXNjcmlwdCBkb3R0ZWRcblx0XHQgKiAgIG9iamVjdCBub3RhdGlvbiB0byBnZXQgYSBkYXRhIHNvdXJjZSBmb3IgbXVsdGlwbGUgbGV2ZWxzIG9mIG5lc3RpbmcsIG9yXG5cdFx0ICogICBpdCBteSBiZSB1c2VkIGFzIGEgZnVuY3Rpb24uIEFzIGEgZnVuY3Rpb24gaXQgdGFrZXMgYSBzaW5nbGUgcGFyYW1ldGVyLFxuXHRcdCAqICAgdGhlIEpTT04gcmV0dXJuZWQgZnJvbSB0aGUgc2VydmVyLCB3aGljaCBjYW4gYmUgbWFuaXB1bGF0ZWQgYXNcblx0XHQgKiAgIHJlcXVpcmVkLCB3aXRoIHRoZSByZXR1cm5lZCB2YWx1ZSBiZWluZyB0aGF0IHVzZWQgYnkgRGF0YVRhYmxlcyBhcyB0aGVcblx0XHQgKiAgIGRhdGEgc291cmNlIGZvciB0aGUgdGFibGUuIFRoaXMgc3VwZXJzZWRlcyBgc0FqYXhEYXRhUHJvcGAgZnJvbVxuXHRcdCAqICAgRGF0YVRhYmxlcyAxLjktLlxuXHRcdCAqXG5cdFx0ICogKiBgc3VjY2Vzc2AgLSBTaG91bGQgbm90IGJlIG92ZXJyaWRkZW4gaXQgaXMgdXNlZCBpbnRlcm5hbGx5IGluXG5cdFx0ICogICBEYXRhVGFibGVzLiBUbyBtYW5pcHVsYXRlIC8gdHJhbnNmb3JtIHRoZSBkYXRhIHJldHVybmVkIGJ5IHRoZSBzZXJ2ZXJcblx0XHQgKiAgIHVzZSBgYWpheC5kYXRhU3JjYCwgb3IgdXNlIGBhamF4YCBhcyBhIGZ1bmN0aW9uIChzZWUgYmVsb3cpLlxuXHRcdCAqXG5cdFx0ICogYGZ1bmN0aW9uYFxuXHRcdCAqIC0tLS0tLS0tLS1cblx0XHQgKlxuXHRcdCAqIEFzIGEgZnVuY3Rpb24sIG1ha2luZyB0aGUgQWpheCBjYWxsIGlzIGxlZnQgdXAgdG8geW91cnNlbGYgYWxsb3dpbmdcblx0XHQgKiBjb21wbGV0ZSBjb250cm9sIG9mIHRoZSBBamF4IHJlcXVlc3QuIEluZGVlZCwgaWYgZGVzaXJlZCwgYSBtZXRob2Qgb3RoZXJcblx0XHQgKiB0aGFuIEFqYXggY291bGQgYmUgdXNlZCB0byBvYnRhaW4gdGhlIHJlcXVpcmVkIGRhdGEsIHN1Y2ggYXMgV2ViIHN0b3JhZ2Vcblx0XHQgKiBvciBhbiBBSVIgZGF0YWJhc2UuXG5cdFx0ICpcblx0XHQgKiBUaGUgZnVuY3Rpb24gaXMgZ2l2ZW4gZm91ciBwYXJhbWV0ZXJzIGFuZCBubyByZXR1cm4gaXMgcmVxdWlyZWQuIFRoZVxuXHRcdCAqIHBhcmFtZXRlcnMgYXJlOlxuXHRcdCAqXG5cdFx0ICogMS4gX29iamVjdF8gLSBEYXRhIHRvIHNlbmQgdG8gdGhlIHNlcnZlclxuXHRcdCAqIDIuIF9mdW5jdGlvbl8gLSBDYWxsYmFjayBmdW5jdGlvbiB0aGF0IG11c3QgYmUgZXhlY3V0ZWQgd2hlbiB0aGUgcmVxdWlyZWRcblx0XHQgKiAgICBkYXRhIGhhcyBiZWVuIG9idGFpbmVkLiBUaGF0IGRhdGEgc2hvdWxkIGJlIHBhc3NlZCBpbnRvIHRoZSBjYWxsYmFja1xuXHRcdCAqICAgIGFzIHRoZSBvbmx5IHBhcmFtZXRlclxuXHRcdCAqIDMuIF9vYmplY3RfIC0gRGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3QgZm9yIHRoZSB0YWJsZVxuXHRcdCAqXG5cdFx0ICogTm90ZSB0aGF0IHRoaXMgc3VwZXJzZWRlcyBgZm5TZXJ2ZXJEYXRhYCBmcm9tIERhdGFUYWJsZXMgMS45LS5cblx0XHQgKlxuXHRcdCAqICBAdHlwZSBzdHJpbmd8b2JqZWN0fGZ1bmN0aW9uXG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgT3B0aW9uXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5hamF4XG5cdFx0ICogIEBzaW5jZSAxLjEwLjBcblx0XHQgKlxuXHRcdCAqIEBleGFtcGxlXG5cdFx0ICogICAvLyBHZXQgSlNPTiBkYXRhIGZyb20gYSBmaWxlIHZpYSBBamF4LlxuXHRcdCAqICAgLy8gTm90ZSBEYXRhVGFibGVzIGV4cGVjdHMgZGF0YSBpbiB0aGUgZm9ybSBgeyBkYXRhOiBbIC4uLmRhdGEuLi4gXSB9YCBieSBkZWZhdWx0KS5cblx0XHQgKiAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgIFwiYWpheFwiOiBcImRhdGEuanNvblwiXG5cdFx0ICogICB9ICk7XG5cdFx0ICpcblx0XHQgKiBAZXhhbXBsZVxuXHRcdCAqICAgLy8gR2V0IEpTT04gZGF0YSBmcm9tIGEgZmlsZSB2aWEgQWpheCwgdXNpbmcgYGRhdGFTcmNgIHRvIGNoYW5nZVxuXHRcdCAqICAgLy8gYGRhdGFgIHRvIGB0YWJsZURhdGFgIChpLmUuIGB7IHRhYmxlRGF0YTogWyAuLi5kYXRhLi4uIF0gfWApXG5cdFx0ICogICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICBcImFqYXhcIjoge1xuXHRcdCAqICAgICAgIFwidXJsXCI6IFwiZGF0YS5qc29uXCIsXG5cdFx0ICogICAgICAgXCJkYXRhU3JjXCI6IFwidGFibGVEYXRhXCJcblx0XHQgKiAgICAgfVxuXHRcdCAqICAgfSApO1xuXHRcdCAqXG5cdFx0ICogQGV4YW1wbGVcblx0XHQgKiAgIC8vIEdldCBKU09OIGRhdGEgZnJvbSBhIGZpbGUgdmlhIEFqYXgsIHVzaW5nIGBkYXRhU3JjYCB0byByZWFkIGRhdGFcblx0XHQgKiAgIC8vIGZyb20gYSBwbGFpbiBhcnJheSByYXRoZXIgdGhhbiBhbiBhcnJheSBpbiBhbiBvYmplY3Rcblx0XHQgKiAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgIFwiYWpheFwiOiB7XG5cdFx0ICogICAgICAgXCJ1cmxcIjogXCJkYXRhLmpzb25cIixcblx0XHQgKiAgICAgICBcImRhdGFTcmNcIjogXCJcIlxuXHRcdCAqICAgICB9XG5cdFx0ICogICB9ICk7XG5cdFx0ICpcblx0XHQgKiBAZXhhbXBsZVxuXHRcdCAqICAgLy8gTWFuaXB1bGF0ZSB0aGUgZGF0YSByZXR1cm5lZCBmcm9tIHRoZSBzZXJ2ZXIgLSBhZGQgYSBsaW5rIHRvIGRhdGFcblx0XHQgKiAgIC8vIChub3RlIHRoaXMgY2FuLCBzaG91bGQsIGJlIGRvbmUgdXNpbmcgYHJlbmRlcmAgZm9yIHRoZSBjb2x1bW4gLSB0aGlzXG5cdFx0ICogICAvLyBpcyBqdXN0IGEgc2ltcGxlIGV4YW1wbGUgb2YgaG93IHRoZSBkYXRhIGNhbiBiZSBtYW5pcHVsYXRlZCkuXG5cdFx0ICogICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICBcImFqYXhcIjoge1xuXHRcdCAqICAgICAgIFwidXJsXCI6IFwiZGF0YS5qc29uXCIsXG5cdFx0ICogICAgICAgXCJkYXRhU3JjXCI6IGZ1bmN0aW9uICgganNvbiApIHtcblx0XHQgKiAgICAgICAgIGZvciAoIHZhciBpPTAsIGllbj1qc29uLmxlbmd0aCA7IGk8aWVuIDsgaSsrICkge1xuXHRcdCAqICAgICAgICAgICBqc29uW2ldWzBdID0gJzxhIGhyZWY9XCIvbWVzc2FnZS8nK2pzb25baV1bMF0rJz5WaWV3IG1lc3NhZ2U8L2E+Jztcblx0XHQgKiAgICAgICAgIH1cblx0XHQgKiAgICAgICAgIHJldHVybiBqc29uO1xuXHRcdCAqICAgICAgIH1cblx0XHQgKiAgICAgfVxuXHRcdCAqICAgfSApO1xuXHRcdCAqXG5cdFx0ICogQGV4YW1wbGVcblx0XHQgKiAgIC8vIEFkZCBkYXRhIHRvIHRoZSByZXF1ZXN0XG5cdFx0ICogICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICBcImFqYXhcIjoge1xuXHRcdCAqICAgICAgIFwidXJsXCI6IFwiZGF0YS5qc29uXCIsXG5cdFx0ICogICAgICAgXCJkYXRhXCI6IGZ1bmN0aW9uICggZCApIHtcblx0XHQgKiAgICAgICAgIHJldHVybiB7XG5cdFx0ICogICAgICAgICAgIFwiZXh0cmFfc2VhcmNoXCI6ICQoJyNleHRyYScpLnZhbCgpXG5cdFx0ICogICAgICAgICB9O1xuXHRcdCAqICAgICAgIH1cblx0XHQgKiAgICAgfVxuXHRcdCAqICAgfSApO1xuXHRcdCAqXG5cdFx0ICogQGV4YW1wbGVcblx0XHQgKiAgIC8vIFNlbmQgcmVxdWVzdCBhcyBQT1NUXG5cdFx0ICogICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICBcImFqYXhcIjoge1xuXHRcdCAqICAgICAgIFwidXJsXCI6IFwiZGF0YS5qc29uXCIsXG5cdFx0ICogICAgICAgXCJ0eXBlXCI6IFwiUE9TVFwiXG5cdFx0ICogICAgIH1cblx0XHQgKiAgIH0gKTtcblx0XHQgKlxuXHRcdCAqIEBleGFtcGxlXG5cdFx0ICogICAvLyBHZXQgdGhlIGRhdGEgZnJvbSBsb2NhbFN0b3JhZ2UgKGNvdWxkIGludGVyZmFjZSB3aXRoIGEgZm9ybSBmb3Jcblx0XHQgKiAgIC8vIGFkZGluZywgZWRpdGluZyBhbmQgcmVtb3Zpbmcgcm93cykuXG5cdFx0ICogICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICBcImFqYXhcIjogZnVuY3Rpb24gKGRhdGEsIGNhbGxiYWNrLCBzZXR0aW5ncykge1xuXHRcdCAqICAgICAgIGNhbGxiYWNrKFxuXHRcdCAqICAgICAgICAgSlNPTi5wYXJzZSggbG9jYWxTdG9yYWdlLmdldEl0ZW0oJ2RhdGFUYWJsZXNEYXRhJykgKVxuXHRcdCAqICAgICAgICk7XG5cdFx0ICogICAgIH1cblx0XHQgKiAgIH0gKTtcblx0XHQgKi9cblx0XHRcImFqYXhcIjogbnVsbCxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIFRoaXMgcGFyYW1ldGVyIGFsbG93cyB5b3UgdG8gcmVhZGlseSBzcGVjaWZ5IHRoZSBlbnRyaWVzIGluIHRoZSBsZW5ndGggZHJvcFxuXHRcdCAqIGRvd24gbWVudSB0aGF0IERhdGFUYWJsZXMgc2hvd3Mgd2hlbiBwYWdpbmF0aW9uIGlzIGVuYWJsZWQuIEl0IGNhbiBiZVxuXHRcdCAqIGVpdGhlciBhIDFEIGFycmF5IG9mIG9wdGlvbnMgd2hpY2ggd2lsbCBiZSB1c2VkIGZvciBib3RoIHRoZSBkaXNwbGF5ZWRcblx0XHQgKiBvcHRpb24gYW5kIHRoZSB2YWx1ZSwgb3IgYSAyRCBhcnJheSB3aGljaCB3aWxsIHVzZSB0aGUgYXJyYXkgaW4gdGhlIGZpcnN0XG5cdFx0ICogcG9zaXRpb24gYXMgdGhlIHZhbHVlLCBhbmQgdGhlIGFycmF5IGluIHRoZSBzZWNvbmQgcG9zaXRpb24gYXMgdGhlXG5cdFx0ICogZGlzcGxheWVkIG9wdGlvbnMgKHVzZWZ1bCBmb3IgbGFuZ3VhZ2Ugc3RyaW5ncyBzdWNoIGFzICdBbGwnKS5cblx0XHQgKlxuXHRcdCAqIE5vdGUgdGhhdCB0aGUgYHBhZ2VMZW5ndGhgIHByb3BlcnR5IHdpbGwgYmUgYXV0b21hdGljYWxseSBzZXQgdG8gdGhlXG5cdFx0ICogZmlyc3QgdmFsdWUgZ2l2ZW4gaW4gdGhpcyBhcnJheSwgdW5sZXNzIGBwYWdlTGVuZ3RoYCBpcyBhbHNvIHByb3ZpZGVkLlxuXHRcdCAqICBAdHlwZSBhcnJheVxuXHRcdCAqICBAZGVmYXVsdCBbIDEwLCAyNSwgNTAsIDEwMCBdXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IE9wdGlvblxuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMubGVuZ3RoTWVudVxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJsZW5ndGhNZW51XCI6IFtbMTAsIDI1LCA1MCwgLTFdLCBbMTAsIDI1LCA1MCwgXCJBbGxcIl1dXG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdFwiYUxlbmd0aE1lbnVcIjogWyAxMCwgMjUsIDUwLCAxMDAgXSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIFRoZSBgY29sdW1uc2Agb3B0aW9uIGluIHRoZSBpbml0aWFsaXNhdGlvbiBwYXJhbWV0ZXIgYWxsb3dzIHlvdSB0byBkZWZpbmVcblx0XHQgKiBkZXRhaWxzIGFib3V0IHRoZSB3YXkgaW5kaXZpZHVhbCBjb2x1bW5zIGJlaGF2ZS4gRm9yIGEgZnVsbCBsaXN0IG9mXG5cdFx0ICogY29sdW1uIG9wdGlvbnMgdGhhdCBjYW4gYmUgc2V0LCBwbGVhc2Ugc2VlXG5cdFx0ICoge0BsaW5rIERhdGFUYWJsZS5kZWZhdWx0cy5jb2x1bW59LiBOb3RlIHRoYXQgaWYgeW91IHVzZSBgY29sdW1uc2AgdG9cblx0XHQgKiBkZWZpbmUgeW91ciBjb2x1bW5zLCB5b3UgbXVzdCBoYXZlIGFuIGVudHJ5IGluIHRoZSBhcnJheSBmb3IgZXZlcnkgc2luZ2xlXG5cdFx0ICogY29sdW1uIHRoYXQgeW91IGhhdmUgaW4geW91ciB0YWJsZSAodGhlc2UgY2FuIGJlIG51bGwgaWYgeW91IGRvbid0IHdoaWNoXG5cdFx0ICogdG8gc3BlY2lmeSBhbnkgb3B0aW9ucykuXG5cdFx0ICogIEBtZW1iZXJcblx0XHQgKlxuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuY29sdW1uXG5cdFx0ICovXG5cdFx0XCJhb0NvbHVtbnNcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogVmVyeSBzaW1pbGFyIHRvIGBjb2x1bW5zYCwgYGNvbHVtbkRlZnNgIGFsbG93cyB5b3UgdG8gdGFyZ2V0IGEgc3BlY2lmaWNcblx0XHQgKiBjb2x1bW4sIG11bHRpcGxlIGNvbHVtbnMsIG9yIGFsbCBjb2x1bW5zLCB1c2luZyB0aGUgYHRhcmdldHNgIHByb3BlcnR5IG9mXG5cdFx0ICogZWFjaCBvYmplY3QgaW4gdGhlIGFycmF5LiBUaGlzIGFsbG93cyBncmVhdCBmbGV4aWJpbGl0eSB3aGVuIGNyZWF0aW5nXG5cdFx0ICogdGFibGVzLCBhcyB0aGUgYGNvbHVtbkRlZnNgIGFycmF5cyBjYW4gYmUgb2YgYW55IGxlbmd0aCwgdGFyZ2V0aW5nIHRoZVxuXHRcdCAqIGNvbHVtbnMgeW91IHNwZWNpZmljYWxseSB3YW50LiBgY29sdW1uRGVmc2AgbWF5IHVzZSBhbnkgb2YgdGhlIGNvbHVtblxuXHRcdCAqIG9wdGlvbnMgYXZhaWxhYmxlOiB7QGxpbmsgRGF0YVRhYmxlLmRlZmF1bHRzLmNvbHVtbn0sIGJ1dCBpdCBfbXVzdF9cblx0XHQgKiBoYXZlIGB0YXJnZXRzYCBkZWZpbmVkIGluIGVhY2ggb2JqZWN0IGluIHRoZSBhcnJheS4gVmFsdWVzIGluIHRoZSBgdGFyZ2V0c2Bcblx0XHQgKiBhcnJheSBtYXkgYmU6XG5cdFx0ICogICA8dWw+XG5cdFx0ICogICAgIDxsaT5hIHN0cmluZyAtIGNsYXNzIG5hbWUgd2lsbCBiZSBtYXRjaGVkIG9uIHRoZSBUSCBmb3IgdGhlIGNvbHVtbjwvbGk+XG5cdFx0ICogICAgIDxsaT4wIG9yIGEgcG9zaXRpdmUgaW50ZWdlciAtIGNvbHVtbiBpbmRleCBjb3VudGluZyBmcm9tIHRoZSBsZWZ0PC9saT5cblx0XHQgKiAgICAgPGxpPmEgbmVnYXRpdmUgaW50ZWdlciAtIGNvbHVtbiBpbmRleCBjb3VudGluZyBmcm9tIHRoZSByaWdodDwvbGk+XG5cdFx0ICogICAgIDxsaT50aGUgc3RyaW5nIFwiX2FsbFwiIC0gYWxsIGNvbHVtbnMgKGkuZS4gYXNzaWduIGEgZGVmYXVsdCk8L2xpPlxuXHRcdCAqICAgPC91bD5cblx0XHQgKiAgQG1lbWJlclxuXHRcdCAqXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5jb2x1bW5EZWZzXG5cdFx0ICovXG5cdFx0XCJhb0NvbHVtbkRlZnNcIjogbnVsbCxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIEJhc2ljYWxseSB0aGUgc2FtZSBhcyBgc2VhcmNoYCwgdGhpcyBwYXJhbWV0ZXIgZGVmaW5lcyB0aGUgaW5kaXZpZHVhbCBjb2x1bW5cblx0XHQgKiBmaWx0ZXJpbmcgc3RhdGUgYXQgaW5pdGlhbGlzYXRpb24gdGltZS4gVGhlIGFycmF5IG11c3QgYmUgb2YgdGhlIHNhbWUgc2l6ZVxuXHRcdCAqIGFzIHRoZSBudW1iZXIgb2YgY29sdW1ucywgYW5kIGVhY2ggZWxlbWVudCBiZSBhbiBvYmplY3Qgd2l0aCB0aGUgcGFyYW1ldGVyc1xuXHRcdCAqIGBzZWFyY2hgIGFuZCBgZXNjYXBlUmVnZXhgICh0aGUgbGF0dGVyIGlzIG9wdGlvbmFsKS4gJ251bGwnIGlzIGFsc29cblx0XHQgKiBhY2NlcHRlZCBhbmQgdGhlIGRlZmF1bHQgd2lsbCBiZSB1c2VkLlxuXHRcdCAqICBAdHlwZSBhcnJheVxuXHRcdCAqICBAZGVmYXVsdCBbXVxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBPcHRpb25cblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLnNlYXJjaENvbHNcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwic2VhcmNoQ29sc1wiOiBbXG5cdFx0ICogICAgICAgICAgbnVsbCxcblx0XHQgKiAgICAgICAgICB7IFwic2VhcmNoXCI6IFwiTXkgZmlsdGVyXCIgfSxcblx0XHQgKiAgICAgICAgICBudWxsLFxuXHRcdCAqICAgICAgICAgIHsgXCJzZWFyY2hcIjogXCJeWzAtOV1cIiwgXCJlc2NhcGVSZWdleFwiOiBmYWxzZSB9XG5cdFx0ICogICAgICAgIF1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9IClcblx0XHQgKi9cblx0XHRcImFvU2VhcmNoQ29sc1wiOiBbXSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIEFuIGFycmF5IG9mIENTUyBjbGFzc2VzIHRoYXQgc2hvdWxkIGJlIGFwcGxpZWQgdG8gZGlzcGxheWVkIHJvd3MuIFRoaXNcblx0XHQgKiBhcnJheSBtYXkgYmUgb2YgYW55IGxlbmd0aCwgYW5kIERhdGFUYWJsZXMgd2lsbCBhcHBseSBlYWNoIGNsYXNzXG5cdFx0ICogc2VxdWVudGlhbGx5LCBsb29waW5nIHdoZW4gcmVxdWlyZWQuXG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICogIEBkZWZhdWx0IG51bGwgPGk+V2lsbCB0YWtlIHRoZSB2YWx1ZXMgZGV0ZXJtaW5lZCBieSB0aGUgYG9DbGFzc2VzLnN0cmlwZSpgXG5cdFx0ICogICAgb3B0aW9uczwvaT5cblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgT3B0aW9uXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5zdHJpcGVDbGFzc2VzXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcInN0cmlwZUNsYXNzZXNcIjogWyAnc3RyaXAxJywgJ3N0cmlwMicsICdzdHJpcDMnIF1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9IClcblx0XHQgKi9cblx0XHRcImFzU3RyaXBlQ2xhc3Nlc1wiOiBudWxsLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogRW5hYmxlIG9yIGRpc2FibGUgYXV0b21hdGljIGNvbHVtbiB3aWR0aCBjYWxjdWxhdGlvbi4gVGhpcyBjYW4gYmUgZGlzYWJsZWRcblx0XHQgKiBhcyBhbiBvcHRpbWlzYXRpb24gKGl0IHRha2VzIHNvbWUgdGltZSB0byBjYWxjdWxhdGUgdGhlIHdpZHRocykgaWYgdGhlXG5cdFx0ICogdGFibGVzIHdpZHRocyBhcmUgcGFzc2VkIGluIHVzaW5nIGBjb2x1bW5zYC5cblx0XHQgKiAgQHR5cGUgYm9vbGVhblxuXHRcdCAqICBAZGVmYXVsdCB0cnVlXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IEZlYXR1cmVzXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5hdXRvV2lkdGhcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbiAoKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImF1dG9XaWR0aFwiOiBmYWxzZVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImJBdXRvV2lkdGhcIjogdHJ1ZSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIERlZmVycmVkIHJlbmRlcmluZyBjYW4gcHJvdmlkZSBEYXRhVGFibGVzIHdpdGggYSBodWdlIHNwZWVkIGJvb3N0IHdoZW4geW91XG5cdFx0ICogYXJlIHVzaW5nIGFuIEFqYXggb3IgSlMgZGF0YSBzb3VyY2UgZm9yIHRoZSB0YWJsZS4gVGhpcyBvcHRpb24sIHdoZW4gc2V0IHRvXG5cdFx0ICogdHJ1ZSwgd2lsbCBjYXVzZSBEYXRhVGFibGVzIHRvIGRlZmVyIHRoZSBjcmVhdGlvbiBvZiB0aGUgdGFibGUgZWxlbWVudHMgZm9yXG5cdFx0ICogZWFjaCByb3cgdW50aWwgdGhleSBhcmUgbmVlZGVkIGZvciBhIGRyYXcgLSBzYXZpbmcgYSBzaWduaWZpY2FudCBhbW91bnQgb2Zcblx0XHQgKiB0aW1lLlxuXHRcdCAqICBAdHlwZSBib29sZWFuXG5cdFx0ICogIEBkZWZhdWx0IGZhbHNlXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IEZlYXR1cmVzXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5kZWZlclJlbmRlclxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJhamF4XCI6IFwic291cmNlcy9hcnJheXMudHh0XCIsXG5cdFx0ICogICAgICAgIFwiZGVmZXJSZW5kZXJcIjogdHJ1ZVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImJEZWZlclJlbmRlclwiOiBmYWxzZSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIFJlcGxhY2UgYSBEYXRhVGFibGUgd2hpY2ggbWF0Y2hlcyB0aGUgZ2l2ZW4gc2VsZWN0b3IgYW5kIHJlcGxhY2UgaXQgd2l0aFxuXHRcdCAqIG9uZSB3aGljaCBoYXMgdGhlIHByb3BlcnRpZXMgb2YgdGhlIG5ldyBpbml0aWFsaXNhdGlvbiBvYmplY3QgcGFzc2VkLiBJZiBub1xuXHRcdCAqIHRhYmxlIG1hdGNoZXMgdGhlIHNlbGVjdG9yLCB0aGVuIHRoZSBuZXcgRGF0YVRhYmxlIHdpbGwgYmUgY29uc3RydWN0ZWQgYXNcblx0XHQgKiBwZXIgbm9ybWFsLlxuXHRcdCAqICBAdHlwZSBib29sZWFuXG5cdFx0ICogIEBkZWZhdWx0IGZhbHNlXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IE9wdGlvbnNcblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLmRlc3Ryb3lcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwic3JvbGxZXCI6IFwiMjAwcHhcIixcblx0XHQgKiAgICAgICAgXCJwYWdpbmF0ZVwiOiBmYWxzZVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqXG5cdFx0ICogICAgICAvLyBTb21lIHRpbWUgbGF0ZXIuLi4uXG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImZpbHRlclwiOiBmYWxzZSxcblx0XHQgKiAgICAgICAgXCJkZXN0cm95XCI6IHRydWVcblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJiRGVzdHJveVwiOiBmYWxzZSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIEVuYWJsZSBvciBkaXNhYmxlIGZpbHRlcmluZyBvZiBkYXRhLiBGaWx0ZXJpbmcgaW4gRGF0YVRhYmxlcyBpcyBcInNtYXJ0XCIgaW5cblx0XHQgKiB0aGF0IGl0IGFsbG93cyB0aGUgZW5kIHVzZXIgdG8gaW5wdXQgbXVsdGlwbGUgd29yZHMgKHNwYWNlIHNlcGFyYXRlZCkgYW5kXG5cdFx0ICogd2lsbCBtYXRjaCBhIHJvdyBjb250YWluaW5nIHRob3NlIHdvcmRzLCBldmVuIGlmIG5vdCBpbiB0aGUgb3JkZXIgdGhhdCB3YXNcblx0XHQgKiBzcGVjaWZpZWQgKHRoaXMgYWxsb3cgbWF0Y2hpbmcgYWNyb3NzIG11bHRpcGxlIGNvbHVtbnMpLiBOb3RlIHRoYXQgaWYgeW91XG5cdFx0ICogd2lzaCB0byB1c2UgZmlsdGVyaW5nIGluIERhdGFUYWJsZXMgdGhpcyBtdXN0IHJlbWFpbiAndHJ1ZScgLSB0byByZW1vdmUgdGhlXG5cdFx0ICogZGVmYXVsdCBmaWx0ZXJpbmcgaW5wdXQgYm94IGFuZCByZXRhaW4gZmlsdGVyaW5nIGFiaWxpdGllcywgcGxlYXNlIHVzZVxuXHRcdCAqIHtAbGluayBEYXRhVGFibGUuZGVmYXVsdHMuZG9tfS5cblx0XHQgKiAgQHR5cGUgYm9vbGVhblxuXHRcdCAqICBAZGVmYXVsdCB0cnVlXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IEZlYXR1cmVzXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5zZWFyY2hpbmdcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbiAoKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcInNlYXJjaGluZ1wiOiBmYWxzZVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImJGaWx0ZXJcIjogdHJ1ZSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIEVuYWJsZSBvciBkaXNhYmxlIHRoZSB0YWJsZSBpbmZvcm1hdGlvbiBkaXNwbGF5LiBUaGlzIHNob3dzIGluZm9ybWF0aW9uXG5cdFx0ICogYWJvdXQgdGhlIGRhdGEgdGhhdCBpcyBjdXJyZW50bHkgdmlzaWJsZSBvbiB0aGUgcGFnZSwgaW5jbHVkaW5nIGluZm9ybWF0aW9uXG5cdFx0ICogYWJvdXQgZmlsdGVyZWQgZGF0YSBpZiB0aGF0IGFjdGlvbiBpcyBiZWluZyBwZXJmb3JtZWQuXG5cdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHQgKiAgQGRlZmF1bHQgdHJ1ZVxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBGZWF0dXJlc1xuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuaW5mb1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uICgpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiaW5mb1wiOiBmYWxzZVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImJJbmZvXCI6IHRydWUsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBBbGxvd3MgdGhlIGVuZCB1c2VyIHRvIHNlbGVjdCB0aGUgc2l6ZSBvZiBhIGZvcm1hdHRlZCBwYWdlIGZyb20gYSBzZWxlY3Rcblx0XHQgKiBtZW51IChzaXplcyBhcmUgMTAsIDI1LCA1MCBhbmQgMTAwKS4gUmVxdWlyZXMgcGFnaW5hdGlvbiAoYHBhZ2luYXRlYCkuXG5cdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHQgKiAgQGRlZmF1bHQgdHJ1ZVxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBGZWF0dXJlc1xuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMubGVuZ3RoQ2hhbmdlXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24gKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJsZW5ndGhDaGFuZ2VcIjogZmFsc2Vcblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJiTGVuZ3RoQ2hhbmdlXCI6IHRydWUsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBFbmFibGUgb3IgZGlzYWJsZSBwYWdpbmF0aW9uLlxuXHRcdCAqICBAdHlwZSBib29sZWFuXG5cdFx0ICogIEBkZWZhdWx0IHRydWVcblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgRmVhdHVyZXNcblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLnBhZ2luZ1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uICgpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwicGFnaW5nXCI6IGZhbHNlXG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdFwiYlBhZ2luYXRlXCI6IHRydWUsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBFbmFibGUgb3IgZGlzYWJsZSB0aGUgZGlzcGxheSBvZiBhICdwcm9jZXNzaW5nJyBpbmRpY2F0b3Igd2hlbiB0aGUgdGFibGUgaXNcblx0XHQgKiBiZWluZyBwcm9jZXNzZWQgKGUuZy4gYSBzb3J0KS4gVGhpcyBpcyBwYXJ0aWN1bGFybHkgdXNlZnVsIGZvciB0YWJsZXMgd2l0aFxuXHRcdCAqIGxhcmdlIGFtb3VudHMgb2YgZGF0YSB3aGVyZSBpdCBjYW4gdGFrZSBhIG5vdGljZWFibGUgYW1vdW50IG9mIHRpbWUgdG8gc29ydFxuXHRcdCAqIHRoZSBlbnRyaWVzLlxuXHRcdCAqICBAdHlwZSBib29sZWFuXG5cdFx0ICogIEBkZWZhdWx0IGZhbHNlXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IEZlYXR1cmVzXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5wcm9jZXNzaW5nXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24gKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJwcm9jZXNzaW5nXCI6IHRydWVcblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJiUHJvY2Vzc2luZ1wiOiBmYWxzZSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIFJldHJpZXZlIHRoZSBEYXRhVGFibGVzIG9iamVjdCBmb3IgdGhlIGdpdmVuIHNlbGVjdG9yLiBOb3RlIHRoYXQgaWYgdGhlXG5cdFx0ICogdGFibGUgaGFzIGFscmVhZHkgYmVlbiBpbml0aWFsaXNlZCwgdGhpcyBwYXJhbWV0ZXIgd2lsbCBjYXVzZSBEYXRhVGFibGVzXG5cdFx0ICogdG8gc2ltcGx5IHJldHVybiB0aGUgb2JqZWN0IHRoYXQgaGFzIGFscmVhZHkgYmVlbiBzZXQgdXAgLSBpdCB3aWxsIG5vdCB0YWtlXG5cdFx0ICogYWNjb3VudCBvZiBhbnkgY2hhbmdlcyB5b3UgbWlnaHQgaGF2ZSBtYWRlIHRvIHRoZSBpbml0aWFsaXNhdGlvbiBvYmplY3Rcblx0XHQgKiBwYXNzZWQgdG8gRGF0YVRhYmxlcyAoc2V0dGluZyB0aGlzIHBhcmFtZXRlciB0byB0cnVlIGlzIGFuIGFja25vd2xlZGdlbWVudFxuXHRcdCAqIHRoYXQgeW91IHVuZGVyc3RhbmQgdGhpcykuIGBkZXN0cm95YCBjYW4gYmUgdXNlZCB0byByZWluaXRpYWxpc2UgYSB0YWJsZSBpZlxuXHRcdCAqIHlvdSBuZWVkLlxuXHRcdCAqICBAdHlwZSBib29sZWFuXG5cdFx0ICogIEBkZWZhdWx0IGZhbHNlXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IE9wdGlvbnNcblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLnJldHJpZXZlXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICBpbml0VGFibGUoKTtcblx0XHQgKiAgICAgIHRhYmxlQWN0aW9ucygpO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKlxuXHRcdCAqICAgIGZ1bmN0aW9uIGluaXRUYWJsZSAoKVxuXHRcdCAqICAgIHtcblx0XHQgKiAgICAgIHJldHVybiAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcInNjcm9sbFlcIjogXCIyMDBweFwiLFxuXHRcdCAqICAgICAgICBcInBhZ2luYXRlXCI6IGZhbHNlLFxuXHRcdCAqICAgICAgICBcInJldHJpZXZlXCI6IHRydWVcblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9XG5cdFx0ICpcblx0XHQgKiAgICBmdW5jdGlvbiB0YWJsZUFjdGlvbnMgKClcblx0XHQgKiAgICB7XG5cdFx0ICogICAgICB2YXIgdGFibGUgPSBpbml0VGFibGUoKTtcblx0XHQgKiAgICAgIC8vIHBlcmZvcm0gQVBJIG9wZXJhdGlvbnMgd2l0aCBvVGFibGVcblx0XHQgKiAgICB9XG5cdFx0ICovXG5cdFx0XCJiUmV0cmlldmVcIjogZmFsc2UsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBXaGVuIHZlcnRpY2FsICh5KSBzY3JvbGxpbmcgaXMgZW5hYmxlZCwgRGF0YVRhYmxlcyB3aWxsIGZvcmNlIHRoZSBoZWlnaHQgb2Zcblx0XHQgKiB0aGUgdGFibGUncyB2aWV3cG9ydCB0byB0aGUgZ2l2ZW4gaGVpZ2h0IGF0IGFsbCB0aW1lcyAodXNlZnVsIGZvciBsYXlvdXQpLlxuXHRcdCAqIEhvd2V2ZXIsIHRoaXMgY2FuIGxvb2sgb2RkIHdoZW4gZmlsdGVyaW5nIGRhdGEgZG93biB0byBhIHNtYWxsIGRhdGEgc2V0LFxuXHRcdCAqIGFuZCB0aGUgZm9vdGVyIGlzIGxlZnQgXCJmbG9hdGluZ1wiIGZ1cnRoZXIgZG93bi4gVGhpcyBwYXJhbWV0ZXIgKHdoZW5cblx0XHQgKiBlbmFibGVkKSB3aWxsIGNhdXNlIERhdGFUYWJsZXMgdG8gY29sbGFwc2UgdGhlIHRhYmxlJ3Mgdmlld3BvcnQgZG93biB3aGVuXG5cdFx0ICogdGhlIHJlc3VsdCBzZXQgd2lsbCBmaXQgd2l0aGluIHRoZSBnaXZlbiBZIGhlaWdodC5cblx0XHQgKiAgQHR5cGUgYm9vbGVhblxuXHRcdCAqICBAZGVmYXVsdCBmYWxzZVxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBPcHRpb25zXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5zY3JvbGxDb2xsYXBzZVxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJzY3JvbGxZXCI6IFwiMjAwXCIsXG5cdFx0ICogICAgICAgIFwic2Nyb2xsQ29sbGFwc2VcIjogdHJ1ZVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImJTY3JvbGxDb2xsYXBzZVwiOiBmYWxzZSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIENvbmZpZ3VyZSBEYXRhVGFibGVzIHRvIHVzZSBzZXJ2ZXItc2lkZSBwcm9jZXNzaW5nLiBOb3RlIHRoYXQgdGhlXG5cdFx0ICogYGFqYXhgIHBhcmFtZXRlciBtdXN0IGFsc28gYmUgZ2l2ZW4gaW4gb3JkZXIgdG8gZ2l2ZSBEYXRhVGFibGVzIGFcblx0XHQgKiBzb3VyY2UgdG8gb2J0YWluIHRoZSByZXF1aXJlZCBkYXRhIGZvciBlYWNoIGRyYXcuXG5cdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHQgKiAgQGRlZmF1bHQgZmFsc2Vcblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgRmVhdHVyZXNcblx0XHQgKiAgQGR0b3B0IFNlcnZlci1zaWRlXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5zZXJ2ZXJTaWRlXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24gKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJzZXJ2ZXJTaWRlXCI6IHRydWUsXG5cdFx0ICogICAgICAgIFwiYWpheFwiOiBcInhoci5waHBcIlxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImJTZXJ2ZXJTaWRlXCI6IGZhbHNlLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogRW5hYmxlIG9yIGRpc2FibGUgc29ydGluZyBvZiBjb2x1bW5zLiBTb3J0aW5nIG9mIGluZGl2aWR1YWwgY29sdW1ucyBjYW4gYmVcblx0XHQgKiBkaXNhYmxlZCBieSB0aGUgYHNvcnRhYmxlYCBvcHRpb24gZm9yIGVhY2ggY29sdW1uLlxuXHRcdCAqICBAdHlwZSBib29sZWFuXG5cdFx0ICogIEBkZWZhdWx0IHRydWVcblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgRmVhdHVyZXNcblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLm9yZGVyaW5nXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24gKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJvcmRlcmluZ1wiOiBmYWxzZVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImJTb3J0XCI6IHRydWUsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBFbmFibGUgb3IgZGlzcGxheSBEYXRhVGFibGVzJyBhYmlsaXR5IHRvIHNvcnQgbXVsdGlwbGUgY29sdW1ucyBhdCB0aGVcblx0XHQgKiBzYW1lIHRpbWUgKGFjdGl2YXRlZCBieSBzaGlmdC1jbGljayBieSB0aGUgdXNlcikuXG5cdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHQgKiAgQGRlZmF1bHQgdHJ1ZVxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBPcHRpb25zXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5vcmRlck11bHRpXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBEaXNhYmxlIG11bHRpcGxlIGNvbHVtbiBzb3J0aW5nIGFiaWxpdHlcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24gKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJvcmRlck11bHRpXCI6IGZhbHNlXG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdFwiYlNvcnRNdWx0aVwiOiB0cnVlLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogQWxsb3dzIGNvbnRyb2wgb3ZlciB3aGV0aGVyIERhdGFUYWJsZXMgc2hvdWxkIHVzZSB0aGUgdG9wICh0cnVlKSB1bmlxdWVcblx0XHQgKiBjZWxsIHRoYXQgaXMgZm91bmQgZm9yIGEgc2luZ2xlIGNvbHVtbiwgb3IgdGhlIGJvdHRvbSAoZmFsc2UgLSBkZWZhdWx0KS5cblx0XHQgKiBUaGlzIGlzIHVzZWZ1bCB3aGVuIHVzaW5nIGNvbXBsZXggaGVhZGVycy5cblx0XHQgKiAgQHR5cGUgYm9vbGVhblxuXHRcdCAqICBAZGVmYXVsdCBmYWxzZVxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBPcHRpb25zXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5vcmRlckNlbGxzVG9wXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcIm9yZGVyQ2VsbHNUb3BcIjogdHJ1ZVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImJTb3J0Q2VsbHNUb3BcIjogZmFsc2UsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBFbmFibGUgb3IgZGlzYWJsZSB0aGUgYWRkaXRpb24gb2YgdGhlIGNsYXNzZXMgYHNvcnRpbmdcXF8xYCwgYHNvcnRpbmdcXF8yYCBhbmRcblx0XHQgKiBgc29ydGluZ1xcXzNgIHRvIHRoZSBjb2x1bW5zIHdoaWNoIGFyZSBjdXJyZW50bHkgYmVpbmcgc29ydGVkIG9uLiBUaGlzIGlzXG5cdFx0ICogcHJlc2VudGVkIGFzIGEgZmVhdHVyZSBzd2l0Y2ggYXMgaXQgY2FuIGluY3JlYXNlIHByb2Nlc3NpbmcgdGltZSAod2hpbGVcblx0XHQgKiBjbGFzc2VzIGFyZSByZW1vdmVkIGFuZCBhZGRlZCkgc28gZm9yIGxhcmdlIGRhdGEgc2V0cyB5b3UgbWlnaHQgd2FudCB0b1xuXHRcdCAqIHR1cm4gdGhpcyBvZmYuXG5cdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHQgKiAgQGRlZmF1bHQgdHJ1ZVxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBGZWF0dXJlc1xuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMub3JkZXJDbGFzc2VzXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24gKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJvcmRlckNsYXNzZXNcIjogZmFsc2Vcblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJiU29ydENsYXNzZXNcIjogdHJ1ZSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIEVuYWJsZSBvciBkaXNhYmxlIHN0YXRlIHNhdmluZy4gV2hlbiBlbmFibGVkIEhUTUw1IGBsb2NhbFN0b3JhZ2VgIHdpbGwgYmVcblx0XHQgKiB1c2VkIHRvIHNhdmUgdGFibGUgZGlzcGxheSBpbmZvcm1hdGlvbiBzdWNoIGFzIHBhZ2luYXRpb24gaW5mb3JtYXRpb24sXG5cdFx0ICogZGlzcGxheSBsZW5ndGgsIGZpbHRlcmluZyBhbmQgc29ydGluZy4gQXMgc3VjaCB3aGVuIHRoZSBlbmQgdXNlciByZWxvYWRzXG5cdFx0ICogdGhlIHBhZ2UgdGhlIGRpc3BsYXkgZGlzcGxheSB3aWxsIG1hdGNoIHdoYXQgdGh5IGhhZCBwcmV2aW91c2x5IHNldCB1cC5cblx0XHQgKlxuXHRcdCAqIER1ZSB0byB0aGUgdXNlIG9mIGBsb2NhbFN0b3JhZ2VgIHRoZSBkZWZhdWx0IHN0YXRlIHNhdmluZyBpcyBub3Qgc3VwcG9ydGVkXG5cdFx0ICogaW4gSUU2IG9yIDcuIElmIHN0YXRlIHNhdmluZyBpcyByZXF1aXJlZCBpbiB0aG9zZSBicm93c2VycywgdXNlXG5cdFx0ICogYHN0YXRlU2F2ZUNhbGxiYWNrYCB0byBwcm92aWRlIGEgc3RvcmFnZSBzb2x1dGlvbiBzdWNoIGFzIGNvb2tpZXMuXG5cdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHQgKiAgQGRlZmF1bHQgZmFsc2Vcblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgRmVhdHVyZXNcblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLnN0YXRlU2F2ZVxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uICgpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwic3RhdGVTYXZlXCI6IHRydWVcblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJiU3RhdGVTYXZlXCI6IGZhbHNlLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogVGhpcyBmdW5jdGlvbiBpcyBjYWxsZWQgd2hlbiBhIFRSIGVsZW1lbnQgaXMgY3JlYXRlZCAoYW5kIGFsbCBURCBjaGlsZFxuXHRcdCAqIGVsZW1lbnRzIGhhdmUgYmVlbiBpbnNlcnRlZCksIG9yIHJlZ2lzdGVyZWQgaWYgdXNpbmcgYSBET00gc291cmNlLCBhbGxvd2luZ1xuXHRcdCAqIG1hbmlwdWxhdGlvbiBvZiB0aGUgVFIgZWxlbWVudCAoYWRkaW5nIGNsYXNzZXMgZXRjKS5cblx0XHQgKiAgQHR5cGUgZnVuY3Rpb25cblx0XHQgKiAgQHBhcmFtIHtub2RlfSByb3cgXCJUUlwiIGVsZW1lbnQgZm9yIHRoZSBjdXJyZW50IHJvd1xuXHRcdCAqICBAcGFyYW0ge2FycmF5fSBkYXRhIFJhdyBkYXRhIGFycmF5IGZvciB0aGlzIHJvd1xuXHRcdCAqICBAcGFyYW0ge2ludH0gZGF0YUluZGV4IFRoZSBpbmRleCBvZiB0aGlzIHJvdyBpbiB0aGUgaW50ZXJuYWwgYW9EYXRhIGFycmF5XG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IENhbGxiYWNrc1xuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuY3JlYXRlZFJvd1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJjcmVhdGVkUm93XCI6IGZ1bmN0aW9uKCByb3csIGRhdGEsIGRhdGFJbmRleCApIHtcblx0XHQgKiAgICAgICAgICAvLyBCb2xkIHRoZSBncmFkZSBmb3IgYWxsICdBJyBncmFkZSBicm93c2Vyc1xuXHRcdCAqICAgICAgICAgIGlmICggZGF0YVs0XSA9PSBcIkFcIiApXG5cdFx0ICogICAgICAgICAge1xuXHRcdCAqICAgICAgICAgICAgJCgndGQ6ZXEoNCknLCByb3cpLmh0bWwoICc8Yj5BPC9iPicgKTtcblx0XHQgKiAgICAgICAgICB9XG5cdFx0ICogICAgICAgIH1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJmbkNyZWF0ZWRSb3dcIjogbnVsbCxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIFRoaXMgZnVuY3Rpb24gaXMgY2FsbGVkIG9uIGV2ZXJ5ICdkcmF3JyBldmVudCwgYW5kIGFsbG93cyB5b3UgdG9cblx0XHQgKiBkeW5hbWljYWxseSBtb2RpZnkgYW55IGFzcGVjdCB5b3Ugd2FudCBhYm91dCB0aGUgY3JlYXRlZCBET00uXG5cdFx0ICogIEB0eXBlIGZ1bmN0aW9uXG5cdFx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBEYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBDYWxsYmFja3Ncblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLmRyYXdDYWxsYmFja1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJkcmF3Q2FsbGJhY2tcIjogZnVuY3Rpb24oIHNldHRpbmdzICkge1xuXHRcdCAqICAgICAgICAgIGFsZXJ0KCAnRGF0YVRhYmxlcyBoYXMgcmVkcmF3biB0aGUgdGFibGUnICk7XG5cdFx0ICogICAgICAgIH1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJmbkRyYXdDYWxsYmFja1wiOiBudWxsLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogSWRlbnRpY2FsIHRvIGZuSGVhZGVyQ2FsbGJhY2soKSBidXQgZm9yIHRoZSB0YWJsZSBmb290ZXIgdGhpcyBmdW5jdGlvblxuXHRcdCAqIGFsbG93cyB5b3UgdG8gbW9kaWZ5IHRoZSB0YWJsZSBmb290ZXIgb24gZXZlcnkgJ2RyYXcnIGV2ZW50LlxuXHRcdCAqICBAdHlwZSBmdW5jdGlvblxuXHRcdCAqICBAcGFyYW0ge25vZGV9IGZvb3QgXCJUUlwiIGVsZW1lbnQgZm9yIHRoZSBmb290ZXJcblx0XHQgKiAgQHBhcmFtIHthcnJheX0gZGF0YSBGdWxsIHRhYmxlIGRhdGEgKGFzIGRlcml2ZWQgZnJvbSB0aGUgb3JpZ2luYWwgSFRNTClcblx0XHQgKiAgQHBhcmFtIHtpbnR9IHN0YXJ0IEluZGV4IGZvciB0aGUgY3VycmVudCBkaXNwbGF5IHN0YXJ0aW5nIHBvaW50IGluIHRoZVxuXHRcdCAqICAgIGRpc3BsYXkgYXJyYXlcblx0XHQgKiAgQHBhcmFtIHtpbnR9IGVuZCBJbmRleCBmb3IgdGhlIGN1cnJlbnQgZGlzcGxheSBlbmRpbmcgcG9pbnQgaW4gdGhlXG5cdFx0ICogICAgZGlzcGxheSBhcnJheVxuXHRcdCAqICBAcGFyYW0ge2FycmF5IGludH0gZGlzcGxheSBJbmRleCBhcnJheSB0byB0cmFuc2xhdGUgdGhlIHZpc3VhbCBwb3NpdGlvblxuXHRcdCAqICAgIHRvIHRoZSBmdWxsIGRhdGEgYXJyYXlcblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgQ2FsbGJhY2tzXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5mb290ZXJDYWxsYmFja1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJmb290ZXJDYWxsYmFja1wiOiBmdW5jdGlvbiggdGZvb3QsIGRhdGEsIHN0YXJ0LCBlbmQsIGRpc3BsYXkgKSB7XG5cdFx0ICogICAgICAgICAgdGZvb3QuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3RoJylbMF0uaW5uZXJIVE1MID0gXCJTdGFydGluZyBpbmRleCBpcyBcIitzdGFydDtcblx0XHQgKiAgICAgICAgfVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKVxuXHRcdCAqL1xuXHRcdFwiZm5Gb290ZXJDYWxsYmFja1wiOiBudWxsLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogV2hlbiByZW5kZXJpbmcgbGFyZ2UgbnVtYmVycyBpbiB0aGUgaW5mb3JtYXRpb24gZWxlbWVudCBmb3IgdGhlIHRhYmxlXG5cdFx0ICogKGkuZS4gXCJTaG93aW5nIDEgdG8gMTAgb2YgNTcgZW50cmllc1wiKSBEYXRhVGFibGVzIHdpbGwgcmVuZGVyIGxhcmdlIG51bWJlcnNcblx0XHQgKiB0byBoYXZlIGEgY29tbWEgc2VwYXJhdG9yIGZvciB0aGUgJ3Rob3VzYW5kcycgdW5pdHMgKGUuZy4gMSBtaWxsaW9uIGlzXG5cdFx0ICogcmVuZGVyZWQgYXMgXCIxLDAwMCwwMDBcIikgdG8gaGVscCByZWFkYWJpbGl0eSBmb3IgdGhlIGVuZCB1c2VyLiBUaGlzXG5cdFx0ICogZnVuY3Rpb24gd2lsbCBvdmVycmlkZSB0aGUgZGVmYXVsdCBtZXRob2QgRGF0YVRhYmxlcyB1c2VzLlxuXHRcdCAqICBAdHlwZSBmdW5jdGlvblxuXHRcdCAqICBAbWVtYmVyXG5cdFx0ICogIEBwYXJhbSB7aW50fSB0b0Zvcm1hdCBudW1iZXIgdG8gYmUgZm9ybWF0dGVkXG5cdFx0ICogIEByZXR1cm5zIHtzdHJpbmd9IGZvcm1hdHRlZCBzdHJpbmcgZm9yIERhdGFUYWJsZXMgdG8gc2hvdyB0aGUgbnVtYmVyXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IENhbGxiYWNrc1xuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuZm9ybWF0TnVtYmVyXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBGb3JtYXQgYSBudW1iZXIgdXNpbmcgYSBzaW5nbGUgcXVvdGUgZm9yIHRoZSBzZXBhcmF0b3IgKG5vdGUgdGhhdFxuXHRcdCAqICAgIC8vIHRoaXMgY2FuIGFsc28gYmUgZG9uZSB3aXRoIHRoZSBsYW5ndWFnZS50aG91c2FuZHMgb3B0aW9uKVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiZm9ybWF0TnVtYmVyXCI6IGZ1bmN0aW9uICggdG9Gb3JtYXQgKSB7XG5cdFx0ICogICAgICAgICAgcmV0dXJuIHRvRm9ybWF0LnRvU3RyaW5nKCkucmVwbGFjZShcblx0XHQgKiAgICAgICAgICAgIC9cXEIoPz0oXFxkezN9KSsoPyFcXGQpKS9nLCBcIidcIlxuXHRcdCAqICAgICAgICAgICk7XG5cdFx0ICogICAgICAgIH07XG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdFwiZm5Gb3JtYXROdW1iZXJcIjogZnVuY3Rpb24gKCB0b0Zvcm1hdCApIHtcblx0XHRcdHJldHVybiB0b0Zvcm1hdC50b1N0cmluZygpLnJlcGxhY2UoXG5cdFx0XHRcdC9cXEIoPz0oXFxkezN9KSsoPyFcXGQpKS9nLFxuXHRcdFx0XHR0aGlzLm9MYW5ndWFnZS5zVGhvdXNhbmRzXG5cdFx0XHQpO1xuXHRcdH0sXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBUaGlzIGZ1bmN0aW9uIGlzIGNhbGxlZCBvbiBldmVyeSAnZHJhdycgZXZlbnQsIGFuZCBhbGxvd3MgeW91IHRvXG5cdFx0ICogZHluYW1pY2FsbHkgbW9kaWZ5IHRoZSBoZWFkZXIgcm93LiBUaGlzIGNhbiBiZSB1c2VkIHRvIGNhbGN1bGF0ZSBhbmRcblx0XHQgKiBkaXNwbGF5IHVzZWZ1bCBpbmZvcm1hdGlvbiBhYm91dCB0aGUgdGFibGUuXG5cdFx0ICogIEB0eXBlIGZ1bmN0aW9uXG5cdFx0ICogIEBwYXJhbSB7bm9kZX0gaGVhZCBcIlRSXCIgZWxlbWVudCBmb3IgdGhlIGhlYWRlclxuXHRcdCAqICBAcGFyYW0ge2FycmF5fSBkYXRhIEZ1bGwgdGFibGUgZGF0YSAoYXMgZGVyaXZlZCBmcm9tIHRoZSBvcmlnaW5hbCBIVE1MKVxuXHRcdCAqICBAcGFyYW0ge2ludH0gc3RhcnQgSW5kZXggZm9yIHRoZSBjdXJyZW50IGRpc3BsYXkgc3RhcnRpbmcgcG9pbnQgaW4gdGhlXG5cdFx0ICogICAgZGlzcGxheSBhcnJheVxuXHRcdCAqICBAcGFyYW0ge2ludH0gZW5kIEluZGV4IGZvciB0aGUgY3VycmVudCBkaXNwbGF5IGVuZGluZyBwb2ludCBpbiB0aGVcblx0XHQgKiAgICBkaXNwbGF5IGFycmF5XG5cdFx0ICogIEBwYXJhbSB7YXJyYXkgaW50fSBkaXNwbGF5IEluZGV4IGFycmF5IHRvIHRyYW5zbGF0ZSB0aGUgdmlzdWFsIHBvc2l0aW9uXG5cdFx0ICogICAgdG8gdGhlIGZ1bGwgZGF0YSBhcnJheVxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBDYWxsYmFja3Ncblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLmhlYWRlckNhbGxiYWNrXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImZoZWFkZXJDYWxsYmFja1wiOiBmdW5jdGlvbiggaGVhZCwgZGF0YSwgc3RhcnQsIGVuZCwgZGlzcGxheSApIHtcblx0XHQgKiAgICAgICAgICBoZWFkLmdldEVsZW1lbnRzQnlUYWdOYW1lKCd0aCcpWzBdLmlubmVySFRNTCA9IFwiRGlzcGxheWluZyBcIisoZW5kLXN0YXJ0KStcIiByZWNvcmRzXCI7XG5cdFx0ICogICAgICAgIH1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9IClcblx0XHQgKi9cblx0XHRcImZuSGVhZGVyQ2FsbGJhY2tcIjogbnVsbCxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIFRoZSBpbmZvcm1hdGlvbiBlbGVtZW50IGNhbiBiZSB1c2VkIHRvIGNvbnZleSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY3VycmVudFxuXHRcdCAqIHN0YXRlIG9mIHRoZSB0YWJsZS4gQWx0aG91Z2ggdGhlIGludGVybmF0aW9uYWxpc2F0aW9uIG9wdGlvbnMgcHJlc2VudGVkIGJ5XG5cdFx0ICogRGF0YVRhYmxlcyBhcmUgcXVpdGUgY2FwYWJsZSBvZiBkZWFsaW5nIHdpdGggbW9zdCBjdXN0b21pc2F0aW9ucywgdGhlcmUgbWF5XG5cdFx0ICogYmUgdGltZXMgd2hlcmUgeW91IHdpc2ggdG8gY3VzdG9taXNlIHRoZSBzdHJpbmcgZnVydGhlci4gVGhpcyBjYWxsYmFja1xuXHRcdCAqIGFsbG93cyB5b3UgdG8gZG8gZXhhY3RseSB0aGF0LlxuXHRcdCAqICBAdHlwZSBmdW5jdGlvblxuXHRcdCAqICBAcGFyYW0ge29iamVjdH0gb1NldHRpbmdzIERhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdFx0ICogIEBwYXJhbSB7aW50fSBzdGFydCBTdGFydGluZyBwb3NpdGlvbiBpbiBkYXRhIGZvciB0aGUgZHJhd1xuXHRcdCAqICBAcGFyYW0ge2ludH0gZW5kIEVuZCBwb3NpdGlvbiBpbiBkYXRhIGZvciB0aGUgZHJhd1xuXHRcdCAqICBAcGFyYW0ge2ludH0gbWF4IFRvdGFsIG51bWJlciBvZiByb3dzIGluIHRoZSB0YWJsZSAocmVnYXJkbGVzcyBvZlxuXHRcdCAqICAgIGZpbHRlcmluZylcblx0XHQgKiAgQHBhcmFtIHtpbnR9IHRvdGFsIFRvdGFsIG51bWJlciBvZiByb3dzIGluIHRoZSBkYXRhIHNldCwgYWZ0ZXIgZmlsdGVyaW5nXG5cdFx0ICogIEBwYXJhbSB7c3RyaW5nfSBwcmUgVGhlIHN0cmluZyB0aGF0IERhdGFUYWJsZXMgaGFzIGZvcm1hdHRlZCB1c2luZyBpdCdzXG5cdFx0ICogICAgb3duIHJ1bGVzXG5cdFx0ICogIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzdHJpbmcgdG8gYmUgZGlzcGxheWVkIGluIHRoZSBpbmZvcm1hdGlvbiBlbGVtZW50LlxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBDYWxsYmFja3Ncblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLmluZm9DYWxsYmFja1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgIFwiaW5mb0NhbGxiYWNrXCI6IGZ1bmN0aW9uKCBzZXR0aW5ncywgc3RhcnQsIGVuZCwgbWF4LCB0b3RhbCwgcHJlICkge1xuXHRcdCAqICAgICAgICByZXR1cm4gc3RhcnQgK1wiIHRvIFwiKyBlbmQ7XG5cdFx0ICogICAgICB9XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdFwiZm5JbmZvQ2FsbGJhY2tcIjogbnVsbCxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIENhbGxlZCB3aGVuIHRoZSB0YWJsZSBoYXMgYmVlbiBpbml0aWFsaXNlZC4gTm9ybWFsbHkgRGF0YVRhYmxlcyB3aWxsXG5cdFx0ICogaW5pdGlhbGlzZSBzZXF1ZW50aWFsbHkgYW5kIHRoZXJlIHdpbGwgYmUgbm8gbmVlZCBmb3IgdGhpcyBmdW5jdGlvbixcblx0XHQgKiBob3dldmVyLCB0aGlzIGRvZXMgbm90IGhvbGQgdHJ1ZSB3aGVuIHVzaW5nIGV4dGVybmFsIGxhbmd1YWdlIGluZm9ybWF0aW9uXG5cdFx0ICogc2luY2UgdGhhdCBpcyBvYnRhaW5lZCB1c2luZyBhbiBhc3luYyBYSFIgY2FsbC5cblx0XHQgKiAgQHR5cGUgZnVuY3Rpb25cblx0XHQgKiAgQHBhcmFtIHtvYmplY3R9IHNldHRpbmdzIERhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdFx0ICogIEBwYXJhbSB7b2JqZWN0fSBqc29uIFRoZSBKU09OIG9iamVjdCByZXF1ZXN0IGZyb20gdGhlIHNlcnZlciAtIG9ubHlcblx0XHQgKiAgICBwcmVzZW50IGlmIGNsaWVudC1zaWRlIEFqYXggc291cmNlZCBkYXRhIGlzIHVzZWRcblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgQ2FsbGJhY2tzXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5pbml0Q29tcGxldGVcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiaW5pdENvbXBsZXRlXCI6IGZ1bmN0aW9uKHNldHRpbmdzLCBqc29uKSB7XG5cdFx0ICogICAgICAgICAgYWxlcnQoICdEYXRhVGFibGVzIGhhcyBmaW5pc2hlZCBpdHMgaW5pdGlhbGlzYXRpb24uJyApO1xuXHRcdCAqICAgICAgICB9XG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApXG5cdFx0ICovXG5cdFx0XCJmbkluaXRDb21wbGV0ZVwiOiBudWxsLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogQ2FsbGVkIGF0IHRoZSB2ZXJ5IHN0YXJ0IG9mIGVhY2ggdGFibGUgZHJhdyBhbmQgY2FuIGJlIHVzZWQgdG8gY2FuY2VsIHRoZVxuXHRcdCAqIGRyYXcgYnkgcmV0dXJuaW5nIGZhbHNlLCBhbnkgb3RoZXIgcmV0dXJuIChpbmNsdWRpbmcgdW5kZWZpbmVkKSByZXN1bHRzIGluXG5cdFx0ICogdGhlIGZ1bGwgZHJhdyBvY2N1cnJpbmcpLlxuXHRcdCAqICBAdHlwZSBmdW5jdGlvblxuXHRcdCAqICBAcGFyYW0ge29iamVjdH0gc2V0dGluZ3MgRGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0XHQgKiAgQHJldHVybnMge2Jvb2xlYW59IEZhbHNlIHdpbGwgY2FuY2VsIHRoZSBkcmF3LCBhbnl0aGluZyBlbHNlIChpbmNsdWRpbmcgbm9cblx0XHQgKiAgICByZXR1cm4pIHdpbGwgYWxsb3cgaXQgdG8gY29tcGxldGUuXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IENhbGxiYWNrc1xuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMucHJlRHJhd0NhbGxiYWNrXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcInByZURyYXdDYWxsYmFja1wiOiBmdW5jdGlvbiggc2V0dGluZ3MgKSB7XG5cdFx0ICogICAgICAgICAgaWYgKCAkKCcjdGVzdCcpLnZhbCgpID09IDEgKSB7XG5cdFx0ICogICAgICAgICAgICByZXR1cm4gZmFsc2U7XG5cdFx0ICogICAgICAgICAgfVxuXHRcdCAqICAgICAgICB9XG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdFwiZm5QcmVEcmF3Q2FsbGJhY2tcIjogbnVsbCxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIFRoaXMgZnVuY3Rpb24gYWxsb3dzIHlvdSB0byAncG9zdCBwcm9jZXNzJyBlYWNoIHJvdyBhZnRlciBpdCBoYXZlIGJlZW5cblx0XHQgKiBnZW5lcmF0ZWQgZm9yIGVhY2ggdGFibGUgZHJhdywgYnV0IGJlZm9yZSBpdCBpcyByZW5kZXJlZCBvbiBzY3JlZW4uIFRoaXNcblx0XHQgKiBmdW5jdGlvbiBtaWdodCBiZSB1c2VkIGZvciBzZXR0aW5nIHRoZSByb3cgY2xhc3MgbmFtZSBldGMuXG5cdFx0ICogIEB0eXBlIGZ1bmN0aW9uXG5cdFx0ICogIEBwYXJhbSB7bm9kZX0gcm93IFwiVFJcIiBlbGVtZW50IGZvciB0aGUgY3VycmVudCByb3dcblx0XHQgKiAgQHBhcmFtIHthcnJheX0gZGF0YSBSYXcgZGF0YSBhcnJheSBmb3IgdGhpcyByb3dcblx0XHQgKiAgQHBhcmFtIHtpbnR9IGRpc3BsYXlJbmRleCBUaGUgZGlzcGxheSBpbmRleCBmb3IgdGhlIGN1cnJlbnQgdGFibGUgZHJhd1xuXHRcdCAqICBAcGFyYW0ge2ludH0gZGlzcGxheUluZGV4RnVsbCBUaGUgaW5kZXggb2YgdGhlIGRhdGEgaW4gdGhlIGZ1bGwgbGlzdCBvZlxuXHRcdCAqICAgIHJvd3MgKGFmdGVyIGZpbHRlcmluZylcblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgQ2FsbGJhY2tzXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5yb3dDYWxsYmFja1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJyb3dDYWxsYmFja1wiOiBmdW5jdGlvbiggcm93LCBkYXRhLCBkaXNwbGF5SW5kZXgsIGRpc3BsYXlJbmRleEZ1bGwgKSB7XG5cdFx0ICogICAgICAgICAgLy8gQm9sZCB0aGUgZ3JhZGUgZm9yIGFsbCAnQScgZ3JhZGUgYnJvd3NlcnNcblx0XHQgKiAgICAgICAgICBpZiAoIGRhdGFbNF0gPT0gXCJBXCIgKSB7XG5cdFx0ICogICAgICAgICAgICAkKCd0ZDplcSg0KScsIHJvdykuaHRtbCggJzxiPkE8L2I+JyApO1xuXHRcdCAqICAgICAgICAgIH1cblx0XHQgKiAgICAgICAgfVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImZuUm93Q2FsbGJhY2tcIjogbnVsbCxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIF9fRGVwcmVjYXRlZF9fIFRoZSBmdW5jdGlvbmFsaXR5IHByb3ZpZGVkIGJ5IHRoaXMgcGFyYW1ldGVyIGhhcyBub3cgYmVlblxuXHRcdCAqIHN1cGVyc2VkZWQgYnkgdGhhdCBwcm92aWRlZCB0aHJvdWdoIGBhamF4YCwgd2hpY2ggc2hvdWxkIGJlIHVzZWQgaW5zdGVhZC5cblx0XHQgKlxuXHRcdCAqIFRoaXMgcGFyYW1ldGVyIGFsbG93cyB5b3UgdG8gb3ZlcnJpZGUgdGhlIGRlZmF1bHQgZnVuY3Rpb24gd2hpY2ggb2J0YWluc1xuXHRcdCAqIHRoZSBkYXRhIGZyb20gdGhlIHNlcnZlciBzbyBzb21ldGhpbmcgbW9yZSBzdWl0YWJsZSBmb3IgeW91ciBhcHBsaWNhdGlvbi5cblx0XHQgKiBGb3IgZXhhbXBsZSB5b3UgY291bGQgdXNlIFBPU1QgZGF0YSwgb3IgcHVsbCBpbmZvcm1hdGlvbiBmcm9tIGEgR2VhcnMgb3Jcblx0XHQgKiBBSVIgZGF0YWJhc2UuXG5cdFx0ICogIEB0eXBlIGZ1bmN0aW9uXG5cdFx0ICogIEBtZW1iZXJcblx0XHQgKiAgQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSBIVFRQIHNvdXJjZSB0byBvYnRhaW4gdGhlIGRhdGEgZnJvbSAoYGFqYXhgKVxuXHRcdCAqICBAcGFyYW0ge2FycmF5fSBkYXRhIEEga2V5L3ZhbHVlIHBhaXIgb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGRhdGEgdG8gc2VuZFxuXHRcdCAqICAgIHRvIHRoZSBzZXJ2ZXJcblx0XHQgKiAgQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2sgdG8gYmUgY2FsbGVkIG9uIGNvbXBsZXRpb24gb2YgdGhlIGRhdGEgZ2V0XG5cdFx0ICogICAgcHJvY2VzcyB0aGF0IHdpbGwgZHJhdyB0aGUgZGF0YSBvbiB0aGUgcGFnZS5cblx0XHQgKiAgQHBhcmFtIHtvYmplY3R9IHNldHRpbmdzIERhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IENhbGxiYWNrc1xuXHRcdCAqICBAZHRvcHQgU2VydmVyLXNpZGVcblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLnNlcnZlckRhdGFcblx0XHQgKlxuXHRcdCAqICBAZGVwcmVjYXRlZCAxLjEwLiBQbGVhc2UgdXNlIGBhamF4YCBmb3IgdGhpcyBmdW5jdGlvbmFsaXR5IG5vdy5cblx0XHQgKi9cblx0XHRcImZuU2VydmVyRGF0YVwiOiBudWxsLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogX19EZXByZWNhdGVkX18gVGhlIGZ1bmN0aW9uYWxpdHkgcHJvdmlkZWQgYnkgdGhpcyBwYXJhbWV0ZXIgaGFzIG5vdyBiZWVuXG5cdFx0ICogc3VwZXJzZWRlZCBieSB0aGF0IHByb3ZpZGVkIHRocm91Z2ggYGFqYXhgLCB3aGljaCBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkLlxuXHRcdCAqXG5cdFx0ICogIEl0IGlzIG9mdGVuIHVzZWZ1bCB0byBzZW5kIGV4dHJhIGRhdGEgdG8gdGhlIHNlcnZlciB3aGVuIG1ha2luZyBhbiBBamF4XG5cdFx0ICogcmVxdWVzdCAtIGZvciBleGFtcGxlIGN1c3RvbSBmaWx0ZXJpbmcgaW5mb3JtYXRpb24sIGFuZCB0aGlzIGNhbGxiYWNrXG5cdFx0ICogZnVuY3Rpb24gbWFrZXMgaXQgdHJpdmlhbCB0byBzZW5kIGV4dHJhIGluZm9ybWF0aW9uIHRvIHRoZSBzZXJ2ZXIuIFRoZVxuXHRcdCAqIHBhc3NlZCBpbiBwYXJhbWV0ZXIgaXMgdGhlIGRhdGEgc2V0IHRoYXQgaGFzIGJlZW4gY29uc3RydWN0ZWQgYnlcblx0XHQgKiBEYXRhVGFibGVzLCBhbmQgeW91IGNhbiBhZGQgdG8gdGhpcyBvciBtb2RpZnkgaXQgYXMgeW91IHJlcXVpcmUuXG5cdFx0ICogIEB0eXBlIGZ1bmN0aW9uXG5cdFx0ICogIEBwYXJhbSB7YXJyYXl9IGRhdGEgRGF0YSBhcnJheSAoYXJyYXkgb2Ygb2JqZWN0cyB3aGljaCBhcmUgbmFtZS92YWx1ZVxuXHRcdCAqICAgIHBhaXJzKSB0aGF0IGhhcyBiZWVuIGNvbnN0cnVjdGVkIGJ5IERhdGFUYWJsZXMgYW5kIHdpbGwgYmUgc2VudCB0byB0aGVcblx0XHQgKiAgICBzZXJ2ZXIuIEluIHRoZSBjYXNlIG9mIEFqYXggc291cmNlZCBkYXRhIHdpdGggc2VydmVyLXNpZGUgcHJvY2Vzc2luZ1xuXHRcdCAqICAgIHRoaXMgd2lsbCBiZSBhbiBlbXB0eSBhcnJheSwgZm9yIHNlcnZlci1zaWRlIHByb2Nlc3NpbmcgdGhlcmUgd2lsbCBiZSBhXG5cdFx0ICogICAgc2lnbmlmaWNhbnQgbnVtYmVyIG9mIHBhcmFtZXRlcnMhXG5cdFx0ICogIEByZXR1cm5zIHt1bmRlZmluZWR9IEVuc3VyZSB0aGF0IHlvdSBtb2RpZnkgdGhlIGRhdGEgYXJyYXkgcGFzc2VkIGluLFxuXHRcdCAqICAgIGFzIHRoaXMgaXMgcGFzc2VkIGJ5IHJlZmVyZW5jZS5cblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgQ2FsbGJhY2tzXG5cdFx0ICogIEBkdG9wdCBTZXJ2ZXItc2lkZVxuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuc2VydmVyUGFyYW1zXG5cdFx0ICpcblx0XHQgKiAgQGRlcHJlY2F0ZWQgMS4xMC4gUGxlYXNlIHVzZSBgYWpheGAgZm9yIHRoaXMgZnVuY3Rpb25hbGl0eSBub3cuXG5cdFx0ICovXG5cdFx0XCJmblNlcnZlclBhcmFtc1wiOiBudWxsLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogTG9hZCB0aGUgdGFibGUgc3RhdGUuIFdpdGggdGhpcyBmdW5jdGlvbiB5b3UgY2FuIGRlZmluZSBmcm9tIHdoZXJlLCBhbmQgaG93LCB0aGVcblx0XHQgKiBzdGF0ZSBvZiBhIHRhYmxlIGlzIGxvYWRlZC4gQnkgZGVmYXVsdCBEYXRhVGFibGVzIHdpbGwgbG9hZCBmcm9tIGBsb2NhbFN0b3JhZ2VgXG5cdFx0ICogYnV0IHlvdSBtaWdodCB3aXNoIHRvIHVzZSBhIHNlcnZlci1zaWRlIGRhdGFiYXNlIG9yIGNvb2tpZXMuXG5cdFx0ICogIEB0eXBlIGZ1bmN0aW9uXG5cdFx0ICogIEBtZW1iZXJcblx0XHQgKiAgQHBhcmFtIHtvYmplY3R9IHNldHRpbmdzIERhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0XG5cdFx0ICogIEBwYXJhbSB7b2JqZWN0fSBjYWxsYmFjayBDYWxsYmFjayB0aGF0IGNhbiBiZSBleGVjdXRlZCB3aGVuIGRvbmUuIEl0XG5cdFx0ICogICAgc2hvdWxkIGJlIHBhc3NlZCB0aGUgbG9hZGVkIHN0YXRlIG9iamVjdC5cblx0XHQgKiAgQHJldHVybiB7b2JqZWN0fSBUaGUgRGF0YVRhYmxlcyBzdGF0ZSBvYmplY3QgdG8gYmUgbG9hZGVkXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IENhbGxiYWNrc1xuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuc3RhdGVMb2FkQ2FsbGJhY2tcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwic3RhdGVTYXZlXCI6IHRydWUsXG5cdFx0ICogICAgICAgIFwic3RhdGVMb2FkQ2FsbGJhY2tcIjogZnVuY3Rpb24gKHNldHRpbmdzLCBjYWxsYmFjaykge1xuXHRcdCAqICAgICAgICAgICQuYWpheCgge1xuXHRcdCAqICAgICAgICAgICAgXCJ1cmxcIjogXCIvc3RhdGVfbG9hZFwiLFxuXHRcdCAqICAgICAgICAgICAgXCJkYXRhVHlwZVwiOiBcImpzb25cIixcblx0XHQgKiAgICAgICAgICAgIFwic3VjY2Vzc1wiOiBmdW5jdGlvbiAoanNvbikge1xuXHRcdCAqICAgICAgICAgICAgICBjYWxsYmFjaygganNvbiApO1xuXHRcdCAqICAgICAgICAgICAgfVxuXHRcdCAqICAgICAgICAgIH0gKTtcblx0XHQgKiAgICAgICAgfVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImZuU3RhdGVMb2FkQ2FsbGJhY2tcIjogZnVuY3Rpb24gKCBzZXR0aW5ncyApIHtcblx0XHRcdHRyeSB7XG5cdFx0XHRcdHJldHVybiBKU09OLnBhcnNlKFxuXHRcdFx0XHRcdChzZXR0aW5ncy5pU3RhdGVEdXJhdGlvbiA9PT0gLTEgPyBzZXNzaW9uU3RvcmFnZSA6IGxvY2FsU3RvcmFnZSkuZ2V0SXRlbShcblx0XHRcdFx0XHRcdCdEYXRhVGFibGVzXycrc2V0dGluZ3Muc0luc3RhbmNlKydfJytsb2NhdGlvbi5wYXRobmFtZVxuXHRcdFx0XHRcdClcblx0XHRcdFx0KTtcblx0XHRcdH0gY2F0Y2ggKGUpIHtcblx0XHRcdFx0cmV0dXJuIHt9O1xuXHRcdFx0fVxuXHRcdH0sXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBDYWxsYmFjayB3aGljaCBhbGxvd3MgbW9kaWZpY2F0aW9uIG9mIHRoZSBzYXZlZCBzdGF0ZSBwcmlvciB0byBsb2FkaW5nIHRoYXQgc3RhdGUuXG5cdFx0ICogVGhpcyBjYWxsYmFjayBpcyBjYWxsZWQgd2hlbiB0aGUgdGFibGUgaXMgbG9hZGluZyBzdGF0ZSBmcm9tIHRoZSBzdG9yZWQgZGF0YSwgYnV0XG5cdFx0ICogcHJpb3IgdG8gdGhlIHNldHRpbmdzIG9iamVjdCBiZWluZyBtb2RpZmllZCBieSB0aGUgc2F2ZWQgc3RhdGUuIE5vdGUgdGhhdCBmb3Jcblx0XHQgKiBwbHVnLWluIGF1dGhvcnMsIHlvdSBzaG91bGQgdXNlIHRoZSBgc3RhdGVMb2FkUGFyYW1zYCBldmVudCB0byBsb2FkIHBhcmFtZXRlcnMgZm9yXG5cdFx0ICogYSBwbHVnLWluLlxuXHRcdCAqICBAdHlwZSBmdW5jdGlvblxuXHRcdCAqICBAcGFyYW0ge29iamVjdH0gc2V0dGluZ3MgRGF0YVRhYmxlcyBzZXR0aW5ncyBvYmplY3Rcblx0XHQgKiAgQHBhcmFtIHtvYmplY3R9IGRhdGEgVGhlIHN0YXRlIG9iamVjdCB0aGF0IGlzIHRvIGJlIGxvYWRlZFxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBDYWxsYmFja3Ncblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLnN0YXRlTG9hZFBhcmFtc1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgLy8gUmVtb3ZlIGEgc2F2ZWQgZmlsdGVyLCBzbyBmaWx0ZXJpbmcgaXMgbmV2ZXIgbG9hZGVkXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJzdGF0ZVNhdmVcIjogdHJ1ZSxcblx0XHQgKiAgICAgICAgXCJzdGF0ZUxvYWRQYXJhbXNcIjogZnVuY3Rpb24gKHNldHRpbmdzLCBkYXRhKSB7XG5cdFx0ICogICAgICAgICAgZGF0YS5vU2VhcmNoLnNTZWFyY2ggPSBcIlwiO1xuXHRcdCAqICAgICAgICB9XG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgLy8gRGlzYWxsb3cgc3RhdGUgbG9hZGluZyBieSByZXR1cm5pbmcgZmFsc2Vcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcInN0YXRlU2F2ZVwiOiB0cnVlLFxuXHRcdCAqICAgICAgICBcInN0YXRlTG9hZFBhcmFtc1wiOiBmdW5jdGlvbiAoc2V0dGluZ3MsIGRhdGEpIHtcblx0XHQgKiAgICAgICAgICByZXR1cm4gZmFsc2U7XG5cdFx0ICogICAgICAgIH1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJmblN0YXRlTG9hZFBhcmFtc1wiOiBudWxsLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogQ2FsbGJhY2sgdGhhdCBpcyBjYWxsZWQgd2hlbiB0aGUgc3RhdGUgaGFzIGJlZW4gbG9hZGVkIGZyb20gdGhlIHN0YXRlIHNhdmluZyBtZXRob2Rcblx0XHQgKiBhbmQgdGhlIERhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0IGhhcyBiZWVuIG1vZGlmaWVkIGFzIGEgcmVzdWx0IG9mIHRoZSBsb2FkZWQgc3RhdGUuXG5cdFx0ICogIEB0eXBlIGZ1bmN0aW9uXG5cdFx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBEYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHRcdCAqICBAcGFyYW0ge29iamVjdH0gZGF0YSBUaGUgc3RhdGUgb2JqZWN0IHRoYXQgd2FzIGxvYWRlZFxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBDYWxsYmFja3Ncblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLnN0YXRlTG9hZGVkXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBTaG93IGFuIGFsZXJ0IHdpdGggdGhlIGZpbHRlcmluZyB2YWx1ZSB0aGF0IHdhcyBzYXZlZFxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwic3RhdGVTYXZlXCI6IHRydWUsXG5cdFx0ICogICAgICAgIFwic3RhdGVMb2FkZWRcIjogZnVuY3Rpb24gKHNldHRpbmdzLCBkYXRhKSB7XG5cdFx0ICogICAgICAgICAgYWxlcnQoICdTYXZlZCBmaWx0ZXIgd2FzOiAnK2RhdGEub1NlYXJjaC5zU2VhcmNoICk7XG5cdFx0ICogICAgICAgIH1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJmblN0YXRlTG9hZGVkXCI6IG51bGwsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBTYXZlIHRoZSB0YWJsZSBzdGF0ZS4gVGhpcyBmdW5jdGlvbiBhbGxvd3MgeW91IHRvIGRlZmluZSB3aGVyZSBhbmQgaG93IHRoZSBzdGF0ZVxuXHRcdCAqIGluZm9ybWF0aW9uIGZvciB0aGUgdGFibGUgaXMgc3RvcmVkIEJ5IGRlZmF1bHQgRGF0YVRhYmxlcyB3aWxsIHVzZSBgbG9jYWxTdG9yYWdlYFxuXHRcdCAqIGJ1dCB5b3UgbWlnaHQgd2lzaCB0byB1c2UgYSBzZXJ2ZXItc2lkZSBkYXRhYmFzZSBvciBjb29raWVzLlxuXHRcdCAqICBAdHlwZSBmdW5jdGlvblxuXHRcdCAqICBAbWVtYmVyXG5cdFx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBEYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHRcdCAqICBAcGFyYW0ge29iamVjdH0gZGF0YSBUaGUgc3RhdGUgb2JqZWN0IHRvIGJlIHNhdmVkXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IENhbGxiYWNrc1xuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuc3RhdGVTYXZlQ2FsbGJhY2tcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwic3RhdGVTYXZlXCI6IHRydWUsXG5cdFx0ICogICAgICAgIFwic3RhdGVTYXZlQ2FsbGJhY2tcIjogZnVuY3Rpb24gKHNldHRpbmdzLCBkYXRhKSB7XG5cdFx0ICogICAgICAgICAgLy8gU2VuZCBhbiBBamF4IHJlcXVlc3QgdG8gdGhlIHNlcnZlciB3aXRoIHRoZSBzdGF0ZSBvYmplY3Rcblx0XHQgKiAgICAgICAgICAkLmFqYXgoIHtcblx0XHQgKiAgICAgICAgICAgIFwidXJsXCI6IFwiL3N0YXRlX3NhdmVcIixcblx0XHQgKiAgICAgICAgICAgIFwiZGF0YVwiOiBkYXRhLFxuXHRcdCAqICAgICAgICAgICAgXCJkYXRhVHlwZVwiOiBcImpzb25cIixcblx0XHQgKiAgICAgICAgICAgIFwibWV0aG9kXCI6IFwiUE9TVFwiXG5cdFx0ICogICAgICAgICAgICBcInN1Y2Nlc3NcIjogZnVuY3Rpb24gKCkge31cblx0XHQgKiAgICAgICAgICB9ICk7XG5cdFx0ICogICAgICAgIH1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJmblN0YXRlU2F2ZUNhbGxiYWNrXCI6IGZ1bmN0aW9uICggc2V0dGluZ3MsIGRhdGEgKSB7XG5cdFx0XHR0cnkge1xuXHRcdFx0XHQoc2V0dGluZ3MuaVN0YXRlRHVyYXRpb24gPT09IC0xID8gc2Vzc2lvblN0b3JhZ2UgOiBsb2NhbFN0b3JhZ2UpLnNldEl0ZW0oXG5cdFx0XHRcdFx0J0RhdGFUYWJsZXNfJytzZXR0aW5ncy5zSW5zdGFuY2UrJ18nK2xvY2F0aW9uLnBhdGhuYW1lLFxuXHRcdFx0XHRcdEpTT04uc3RyaW5naWZ5KCBkYXRhIClcblx0XHRcdFx0KTtcblx0XHRcdH0gY2F0Y2ggKGUpIHt9XG5cdFx0fSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIENhbGxiYWNrIHdoaWNoIGFsbG93cyBtb2RpZmljYXRpb24gb2YgdGhlIHN0YXRlIHRvIGJlIHNhdmVkLiBDYWxsZWQgd2hlbiB0aGUgdGFibGVcblx0XHQgKiBoYXMgY2hhbmdlZCBzdGF0ZSBhIG5ldyBzdGF0ZSBzYXZlIGlzIHJlcXVpcmVkLiBUaGlzIG1ldGhvZCBhbGxvd3MgbW9kaWZpY2F0aW9uIG9mXG5cdFx0ICogdGhlIHN0YXRlIHNhdmluZyBvYmplY3QgcHJpb3IgdG8gYWN0dWFsbHkgZG9pbmcgdGhlIHNhdmUsIGluY2x1ZGluZyBhZGRpdGlvbiBvclxuXHRcdCAqIG90aGVyIHN0YXRlIHByb3BlcnRpZXMgb3IgbW9kaWZpY2F0aW9uLiBOb3RlIHRoYXQgZm9yIHBsdWctaW4gYXV0aG9ycywgeW91IHNob3VsZFxuXHRcdCAqIHVzZSB0aGUgYHN0YXRlU2F2ZVBhcmFtc2AgZXZlbnQgdG8gc2F2ZSBwYXJhbWV0ZXJzIGZvciBhIHBsdWctaW4uXG5cdFx0ICogIEB0eXBlIGZ1bmN0aW9uXG5cdFx0ICogIEBwYXJhbSB7b2JqZWN0fSBzZXR0aW5ncyBEYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdFxuXHRcdCAqICBAcGFyYW0ge29iamVjdH0gZGF0YSBUaGUgc3RhdGUgb2JqZWN0IHRvIGJlIHNhdmVkXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IENhbGxiYWNrc1xuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuc3RhdGVTYXZlUGFyYW1zXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBSZW1vdmUgYSBzYXZlZCBmaWx0ZXIsIHNvIGZpbHRlcmluZyBpcyBuZXZlciBzYXZlZFxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwic3RhdGVTYXZlXCI6IHRydWUsXG5cdFx0ICogICAgICAgIFwic3RhdGVTYXZlUGFyYW1zXCI6IGZ1bmN0aW9uIChzZXR0aW5ncywgZGF0YSkge1xuXHRcdCAqICAgICAgICAgIGRhdGEub1NlYXJjaC5zU2VhcmNoID0gXCJcIjtcblx0XHQgKiAgICAgICAgfVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImZuU3RhdGVTYXZlUGFyYW1zXCI6IG51bGwsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBEdXJhdGlvbiBmb3Igd2hpY2ggdGhlIHNhdmVkIHN0YXRlIGluZm9ybWF0aW9uIGlzIGNvbnNpZGVyZWQgdmFsaWQuIEFmdGVyIHRoaXMgcGVyaW9kXG5cdFx0ICogaGFzIGVsYXBzZWQgdGhlIHN0YXRlIHdpbGwgYmUgcmV0dXJuZWQgdG8gdGhlIGRlZmF1bHQuXG5cdFx0ICogVmFsdWUgaXMgZ2l2ZW4gaW4gc2Vjb25kcy5cblx0XHQgKiAgQHR5cGUgaW50XG5cdFx0ICogIEBkZWZhdWx0IDcyMDAgPGk+KDIgaG91cnMpPC9pPlxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBPcHRpb25zXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5zdGF0ZUR1cmF0aW9uXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcInN0YXRlRHVyYXRpb25cIjogNjAqNjAqMjQ7IC8vIDEgZGF5XG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApXG5cdFx0ICovXG5cdFx0XCJpU3RhdGVEdXJhdGlvblwiOiA3MjAwLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogV2hlbiBlbmFibGVkIERhdGFUYWJsZXMgd2lsbCBub3QgbWFrZSBhIHJlcXVlc3QgdG8gdGhlIHNlcnZlciBmb3IgdGhlIGZpcnN0XG5cdFx0ICogcGFnZSBkcmF3IC0gcmF0aGVyIGl0IHdpbGwgdXNlIHRoZSBkYXRhIGFscmVhZHkgb24gdGhlIHBhZ2UgKG5vIHNvcnRpbmcgZXRjXG5cdFx0ICogd2lsbCBiZSBhcHBsaWVkIHRvIGl0KSwgdGh1cyBzYXZpbmcgb24gYW4gWEhSIGF0IGxvYWQgdGltZS4gYGRlZmVyTG9hZGluZ2Bcblx0XHQgKiBpcyB1c2VkIHRvIGluZGljYXRlIHRoYXQgZGVmZXJyZWQgbG9hZGluZyBpcyByZXF1aXJlZCwgYnV0IGl0IGlzIGFsc28gdXNlZFxuXHRcdCAqIHRvIHRlbGwgRGF0YVRhYmxlcyBob3cgbWFueSByZWNvcmRzIHRoZXJlIGFyZSBpbiB0aGUgZnVsbCB0YWJsZSAoYWxsb3dpbmdcblx0XHQgKiB0aGUgaW5mb3JtYXRpb24gZWxlbWVudCBhbmQgcGFnaW5hdGlvbiB0byBiZSBkaXNwbGF5ZWQgY29ycmVjdGx5KS4gSW4gdGhlIGNhc2Vcblx0XHQgKiB3aGVyZSBhIGZpbHRlcmluZyBpcyBhcHBsaWVkIHRvIHRoZSB0YWJsZSBvbiBpbml0aWFsIGxvYWQsIHRoaXMgY2FuIGJlXG5cdFx0ICogaW5kaWNhdGVkIGJ5IGdpdmluZyB0aGUgcGFyYW1ldGVyIGFzIGFuIGFycmF5LCB3aGVyZSB0aGUgZmlyc3QgZWxlbWVudCBpc1xuXHRcdCAqIHRoZSBudW1iZXIgb2YgcmVjb3JkcyBhdmFpbGFibGUgYWZ0ZXIgZmlsdGVyaW5nIGFuZCB0aGUgc2Vjb25kIGVsZW1lbnQgaXMgdGhlXG5cdFx0ICogbnVtYmVyIG9mIHJlY29yZHMgd2l0aG91dCBmaWx0ZXJpbmcgKGFsbG93aW5nIHRoZSB0YWJsZSBpbmZvcm1hdGlvbiBlbGVtZW50XG5cdFx0ICogdG8gYmUgc2hvd24gY29ycmVjdGx5KS5cblx0XHQgKiAgQHR5cGUgaW50IHwgYXJyYXlcblx0XHQgKiAgQGRlZmF1bHQgbnVsbFxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBPcHRpb25zXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5kZWZlckxvYWRpbmdcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgIC8vIDU3IHJlY29yZHMgYXZhaWxhYmxlIGluIHRoZSB0YWJsZSwgbm8gZmlsdGVyaW5nIGFwcGxpZWRcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcInNlcnZlclNpZGVcIjogdHJ1ZSxcblx0XHQgKiAgICAgICAgXCJhamF4XCI6IFwic2NyaXB0cy9zZXJ2ZXJfcHJvY2Vzc2luZy5waHBcIixcblx0XHQgKiAgICAgICAgXCJkZWZlckxvYWRpbmdcIjogNTdcblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyA1NyByZWNvcmRzIGFmdGVyIGZpbHRlcmluZywgMTAwIHdpdGhvdXQgZmlsdGVyaW5nIChhbiBpbml0aWFsIGZpbHRlciBhcHBsaWVkKVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwic2VydmVyU2lkZVwiOiB0cnVlLFxuXHRcdCAqICAgICAgICBcImFqYXhcIjogXCJzY3JpcHRzL3NlcnZlcl9wcm9jZXNzaW5nLnBocFwiLFxuXHRcdCAqICAgICAgICBcImRlZmVyTG9hZGluZ1wiOiBbIDU3LCAxMDAgXSxcblx0XHQgKiAgICAgICAgXCJzZWFyY2hcIjoge1xuXHRcdCAqICAgICAgICAgIFwic2VhcmNoXCI6IFwibXlfZmlsdGVyXCJcblx0XHQgKiAgICAgICAgfVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImlEZWZlckxvYWRpbmdcIjogbnVsbCxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIE51bWJlciBvZiByb3dzIHRvIGRpc3BsYXkgb24gYSBzaW5nbGUgcGFnZSB3aGVuIHVzaW5nIHBhZ2luYXRpb24uIElmXG5cdFx0ICogZmVhdHVyZSBlbmFibGVkIChgbGVuZ3RoQ2hhbmdlYCkgdGhlbiB0aGUgZW5kIHVzZXIgd2lsbCBiZSBhYmxlIHRvIG92ZXJyaWRlXG5cdFx0ICogdGhpcyB0byBhIGN1c3RvbSBzZXR0aW5nIHVzaW5nIGEgcG9wLXVwIG1lbnUuXG5cdFx0ICogIEB0eXBlIGludFxuXHRcdCAqICBAZGVmYXVsdCAxMFxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBPcHRpb25zXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5wYWdlTGVuZ3RoXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcInBhZ2VMZW5ndGhcIjogNTBcblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9IClcblx0XHQgKi9cblx0XHRcImlEaXNwbGF5TGVuZ3RoXCI6IDEwLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogRGVmaW5lIHRoZSBzdGFydGluZyBwb2ludCBmb3IgZGF0YSBkaXNwbGF5IHdoZW4gdXNpbmcgRGF0YVRhYmxlcyB3aXRoXG5cdFx0ICogcGFnaW5hdGlvbi4gTm90ZSB0aGF0IHRoaXMgcGFyYW1ldGVyIGlzIHRoZSBudW1iZXIgb2YgcmVjb3JkcywgcmF0aGVyIHRoYW5cblx0XHQgKiB0aGUgcGFnZSBudW1iZXIsIHNvIGlmIHlvdSBoYXZlIDEwIHJlY29yZHMgcGVyIHBhZ2UgYW5kIHdhbnQgdG8gc3RhcnQgb25cblx0XHQgKiB0aGUgdGhpcmQgcGFnZSwgaXQgc2hvdWxkIGJlIFwiMjBcIi5cblx0XHQgKiAgQHR5cGUgaW50XG5cdFx0ICogIEBkZWZhdWx0IDBcblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgT3B0aW9uc1xuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuZGlzcGxheVN0YXJ0XG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImRpc3BsYXlTdGFydFwiOiAyMFxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKVxuXHRcdCAqL1xuXHRcdFwiaURpc3BsYXlTdGFydFwiOiAwLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogQnkgZGVmYXVsdCBEYXRhVGFibGVzIGFsbG93cyBrZXlib2FyZCBuYXZpZ2F0aW9uIG9mIHRoZSB0YWJsZSAoc29ydGluZywgcGFnaW5nLFxuXHRcdCAqIGFuZCBmaWx0ZXJpbmcpIGJ5IGFkZGluZyBhIGB0YWJpbmRleGAgYXR0cmlidXRlIHRvIHRoZSByZXF1aXJlZCBlbGVtZW50cy4gVGhpc1xuXHRcdCAqIGFsbG93cyB5b3UgdG8gdGFiIHRocm91Z2ggdGhlIGNvbnRyb2xzIGFuZCBwcmVzcyB0aGUgZW50ZXIga2V5IHRvIGFjdGl2YXRlIHRoZW0uXG5cdFx0ICogVGhlIHRhYmluZGV4IGlzIGRlZmF1bHQgMCwgbWVhbmluZyB0aGF0IHRoZSB0YWIgZm9sbG93cyB0aGUgZmxvdyBvZiB0aGUgZG9jdW1lbnQuXG5cdFx0ICogWW91IGNhbiBvdmVycnVsZSB0aGlzIHVzaW5nIHRoaXMgcGFyYW1ldGVyIGlmIHlvdSB3aXNoLiBVc2UgYSB2YWx1ZSBvZiAtMSB0b1xuXHRcdCAqIGRpc2FibGUgYnVpbHQtaW4ga2V5Ym9hcmQgbmF2aWdhdGlvbi5cblx0XHQgKiAgQHR5cGUgaW50XG5cdFx0ICogIEBkZWZhdWx0IDBcblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgT3B0aW9uc1xuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMudGFiSW5kZXhcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwidGFiSW5kZXhcIjogMVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImlUYWJJbmRleFwiOiAwLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogQ2xhc3NlcyB0aGF0IERhdGFUYWJsZXMgYXNzaWducyB0byB0aGUgdmFyaW91cyBjb21wb25lbnRzIGFuZCBmZWF0dXJlc1xuXHRcdCAqIHRoYXQgaXQgYWRkcyB0byB0aGUgSFRNTCB0YWJsZS4gVGhpcyBhbGxvd3MgY2xhc3NlcyB0byBiZSBjb25maWd1cmVkXG5cdFx0ICogZHVyaW5nIGluaXRpYWxpc2F0aW9uIGluIGFkZGl0aW9uIHRvIHRocm91Z2ggdGhlIHN0YXRpY1xuXHRcdCAqIHtAbGluayBEYXRhVGFibGUuZXh0Lm9TdGRDbGFzc2VzfSBvYmplY3QpLlxuXHRcdCAqICBAbmFtZXNwYWNlXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5jbGFzc2VzXG5cdFx0ICovXG5cdFx0XCJvQ2xhc3Nlc1wiOiB7fSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIEFsbCBzdHJpbmdzIHRoYXQgRGF0YVRhYmxlcyB1c2VzIGluIHRoZSB1c2VyIGludGVyZmFjZSB0aGF0IGl0IGNyZWF0ZXNcblx0XHQgKiBhcmUgZGVmaW5lZCBpbiB0aGlzIG9iamVjdCwgYWxsb3dpbmcgeW91IHRvIG1vZGlmaWVkIHRoZW0gaW5kaXZpZHVhbGx5IG9yXG5cdFx0ICogY29tcGxldGVseSByZXBsYWNlIHRoZW0gYWxsIGFzIHJlcXVpcmVkLlxuXHRcdCAqICBAbmFtZXNwYWNlXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5sYW5ndWFnZVxuXHRcdCAqL1xuXHRcdFwib0xhbmd1YWdlXCI6IHtcblx0XHRcdC8qKlxuXHRcdFx0ICogU3RyaW5ncyB0aGF0IGFyZSB1c2VkIGZvciBXQUktQVJJQSBsYWJlbHMgYW5kIGNvbnRyb2xzIG9ubHkgKHRoZXNlIGFyZSBub3Rcblx0XHRcdCAqIGFjdHVhbGx5IHZpc2libGUgb24gdGhlIHBhZ2UsIGJ1dCB3aWxsIGJlIHJlYWQgYnkgc2NyZWVucmVhZGVycywgYW5kIHRodXNcblx0XHRcdCAqIG11c3QgYmUgaW50ZXJuYXRpb25hbGlzZWQgYXMgd2VsbCkuXG5cdFx0XHQgKiAgQG5hbWVzcGFjZVxuXHRcdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5sYW5ndWFnZS5hcmlhXG5cdFx0XHQgKi9cblx0XHRcdFwib0FyaWFcIjoge1xuXHRcdFx0XHQvKipcblx0XHRcdFx0ICogQVJJQSBsYWJlbCB0aGF0IGlzIGFkZGVkIHRvIHRoZSB0YWJsZSBoZWFkZXJzIHdoZW4gdGhlIGNvbHVtbiBtYXkgYmVcblx0XHRcdFx0ICogc29ydGVkIGFzY2VuZGluZyBieSBhY3RpdmluZyB0aGUgY29sdW1uIChjbGljayBvciByZXR1cm4gd2hlbiBmb2N1c2VkKS5cblx0XHRcdFx0ICogTm90ZSB0aGF0IHRoZSBjb2x1bW4gaGVhZGVyIGlzIHByZWZpeGVkIHRvIHRoaXMgc3RyaW5nLlxuXHRcdFx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0XHRcdCAqICBAZGVmYXVsdCA6IGFjdGl2YXRlIHRvIHNvcnQgY29sdW1uIGFzY2VuZGluZ1xuXHRcdFx0XHQgKlxuXHRcdFx0XHQgKiAgQGR0b3B0IExhbmd1YWdlXG5cdFx0XHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMubGFuZ3VhZ2UuYXJpYS5zb3J0QXNjZW5kaW5nXG5cdFx0XHRcdCAqXG5cdFx0XHRcdCAqICBAZXhhbXBsZVxuXHRcdFx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHRcdFx0ICogICAgICAgIFwibGFuZ3VhZ2VcIjoge1xuXHRcdFx0XHQgKiAgICAgICAgICBcImFyaWFcIjoge1xuXHRcdFx0XHQgKiAgICAgICAgICAgIFwic29ydEFzY2VuZGluZ1wiOiBcIiAtIGNsaWNrL3JldHVybiB0byBzb3J0IGFzY2VuZGluZ1wiXG5cdFx0XHRcdCAqICAgICAgICAgIH1cblx0XHRcdFx0ICogICAgICAgIH1cblx0XHRcdFx0ICogICAgICB9ICk7XG5cdFx0XHRcdCAqICAgIH0gKTtcblx0XHRcdFx0ICovXG5cdFx0XHRcdFwic1NvcnRBc2NlbmRpbmdcIjogXCI6IGFjdGl2YXRlIHRvIHNvcnQgY29sdW1uIGFzY2VuZGluZ1wiLFxuXHRcblx0XHRcdFx0LyoqXG5cdFx0XHRcdCAqIEFSSUEgbGFiZWwgdGhhdCBpcyBhZGRlZCB0byB0aGUgdGFibGUgaGVhZGVycyB3aGVuIHRoZSBjb2x1bW4gbWF5IGJlXG5cdFx0XHRcdCAqIHNvcnRlZCBkZXNjZW5kaW5nIGJ5IGFjdGl2aW5nIHRoZSBjb2x1bW4gKGNsaWNrIG9yIHJldHVybiB3aGVuIGZvY3VzZWQpLlxuXHRcdFx0XHQgKiBOb3RlIHRoYXQgdGhlIGNvbHVtbiBoZWFkZXIgaXMgcHJlZml4ZWQgdG8gdGhpcyBzdHJpbmcuXG5cdFx0XHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHRcdFx0ICogIEBkZWZhdWx0IDogYWN0aXZhdGUgdG8gc29ydCBjb2x1bW4gYXNjZW5kaW5nXG5cdFx0XHRcdCAqXG5cdFx0XHRcdCAqICBAZHRvcHQgTGFuZ3VhZ2Vcblx0XHRcdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5sYW5ndWFnZS5hcmlhLnNvcnREZXNjZW5kaW5nXG5cdFx0XHRcdCAqXG5cdFx0XHRcdCAqICBAZXhhbXBsZVxuXHRcdFx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHRcdFx0ICogICAgICAgIFwibGFuZ3VhZ2VcIjoge1xuXHRcdFx0XHQgKiAgICAgICAgICBcImFyaWFcIjoge1xuXHRcdFx0XHQgKiAgICAgICAgICAgIFwic29ydERlc2NlbmRpbmdcIjogXCIgLSBjbGljay9yZXR1cm4gdG8gc29ydCBkZXNjZW5kaW5nXCJcblx0XHRcdFx0ICogICAgICAgICAgfVxuXHRcdFx0XHQgKiAgICAgICAgfVxuXHRcdFx0XHQgKiAgICAgIH0gKTtcblx0XHRcdFx0ICogICAgfSApO1xuXHRcdFx0XHQgKi9cblx0XHRcdFx0XCJzU29ydERlc2NlbmRpbmdcIjogXCI6IGFjdGl2YXRlIHRvIHNvcnQgY29sdW1uIGRlc2NlbmRpbmdcIlxuXHRcdFx0fSxcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIFBhZ2luYXRpb24gc3RyaW5nIHVzZWQgYnkgRGF0YVRhYmxlcyBmb3IgdGhlIGJ1aWx0LWluIHBhZ2luYXRpb25cblx0XHRcdCAqIGNvbnRyb2wgdHlwZXMuXG5cdFx0XHQgKiAgQG5hbWVzcGFjZVxuXHRcdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5sYW5ndWFnZS5wYWdpbmF0ZVxuXHRcdFx0ICovXG5cdFx0XHRcIm9QYWdpbmF0ZVwiOiB7XG5cdFx0XHRcdC8qKlxuXHRcdFx0XHQgKiBUZXh0IHRvIHVzZSB3aGVuIHVzaW5nIHRoZSAnZnVsbF9udW1iZXJzJyB0eXBlIG9mIHBhZ2luYXRpb24gZm9yIHRoZVxuXHRcdFx0XHQgKiBidXR0b24gdG8gdGFrZSB0aGUgdXNlciB0byB0aGUgZmlyc3QgcGFnZS5cblx0XHRcdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdFx0XHQgKiAgQGRlZmF1bHQgRmlyc3Rcblx0XHRcdFx0ICpcblx0XHRcdFx0ICogIEBkdG9wdCBMYW5ndWFnZVxuXHRcdFx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLmxhbmd1YWdlLnBhZ2luYXRlLmZpcnN0XG5cdFx0XHRcdCAqXG5cdFx0XHRcdCAqICBAZXhhbXBsZVxuXHRcdFx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHRcdFx0ICogICAgICAgIFwibGFuZ3VhZ2VcIjoge1xuXHRcdFx0XHQgKiAgICAgICAgICBcInBhZ2luYXRlXCI6IHtcblx0XHRcdFx0ICogICAgICAgICAgICBcImZpcnN0XCI6IFwiRmlyc3QgcGFnZVwiXG5cdFx0XHRcdCAqICAgICAgICAgIH1cblx0XHRcdFx0ICogICAgICAgIH1cblx0XHRcdFx0ICogICAgICB9ICk7XG5cdFx0XHRcdCAqICAgIH0gKTtcblx0XHRcdFx0ICovXG5cdFx0XHRcdFwic0ZpcnN0XCI6IFwiRmlyc3RcIixcblx0XG5cdFxuXHRcdFx0XHQvKipcblx0XHRcdFx0ICogVGV4dCB0byB1c2Ugd2hlbiB1c2luZyB0aGUgJ2Z1bGxfbnVtYmVycycgdHlwZSBvZiBwYWdpbmF0aW9uIGZvciB0aGVcblx0XHRcdFx0ICogYnV0dG9uIHRvIHRha2UgdGhlIHVzZXIgdG8gdGhlIGxhc3QgcGFnZS5cblx0XHRcdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdFx0XHQgKiAgQGRlZmF1bHQgTGFzdFxuXHRcdFx0XHQgKlxuXHRcdFx0XHQgKiAgQGR0b3B0IExhbmd1YWdlXG5cdFx0XHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMubGFuZ3VhZ2UucGFnaW5hdGUubGFzdFxuXHRcdFx0XHQgKlxuXHRcdFx0XHQgKiAgQGV4YW1wbGVcblx0XHRcdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0XHRcdCAqICAgICAgICBcImxhbmd1YWdlXCI6IHtcblx0XHRcdFx0ICogICAgICAgICAgXCJwYWdpbmF0ZVwiOiB7XG5cdFx0XHRcdCAqICAgICAgICAgICAgXCJsYXN0XCI6IFwiTGFzdCBwYWdlXCJcblx0XHRcdFx0ICogICAgICAgICAgfVxuXHRcdFx0XHQgKiAgICAgICAgfVxuXHRcdFx0XHQgKiAgICAgIH0gKTtcblx0XHRcdFx0ICogICAgfSApO1xuXHRcdFx0XHQgKi9cblx0XHRcdFx0XCJzTGFzdFwiOiBcIkxhc3RcIixcblx0XG5cdFxuXHRcdFx0XHQvKipcblx0XHRcdFx0ICogVGV4dCB0byB1c2UgZm9yIHRoZSAnbmV4dCcgcGFnaW5hdGlvbiBidXR0b24gKHRvIHRha2UgdGhlIHVzZXIgdG8gdGhlXG5cdFx0XHRcdCAqIG5leHQgcGFnZSkuXG5cdFx0XHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHRcdFx0ICogIEBkZWZhdWx0IE5leHRcblx0XHRcdFx0ICpcblx0XHRcdFx0ICogIEBkdG9wdCBMYW5ndWFnZVxuXHRcdFx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLmxhbmd1YWdlLnBhZ2luYXRlLm5leHRcblx0XHRcdFx0ICpcblx0XHRcdFx0ICogIEBleGFtcGxlXG5cdFx0XHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdFx0XHQgKiAgICAgICAgXCJsYW5ndWFnZVwiOiB7XG5cdFx0XHRcdCAqICAgICAgICAgIFwicGFnaW5hdGVcIjoge1xuXHRcdFx0XHQgKiAgICAgICAgICAgIFwibmV4dFwiOiBcIk5leHQgcGFnZVwiXG5cdFx0XHRcdCAqICAgICAgICAgIH1cblx0XHRcdFx0ICogICAgICAgIH1cblx0XHRcdFx0ICogICAgICB9ICk7XG5cdFx0XHRcdCAqICAgIH0gKTtcblx0XHRcdFx0ICovXG5cdFx0XHRcdFwic05leHRcIjogXCJOZXh0XCIsXG5cdFxuXHRcblx0XHRcdFx0LyoqXG5cdFx0XHRcdCAqIFRleHQgdG8gdXNlIGZvciB0aGUgJ3ByZXZpb3VzJyBwYWdpbmF0aW9uIGJ1dHRvbiAodG8gdGFrZSB0aGUgdXNlciB0b1xuXHRcdFx0XHQgKiB0aGUgcHJldmlvdXMgcGFnZSkuXG5cdFx0XHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHRcdFx0ICogIEBkZWZhdWx0IFByZXZpb3VzXG5cdFx0XHRcdCAqXG5cdFx0XHRcdCAqICBAZHRvcHQgTGFuZ3VhZ2Vcblx0XHRcdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5sYW5ndWFnZS5wYWdpbmF0ZS5wcmV2aW91c1xuXHRcdFx0XHQgKlxuXHRcdFx0XHQgKiAgQGV4YW1wbGVcblx0XHRcdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0XHRcdCAqICAgICAgICBcImxhbmd1YWdlXCI6IHtcblx0XHRcdFx0ICogICAgICAgICAgXCJwYWdpbmF0ZVwiOiB7XG5cdFx0XHRcdCAqICAgICAgICAgICAgXCJwcmV2aW91c1wiOiBcIlByZXZpb3VzIHBhZ2VcIlxuXHRcdFx0XHQgKiAgICAgICAgICB9XG5cdFx0XHRcdCAqICAgICAgICB9XG5cdFx0XHRcdCAqICAgICAgfSApO1xuXHRcdFx0XHQgKiAgICB9ICk7XG5cdFx0XHRcdCAqL1xuXHRcdFx0XHRcInNQcmV2aW91c1wiOiBcIlByZXZpb3VzXCJcblx0XHRcdH0sXG5cdFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBUaGlzIHN0cmluZyBpcyBzaG93biBpbiBwcmVmZXJlbmNlIHRvIGB6ZXJvUmVjb3Jkc2Agd2hlbiB0aGUgdGFibGUgaXNcblx0XHRcdCAqIGVtcHR5IG9mIGRhdGEgKHJlZ2FyZGxlc3Mgb2YgZmlsdGVyaW5nKS4gTm90ZSB0aGF0IHRoaXMgaXMgYW4gb3B0aW9uYWxcblx0XHRcdCAqIHBhcmFtZXRlciAtIGlmIGl0IGlzIG5vdCBnaXZlbiwgdGhlIHZhbHVlIG9mIGB6ZXJvUmVjb3Jkc2Agd2lsbCBiZSB1c2VkXG5cdFx0XHQgKiBpbnN0ZWFkIChlaXRoZXIgdGhlIGRlZmF1bHQgb3IgZ2l2ZW4gdmFsdWUpLlxuXHRcdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdFx0ICogIEBkZWZhdWx0IE5vIGRhdGEgYXZhaWxhYmxlIGluIHRhYmxlXG5cdFx0XHQgKlxuXHRcdFx0ICogIEBkdG9wdCBMYW5ndWFnZVxuXHRcdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5sYW5ndWFnZS5lbXB0eVRhYmxlXG5cdFx0XHQgKlxuXHRcdFx0ICogIEBleGFtcGxlXG5cdFx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0XHQgKiAgICAgICAgXCJsYW5ndWFnZVwiOiB7XG5cdFx0XHQgKiAgICAgICAgICBcImVtcHR5VGFibGVcIjogXCJObyBkYXRhIGF2YWlsYWJsZSBpbiB0YWJsZVwiXG5cdFx0XHQgKiAgICAgICAgfVxuXHRcdFx0ICogICAgICB9ICk7XG5cdFx0XHQgKiAgICB9ICk7XG5cdFx0XHQgKi9cblx0XHRcdFwic0VtcHR5VGFibGVcIjogXCJObyBkYXRhIGF2YWlsYWJsZSBpbiB0YWJsZVwiLFxuXHRcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIFRoaXMgc3RyaW5nIGdpdmVzIGluZm9ybWF0aW9uIHRvIHRoZSBlbmQgdXNlciBhYm91dCB0aGUgaW5mb3JtYXRpb25cblx0XHRcdCAqIHRoYXQgaXMgY3VycmVudCBvbiBkaXNwbGF5IG9uIHRoZSBwYWdlLiBUaGUgZm9sbG93aW5nIHRva2VucyBjYW4gYmVcblx0XHRcdCAqIHVzZWQgaW4gdGhlIHN0cmluZyBhbmQgd2lsbCBiZSBkeW5hbWljYWxseSByZXBsYWNlZCBhcyB0aGUgdGFibGVcblx0XHRcdCAqIGRpc3BsYXkgdXBkYXRlcy4gVGhpcyB0b2tlbnMgY2FuIGJlIHBsYWNlZCBhbnl3aGVyZSBpbiB0aGUgc3RyaW5nLCBvclxuXHRcdFx0ICogcmVtb3ZlZCBhcyBuZWVkZWQgYnkgdGhlIGxhbmd1YWdlIHJlcXVpcmVzOlxuXHRcdFx0ICpcblx0XHRcdCAqICogYFxcX1NUQVJUXFxfYCAtIERpc3BsYXkgaW5kZXggb2YgdGhlIGZpcnN0IHJlY29yZCBvbiB0aGUgY3VycmVudCBwYWdlXG5cdFx0XHQgKiAqIGBcXF9FTkRcXF9gIC0gRGlzcGxheSBpbmRleCBvZiB0aGUgbGFzdCByZWNvcmQgb24gdGhlIGN1cnJlbnQgcGFnZVxuXHRcdFx0ICogKiBgXFxfVE9UQUxcXF9gIC0gTnVtYmVyIG9mIHJlY29yZHMgaW4gdGhlIHRhYmxlIGFmdGVyIGZpbHRlcmluZ1xuXHRcdFx0ICogKiBgXFxfTUFYXFxfYCAtIE51bWJlciBvZiByZWNvcmRzIGluIHRoZSB0YWJsZSB3aXRob3V0IGZpbHRlcmluZ1xuXHRcdFx0ICogKiBgXFxfUEFHRVxcX2AgLSBDdXJyZW50IHBhZ2UgbnVtYmVyXG5cdFx0XHQgKiAqIGBcXF9QQUdFU1xcX2AgLSBUb3RhbCBudW1iZXIgb2YgcGFnZXMgb2YgZGF0YSBpbiB0aGUgdGFibGVcblx0XHRcdCAqXG5cdFx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0XHQgKiAgQGRlZmF1bHQgU2hvd2luZyBfU1RBUlRfIHRvIF9FTkRfIG9mIF9UT1RBTF8gZW50cmllc1xuXHRcdFx0ICpcblx0XHRcdCAqICBAZHRvcHQgTGFuZ3VhZ2Vcblx0XHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMubGFuZ3VhZ2UuaW5mb1xuXHRcdFx0ICpcblx0XHRcdCAqICBAZXhhbXBsZVxuXHRcdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdFx0ICogICAgICAgIFwibGFuZ3VhZ2VcIjoge1xuXHRcdFx0ICogICAgICAgICAgXCJpbmZvXCI6IFwiU2hvd2luZyBwYWdlIF9QQUdFXyBvZiBfUEFHRVNfXCJcblx0XHRcdCAqICAgICAgICB9XG5cdFx0XHQgKiAgICAgIH0gKTtcblx0XHRcdCAqICAgIH0gKTtcblx0XHRcdCAqL1xuXHRcdFx0XCJzSW5mb1wiOiBcIlNob3dpbmcgX1NUQVJUXyB0byBfRU5EXyBvZiBfVE9UQUxfIGVudHJpZXNcIixcblx0XG5cdFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBEaXNwbGF5IGluZm9ybWF0aW9uIHN0cmluZyBmb3Igd2hlbiB0aGUgdGFibGUgaXMgZW1wdHkuIFR5cGljYWxseSB0aGVcblx0XHRcdCAqIGZvcm1hdCBvZiB0aGlzIHN0cmluZyBzaG91bGQgbWF0Y2ggYGluZm9gLlxuXHRcdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdFx0ICogIEBkZWZhdWx0IFNob3dpbmcgMCB0byAwIG9mIDAgZW50cmllc1xuXHRcdFx0ICpcblx0XHRcdCAqICBAZHRvcHQgTGFuZ3VhZ2Vcblx0XHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMubGFuZ3VhZ2UuaW5mb0VtcHR5XG5cdFx0XHQgKlxuXHRcdFx0ICogIEBleGFtcGxlXG5cdFx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0XHQgKiAgICAgICAgXCJsYW5ndWFnZVwiOiB7XG5cdFx0XHQgKiAgICAgICAgICBcImluZm9FbXB0eVwiOiBcIk5vIGVudHJpZXMgdG8gc2hvd1wiXG5cdFx0XHQgKiAgICAgICAgfVxuXHRcdFx0ICogICAgICB9ICk7XG5cdFx0XHQgKiAgICB9ICk7XG5cdFx0XHQgKi9cblx0XHRcdFwic0luZm9FbXB0eVwiOiBcIlNob3dpbmcgMCB0byAwIG9mIDAgZW50cmllc1wiLFxuXHRcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIFdoZW4gYSB1c2VyIGZpbHRlcnMgdGhlIGluZm9ybWF0aW9uIGluIGEgdGFibGUsIHRoaXMgc3RyaW5nIGlzIGFwcGVuZGVkXG5cdFx0XHQgKiB0byB0aGUgaW5mb3JtYXRpb24gKGBpbmZvYCkgdG8gZ2l2ZSBhbiBpZGVhIG9mIGhvdyBzdHJvbmcgdGhlIGZpbHRlcmluZ1xuXHRcdFx0ICogaXMuIFRoZSB2YXJpYWJsZSBfTUFYXyBpcyBkeW5hbWljYWxseSB1cGRhdGVkLlxuXHRcdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdFx0ICogIEBkZWZhdWx0IChmaWx0ZXJlZCBmcm9tIF9NQVhfIHRvdGFsIGVudHJpZXMpXG5cdFx0XHQgKlxuXHRcdFx0ICogIEBkdG9wdCBMYW5ndWFnZVxuXHRcdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5sYW5ndWFnZS5pbmZvRmlsdGVyZWRcblx0XHRcdCAqXG5cdFx0XHQgKiAgQGV4YW1wbGVcblx0XHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHRcdCAqICAgICAgICBcImxhbmd1YWdlXCI6IHtcblx0XHRcdCAqICAgICAgICAgIFwiaW5mb0ZpbHRlcmVkXCI6IFwiIC0gZmlsdGVyaW5nIGZyb20gX01BWF8gcmVjb3Jkc1wiXG5cdFx0XHQgKiAgICAgICAgfVxuXHRcdFx0ICogICAgICB9ICk7XG5cdFx0XHQgKiAgICB9ICk7XG5cdFx0XHQgKi9cblx0XHRcdFwic0luZm9GaWx0ZXJlZFwiOiBcIihmaWx0ZXJlZCBmcm9tIF9NQVhfIHRvdGFsIGVudHJpZXMpXCIsXG5cdFxuXHRcblx0XHRcdC8qKlxuXHRcdFx0ICogSWYgY2FuIGJlIHVzZWZ1bCB0byBhcHBlbmQgZXh0cmEgaW5mb3JtYXRpb24gdG8gdGhlIGluZm8gc3RyaW5nIGF0IHRpbWVzLFxuXHRcdFx0ICogYW5kIHRoaXMgdmFyaWFibGUgZG9lcyBleGFjdGx5IHRoYXQuIFRoaXMgaW5mb3JtYXRpb24gd2lsbCBiZSBhcHBlbmRlZCB0b1xuXHRcdFx0ICogdGhlIGBpbmZvYCAoYGluZm9FbXB0eWAgYW5kIGBpbmZvRmlsdGVyZWRgIGluIHdoYXRldmVyIGNvbWJpbmF0aW9uIHRoZXkgYXJlXG5cdFx0XHQgKiBiZWluZyB1c2VkKSBhdCBhbGwgdGltZXMuXG5cdFx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0XHQgKiAgQGRlZmF1bHQgPGk+RW1wdHkgc3RyaW5nPC9pPlxuXHRcdFx0ICpcblx0XHRcdCAqICBAZHRvcHQgTGFuZ3VhZ2Vcblx0XHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMubGFuZ3VhZ2UuaW5mb1Bvc3RGaXhcblx0XHRcdCAqXG5cdFx0XHQgKiAgQGV4YW1wbGVcblx0XHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHRcdCAqICAgICAgICBcImxhbmd1YWdlXCI6IHtcblx0XHRcdCAqICAgICAgICAgIFwiaW5mb1Bvc3RGaXhcIjogXCJBbGwgcmVjb3JkcyBzaG93biBhcmUgZGVyaXZlZCBmcm9tIHJlYWwgaW5mb3JtYXRpb24uXCJcblx0XHRcdCAqICAgICAgICB9XG5cdFx0XHQgKiAgICAgIH0gKTtcblx0XHRcdCAqICAgIH0gKTtcblx0XHRcdCAqL1xuXHRcdFx0XCJzSW5mb1Bvc3RGaXhcIjogXCJcIixcblx0XG5cdFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBUaGlzIGRlY2ltYWwgcGxhY2Ugb3BlcmF0b3IgaXMgYSBsaXR0bGUgZGlmZmVyZW50IGZyb20gdGhlIG90aGVyXG5cdFx0XHQgKiBsYW5ndWFnZSBvcHRpb25zIHNpbmNlIERhdGFUYWJsZXMgZG9lc24ndCBvdXRwdXQgZmxvYXRpbmcgcG9pbnRcblx0XHRcdCAqIG51bWJlcnMsIHNvIGl0IHdvbid0IGV2ZXIgdXNlIHRoaXMgZm9yIGRpc3BsYXkgb2YgYSBudW1iZXIuIFJhdGhlcixcblx0XHRcdCAqIHdoYXQgdGhpcyBwYXJhbWV0ZXIgZG9lcyBpcyBtb2RpZnkgdGhlIHNvcnQgbWV0aG9kcyBvZiB0aGUgdGFibGUgc29cblx0XHRcdCAqIHRoYXQgbnVtYmVycyB3aGljaCBhcmUgaW4gYSBmb3JtYXQgd2hpY2ggaGFzIGEgY2hhcmFjdGVyIG90aGVyIHRoYW5cblx0XHRcdCAqIGEgcGVyaW9kIChgLmApIGFzIGEgZGVjaW1hbCBwbGFjZSB3aWxsIGJlIHNvcnRlZCBudW1lcmljYWxseS5cblx0XHRcdCAqXG5cdFx0XHQgKiBOb3RlIHRoYXQgbnVtYmVycyB3aXRoIGRpZmZlcmVudCBkZWNpbWFsIHBsYWNlcyBjYW5ub3QgYmUgc2hvd24gaW5cblx0XHRcdCAqIHRoZSBzYW1lIHRhYmxlIGFuZCBzdGlsbCBiZSBzb3J0YWJsZSwgdGhlIHRhYmxlIG11c3QgYmUgY29uc2lzdGVudC5cblx0XHRcdCAqIEhvd2V2ZXIsIG11bHRpcGxlIGRpZmZlcmVudCB0YWJsZXMgb24gdGhlIHBhZ2UgY2FuIHVzZSBkaWZmZXJlbnRcblx0XHRcdCAqIGRlY2ltYWwgcGxhY2UgY2hhcmFjdGVycy5cblx0XHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHRcdCAqICBAZGVmYXVsdCBcblx0XHRcdCAqXG5cdFx0XHQgKiAgQGR0b3B0IExhbmd1YWdlXG5cdFx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLmxhbmd1YWdlLmRlY2ltYWxcblx0XHRcdCAqXG5cdFx0XHQgKiAgQGV4YW1wbGVcblx0XHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHRcdCAqICAgICAgICBcImxhbmd1YWdlXCI6IHtcblx0XHRcdCAqICAgICAgICAgIFwiZGVjaW1hbFwiOiBcIixcIlxuXHRcdFx0ICogICAgICAgICAgXCJ0aG91c2FuZHNcIjogXCIuXCJcblx0XHRcdCAqICAgICAgICB9XG5cdFx0XHQgKiAgICAgIH0gKTtcblx0XHRcdCAqICAgIH0gKTtcblx0XHRcdCAqL1xuXHRcdFx0XCJzRGVjaW1hbFwiOiBcIlwiLFxuXHRcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIERhdGFUYWJsZXMgaGFzIGEgYnVpbGQgaW4gbnVtYmVyIGZvcm1hdHRlciAoYGZvcm1hdE51bWJlcmApIHdoaWNoIGlzXG5cdFx0XHQgKiB1c2VkIHRvIGZvcm1hdCBsYXJnZSBudW1iZXJzIHRoYXQgYXJlIHVzZWQgaW4gdGhlIHRhYmxlIGluZm9ybWF0aW9uLlxuXHRcdFx0ICogQnkgZGVmYXVsdCBhIGNvbW1hIGlzIHVzZWQsIGJ1dCB0aGlzIGNhbiBiZSB0cml2aWFsbHkgY2hhbmdlZCB0byBhbnlcblx0XHRcdCAqIGNoYXJhY3RlciB5b3Ugd2lzaCB3aXRoIHRoaXMgcGFyYW1ldGVyLlxuXHRcdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdFx0ICogIEBkZWZhdWx0ICxcblx0XHRcdCAqXG5cdFx0XHQgKiAgQGR0b3B0IExhbmd1YWdlXG5cdFx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLmxhbmd1YWdlLnRob3VzYW5kc1xuXHRcdFx0ICpcblx0XHRcdCAqICBAZXhhbXBsZVxuXHRcdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdFx0ICogICAgICAgIFwibGFuZ3VhZ2VcIjoge1xuXHRcdFx0ICogICAgICAgICAgXCJ0aG91c2FuZHNcIjogXCInXCJcblx0XHRcdCAqICAgICAgICB9XG5cdFx0XHQgKiAgICAgIH0gKTtcblx0XHRcdCAqICAgIH0gKTtcblx0XHRcdCAqL1xuXHRcdFx0XCJzVGhvdXNhbmRzXCI6IFwiLFwiLFxuXHRcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIERldGFpbCB0aGUgYWN0aW9uIHRoYXQgd2lsbCBiZSB0YWtlbiB3aGVuIHRoZSBkcm9wIGRvd24gbWVudSBmb3IgdGhlXG5cdFx0XHQgKiBwYWdpbmF0aW9uIGxlbmd0aCBvcHRpb24gaXMgY2hhbmdlZC4gVGhlICdfTUVOVV8nIHZhcmlhYmxlIGlzIHJlcGxhY2VkXG5cdFx0XHQgKiB3aXRoIGEgZGVmYXVsdCBzZWxlY3QgbGlzdCBvZiAxMCwgMjUsIDUwIGFuZCAxMDAsIGFuZCBjYW4gYmUgcmVwbGFjZWRcblx0XHRcdCAqIHdpdGggYSBjdXN0b20gc2VsZWN0IGJveCBpZiByZXF1aXJlZC5cblx0XHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHRcdCAqICBAZGVmYXVsdCBTaG93IF9NRU5VXyBlbnRyaWVzXG5cdFx0XHQgKlxuXHRcdFx0ICogIEBkdG9wdCBMYW5ndWFnZVxuXHRcdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5sYW5ndWFnZS5sZW5ndGhNZW51XG5cdFx0XHQgKlxuXHRcdFx0ICogIEBleGFtcGxlXG5cdFx0XHQgKiAgICAvLyBMYW5ndWFnZSBjaGFuZ2Ugb25seVxuXHRcdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdFx0ICogICAgICAgIFwibGFuZ3VhZ2VcIjoge1xuXHRcdFx0ICogICAgICAgICAgXCJsZW5ndGhNZW51XCI6IFwiRGlzcGxheSBfTUVOVV8gcmVjb3Jkc1wiXG5cdFx0XHQgKiAgICAgICAgfVxuXHRcdFx0ICogICAgICB9ICk7XG5cdFx0XHQgKiAgICB9ICk7XG5cdFx0XHQgKlxuXHRcdFx0ICogIEBleGFtcGxlXG5cdFx0XHQgKiAgICAvLyBMYW5ndWFnZSBhbmQgb3B0aW9ucyBjaGFuZ2Vcblx0XHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHRcdCAqICAgICAgICBcImxhbmd1YWdlXCI6IHtcblx0XHRcdCAqICAgICAgICAgIFwibGVuZ3RoTWVudVwiOiAnRGlzcGxheSA8c2VsZWN0PicrXG5cdFx0XHQgKiAgICAgICAgICAgICc8b3B0aW9uIHZhbHVlPVwiMTBcIj4xMDwvb3B0aW9uPicrXG5cdFx0XHQgKiAgICAgICAgICAgICc8b3B0aW9uIHZhbHVlPVwiMjBcIj4yMDwvb3B0aW9uPicrXG5cdFx0XHQgKiAgICAgICAgICAgICc8b3B0aW9uIHZhbHVlPVwiMzBcIj4zMDwvb3B0aW9uPicrXG5cdFx0XHQgKiAgICAgICAgICAgICc8b3B0aW9uIHZhbHVlPVwiNDBcIj40MDwvb3B0aW9uPicrXG5cdFx0XHQgKiAgICAgICAgICAgICc8b3B0aW9uIHZhbHVlPVwiNTBcIj41MDwvb3B0aW9uPicrXG5cdFx0XHQgKiAgICAgICAgICAgICc8b3B0aW9uIHZhbHVlPVwiLTFcIj5BbGw8L29wdGlvbj4nK1xuXHRcdFx0ICogICAgICAgICAgICAnPC9zZWxlY3Q+IHJlY29yZHMnXG5cdFx0XHQgKiAgICAgICAgfVxuXHRcdFx0ICogICAgICB9ICk7XG5cdFx0XHQgKiAgICB9ICk7XG5cdFx0XHQgKi9cblx0XHRcdFwic0xlbmd0aE1lbnVcIjogXCJTaG93IF9NRU5VXyBlbnRyaWVzXCIsXG5cdFxuXHRcblx0XHRcdC8qKlxuXHRcdFx0ICogV2hlbiB1c2luZyBBamF4IHNvdXJjZWQgZGF0YSBhbmQgZHVyaW5nIHRoZSBmaXJzdCBkcmF3IHdoZW4gRGF0YVRhYmxlcyBpc1xuXHRcdFx0ICogZ2F0aGVyaW5nIHRoZSBkYXRhLCB0aGlzIG1lc3NhZ2UgaXMgc2hvd24gaW4gYW4gZW1wdHkgcm93IGluIHRoZSB0YWJsZSB0b1xuXHRcdFx0ICogaW5kaWNhdGUgdG8gdGhlIGVuZCB1c2VyIHRoZSB0aGUgZGF0YSBpcyBiZWluZyBsb2FkZWQuIE5vdGUgdGhhdCB0aGlzXG5cdFx0XHQgKiBwYXJhbWV0ZXIgaXMgbm90IHVzZWQgd2hlbiBsb2FkaW5nIGRhdGEgYnkgc2VydmVyLXNpZGUgcHJvY2Vzc2luZywganVzdFxuXHRcdFx0ICogQWpheCBzb3VyY2VkIGRhdGEgd2l0aCBjbGllbnQtc2lkZSBwcm9jZXNzaW5nLlxuXHRcdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdFx0ICogIEBkZWZhdWx0IExvYWRpbmcuLi5cblx0XHRcdCAqXG5cdFx0XHQgKiAgQGR0b3B0IExhbmd1YWdlXG5cdFx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLmxhbmd1YWdlLmxvYWRpbmdSZWNvcmRzXG5cdFx0XHQgKlxuXHRcdFx0ICogIEBleGFtcGxlXG5cdFx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0XHQgKiAgICAgICAgXCJsYW5ndWFnZVwiOiB7XG5cdFx0XHQgKiAgICAgICAgICBcImxvYWRpbmdSZWNvcmRzXCI6IFwiUGxlYXNlIHdhaXQgLSBsb2FkaW5nLi4uXCJcblx0XHRcdCAqICAgICAgICB9XG5cdFx0XHQgKiAgICAgIH0gKTtcblx0XHRcdCAqICAgIH0gKTtcblx0XHRcdCAqL1xuXHRcdFx0XCJzTG9hZGluZ1JlY29yZHNcIjogXCJMb2FkaW5nLi4uXCIsXG5cdFxuXHRcblx0XHRcdC8qKlxuXHRcdFx0ICogVGV4dCB3aGljaCBpcyBkaXNwbGF5ZWQgd2hlbiB0aGUgdGFibGUgaXMgcHJvY2Vzc2luZyBhIHVzZXIgYWN0aW9uXG5cdFx0XHQgKiAodXN1YWxseSBhIHNvcnQgY29tbWFuZCBvciBzaW1pbGFyKS5cblx0XHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHRcdCAqICBAZGVmYXVsdCBQcm9jZXNzaW5nLi4uXG5cdFx0XHQgKlxuXHRcdFx0ICogIEBkdG9wdCBMYW5ndWFnZVxuXHRcdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5sYW5ndWFnZS5wcm9jZXNzaW5nXG5cdFx0XHQgKlxuXHRcdFx0ICogIEBleGFtcGxlXG5cdFx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0XHQgKiAgICAgICAgXCJsYW5ndWFnZVwiOiB7XG5cdFx0XHQgKiAgICAgICAgICBcInByb2Nlc3NpbmdcIjogXCJEYXRhVGFibGVzIGlzIGN1cnJlbnRseSBidXN5XCJcblx0XHRcdCAqICAgICAgICB9XG5cdFx0XHQgKiAgICAgIH0gKTtcblx0XHRcdCAqICAgIH0gKTtcblx0XHRcdCAqL1xuXHRcdFx0XCJzUHJvY2Vzc2luZ1wiOiBcIlByb2Nlc3NpbmcuLi5cIixcblx0XG5cdFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBEZXRhaWxzIHRoZSBhY3Rpb25zIHRoYXQgd2lsbCBiZSB0YWtlbiB3aGVuIHRoZSB1c2VyIHR5cGVzIGludG8gdGhlXG5cdFx0XHQgKiBmaWx0ZXJpbmcgaW5wdXQgdGV4dCBib3guIFRoZSB2YXJpYWJsZSBcIl9JTlBVVF9cIiwgaWYgdXNlZCBpbiB0aGUgc3RyaW5nLFxuXHRcdFx0ICogaXMgcmVwbGFjZWQgd2l0aCB0aGUgSFRNTCB0ZXh0IGJveCBmb3IgdGhlIGZpbHRlcmluZyBpbnB1dCBhbGxvd2luZ1xuXHRcdFx0ICogY29udHJvbCBvdmVyIHdoZXJlIGl0IGFwcGVhcnMgaW4gdGhlIHN0cmluZy4gSWYgXCJfSU5QVVRfXCIgaXMgbm90IGdpdmVuXG5cdFx0XHQgKiB0aGVuIHRoZSBpbnB1dCBib3ggaXMgYXBwZW5kZWQgdG8gdGhlIHN0cmluZyBhdXRvbWF0aWNhbGx5LlxuXHRcdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdFx0ICogIEBkZWZhdWx0IFNlYXJjaDpcblx0XHRcdCAqXG5cdFx0XHQgKiAgQGR0b3B0IExhbmd1YWdlXG5cdFx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLmxhbmd1YWdlLnNlYXJjaFxuXHRcdFx0ICpcblx0XHRcdCAqICBAZXhhbXBsZVxuXHRcdFx0ICogICAgLy8gSW5wdXQgdGV4dCBib3ggd2lsbCBiZSBhcHBlbmRlZCBhdCB0aGUgZW5kIGF1dG9tYXRpY2FsbHlcblx0XHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHRcdCAqICAgICAgICBcImxhbmd1YWdlXCI6IHtcblx0XHRcdCAqICAgICAgICAgIFwic2VhcmNoXCI6IFwiRmlsdGVyIHJlY29yZHM6XCJcblx0XHRcdCAqICAgICAgICB9XG5cdFx0XHQgKiAgICAgIH0gKTtcblx0XHRcdCAqICAgIH0gKTtcblx0XHRcdCAqXG5cdFx0XHQgKiAgQGV4YW1wbGVcblx0XHRcdCAqICAgIC8vIFNwZWNpZnkgd2hlcmUgdGhlIGZpbHRlciBzaG91bGQgYXBwZWFyXG5cdFx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0XHQgKiAgICAgICAgXCJsYW5ndWFnZVwiOiB7XG5cdFx0XHQgKiAgICAgICAgICBcInNlYXJjaFwiOiBcIkFwcGx5IGZpbHRlciBfSU5QVVRfIHRvIHRhYmxlXCJcblx0XHRcdCAqICAgICAgICB9XG5cdFx0XHQgKiAgICAgIH0gKTtcblx0XHRcdCAqICAgIH0gKTtcblx0XHRcdCAqL1xuXHRcdFx0XCJzU2VhcmNoXCI6IFwiU2VhcmNoOlwiLFxuXHRcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIEFzc2lnbiBhIGBwbGFjZWhvbGRlcmAgYXR0cmlidXRlIHRvIHRoZSBzZWFyY2ggYGlucHV0YCBlbGVtZW50XG5cdFx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0XHQgKiAgQGRlZmF1bHQgXG5cdFx0XHQgKlxuXHRcdFx0ICogIEBkdG9wdCBMYW5ndWFnZVxuXHRcdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5sYW5ndWFnZS5zZWFyY2hQbGFjZWhvbGRlclxuXHRcdFx0ICovXG5cdFx0XHRcInNTZWFyY2hQbGFjZWhvbGRlclwiOiBcIlwiLFxuXHRcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIEFsbCBvZiB0aGUgbGFuZ3VhZ2UgaW5mb3JtYXRpb24gY2FuIGJlIHN0b3JlZCBpbiBhIGZpbGUgb24gdGhlXG5cdFx0XHQgKiBzZXJ2ZXItc2lkZSwgd2hpY2ggRGF0YVRhYmxlcyB3aWxsIGxvb2sgdXAgaWYgdGhpcyBwYXJhbWV0ZXIgaXMgcGFzc2VkLlxuXHRcdFx0ICogSXQgbXVzdCBzdG9yZSB0aGUgVVJMIG9mIHRoZSBsYW5ndWFnZSBmaWxlLCB3aGljaCBpcyBpbiBhIEpTT04gZm9ybWF0LFxuXHRcdFx0ICogYW5kIHRoZSBvYmplY3QgaGFzIHRoZSBzYW1lIHByb3BlcnRpZXMgYXMgdGhlIG9MYW5ndWFnZSBvYmplY3QgaW4gdGhlXG5cdFx0XHQgKiBpbml0aWFsaXNlciBvYmplY3QgKGkuZS4gdGhlIGFib3ZlIHBhcmFtZXRlcnMpLiBQbGVhc2UgcmVmZXIgdG8gb25lIG9mXG5cdFx0XHQgKiB0aGUgZXhhbXBsZSBsYW5ndWFnZSBmaWxlcyB0byBzZWUgaG93IHRoaXMgd29ya3MgaW4gYWN0aW9uLlxuXHRcdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdFx0ICogIEBkZWZhdWx0IDxpPkVtcHR5IHN0cmluZyAtIGkuZS4gZGlzYWJsZWQ8L2k+XG5cdFx0XHQgKlxuXHRcdFx0ICogIEBkdG9wdCBMYW5ndWFnZVxuXHRcdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5sYW5ndWFnZS51cmxcblx0XHRcdCAqXG5cdFx0XHQgKiAgQGV4YW1wbGVcblx0XHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHRcdCAqICAgICAgICBcImxhbmd1YWdlXCI6IHtcblx0XHRcdCAqICAgICAgICAgIFwidXJsXCI6IFwiaHR0cDovL3d3dy5zcHJ5bWVkaWEuY28udWsvZGF0YVRhYmxlcy9sYW5nLnR4dFwiXG5cdFx0XHQgKiAgICAgICAgfVxuXHRcdFx0ICogICAgICB9ICk7XG5cdFx0XHQgKiAgICB9ICk7XG5cdFx0XHQgKi9cblx0XHRcdFwic1VybFwiOiBcIlwiLFxuXHRcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIFRleHQgc2hvd24gaW5zaWRlIHRoZSB0YWJsZSByZWNvcmRzIHdoZW4gdGhlIGlzIG5vIGluZm9ybWF0aW9uIHRvIGJlXG5cdFx0XHQgKiBkaXNwbGF5ZWQgYWZ0ZXIgZmlsdGVyaW5nLiBgZW1wdHlUYWJsZWAgaXMgc2hvd24gd2hlbiB0aGVyZSBpcyBzaW1wbHkgbm9cblx0XHRcdCAqIGluZm9ybWF0aW9uIGluIHRoZSB0YWJsZSBhdCBhbGwgKHJlZ2FyZGxlc3Mgb2YgZmlsdGVyaW5nKS5cblx0XHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHRcdCAqICBAZGVmYXVsdCBObyBtYXRjaGluZyByZWNvcmRzIGZvdW5kXG5cdFx0XHQgKlxuXHRcdFx0ICogIEBkdG9wdCBMYW5ndWFnZVxuXHRcdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5sYW5ndWFnZS56ZXJvUmVjb3Jkc1xuXHRcdFx0ICpcblx0XHRcdCAqICBAZXhhbXBsZVxuXHRcdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdFx0ICogICAgICAgIFwibGFuZ3VhZ2VcIjoge1xuXHRcdFx0ICogICAgICAgICAgXCJ6ZXJvUmVjb3Jkc1wiOiBcIk5vIHJlY29yZHMgdG8gZGlzcGxheVwiXG5cdFx0XHQgKiAgICAgICAgfVxuXHRcdFx0ICogICAgICB9ICk7XG5cdFx0XHQgKiAgICB9ICk7XG5cdFx0XHQgKi9cblx0XHRcdFwic1plcm9SZWNvcmRzXCI6IFwiTm8gbWF0Y2hpbmcgcmVjb3JkcyBmb3VuZFwiXG5cdFx0fSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIFRoaXMgcGFyYW1ldGVyIGFsbG93cyB5b3UgdG8gaGF2ZSBkZWZpbmUgdGhlIGdsb2JhbCBmaWx0ZXJpbmcgc3RhdGUgYXRcblx0XHQgKiBpbml0aWFsaXNhdGlvbiB0aW1lLiBBcyBhbiBvYmplY3QgdGhlIGBzZWFyY2hgIHBhcmFtZXRlciBtdXN0IGJlXG5cdFx0ICogZGVmaW5lZCwgYnV0IGFsbCBvdGhlciBwYXJhbWV0ZXJzIGFyZSBvcHRpb25hbC4gV2hlbiBgcmVnZXhgIGlzIHRydWUsXG5cdFx0ICogdGhlIHNlYXJjaCBzdHJpbmcgd2lsbCBiZSB0cmVhdGVkIGFzIGEgcmVndWxhciBleHByZXNzaW9uLCB3aGVuIGZhbHNlXG5cdFx0ICogKGRlZmF1bHQpIGl0IHdpbGwgYmUgdHJlYXRlZCBhcyBhIHN0cmFpZ2h0IHN0cmluZy4gV2hlbiBgc21hcnRgXG5cdFx0ICogRGF0YVRhYmxlcyB3aWxsIHVzZSBpdCdzIHNtYXJ0IGZpbHRlcmluZyBtZXRob2RzICh0byB3b3JkIG1hdGNoIGF0XG5cdFx0ICogYW55IHBvaW50IGluIHRoZSBkYXRhKSwgd2hlbiBmYWxzZSB0aGlzIHdpbGwgbm90IGJlIGRvbmUuXG5cdFx0ICogIEBuYW1lc3BhY2Vcblx0XHQgKiAgQGV4dGVuZHMgRGF0YVRhYmxlLm1vZGVscy5vU2VhcmNoXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IE9wdGlvbnNcblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLnNlYXJjaFxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJzZWFyY2hcIjoge1wic2VhcmNoXCI6IFwiSW5pdGlhbCBzZWFyY2hcIn1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9IClcblx0XHQgKi9cblx0XHRcIm9TZWFyY2hcIjogJC5leHRlbmQoIHt9LCBEYXRhVGFibGUubW9kZWxzLm9TZWFyY2ggKSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIF9fRGVwcmVjYXRlZF9fIFRoZSBmdW5jdGlvbmFsaXR5IHByb3ZpZGVkIGJ5IHRoaXMgcGFyYW1ldGVyIGhhcyBub3cgYmVlblxuXHRcdCAqIHN1cGVyc2VkZWQgYnkgdGhhdCBwcm92aWRlZCB0aHJvdWdoIGBhamF4YCwgd2hpY2ggc2hvdWxkIGJlIHVzZWQgaW5zdGVhZC5cblx0XHQgKlxuXHRcdCAqIEJ5IGRlZmF1bHQgRGF0YVRhYmxlcyB3aWxsIGxvb2sgZm9yIHRoZSBwcm9wZXJ0eSBgZGF0YWAgKG9yIGBhYURhdGFgIGZvclxuXHRcdCAqIGNvbXBhdGliaWxpdHkgd2l0aCBEYXRhVGFibGVzIDEuOS0pIHdoZW4gb2J0YWluaW5nIGRhdGEgZnJvbSBhbiBBamF4XG5cdFx0ICogc291cmNlIG9yIGZvciBzZXJ2ZXItc2lkZSBwcm9jZXNzaW5nIC0gdGhpcyBwYXJhbWV0ZXIgYWxsb3dzIHRoYXRcblx0XHQgKiBwcm9wZXJ0eSB0byBiZSBjaGFuZ2VkLiBZb3UgY2FuIHVzZSBKYXZhc2NyaXB0IGRvdHRlZCBvYmplY3Qgbm90YXRpb24gdG9cblx0XHQgKiBnZXQgYSBkYXRhIHNvdXJjZSBmb3IgbXVsdGlwbGUgbGV2ZWxzIG9mIG5lc3RpbmcuXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqICBAZGVmYXVsdCBkYXRhXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IE9wdGlvbnNcblx0XHQgKiAgQGR0b3B0IFNlcnZlci1zaWRlXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5hamF4RGF0YVByb3Bcblx0XHQgKlxuXHRcdCAqICBAZGVwcmVjYXRlZCAxLjEwLiBQbGVhc2UgdXNlIGBhamF4YCBmb3IgdGhpcyBmdW5jdGlvbmFsaXR5IG5vdy5cblx0XHQgKi9cblx0XHRcInNBamF4RGF0YVByb3BcIjogXCJkYXRhXCIsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBfX0RlcHJlY2F0ZWRfXyBUaGUgZnVuY3Rpb25hbGl0eSBwcm92aWRlZCBieSB0aGlzIHBhcmFtZXRlciBoYXMgbm93IGJlZW5cblx0XHQgKiBzdXBlcnNlZGVkIGJ5IHRoYXQgcHJvdmlkZWQgdGhyb3VnaCBgYWpheGAsIHdoaWNoIHNob3VsZCBiZSB1c2VkIGluc3RlYWQuXG5cdFx0ICpcblx0XHQgKiBZb3UgY2FuIGluc3RydWN0IERhdGFUYWJsZXMgdG8gbG9hZCBkYXRhIGZyb20gYW4gZXh0ZXJuYWxcblx0XHQgKiBzb3VyY2UgdXNpbmcgdGhpcyBwYXJhbWV0ZXIgKHVzZSBhRGF0YSBpZiB5b3Ugd2FudCB0byBwYXNzIGRhdGEgaW4geW91XG5cdFx0ICogYWxyZWFkeSBoYXZlKS4gU2ltcGx5IHByb3ZpZGUgYSB1cmwgYSBKU09OIG9iamVjdCBjYW4gYmUgb2J0YWluZWQgZnJvbS5cblx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgT3B0aW9uc1xuXHRcdCAqICBAZHRvcHQgU2VydmVyLXNpZGVcblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLmFqYXhTb3VyY2Vcblx0XHQgKlxuXHRcdCAqICBAZGVwcmVjYXRlZCAxLjEwLiBQbGVhc2UgdXNlIGBhamF4YCBmb3IgdGhpcyBmdW5jdGlvbmFsaXR5IG5vdy5cblx0XHQgKi9cblx0XHRcInNBamF4U291cmNlXCI6IG51bGwsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBUaGlzIGluaXRpYWxpc2F0aW9uIHZhcmlhYmxlIGFsbG93cyB5b3UgdG8gc3BlY2lmeSBleGFjdGx5IHdoZXJlIGluIHRoZVxuXHRcdCAqIERPTSB5b3Ugd2FudCBEYXRhVGFibGVzIHRvIGluamVjdCB0aGUgdmFyaW91cyBjb250cm9scyBpdCBhZGRzIHRvIHRoZSBwYWdlXG5cdFx0ICogKGZvciBleGFtcGxlIHlvdSBtaWdodCB3YW50IHRoZSBwYWdpbmF0aW9uIGNvbnRyb2xzIGF0IHRoZSB0b3Agb2YgdGhlXG5cdFx0ICogdGFibGUpLiBESVYgZWxlbWVudHMgKHdpdGggb3Igd2l0aG91dCBhIGN1c3RvbSBjbGFzcykgY2FuIGFsc28gYmUgYWRkZWQgdG9cblx0XHQgKiBhaWQgc3R5bGluZy4gVGhlIGZvbGxvdyBzeW50YXggaXMgdXNlZDpcblx0XHQgKiAgIDx1bD5cblx0XHQgKiAgICAgPGxpPlRoZSBmb2xsb3dpbmcgb3B0aW9ucyBhcmUgYWxsb3dlZDpcblx0XHQgKiAgICAgICA8dWw+XG5cdFx0ICogICAgICAgICA8bGk+J2wnIC0gTGVuZ3RoIGNoYW5naW5nPC9saT5cblx0XHQgKiAgICAgICAgIDxsaT4nZicgLSBGaWx0ZXJpbmcgaW5wdXQ8L2xpPlxuXHRcdCAqICAgICAgICAgPGxpPid0JyAtIFRoZSB0YWJsZSE8L2xpPlxuXHRcdCAqICAgICAgICAgPGxpPidpJyAtIEluZm9ybWF0aW9uPC9saT5cblx0XHQgKiAgICAgICAgIDxsaT4ncCcgLSBQYWdpbmF0aW9uPC9saT5cblx0XHQgKiAgICAgICAgIDxsaT4ncicgLSBwUm9jZXNzaW5nPC9saT5cblx0XHQgKiAgICAgICA8L3VsPlxuXHRcdCAqICAgICA8L2xpPlxuXHRcdCAqICAgICA8bGk+VGhlIGZvbGxvd2luZyBjb25zdGFudHMgYXJlIGFsbG93ZWQ6XG5cdFx0ICogICAgICAgPHVsPlxuXHRcdCAqICAgICAgICAgPGxpPidIJyAtIGpRdWVyeVVJIHRoZW1lIFwiaGVhZGVyXCIgY2xhc3NlcyAoJ2ZnLXRvb2xiYXIgdWktd2lkZ2V0LWhlYWRlciB1aS1jb3JuZXItdGwgdWktY29ybmVyLXRyIHVpLWhlbHBlci1jbGVhcmZpeCcpPC9saT5cblx0XHQgKiAgICAgICAgIDxsaT4nRicgLSBqUXVlcnlVSSB0aGVtZSBcImZvb3RlclwiIGNsYXNzZXMgKCdmZy10b29sYmFyIHVpLXdpZGdldC1oZWFkZXIgdWktY29ybmVyLWJsIHVpLWNvcm5lci1iciB1aS1oZWxwZXItY2xlYXJmaXgnKTwvbGk+XG5cdFx0ICogICAgICAgPC91bD5cblx0XHQgKiAgICAgPC9saT5cblx0XHQgKiAgICAgPGxpPlRoZSBmb2xsb3dpbmcgc3ludGF4IGlzIGV4cGVjdGVkOlxuXHRcdCAqICAgICAgIDx1bD5cblx0XHQgKiAgICAgICAgIDxsaT4nJmx0OycgYW5kICcmZ3Q7JyAtIGRpdiBlbGVtZW50czwvbGk+XG5cdFx0ICogICAgICAgICA8bGk+JyZsdDtcImNsYXNzXCIgYW5kICcmZ3Q7JyAtIGRpdiB3aXRoIGEgY2xhc3M8L2xpPlxuXHRcdCAqICAgICAgICAgPGxpPicmbHQ7XCIjaWRcIiBhbmQgJyZndDsnIC0gZGl2IHdpdGggYW4gSUQ8L2xpPlxuXHRcdCAqICAgICAgIDwvdWw+XG5cdFx0ICogICAgIDwvbGk+XG5cdFx0ICogICAgIDxsaT5FeGFtcGxlczpcblx0XHQgKiAgICAgICA8dWw+XG5cdFx0ICogICAgICAgICA8bGk+JyZsdDtcIndyYXBwZXJcImZsaXB0Jmd0Oyc8L2xpPlxuXHRcdCAqICAgICAgICAgPGxpPicmbHQ7bGYmbHQ7dCZndDtpcCZndDsnPC9saT5cblx0XHQgKiAgICAgICA8L3VsPlxuXHRcdCAqICAgICA8L2xpPlxuXHRcdCAqICAgPC91bD5cblx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0ICogIEBkZWZhdWx0IGxmcnRpcCA8aT4od2hlbiBgalF1ZXJ5VUlgIGlzIGZhbHNlKTwvaT4gPGI+b3I8L2I+XG5cdFx0ICogICAgPFwiSFwibGZyPnQ8XCJGXCJpcD4gPGk+KHdoZW4gYGpRdWVyeVVJYCBpcyB0cnVlKTwvaT5cblx0XHQgKlxuXHRcdCAqICBAZHRvcHQgT3B0aW9uc1xuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuZG9tXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImRvbVwiOiAnJmx0O1widG9wXCJpJmd0O3J0Jmx0O1wiYm90dG9tXCJmbHAmZ3Q7Jmx0O1wiY2xlYXJcIiZndDsnXG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdFwic0RvbVwiOiBcImxmcnRpcFwiLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogU2VhcmNoIGRlbGF5IG9wdGlvbi4gVGhpcyB3aWxsIHRocm90dGxlIGZ1bGwgdGFibGUgc2VhcmNoZXMgdGhhdCB1c2UgdGhlXG5cdFx0ICogRGF0YVRhYmxlcyBwcm92aWRlZCBzZWFyY2ggaW5wdXQgZWxlbWVudCAoaXQgZG9lcyBub3QgZWZmZWN0IGNhbGxzIHRvXG5cdFx0ICogYGR0LWFwaSBzZWFyY2goKWAsIHByb3ZpZGluZyBhIGRlbGF5IGJlZm9yZSB0aGUgc2VhcmNoIGlzIG1hZGUuXG5cdFx0ICogIEB0eXBlIGludGVnZXJcblx0XHQgKiAgQGRlZmF1bHQgMFxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBPcHRpb25zXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5zZWFyY2hEZWxheVxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJzZWFyY2hEZWxheVwiOiAyMDBcblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9IClcblx0XHQgKi9cblx0XHRcInNlYXJjaERlbGF5XCI6IG51bGwsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBEYXRhVGFibGVzIGZlYXR1cmVzIHNpeCBkaWZmZXJlbnQgYnVpbHQtaW4gb3B0aW9ucyBmb3IgdGhlIGJ1dHRvbnMgdG9cblx0XHQgKiBkaXNwbGF5IGZvciBwYWdpbmF0aW9uIGNvbnRyb2w6XG5cdFx0ICpcblx0XHQgKiAqIGBudW1iZXJzYCAtIFBhZ2UgbnVtYmVyIGJ1dHRvbnMgb25seVxuXHRcdCAqICogYHNpbXBsZWAgLSAnUHJldmlvdXMnIGFuZCAnTmV4dCcgYnV0dG9ucyBvbmx5XG5cdFx0ICogKiAnc2ltcGxlX251bWJlcnNgIC0gJ1ByZXZpb3VzJyBhbmQgJ05leHQnIGJ1dHRvbnMsIHBsdXMgcGFnZSBudW1iZXJzXG5cdFx0ICogKiBgZnVsbGAgLSAnRmlyc3QnLCAnUHJldmlvdXMnLCAnTmV4dCcgYW5kICdMYXN0JyBidXR0b25zXG5cdFx0ICogKiBgZnVsbF9udW1iZXJzYCAtICdGaXJzdCcsICdQcmV2aW91cycsICdOZXh0JyBhbmQgJ0xhc3QnIGJ1dHRvbnMsIHBsdXMgcGFnZSBudW1iZXJzXG5cdFx0ICogKiBgZmlyc3RfbGFzdF9udW1iZXJzYCAtICdGaXJzdCcgYW5kICdMYXN0JyBidXR0b25zLCBwbHVzIHBhZ2UgbnVtYmVyc1xuXHRcdCAqICBcblx0XHQgKiBGdXJ0aGVyIG1ldGhvZHMgY2FuIGJlIGFkZGVkIHVzaW5nIHtAbGluayBEYXRhVGFibGUuZXh0Lm9QYWdpbmF0aW9ufS5cblx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0ICogIEBkZWZhdWx0IHNpbXBsZV9udW1iZXJzXG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IE9wdGlvbnNcblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLnBhZ2luZ1R5cGVcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwicGFnaW5nVHlwZVwiOiBcImZ1bGxfbnVtYmVyc1wiXG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApXG5cdFx0ICovXG5cdFx0XCJzUGFnaW5hdGlvblR5cGVcIjogXCJzaW1wbGVfbnVtYmVyc1wiLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogRW5hYmxlIGhvcml6b250YWwgc2Nyb2xsaW5nLiBXaGVuIGEgdGFibGUgaXMgdG9vIHdpZGUgdG8gZml0IGludG8gYVxuXHRcdCAqIGNlcnRhaW4gbGF5b3V0LCBvciB5b3UgaGF2ZSBhIGxhcmdlIG51bWJlciBvZiBjb2x1bW5zIGluIHRoZSB0YWJsZSwgeW91XG5cdFx0ICogY2FuIGVuYWJsZSB4LXNjcm9sbGluZyB0byBzaG93IHRoZSB0YWJsZSBpbiBhIHZpZXdwb3J0LCB3aGljaCBjYW4gYmVcblx0XHQgKiBzY3JvbGxlZC4gVGhpcyBwcm9wZXJ0eSBjYW4gYmUgYHRydWVgIHdoaWNoIHdpbGwgYWxsb3cgdGhlIHRhYmxlIHRvXG5cdFx0ICogc2Nyb2xsIGhvcml6b250YWxseSB3aGVuIG5lZWRlZCwgb3IgYW55IENTUyB1bml0LCBvciBhIG51bWJlciAoaW4gd2hpY2hcblx0XHQgKiBjYXNlIGl0IHdpbGwgYmUgdHJlYXRlZCBhcyBhIHBpeGVsIG1lYXN1cmVtZW50KS4gU2V0dGluZyBhcyBzaW1wbHkgYHRydWVgXG5cdFx0ICogaXMgcmVjb21tZW5kZWQuXG5cdFx0ICogIEB0eXBlIGJvb2xlYW58c3RyaW5nXG5cdFx0ICogIEBkZWZhdWx0IDxpPmJsYW5rIHN0cmluZyAtIGkuZS4gZGlzYWJsZWQ8L2k+XG5cdFx0ICpcblx0XHQgKiAgQGR0b3B0IEZlYXR1cmVzXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5zY3JvbGxYXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcInNjcm9sbFhcIjogdHJ1ZSxcblx0XHQgKiAgICAgICAgXCJzY3JvbGxDb2xsYXBzZVwiOiB0cnVlXG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdFwic1Njcm9sbFhcIjogXCJcIixcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIFRoaXMgcHJvcGVydHkgY2FuIGJlIHVzZWQgdG8gZm9yY2UgYSBEYXRhVGFibGUgdG8gdXNlIG1vcmUgd2lkdGggdGhhbiBpdFxuXHRcdCAqIG1pZ2h0IG90aGVyd2lzZSBkbyB3aGVuIHgtc2Nyb2xsaW5nIGlzIGVuYWJsZWQuIEZvciBleGFtcGxlIGlmIHlvdSBoYXZlIGFcblx0XHQgKiB0YWJsZSB3aGljaCByZXF1aXJlcyB0byBiZSB3ZWxsIHNwYWNlZCwgdGhpcyBwYXJhbWV0ZXIgaXMgdXNlZnVsIGZvclxuXHRcdCAqIFwib3Zlci1zaXppbmdcIiB0aGUgdGFibGUsIGFuZCB0aHVzIGZvcmNpbmcgc2Nyb2xsaW5nLiBUaGlzIHByb3BlcnR5IGNhbiBieVxuXHRcdCAqIGFueSBDU1MgdW5pdCwgb3IgYSBudW1iZXIgKGluIHdoaWNoIGNhc2UgaXQgd2lsbCBiZSB0cmVhdGVkIGFzIGEgcGl4ZWxcblx0XHQgKiBtZWFzdXJlbWVudCkuXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqICBAZGVmYXVsdCA8aT5ibGFuayBzdHJpbmcgLSBpLmUuIGRpc2FibGVkPC9pPlxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBPcHRpb25zXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5zY3JvbGxYSW5uZXJcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwic2Nyb2xsWFwiOiBcIjEwMCVcIixcblx0XHQgKiAgICAgICAgXCJzY3JvbGxYSW5uZXJcIjogXCIxMTAlXCJcblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJzU2Nyb2xsWElubmVyXCI6IFwiXCIsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBFbmFibGUgdmVydGljYWwgc2Nyb2xsaW5nLiBWZXJ0aWNhbCBzY3JvbGxpbmcgd2lsbCBjb25zdHJhaW4gdGhlIERhdGFUYWJsZVxuXHRcdCAqIHRvIHRoZSBnaXZlbiBoZWlnaHQsIGFuZCBlbmFibGUgc2Nyb2xsaW5nIGZvciBhbnkgZGF0YSB3aGljaCBvdmVyZmxvd3MgdGhlXG5cdFx0ICogY3VycmVudCB2aWV3cG9ydC4gVGhpcyBjYW4gYmUgdXNlZCBhcyBhbiBhbHRlcm5hdGl2ZSB0byBwYWdpbmcgdG8gZGlzcGxheVxuXHRcdCAqIGEgbG90IG9mIGRhdGEgaW4gYSBzbWFsbCBhcmVhIChhbHRob3VnaCBwYWdpbmcgYW5kIHNjcm9sbGluZyBjYW4gYm90aCBiZVxuXHRcdCAqIGVuYWJsZWQgYXQgdGhlIHNhbWUgdGltZSkuIFRoaXMgcHJvcGVydHkgY2FuIGJlIGFueSBDU1MgdW5pdCwgb3IgYSBudW1iZXJcblx0XHQgKiAoaW4gd2hpY2ggY2FzZSBpdCB3aWxsIGJlIHRyZWF0ZWQgYXMgYSBwaXhlbCBtZWFzdXJlbWVudCkuXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqICBAZGVmYXVsdCA8aT5ibGFuayBzdHJpbmcgLSBpLmUuIGRpc2FibGVkPC9pPlxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBGZWF0dXJlc1xuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuc2Nyb2xsWVxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJzY3JvbGxZXCI6IFwiMjAwcHhcIixcblx0XHQgKiAgICAgICAgXCJwYWdpbmF0ZVwiOiBmYWxzZVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcInNTY3JvbGxZXCI6IFwiXCIsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBfX0RlcHJlY2F0ZWRfXyBUaGUgZnVuY3Rpb25hbGl0eSBwcm92aWRlZCBieSB0aGlzIHBhcmFtZXRlciBoYXMgbm93IGJlZW5cblx0XHQgKiBzdXBlcnNlZGVkIGJ5IHRoYXQgcHJvdmlkZWQgdGhyb3VnaCBgYWpheGAsIHdoaWNoIHNob3VsZCBiZSB1c2VkIGluc3RlYWQuXG5cdFx0ICpcblx0XHQgKiBTZXQgdGhlIEhUVFAgbWV0aG9kIHRoYXQgaXMgdXNlZCB0byBtYWtlIHRoZSBBamF4IGNhbGwgZm9yIHNlcnZlci1zaWRlXG5cdFx0ICogcHJvY2Vzc2luZyBvciBBamF4IHNvdXJjZWQgZGF0YS5cblx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0ICogIEBkZWZhdWx0IEdFVFxuXHRcdCAqXG5cdFx0ICogIEBkdG9wdCBPcHRpb25zXG5cdFx0ICogIEBkdG9wdCBTZXJ2ZXItc2lkZVxuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuc2VydmVyTWV0aG9kXG5cdFx0ICpcblx0XHQgKiAgQGRlcHJlY2F0ZWQgMS4xMC4gUGxlYXNlIHVzZSBgYWpheGAgZm9yIHRoaXMgZnVuY3Rpb25hbGl0eSBub3cuXG5cdFx0ICovXG5cdFx0XCJzU2VydmVyTWV0aG9kXCI6IFwiR0VUXCIsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBEYXRhVGFibGVzIG1ha2VzIHVzZSBvZiByZW5kZXJlcnMgd2hlbiBkaXNwbGF5aW5nIEhUTUwgZWxlbWVudHMgZm9yXG5cdFx0ICogYSB0YWJsZS4gVGhlc2UgcmVuZGVyZXJzIGNhbiBiZSBhZGRlZCBvciBtb2RpZmllZCBieSBwbHVnLWlucyB0b1xuXHRcdCAqIGdlbmVyYXRlIHN1aXRhYmxlIG1hcmstdXAgZm9yIGEgc2l0ZS4gRm9yIGV4YW1wbGUgdGhlIEJvb3RzdHJhcFxuXHRcdCAqIGludGVncmF0aW9uIHBsdWctaW4gZm9yIERhdGFUYWJsZXMgdXNlcyBhIHBhZ2luZyBidXR0b24gcmVuZGVyZXIgdG9cblx0XHQgKiBkaXNwbGF5IHBhZ2luYXRpb24gYnV0dG9ucyBpbiB0aGUgbWFyay11cCByZXF1aXJlZCBieSBCb290c3RyYXAuXG5cdFx0ICpcblx0XHQgKiBGb3IgZnVydGhlciBpbmZvcm1hdGlvbiBhYm91dCB0aGUgcmVuZGVyZXJzIGF2YWlsYWJsZSBzZWVcblx0XHQgKiBEYXRhVGFibGUuZXh0LnJlbmRlcmVyXG5cdFx0ICogIEB0eXBlIHN0cmluZ3xvYmplY3Rcblx0XHQgKiAgQGRlZmF1bHQgbnVsbFxuXHRcdCAqXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5yZW5kZXJlclxuXHRcdCAqXG5cdFx0ICovXG5cdFx0XCJyZW5kZXJlclwiOiBudWxsLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogU2V0IHRoZSBkYXRhIHByb3BlcnR5IG5hbWUgdGhhdCBEYXRhVGFibGVzIHNob3VsZCB1c2UgdG8gZ2V0IGEgcm93J3MgaWRcblx0XHQgKiB0byBzZXQgYXMgdGhlIGBpZGAgcHJvcGVydHkgaW4gdGhlIG5vZGUuXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqICBAZGVmYXVsdCBEVF9Sb3dJZFxuXHRcdCAqXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5yb3dJZFxuXHRcdCAqL1xuXHRcdFwicm93SWRcIjogXCJEVF9Sb3dJZFwiXG5cdH07XG5cdFxuXHRfZm5IdW5nYXJpYW5NYXAoIERhdGFUYWJsZS5kZWZhdWx0cyApO1xuXHRcblx0XG5cdFxuXHQvKlxuXHQgKiBEZXZlbG9wZXIgbm90ZSAtIFNlZSBub3RlIGluIG1vZGVsLmRlZmF1bHRzLmpzIGFib3V0IHRoZSB1c2Ugb2YgSHVuZ2FyaWFuXG5cdCAqIG5vdGF0aW9uIGFuZCBjYW1lbCBjYXNlLlxuXHQgKi9cblx0XG5cdC8qKlxuXHQgKiBDb2x1bW4gb3B0aW9ucyB0aGF0IGNhbiBiZSBnaXZlbiB0byBEYXRhVGFibGVzIGF0IGluaXRpYWxpc2F0aW9uIHRpbWUuXG5cdCAqICBAbmFtZXNwYWNlXG5cdCAqL1xuXHREYXRhVGFibGUuZGVmYXVsdHMuY29sdW1uID0ge1xuXHRcdC8qKlxuXHRcdCAqIERlZmluZSB3aGljaCBjb2x1bW4ocykgYW4gb3JkZXIgd2lsbCBvY2N1ciBvbiBmb3IgdGhpcyBjb2x1bW4uIFRoaXNcblx0XHQgKiBhbGxvd3MgYSBjb2x1bW4ncyBvcmRlcmluZyB0byB0YWtlIG11bHRpcGxlIGNvbHVtbnMgaW50byBhY2NvdW50IHdoZW5cblx0XHQgKiBkb2luZyBhIHNvcnQgb3IgdXNlIHRoZSBkYXRhIGZyb20gYSBkaWZmZXJlbnQgY29sdW1uLiBGb3IgZXhhbXBsZSBmaXJzdFxuXHRcdCAqIG5hbWUgLyBsYXN0IG5hbWUgY29sdW1ucyBtYWtlIHNlbnNlIHRvIGRvIGEgbXVsdGktY29sdW1uIHNvcnQgb3ZlciB0aGVcblx0XHQgKiB0d28gY29sdW1ucy5cblx0XHQgKiAgQHR5cGUgYXJyYXl8aW50XG5cdFx0ICogIEBkZWZhdWx0IG51bGwgPGk+VGFrZXMgdGhlIHZhbHVlIG9mIHRoZSBjb2x1bW4gaW5kZXggYXV0b21hdGljYWxseTwvaT5cblx0XHQgKlxuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuY29sdW1uLm9yZGVyRGF0YVxuXHRcdCAqICBAZHRvcHQgQ29sdW1uc1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgLy8gVXNpbmcgYGNvbHVtbkRlZnNgXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJjb2x1bW5EZWZzXCI6IFtcblx0XHQgKiAgICAgICAgICB7IFwib3JkZXJEYXRhXCI6IFsgMCwgMSBdLCBcInRhcmdldHNcIjogWyAwIF0gfSxcblx0XHQgKiAgICAgICAgICB7IFwib3JkZXJEYXRhXCI6IFsgMSwgMCBdLCBcInRhcmdldHNcIjogWyAxIF0gfSxcblx0XHQgKiAgICAgICAgICB7IFwib3JkZXJEYXRhXCI6IDIsIFwidGFyZ2V0c1wiOiBbIDIgXSB9XG5cdFx0ICogICAgICAgIF1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBVc2luZyBgY29sdW1uc2Bcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImNvbHVtbnNcIjogW1xuXHRcdCAqICAgICAgICAgIHsgXCJvcmRlckRhdGFcIjogWyAwLCAxIF0gfSxcblx0XHQgKiAgICAgICAgICB7IFwib3JkZXJEYXRhXCI6IFsgMSwgMCBdIH0sXG5cdFx0ICogICAgICAgICAgeyBcIm9yZGVyRGF0YVwiOiAyIH0sXG5cdFx0ICogICAgICAgICAgbnVsbCxcblx0XHQgKiAgICAgICAgICBudWxsXG5cdFx0ICogICAgICAgIF1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJhRGF0YVNvcnRcIjogbnVsbCxcblx0XHRcImlEYXRhU29ydFwiOiAtMSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIFlvdSBjYW4gY29udHJvbCB0aGUgZGVmYXVsdCBvcmRlcmluZyBkaXJlY3Rpb24sIGFuZCBldmVuIGFsdGVyIHRoZVxuXHRcdCAqIGJlaGF2aW91ciBvZiB0aGUgc29ydCBoYW5kbGVyIChpLmUuIG9ubHkgYWxsb3cgYXNjZW5kaW5nIG9yZGVyaW5nIGV0Yylcblx0XHQgKiB1c2luZyB0aGlzIHBhcmFtZXRlci5cblx0XHQgKiAgQHR5cGUgYXJyYXlcblx0XHQgKiAgQGRlZmF1bHQgWyAnYXNjJywgJ2Rlc2MnIF1cblx0XHQgKlxuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuY29sdW1uLm9yZGVyU2VxdWVuY2Vcblx0XHQgKiAgQGR0b3B0IENvbHVtbnNcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgIC8vIFVzaW5nIGBjb2x1bW5EZWZzYFxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiY29sdW1uRGVmc1wiOiBbXG5cdFx0ICogICAgICAgICAgeyBcIm9yZGVyU2VxdWVuY2VcIjogWyBcImFzY1wiIF0sIFwidGFyZ2V0c1wiOiBbIDEgXSB9LFxuXHRcdCAqICAgICAgICAgIHsgXCJvcmRlclNlcXVlbmNlXCI6IFsgXCJkZXNjXCIsIFwiYXNjXCIsIFwiYXNjXCIgXSwgXCJ0YXJnZXRzXCI6IFsgMiBdIH0sXG5cdFx0ICogICAgICAgICAgeyBcIm9yZGVyU2VxdWVuY2VcIjogWyBcImRlc2NcIiBdLCBcInRhcmdldHNcIjogWyAzIF0gfVxuXHRcdCAqICAgICAgICBdXG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgLy8gVXNpbmcgYGNvbHVtbnNgXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJjb2x1bW5zXCI6IFtcblx0XHQgKiAgICAgICAgICBudWxsLFxuXHRcdCAqICAgICAgICAgIHsgXCJvcmRlclNlcXVlbmNlXCI6IFsgXCJhc2NcIiBdIH0sXG5cdFx0ICogICAgICAgICAgeyBcIm9yZGVyU2VxdWVuY2VcIjogWyBcImRlc2NcIiwgXCJhc2NcIiwgXCJhc2NcIiBdIH0sXG5cdFx0ICogICAgICAgICAgeyBcIm9yZGVyU2VxdWVuY2VcIjogWyBcImRlc2NcIiBdIH0sXG5cdFx0ICogICAgICAgICAgbnVsbFxuXHRcdCAqICAgICAgICBdXG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdFwiYXNTb3J0aW5nXCI6IFsgJ2FzYycsICdkZXNjJyBdLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogRW5hYmxlIG9yIGRpc2FibGUgZmlsdGVyaW5nIG9uIHRoZSBkYXRhIGluIHRoaXMgY29sdW1uLlxuXHRcdCAqICBAdHlwZSBib29sZWFuXG5cdFx0ICogIEBkZWZhdWx0IHRydWVcblx0XHQgKlxuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuY29sdW1uLnNlYXJjaGFibGVcblx0XHQgKiAgQGR0b3B0IENvbHVtbnNcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgIC8vIFVzaW5nIGBjb2x1bW5EZWZzYFxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiY29sdW1uRGVmc1wiOiBbXG5cdFx0ICogICAgICAgICAgeyBcInNlYXJjaGFibGVcIjogZmFsc2UsIFwidGFyZ2V0c1wiOiBbIDAgXSB9XG5cdFx0ICogICAgICAgIF0gfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgIC8vIFVzaW5nIGBjb2x1bW5zYFxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiY29sdW1uc1wiOiBbXG5cdFx0ICogICAgICAgICAgeyBcInNlYXJjaGFibGVcIjogZmFsc2UgfSxcblx0XHQgKiAgICAgICAgICBudWxsLFxuXHRcdCAqICAgICAgICAgIG51bGwsXG5cdFx0ICogICAgICAgICAgbnVsbCxcblx0XHQgKiAgICAgICAgICBudWxsXG5cdFx0ICogICAgICAgIF0gfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImJTZWFyY2hhYmxlXCI6IHRydWUsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBFbmFibGUgb3IgZGlzYWJsZSBvcmRlcmluZyBvbiB0aGlzIGNvbHVtbi5cblx0XHQgKiAgQHR5cGUgYm9vbGVhblxuXHRcdCAqICBAZGVmYXVsdCB0cnVlXG5cdFx0ICpcblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLmNvbHVtbi5vcmRlcmFibGVcblx0XHQgKiAgQGR0b3B0IENvbHVtbnNcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgIC8vIFVzaW5nIGBjb2x1bW5EZWZzYFxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiY29sdW1uRGVmc1wiOiBbXG5cdFx0ICogICAgICAgICAgeyBcIm9yZGVyYWJsZVwiOiBmYWxzZSwgXCJ0YXJnZXRzXCI6IFsgMCBdIH1cblx0XHQgKiAgICAgICAgXSB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgLy8gVXNpbmcgYGNvbHVtbnNgXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJjb2x1bW5zXCI6IFtcblx0XHQgKiAgICAgICAgICB7IFwib3JkZXJhYmxlXCI6IGZhbHNlIH0sXG5cdFx0ICogICAgICAgICAgbnVsbCxcblx0XHQgKiAgICAgICAgICBudWxsLFxuXHRcdCAqICAgICAgICAgIG51bGwsXG5cdFx0ICogICAgICAgICAgbnVsbFxuXHRcdCAqICAgICAgICBdIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJiU29ydGFibGVcIjogdHJ1ZSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIEVuYWJsZSBvciBkaXNhYmxlIHRoZSBkaXNwbGF5IG9mIHRoaXMgY29sdW1uLlxuXHRcdCAqICBAdHlwZSBib29sZWFuXG5cdFx0ICogIEBkZWZhdWx0IHRydWVcblx0XHQgKlxuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuY29sdW1uLnZpc2libGVcblx0XHQgKiAgQGR0b3B0IENvbHVtbnNcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgIC8vIFVzaW5nIGBjb2x1bW5EZWZzYFxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiY29sdW1uRGVmc1wiOiBbXG5cdFx0ICogICAgICAgICAgeyBcInZpc2libGVcIjogZmFsc2UsIFwidGFyZ2V0c1wiOiBbIDAgXSB9XG5cdFx0ICogICAgICAgIF0gfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgIC8vIFVzaW5nIGBjb2x1bW5zYFxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiY29sdW1uc1wiOiBbXG5cdFx0ICogICAgICAgICAgeyBcInZpc2libGVcIjogZmFsc2UgfSxcblx0XHQgKiAgICAgICAgICBudWxsLFxuXHRcdCAqICAgICAgICAgIG51bGwsXG5cdFx0ICogICAgICAgICAgbnVsbCxcblx0XHQgKiAgICAgICAgICBudWxsXG5cdFx0ICogICAgICAgIF0gfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImJWaXNpYmxlXCI6IHRydWUsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBEZXZlbG9wZXIgZGVmaW5hYmxlIGZ1bmN0aW9uIHRoYXQgaXMgY2FsbGVkIHdoZW5ldmVyIGEgY2VsbCBpcyBjcmVhdGVkIChBamF4IHNvdXJjZSxcblx0XHQgKiBldGMpIG9yIHByb2Nlc3NlZCBmb3IgaW5wdXQgKERPTSBzb3VyY2UpLiBUaGlzIGNhbiBiZSB1c2VkIGFzIGEgY29tcGxpbWVudCB0byBtUmVuZGVyXG5cdFx0ICogYWxsb3dpbmcgeW91IHRvIG1vZGlmeSB0aGUgRE9NIGVsZW1lbnQgKGFkZCBiYWNrZ3JvdW5kIGNvbG91ciBmb3IgZXhhbXBsZSkgd2hlbiB0aGVcblx0XHQgKiBlbGVtZW50IGlzIGF2YWlsYWJsZS5cblx0XHQgKiAgQHR5cGUgZnVuY3Rpb25cblx0XHQgKiAgQHBhcmFtIHtlbGVtZW50fSB0ZCBUaGUgVEQgbm9kZSB0aGF0IGhhcyBiZWVuIGNyZWF0ZWRcblx0XHQgKiAgQHBhcmFtIHsqfSBjZWxsRGF0YSBUaGUgRGF0YSBmb3IgdGhlIGNlbGxcblx0XHQgKiAgQHBhcmFtIHthcnJheXxvYmplY3R9IHJvd0RhdGEgVGhlIGRhdGEgZm9yIHRoZSB3aG9sZSByb3dcblx0XHQgKiAgQHBhcmFtIHtpbnR9IHJvdyBUaGUgcm93IGluZGV4IGZvciB0aGUgYW9EYXRhIGRhdGEgc3RvcmVcblx0XHQgKiAgQHBhcmFtIHtpbnR9IGNvbCBUaGUgY29sdW1uIGluZGV4IGZvciBhb0NvbHVtbnNcblx0XHQgKlxuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuY29sdW1uLmNyZWF0ZWRDZWxsXG5cdFx0ICogIEBkdG9wdCBDb2x1bW5zXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImNvbHVtbkRlZnNcIjogWyB7XG5cdFx0ICogICAgICAgICAgXCJ0YXJnZXRzXCI6IFszXSxcblx0XHQgKiAgICAgICAgICBcImNyZWF0ZWRDZWxsXCI6IGZ1bmN0aW9uICh0ZCwgY2VsbERhdGEsIHJvd0RhdGEsIHJvdywgY29sKSB7XG5cdFx0ICogICAgICAgICAgICBpZiAoIGNlbGxEYXRhID09IFwiMS43XCIgKSB7XG5cdFx0ICogICAgICAgICAgICAgICQodGQpLmNzcygnY29sb3InLCAnYmx1ZScpXG5cdFx0ICogICAgICAgICAgICB9XG5cdFx0ICogICAgICAgICAgfVxuXHRcdCAqICAgICAgICB9IF1cblx0XHQgKiAgICAgIH0pO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcImZuQ3JlYXRlZENlbGxcIjogbnVsbCxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIFRoaXMgcGFyYW1ldGVyIGhhcyBiZWVuIHJlcGxhY2VkIGJ5IGBkYXRhYCBpbiBEYXRhVGFibGVzIHRvIGVuc3VyZSBuYW1pbmdcblx0XHQgKiBjb25zaXN0ZW5jeS4gYGRhdGFQcm9wYCBjYW4gc3RpbGwgYmUgdXNlZCwgYXMgdGhlcmUgaXMgYmFja3dhcmRzXG5cdFx0ICogY29tcGF0aWJpbGl0eSBpbiBEYXRhVGFibGVzIGZvciB0aGlzIG9wdGlvbiwgYnV0IGl0IGlzIHN0cm9uZ2x5XG5cdFx0ICogcmVjb21tZW5kZWQgdGhhdCB5b3UgdXNlIGBkYXRhYCBpbiBwcmVmZXJlbmNlIHRvIGBkYXRhUHJvcGAuXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5jb2x1bW4uZGF0YVByb3Bcblx0XHQgKi9cblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIFRoaXMgcHJvcGVydHkgY2FuIGJlIHVzZWQgdG8gcmVhZCBkYXRhIGZyb20gYW55IGRhdGEgc291cmNlIHByb3BlcnR5LFxuXHRcdCAqIGluY2x1ZGluZyBkZWVwbHkgbmVzdGVkIG9iamVjdHMgLyBwcm9wZXJ0aWVzLiBgZGF0YWAgY2FuIGJlIGdpdmVuIGluIGFcblx0XHQgKiBudW1iZXIgb2YgZGlmZmVyZW50IHdheXMgd2hpY2ggZWZmZWN0IGl0cyBiZWhhdmlvdXI6XG5cdFx0ICpcblx0XHQgKiAqIGBpbnRlZ2VyYCAtIHRyZWF0ZWQgYXMgYW4gYXJyYXkgaW5kZXggZm9yIHRoZSBkYXRhIHNvdXJjZS4gVGhpcyBpcyB0aGVcblx0XHQgKiAgIGRlZmF1bHQgdGhhdCBEYXRhVGFibGVzIHVzZXMgKGluY3JlbWVudGFsbHkgaW5jcmVhc2VkIGZvciBlYWNoIGNvbHVtbikuXG5cdFx0ICogKiBgc3RyaW5nYCAtIHJlYWQgYW4gb2JqZWN0IHByb3BlcnR5IGZyb20gdGhlIGRhdGEgc291cmNlLiBUaGVyZSBhcmVcblx0XHQgKiAgIHRocmVlICdzcGVjaWFsJyBvcHRpb25zIHRoYXQgY2FuIGJlIHVzZWQgaW4gdGhlIHN0cmluZyB0byBhbHRlciBob3dcblx0XHQgKiAgIERhdGFUYWJsZXMgcmVhZHMgdGhlIGRhdGEgZnJvbSB0aGUgc291cmNlIG9iamVjdDpcblx0XHQgKiAgICAqIGAuYCAtIERvdHRlZCBKYXZhc2NyaXB0IG5vdGF0aW9uLiBKdXN0IGFzIHlvdSB1c2UgYSBgLmAgaW5cblx0XHQgKiAgICAgIEphdmFzY3JpcHQgdG8gcmVhZCBmcm9tIG5lc3RlZCBvYmplY3RzLCBzbyB0byBjYW4gdGhlIG9wdGlvbnNcblx0XHQgKiAgICAgIHNwZWNpZmllZCBpbiBgZGF0YWAuIEZvciBleGFtcGxlOiBgYnJvd3Nlci52ZXJzaW9uYCBvclxuXHRcdCAqICAgICAgYGJyb3dzZXIubmFtZWAuIElmIHlvdXIgb2JqZWN0IHBhcmFtZXRlciBuYW1lIGNvbnRhaW5zIGEgcGVyaW9kLCB1c2Vcblx0XHQgKiAgICAgIGBcXFxcYCB0byBlc2NhcGUgaXQgLSBpLmUuIGBmaXJzdFxcXFwubmFtZWAuXG5cdFx0ICogICAgKiBgW11gIC0gQXJyYXkgbm90YXRpb24uIERhdGFUYWJsZXMgY2FuIGF1dG9tYXRpY2FsbHkgY29tYmluZSBkYXRhXG5cdFx0ICogICAgICBmcm9tIGFuZCBhcnJheSBzb3VyY2UsIGpvaW5pbmcgdGhlIGRhdGEgd2l0aCB0aGUgY2hhcmFjdGVycyBwcm92aWRlZFxuXHRcdCAqICAgICAgYmV0d2VlbiB0aGUgdHdvIGJyYWNrZXRzLiBGb3IgZXhhbXBsZTogYG5hbWVbLCBdYCB3b3VsZCBwcm92aWRlIGFcblx0XHQgKiAgICAgIGNvbW1hLXNwYWNlIHNlcGFyYXRlZCBsaXN0IGZyb20gdGhlIHNvdXJjZSBhcnJheS4gSWYgbm8gY2hhcmFjdGVyc1xuXHRcdCAqICAgICAgYXJlIHByb3ZpZGVkIGJldHdlZW4gdGhlIGJyYWNrZXRzLCB0aGUgb3JpZ2luYWwgYXJyYXkgc291cmNlIGlzXG5cdFx0ICogICAgICByZXR1cm5lZC5cblx0XHQgKiAgICAqIGAoKWAgLSBGdW5jdGlvbiBub3RhdGlvbi4gQWRkaW5nIGAoKWAgdG8gdGhlIGVuZCBvZiBhIHBhcmFtZXRlciB3aWxsXG5cdFx0ICogICAgICBleGVjdXRlIGEgZnVuY3Rpb24gb2YgdGhlIG5hbWUgZ2l2ZW4uIEZvciBleGFtcGxlOiBgYnJvd3NlcigpYCBmb3IgYVxuXHRcdCAqICAgICAgc2ltcGxlIGZ1bmN0aW9uIG9uIHRoZSBkYXRhIHNvdXJjZSwgYGJyb3dzZXIudmVyc2lvbigpYCBmb3IgYVxuXHRcdCAqICAgICAgZnVuY3Rpb24gaW4gYSBuZXN0ZWQgcHJvcGVydHkgb3IgZXZlbiBgYnJvd3NlcigpLnZlcnNpb25gIHRvIGdldCBhblxuXHRcdCAqICAgICAgb2JqZWN0IHByb3BlcnR5IGlmIHRoZSBmdW5jdGlvbiBjYWxsZWQgcmV0dXJucyBhbiBvYmplY3QuIE5vdGUgdGhhdFxuXHRcdCAqICAgICAgZnVuY3Rpb24gbm90YXRpb24gaXMgcmVjb21tZW5kZWQgZm9yIHVzZSBpbiBgcmVuZGVyYCByYXRoZXIgdGhhblxuXHRcdCAqICAgICAgYGRhdGFgIGFzIGl0IGlzIG11Y2ggc2ltcGxlciB0byB1c2UgYXMgYSByZW5kZXJlci5cblx0XHQgKiAqIGBudWxsYCAtIHVzZSB0aGUgb3JpZ2luYWwgZGF0YSBzb3VyY2UgZm9yIHRoZSByb3cgcmF0aGVyIHRoYW4gcGx1Y2tpbmdcblx0XHQgKiAgIGRhdGEgZGlyZWN0bHkgZnJvbSBpdC4gVGhpcyBhY3Rpb24gaGFzIGVmZmVjdHMgb24gdHdvIG90aGVyXG5cdFx0ICogICBpbml0aWFsaXNhdGlvbiBvcHRpb25zOlxuXHRcdCAqICAgICogYGRlZmF1bHRDb250ZW50YCAtIFdoZW4gbnVsbCBpcyBnaXZlbiBhcyB0aGUgYGRhdGFgIG9wdGlvbiBhbmRcblx0XHQgKiAgICAgIGBkZWZhdWx0Q29udGVudGAgaXMgc3BlY2lmaWVkIGZvciB0aGUgY29sdW1uLCB0aGUgdmFsdWUgZGVmaW5lZCBieVxuXHRcdCAqICAgICAgYGRlZmF1bHRDb250ZW50YCB3aWxsIGJlIHVzZWQgZm9yIHRoZSBjZWxsLlxuXHRcdCAqICAgICogYHJlbmRlcmAgLSBXaGVuIG51bGwgaXMgdXNlZCBmb3IgdGhlIGBkYXRhYCBvcHRpb24gYW5kIHRoZSBgcmVuZGVyYFxuXHRcdCAqICAgICAgb3B0aW9uIGlzIHNwZWNpZmllZCBmb3IgdGhlIGNvbHVtbiwgdGhlIHdob2xlIGRhdGEgc291cmNlIGZvciB0aGVcblx0XHQgKiAgICAgIHJvdyBpcyB1c2VkIGZvciB0aGUgcmVuZGVyZXIuXG5cdFx0ICogKiBgZnVuY3Rpb25gIC0gdGhlIGZ1bmN0aW9uIGdpdmVuIHdpbGwgYmUgZXhlY3V0ZWQgd2hlbmV2ZXIgRGF0YVRhYmxlc1xuXHRcdCAqICAgbmVlZHMgdG8gc2V0IG9yIGdldCB0aGUgZGF0YSBmb3IgYSBjZWxsIGluIHRoZSBjb2x1bW4uIFRoZSBmdW5jdGlvblxuXHRcdCAqICAgdGFrZXMgdGhyZWUgcGFyYW1ldGVyczpcblx0XHQgKiAgICAqIFBhcmFtZXRlcnM6XG5cdFx0ICogICAgICAqIGB7YXJyYXl8b2JqZWN0fWAgVGhlIGRhdGEgc291cmNlIGZvciB0aGUgcm93XG5cdFx0ICogICAgICAqIGB7c3RyaW5nfWAgVGhlIHR5cGUgY2FsbCBkYXRhIHJlcXVlc3RlZCAtIHRoaXMgd2lsbCBiZSAnc2V0JyB3aGVuXG5cdFx0ICogICAgICAgIHNldHRpbmcgZGF0YSBvciAnZmlsdGVyJywgJ2Rpc3BsYXknLCAndHlwZScsICdzb3J0JyBvciB1bmRlZmluZWRcblx0XHQgKiAgICAgICAgd2hlbiBnYXRoZXJpbmcgZGF0YS4gTm90ZSB0aGF0IHdoZW4gYHVuZGVmaW5lZGAgaXMgZ2l2ZW4gZm9yIHRoZVxuXHRcdCAqICAgICAgICB0eXBlIERhdGFUYWJsZXMgZXhwZWN0cyB0byBnZXQgdGhlIHJhdyBkYXRhIGZvciB0aGUgb2JqZWN0IGJhY2s8XG5cdFx0ICogICAgICAqIGB7Kn1gIERhdGEgdG8gc2V0IHdoZW4gdGhlIHNlY29uZCBwYXJhbWV0ZXIgaXMgJ3NldCcuXG5cdFx0ICogICAgKiBSZXR1cm46XG5cdFx0ICogICAgICAqIFRoZSByZXR1cm4gdmFsdWUgZnJvbSB0aGUgZnVuY3Rpb24gaXMgbm90IHJlcXVpcmVkIHdoZW4gJ3NldCcgaXNcblx0XHQgKiAgICAgICAgdGhlIHR5cGUgb2YgY2FsbCwgYnV0IG90aGVyd2lzZSB0aGUgcmV0dXJuIGlzIHdoYXQgd2lsbCBiZSB1c2VkXG5cdFx0ICogICAgICAgIGZvciB0aGUgZGF0YSByZXF1ZXN0ZWQuXG5cdFx0ICpcblx0XHQgKiBOb3RlIHRoYXQgYGRhdGFgIGlzIGEgZ2V0dGVyIGFuZCBzZXR0ZXIgb3B0aW9uLiBJZiB5b3UganVzdCByZXF1aXJlXG5cdFx0ICogZm9ybWF0dGluZyBvZiBkYXRhIGZvciBvdXRwdXQsIHlvdSB3aWxsIGxpa2VseSB3YW50IHRvIHVzZSBgcmVuZGVyYCB3aGljaFxuXHRcdCAqIGlzIHNpbXBseSBhIGdldHRlciBhbmQgdGh1cyBzaW1wbGVyIHRvIHVzZS5cblx0XHQgKlxuXHRcdCAqIE5vdGUgdGhhdCBwcmlvciB0byBEYXRhVGFibGVzIDEuOS4yIGBkYXRhYCB3YXMgY2FsbGVkIGBtRGF0YVByb3BgLiBUaGVcblx0XHQgKiBuYW1lIGNoYW5nZSByZWZsZWN0cyB0aGUgZmxleGliaWxpdHkgb2YgdGhpcyBwcm9wZXJ0eSBhbmQgaXMgY29uc2lzdGVudFxuXHRcdCAqIHdpdGggdGhlIG5hbWluZyBvZiBtUmVuZGVyLiBJZiAnbURhdGFQcm9wJyBpcyBnaXZlbiwgdGhlbiBpdCB3aWxsIHN0aWxsXG5cdFx0ICogYmUgdXNlZCBieSBEYXRhVGFibGVzLCBhcyBpdCBhdXRvbWF0aWNhbGx5IG1hcHMgdGhlIG9sZCBuYW1lIHRvIHRoZSBuZXdcblx0XHQgKiBpZiByZXF1aXJlZC5cblx0XHQgKlxuXHRcdCAqICBAdHlwZSBzdHJpbmd8aW50fGZ1bmN0aW9ufG51bGxcblx0XHQgKiAgQGRlZmF1bHQgbnVsbCA8aT5Vc2UgYXV0b21hdGljYWxseSBjYWxjdWxhdGVkIGNvbHVtbiBpbmRleDwvaT5cblx0XHQgKlxuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuY29sdW1uLmRhdGFcblx0XHQgKiAgQGR0b3B0IENvbHVtbnNcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgIC8vIFJlYWQgdGFibGUgZGF0YSBmcm9tIG9iamVjdHNcblx0XHQgKiAgICAvLyBKU09OIHN0cnVjdHVyZSBmb3IgZWFjaCByb3c6XG5cdFx0ICogICAgLy8gICB7XG5cdFx0ICogICAgLy8gICAgICBcImVuZ2luZVwiOiB7dmFsdWV9LFxuXHRcdCAqICAgIC8vICAgICAgXCJicm93c2VyXCI6IHt2YWx1ZX0sXG5cdFx0ICogICAgLy8gICAgICBcInBsYXRmb3JtXCI6IHt2YWx1ZX0sXG5cdFx0ICogICAgLy8gICAgICBcInZlcnNpb25cIjoge3ZhbHVlfSxcblx0XHQgKiAgICAvLyAgICAgIFwiZ3JhZGVcIjoge3ZhbHVlfVxuXHRcdCAqICAgIC8vICAgfVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiYWpheFNvdXJjZVwiOiBcInNvdXJjZXMvb2JqZWN0cy50eHRcIixcblx0XHQgKiAgICAgICAgXCJjb2x1bW5zXCI6IFtcblx0XHQgKiAgICAgICAgICB7IFwiZGF0YVwiOiBcImVuZ2luZVwiIH0sXG5cdFx0ICogICAgICAgICAgeyBcImRhdGFcIjogXCJicm93c2VyXCIgfSxcblx0XHQgKiAgICAgICAgICB7IFwiZGF0YVwiOiBcInBsYXRmb3JtXCIgfSxcblx0XHQgKiAgICAgICAgICB7IFwiZGF0YVwiOiBcInZlcnNpb25cIiB9LFxuXHRcdCAqICAgICAgICAgIHsgXCJkYXRhXCI6IFwiZ3JhZGVcIiB9XG5cdFx0ICogICAgICAgIF1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBSZWFkIGluZm9ybWF0aW9uIGZyb20gZGVlcGx5IG5lc3RlZCBvYmplY3RzXG5cdFx0ICogICAgLy8gSlNPTiBzdHJ1Y3R1cmUgZm9yIGVhY2ggcm93OlxuXHRcdCAqICAgIC8vICAge1xuXHRcdCAqICAgIC8vICAgICAgXCJlbmdpbmVcIjoge3ZhbHVlfSxcblx0XHQgKiAgICAvLyAgICAgIFwiYnJvd3NlclwiOiB7dmFsdWV9LFxuXHRcdCAqICAgIC8vICAgICAgXCJwbGF0Zm9ybVwiOiB7XG5cdFx0ICogICAgLy8gICAgICAgICBcImlubmVyXCI6IHt2YWx1ZX1cblx0XHQgKiAgICAvLyAgICAgIH0sXG5cdFx0ICogICAgLy8gICAgICBcImRldGFpbHNcIjogW1xuXHRcdCAqICAgIC8vICAgICAgICAge3ZhbHVlfSwge3ZhbHVlfVxuXHRcdCAqICAgIC8vICAgICAgXVxuXHRcdCAqICAgIC8vICAgfVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiYWpheFNvdXJjZVwiOiBcInNvdXJjZXMvZGVlcC50eHRcIixcblx0XHQgKiAgICAgICAgXCJjb2x1bW5zXCI6IFtcblx0XHQgKiAgICAgICAgICB7IFwiZGF0YVwiOiBcImVuZ2luZVwiIH0sXG5cdFx0ICogICAgICAgICAgeyBcImRhdGFcIjogXCJicm93c2VyXCIgfSxcblx0XHQgKiAgICAgICAgICB7IFwiZGF0YVwiOiBcInBsYXRmb3JtLmlubmVyXCIgfSxcblx0XHQgKiAgICAgICAgICB7IFwiZGF0YVwiOiBcImRldGFpbHMuMFwiIH0sXG5cdFx0ICogICAgICAgICAgeyBcImRhdGFcIjogXCJkZXRhaWxzLjFcIiB9XG5cdFx0ICogICAgICAgIF1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBVc2luZyBgZGF0YWAgYXMgYSBmdW5jdGlvbiB0byBwcm92aWRlIGRpZmZlcmVudCBpbmZvcm1hdGlvbiBmb3Jcblx0XHQgKiAgICAvLyBzb3J0aW5nLCBmaWx0ZXJpbmcgYW5kIGRpc3BsYXkuIEluIHRoaXMgY2FzZSwgY3VycmVuY3kgKHByaWNlKVxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiY29sdW1uRGVmc1wiOiBbIHtcblx0XHQgKiAgICAgICAgICBcInRhcmdldHNcIjogWyAwIF0sXG5cdFx0ICogICAgICAgICAgXCJkYXRhXCI6IGZ1bmN0aW9uICggc291cmNlLCB0eXBlLCB2YWwgKSB7XG5cdFx0ICogICAgICAgICAgICBpZiAodHlwZSA9PT0gJ3NldCcpIHtcblx0XHQgKiAgICAgICAgICAgICAgc291cmNlLnByaWNlID0gdmFsO1xuXHRcdCAqICAgICAgICAgICAgICAvLyBTdG9yZSB0aGUgY29tcHV0ZWQgZGlzcGxheSBhbmQgZmlsdGVyIHZhbHVlcyBmb3IgZWZmaWNpZW5jeVxuXHRcdCAqICAgICAgICAgICAgICBzb3VyY2UucHJpY2VfZGlzcGxheSA9IHZhbD09XCJcIiA/IFwiXCIgOiBcIiRcIitudW1iZXJGb3JtYXQodmFsKTtcblx0XHQgKiAgICAgICAgICAgICAgc291cmNlLnByaWNlX2ZpbHRlciAgPSB2YWw9PVwiXCIgPyBcIlwiIDogXCIkXCIrbnVtYmVyRm9ybWF0KHZhbCkrXCIgXCIrdmFsO1xuXHRcdCAqICAgICAgICAgICAgICByZXR1cm47XG5cdFx0ICogICAgICAgICAgICB9XG5cdFx0ICogICAgICAgICAgICBlbHNlIGlmICh0eXBlID09PSAnZGlzcGxheScpIHtcblx0XHQgKiAgICAgICAgICAgICAgcmV0dXJuIHNvdXJjZS5wcmljZV9kaXNwbGF5O1xuXHRcdCAqICAgICAgICAgICAgfVxuXHRcdCAqICAgICAgICAgICAgZWxzZSBpZiAodHlwZSA9PT0gJ2ZpbHRlcicpIHtcblx0XHQgKiAgICAgICAgICAgICAgcmV0dXJuIHNvdXJjZS5wcmljZV9maWx0ZXI7XG5cdFx0ICogICAgICAgICAgICB9XG5cdFx0ICogICAgICAgICAgICAvLyAnc29ydCcsICd0eXBlJyBhbmQgdW5kZWZpbmVkIGFsbCBqdXN0IHVzZSB0aGUgaW50ZWdlclxuXHRcdCAqICAgICAgICAgICAgcmV0dXJuIHNvdXJjZS5wcmljZTtcblx0XHQgKiAgICAgICAgICB9XG5cdFx0ICogICAgICAgIH0gXVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgIC8vIFVzaW5nIGRlZmF1bHQgY29udGVudFxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiY29sdW1uRGVmc1wiOiBbIHtcblx0XHQgKiAgICAgICAgICBcInRhcmdldHNcIjogWyAwIF0sXG5cdFx0ICogICAgICAgICAgXCJkYXRhXCI6IG51bGwsXG5cdFx0ICogICAgICAgICAgXCJkZWZhdWx0Q29udGVudFwiOiBcIkNsaWNrIHRvIGVkaXRcIlxuXHRcdCAqICAgICAgICB9IF1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBVc2luZyBhcnJheSBub3RhdGlvbiAtIG91dHB1dHRpbmcgYSBsaXN0IGZyb20gYW4gYXJyYXlcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImNvbHVtbkRlZnNcIjogWyB7XG5cdFx0ICogICAgICAgICAgXCJ0YXJnZXRzXCI6IFsgMCBdLFxuXHRcdCAqICAgICAgICAgIFwiZGF0YVwiOiBcIm5hbWVbLCBdXCJcblx0XHQgKiAgICAgICAgfSBdXG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqXG5cdFx0ICovXG5cdFx0XCJtRGF0YVwiOiBudWxsLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogVGhpcyBwcm9wZXJ0eSBpcyB0aGUgcmVuZGVyaW5nIHBhcnRuZXIgdG8gYGRhdGFgIGFuZCBpdCBpcyBzdWdnZXN0ZWQgdGhhdFxuXHRcdCAqIHdoZW4geW91IHdhbnQgdG8gbWFuaXB1bGF0ZSBkYXRhIGZvciBkaXNwbGF5IChpbmNsdWRpbmcgZmlsdGVyaW5nLFxuXHRcdCAqIHNvcnRpbmcgZXRjKSB3aXRob3V0IGFsdGVyaW5nIHRoZSB1bmRlcmx5aW5nIGRhdGEgZm9yIHRoZSB0YWJsZSwgdXNlIHRoaXNcblx0XHQgKiBwcm9wZXJ0eS4gYHJlbmRlcmAgY2FuIGJlIGNvbnNpZGVyZWQgdG8gYmUgdGhlIHRoZSByZWFkIG9ubHkgY29tcGFuaW9uIHRvXG5cdFx0ICogYGRhdGFgIHdoaWNoIGlzIHJlYWQgLyB3cml0ZSAodGhlbiBhcyBzdWNoIG1vcmUgY29tcGxleCkuIExpa2UgYGRhdGFgXG5cdFx0ICogdGhpcyBvcHRpb24gY2FuIGJlIGdpdmVuIGluIGEgbnVtYmVyIG9mIGRpZmZlcmVudCB3YXlzIHRvIGVmZmVjdCBpdHNcblx0XHQgKiBiZWhhdmlvdXI6XG5cdFx0ICpcblx0XHQgKiAqIGBpbnRlZ2VyYCAtIHRyZWF0ZWQgYXMgYW4gYXJyYXkgaW5kZXggZm9yIHRoZSBkYXRhIHNvdXJjZS4gVGhpcyBpcyB0aGVcblx0XHQgKiAgIGRlZmF1bHQgdGhhdCBEYXRhVGFibGVzIHVzZXMgKGluY3JlbWVudGFsbHkgaW5jcmVhc2VkIGZvciBlYWNoIGNvbHVtbikuXG5cdFx0ICogKiBgc3RyaW5nYCAtIHJlYWQgYW4gb2JqZWN0IHByb3BlcnR5IGZyb20gdGhlIGRhdGEgc291cmNlLiBUaGVyZSBhcmVcblx0XHQgKiAgIHRocmVlICdzcGVjaWFsJyBvcHRpb25zIHRoYXQgY2FuIGJlIHVzZWQgaW4gdGhlIHN0cmluZyB0byBhbHRlciBob3dcblx0XHQgKiAgIERhdGFUYWJsZXMgcmVhZHMgdGhlIGRhdGEgZnJvbSB0aGUgc291cmNlIG9iamVjdDpcblx0XHQgKiAgICAqIGAuYCAtIERvdHRlZCBKYXZhc2NyaXB0IG5vdGF0aW9uLiBKdXN0IGFzIHlvdSB1c2UgYSBgLmAgaW5cblx0XHQgKiAgICAgIEphdmFzY3JpcHQgdG8gcmVhZCBmcm9tIG5lc3RlZCBvYmplY3RzLCBzbyB0byBjYW4gdGhlIG9wdGlvbnNcblx0XHQgKiAgICAgIHNwZWNpZmllZCBpbiBgZGF0YWAuIEZvciBleGFtcGxlOiBgYnJvd3Nlci52ZXJzaW9uYCBvclxuXHRcdCAqICAgICAgYGJyb3dzZXIubmFtZWAuIElmIHlvdXIgb2JqZWN0IHBhcmFtZXRlciBuYW1lIGNvbnRhaW5zIGEgcGVyaW9kLCB1c2Vcblx0XHQgKiAgICAgIGBcXFxcYCB0byBlc2NhcGUgaXQgLSBpLmUuIGBmaXJzdFxcXFwubmFtZWAuXG5cdFx0ICogICAgKiBgW11gIC0gQXJyYXkgbm90YXRpb24uIERhdGFUYWJsZXMgY2FuIGF1dG9tYXRpY2FsbHkgY29tYmluZSBkYXRhXG5cdFx0ICogICAgICBmcm9tIGFuZCBhcnJheSBzb3VyY2UsIGpvaW5pbmcgdGhlIGRhdGEgd2l0aCB0aGUgY2hhcmFjdGVycyBwcm92aWRlZFxuXHRcdCAqICAgICAgYmV0d2VlbiB0aGUgdHdvIGJyYWNrZXRzLiBGb3IgZXhhbXBsZTogYG5hbWVbLCBdYCB3b3VsZCBwcm92aWRlIGFcblx0XHQgKiAgICAgIGNvbW1hLXNwYWNlIHNlcGFyYXRlZCBsaXN0IGZyb20gdGhlIHNvdXJjZSBhcnJheS4gSWYgbm8gY2hhcmFjdGVyc1xuXHRcdCAqICAgICAgYXJlIHByb3ZpZGVkIGJldHdlZW4gdGhlIGJyYWNrZXRzLCB0aGUgb3JpZ2luYWwgYXJyYXkgc291cmNlIGlzXG5cdFx0ICogICAgICByZXR1cm5lZC5cblx0XHQgKiAgICAqIGAoKWAgLSBGdW5jdGlvbiBub3RhdGlvbi4gQWRkaW5nIGAoKWAgdG8gdGhlIGVuZCBvZiBhIHBhcmFtZXRlciB3aWxsXG5cdFx0ICogICAgICBleGVjdXRlIGEgZnVuY3Rpb24gb2YgdGhlIG5hbWUgZ2l2ZW4uIEZvciBleGFtcGxlOiBgYnJvd3NlcigpYCBmb3IgYVxuXHRcdCAqICAgICAgc2ltcGxlIGZ1bmN0aW9uIG9uIHRoZSBkYXRhIHNvdXJjZSwgYGJyb3dzZXIudmVyc2lvbigpYCBmb3IgYVxuXHRcdCAqICAgICAgZnVuY3Rpb24gaW4gYSBuZXN0ZWQgcHJvcGVydHkgb3IgZXZlbiBgYnJvd3NlcigpLnZlcnNpb25gIHRvIGdldCBhblxuXHRcdCAqICAgICAgb2JqZWN0IHByb3BlcnR5IGlmIHRoZSBmdW5jdGlvbiBjYWxsZWQgcmV0dXJucyBhbiBvYmplY3QuXG5cdFx0ICogKiBgb2JqZWN0YCAtIHVzZSBkaWZmZXJlbnQgZGF0YSBmb3IgdGhlIGRpZmZlcmVudCBkYXRhIHR5cGVzIHJlcXVlc3RlZCBieVxuXHRcdCAqICAgRGF0YVRhYmxlcyAoJ2ZpbHRlcicsICdkaXNwbGF5JywgJ3R5cGUnIG9yICdzb3J0JykuIFRoZSBwcm9wZXJ0eSBuYW1lc1xuXHRcdCAqICAgb2YgdGhlIG9iamVjdCBpcyB0aGUgZGF0YSB0eXBlIHRoZSBwcm9wZXJ0eSByZWZlcnMgdG8gYW5kIHRoZSB2YWx1ZSBjYW5cblx0XHQgKiAgIGRlZmluZWQgdXNpbmcgYW4gaW50ZWdlciwgc3RyaW5nIG9yIGZ1bmN0aW9uIHVzaW5nIHRoZSBzYW1lIHJ1bGVzIGFzXG5cdFx0ICogICBgcmVuZGVyYCBub3JtYWxseSBkb2VzLiBOb3RlIHRoYXQgYW4gYF9gIG9wdGlvbiBfbXVzdF8gYmUgc3BlY2lmaWVkLlxuXHRcdCAqICAgVGhpcyBpcyB0aGUgZGVmYXVsdCB2YWx1ZSB0byB1c2UgaWYgeW91IGhhdmVuJ3Qgc3BlY2lmaWVkIGEgdmFsdWUgZm9yXG5cdFx0ICogICB0aGUgZGF0YSB0eXBlIHJlcXVlc3RlZCBieSBEYXRhVGFibGVzLlxuXHRcdCAqICogYGZ1bmN0aW9uYCAtIHRoZSBmdW5jdGlvbiBnaXZlbiB3aWxsIGJlIGV4ZWN1dGVkIHdoZW5ldmVyIERhdGFUYWJsZXNcblx0XHQgKiAgIG5lZWRzIHRvIHNldCBvciBnZXQgdGhlIGRhdGEgZm9yIGEgY2VsbCBpbiB0aGUgY29sdW1uLiBUaGUgZnVuY3Rpb25cblx0XHQgKiAgIHRha2VzIHRocmVlIHBhcmFtZXRlcnM6XG5cdFx0ICogICAgKiBQYXJhbWV0ZXJzOlxuXHRcdCAqICAgICAgKiB7YXJyYXl8b2JqZWN0fSBUaGUgZGF0YSBzb3VyY2UgZm9yIHRoZSByb3cgKGJhc2VkIG9uIGBkYXRhYClcblx0XHQgKiAgICAgICoge3N0cmluZ30gVGhlIHR5cGUgY2FsbCBkYXRhIHJlcXVlc3RlZCAtIHRoaXMgd2lsbCBiZSAnZmlsdGVyJyxcblx0XHQgKiAgICAgICAgJ2Rpc3BsYXknLCAndHlwZScgb3IgJ3NvcnQnLlxuXHRcdCAqICAgICAgKiB7YXJyYXl8b2JqZWN0fSBUaGUgZnVsbCBkYXRhIHNvdXJjZSBmb3IgdGhlIHJvdyAobm90IGJhc2VkIG9uXG5cdFx0ICogICAgICAgIGBkYXRhYClcblx0XHQgKiAgICAqIFJldHVybjpcblx0XHQgKiAgICAgICogVGhlIHJldHVybiB2YWx1ZSBmcm9tIHRoZSBmdW5jdGlvbiBpcyB3aGF0IHdpbGwgYmUgdXNlZCBmb3IgdGhlXG5cdFx0ICogICAgICAgIGRhdGEgcmVxdWVzdGVkLlxuXHRcdCAqXG5cdFx0ICogIEB0eXBlIHN0cmluZ3xpbnR8ZnVuY3Rpb258b2JqZWN0fG51bGxcblx0XHQgKiAgQGRlZmF1bHQgbnVsbCBVc2UgdGhlIGRhdGEgc291cmNlIHZhbHVlLlxuXHRcdCAqXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5jb2x1bW4ucmVuZGVyXG5cdFx0ICogIEBkdG9wdCBDb2x1bW5zXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBDcmVhdGUgYSBjb21tYSBzZXBhcmF0ZWQgbGlzdCBmcm9tIGFuIGFycmF5IG9mIG9iamVjdHNcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImFqYXhTb3VyY2VcIjogXCJzb3VyY2VzL2RlZXAudHh0XCIsXG5cdFx0ICogICAgICAgIFwiY29sdW1uc1wiOiBbXG5cdFx0ICogICAgICAgICAgeyBcImRhdGFcIjogXCJlbmdpbmVcIiB9LFxuXHRcdCAqICAgICAgICAgIHsgXCJkYXRhXCI6IFwiYnJvd3NlclwiIH0sXG5cdFx0ICogICAgICAgICAge1xuXHRcdCAqICAgICAgICAgICAgXCJkYXRhXCI6IFwicGxhdGZvcm1cIixcblx0XHQgKiAgICAgICAgICAgIFwicmVuZGVyXCI6IFwiWywgXS5uYW1lXCJcblx0XHQgKiAgICAgICAgICB9XG5cdFx0ICogICAgICAgIF1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBFeGVjdXRlIGEgZnVuY3Rpb24gdG8gb2J0YWluIGRhdGFcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImNvbHVtbkRlZnNcIjogWyB7XG5cdFx0ICogICAgICAgICAgXCJ0YXJnZXRzXCI6IFsgMCBdLFxuXHRcdCAqICAgICAgICAgIFwiZGF0YVwiOiBudWxsLCAvLyBVc2UgdGhlIGZ1bGwgZGF0YSBzb3VyY2Ugb2JqZWN0IGZvciB0aGUgcmVuZGVyZXIncyBzb3VyY2Vcblx0XHQgKiAgICAgICAgICBcInJlbmRlclwiOiBcImJyb3dzZXJOYW1lKClcIlxuXHRcdCAqICAgICAgICB9IF1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBBcyBhbiBvYmplY3QsIGV4dHJhY3RpbmcgZGlmZmVyZW50IGRhdGEgZm9yIHRoZSBkaWZmZXJlbnQgdHlwZXNcblx0XHQgKiAgICAvLyBUaGlzIHdvdWxkIGJlIHVzZWQgd2l0aCBhIGRhdGEgc291cmNlIHN1Y2ggYXM6XG5cdFx0ICogICAgLy8gICB7IFwicGhvbmVcIjogNTU1MjM2OCwgXCJwaG9uZV9maWx0ZXJcIjogXCI1NTUyMzY4IDU1NS0yMzY4XCIsIFwicGhvbmVfZGlzcGxheVwiOiBcIjU1NS0yMzY4XCIgfVxuXHRcdCAqICAgIC8vIEhlcmUgdGhlIGBwaG9uZWAgaW50ZWdlciBpcyB1c2VkIGZvciBzb3J0aW5nIGFuZCB0eXBlIGRldGVjdGlvbiwgd2hpbGUgYHBob25lX2ZpbHRlcmBcblx0XHQgKiAgICAvLyAod2hpY2ggaGFzIGJvdGggZm9ybXMpIGlzIHVzZWQgZm9yIGZpbHRlcmluZyBmb3IgaWYgYSB1c2VyIGlucHV0cyBlaXRoZXIgZm9ybWF0LCB3aGlsZVxuXHRcdCAqICAgIC8vIHRoZSBmb3JtYXR0ZWQgcGhvbmUgbnVtYmVyIGlzIHRoZSBvbmUgdGhhdCBpcyBzaG93biBpbiB0aGUgdGFibGUuXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJjb2x1bW5EZWZzXCI6IFsge1xuXHRcdCAqICAgICAgICAgIFwidGFyZ2V0c1wiOiBbIDAgXSxcblx0XHQgKiAgICAgICAgICBcImRhdGFcIjogbnVsbCwgLy8gVXNlIHRoZSBmdWxsIGRhdGEgc291cmNlIG9iamVjdCBmb3IgdGhlIHJlbmRlcmVyJ3Mgc291cmNlXG5cdFx0ICogICAgICAgICAgXCJyZW5kZXJcIjoge1xuXHRcdCAqICAgICAgICAgICAgXCJfXCI6IFwicGhvbmVcIixcblx0XHQgKiAgICAgICAgICAgIFwiZmlsdGVyXCI6IFwicGhvbmVfZmlsdGVyXCIsXG5cdFx0ICogICAgICAgICAgICBcImRpc3BsYXlcIjogXCJwaG9uZV9kaXNwbGF5XCJcblx0XHQgKiAgICAgICAgICB9XG5cdFx0ICogICAgICAgIH0gXVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgIC8vIFVzZSBhcyBhIGZ1bmN0aW9uIHRvIGNyZWF0ZSBhIGxpbmsgZnJvbSB0aGUgZGF0YSBzb3VyY2Vcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImNvbHVtbkRlZnNcIjogWyB7XG5cdFx0ICogICAgICAgICAgXCJ0YXJnZXRzXCI6IFsgMCBdLFxuXHRcdCAqICAgICAgICAgIFwiZGF0YVwiOiBcImRvd25sb2FkX2xpbmtcIixcblx0XHQgKiAgICAgICAgICBcInJlbmRlclwiOiBmdW5jdGlvbiAoIGRhdGEsIHR5cGUsIGZ1bGwgKSB7XG5cdFx0ICogICAgICAgICAgICByZXR1cm4gJzxhIGhyZWY9XCInK2RhdGErJ1wiPkRvd25sb2FkPC9hPic7XG5cdFx0ICogICAgICAgICAgfVxuXHRcdCAqICAgICAgICB9IF1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJtUmVuZGVyXCI6IG51bGwsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBDaGFuZ2UgdGhlIGNlbGwgdHlwZSBjcmVhdGVkIGZvciB0aGUgY29sdW1uIC0gZWl0aGVyIFREIGNlbGxzIG9yIFRIIGNlbGxzLiBUaGlzXG5cdFx0ICogY2FuIGJlIHVzZWZ1bCBhcyBUSCBjZWxscyBoYXZlIHNlbWFudGljIG1lYW5pbmcgaW4gdGhlIHRhYmxlIGJvZHksIGFsbG93aW5nIHRoZW1cblx0XHQgKiB0byBhY3QgYXMgYSBoZWFkZXIgZm9yIGEgcm93ICh5b3UgbWF5IHdpc2ggdG8gYWRkIHNjb3BlPSdyb3cnIHRvIHRoZSBUSCBlbGVtZW50cykuXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqICBAZGVmYXVsdCB0ZFxuXHRcdCAqXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5jb2x1bW4uY2VsbFR5cGVcblx0XHQgKiAgQGR0b3B0IENvbHVtbnNcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgIC8vIE1ha2UgdGhlIGZpcnN0IGNvbHVtbiB1c2UgVEggY2VsbHNcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImNvbHVtbkRlZnNcIjogWyB7XG5cdFx0ICogICAgICAgICAgXCJ0YXJnZXRzXCI6IFsgMCBdLFxuXHRcdCAqICAgICAgICAgIFwiY2VsbFR5cGVcIjogXCJ0aFwiXG5cdFx0ICogICAgICAgIH0gXVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcInNDZWxsVHlwZVwiOiBcInRkXCIsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBDbGFzcyB0byBnaXZlIHRvIGVhY2ggY2VsbCBpbiB0aGlzIGNvbHVtbi5cblx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0ICogIEBkZWZhdWx0IDxpPkVtcHR5IHN0cmluZzwvaT5cblx0XHQgKlxuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuY29sdW1uLmNsYXNzXG5cdFx0ICogIEBkdG9wdCBDb2x1bW5zXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBVc2luZyBgY29sdW1uRGVmc2Bcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImNvbHVtbkRlZnNcIjogW1xuXHRcdCAqICAgICAgICAgIHsgXCJjbGFzc1wiOiBcIm15X2NsYXNzXCIsIFwidGFyZ2V0c1wiOiBbIDAgXSB9XG5cdFx0ICogICAgICAgIF1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBVc2luZyBgY29sdW1uc2Bcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImNvbHVtbnNcIjogW1xuXHRcdCAqICAgICAgICAgIHsgXCJjbGFzc1wiOiBcIm15X2NsYXNzXCIgfSxcblx0XHQgKiAgICAgICAgICBudWxsLFxuXHRcdCAqICAgICAgICAgIG51bGwsXG5cdFx0ICogICAgICAgICAgbnVsbCxcblx0XHQgKiAgICAgICAgICBudWxsXG5cdFx0ICogICAgICAgIF1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJzQ2xhc3NcIjogXCJcIixcblx0XG5cdFx0LyoqXG5cdFx0ICogV2hlbiBEYXRhVGFibGVzIGNhbGN1bGF0ZXMgdGhlIGNvbHVtbiB3aWR0aHMgdG8gYXNzaWduIHRvIGVhY2ggY29sdW1uLFxuXHRcdCAqIGl0IGZpbmRzIHRoZSBsb25nZXN0IHN0cmluZyBpbiBlYWNoIGNvbHVtbiBhbmQgdGhlbiBjb25zdHJ1Y3RzIGFcblx0XHQgKiB0ZW1wb3JhcnkgdGFibGUgYW5kIHJlYWRzIHRoZSB3aWR0aHMgZnJvbSB0aGF0LiBUaGUgcHJvYmxlbSB3aXRoIHRoaXNcblx0XHQgKiBpcyB0aGF0IFwibW1tXCIgaXMgbXVjaCB3aWRlciB0aGVuIFwiaWlpaVwiLCBidXQgdGhlIGxhdHRlciBpcyBhIGxvbmdlclxuXHRcdCAqIHN0cmluZyAtIHRodXMgdGhlIGNhbGN1bGF0aW9uIGNhbiBnbyB3cm9uZyAoZG9pbmcgaXQgcHJvcGVybHkgYW5kIHB1dHRpbmdcblx0XHQgKiBpdCBpbnRvIGFuIERPTSBvYmplY3QgYW5kIG1lYXN1cmluZyB0aGF0IGlzIGhvcnJpYmx5KCEpIHNsb3cpLiBUaHVzIGFzXG5cdFx0ICogYSBcIndvcmsgYXJvdW5kXCIgd2UgcHJvdmlkZSB0aGlzIG9wdGlvbi4gSXQgd2lsbCBhcHBlbmQgaXRzIHZhbHVlIHRvIHRoZVxuXHRcdCAqIHRleHQgdGhhdCBpcyBmb3VuZCB0byBiZSB0aGUgbG9uZ2VzdCBzdHJpbmcgZm9yIHRoZSBjb2x1bW4gLSBpLmUuIHBhZGRpbmcuXG5cdFx0ICogR2VuZXJhbGx5IHlvdSBzaG91bGRuJ3QgbmVlZCB0aGlzIVxuXHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHQgKiAgQGRlZmF1bHQgPGk+RW1wdHkgc3RyaW5nPGk+XG5cdFx0ICpcblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLmNvbHVtbi5jb250ZW50UGFkZGluZ1xuXHRcdCAqICBAZHRvcHQgQ29sdW1uc1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgLy8gVXNpbmcgYGNvbHVtbnNgXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJjb2x1bW5zXCI6IFtcblx0XHQgKiAgICAgICAgICBudWxsLFxuXHRcdCAqICAgICAgICAgIG51bGwsXG5cdFx0ICogICAgICAgICAgbnVsbCxcblx0XHQgKiAgICAgICAgICB7XG5cdFx0ICogICAgICAgICAgICBcImNvbnRlbnRQYWRkaW5nXCI6IFwibW1tXCJcblx0XHQgKiAgICAgICAgICB9XG5cdFx0ICogICAgICAgIF1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICovXG5cdFx0XCJzQ29udGVudFBhZGRpbmdcIjogXCJcIixcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIEFsbG93cyBhIGRlZmF1bHQgdmFsdWUgdG8gYmUgZ2l2ZW4gZm9yIGEgY29sdW1uJ3MgZGF0YSwgYW5kIHdpbGwgYmUgdXNlZFxuXHRcdCAqIHdoZW5ldmVyIGEgbnVsbCBkYXRhIHNvdXJjZSBpcyBlbmNvdW50ZXJlZCAodGhpcyBjYW4gYmUgYmVjYXVzZSBgZGF0YWBcblx0XHQgKiBpcyBzZXQgdG8gbnVsbCwgb3IgYmVjYXVzZSB0aGUgZGF0YSBzb3VyY2UgaXRzZWxmIGlzIG51bGwpLlxuXHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHQgKiAgQGRlZmF1bHQgbnVsbFxuXHRcdCAqXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5jb2x1bW4uZGVmYXVsdENvbnRlbnRcblx0XHQgKiAgQGR0b3B0IENvbHVtbnNcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgIC8vIFVzaW5nIGBjb2x1bW5EZWZzYFxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiY29sdW1uRGVmc1wiOiBbXG5cdFx0ICogICAgICAgICAge1xuXHRcdCAqICAgICAgICAgICAgXCJkYXRhXCI6IG51bGwsXG5cdFx0ICogICAgICAgICAgICBcImRlZmF1bHRDb250ZW50XCI6IFwiRWRpdFwiLFxuXHRcdCAqICAgICAgICAgICAgXCJ0YXJnZXRzXCI6IFsgLTEgXVxuXHRcdCAqICAgICAgICAgIH1cblx0XHQgKiAgICAgICAgXVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgIC8vIFVzaW5nIGBjb2x1bW5zYFxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiY29sdW1uc1wiOiBbXG5cdFx0ICogICAgICAgICAgbnVsbCxcblx0XHQgKiAgICAgICAgICBudWxsLFxuXHRcdCAqICAgICAgICAgIG51bGwsXG5cdFx0ICogICAgICAgICAge1xuXHRcdCAqICAgICAgICAgICAgXCJkYXRhXCI6IG51bGwsXG5cdFx0ICogICAgICAgICAgICBcImRlZmF1bHRDb250ZW50XCI6IFwiRWRpdFwiXG5cdFx0ICogICAgICAgICAgfVxuXHRcdCAqICAgICAgICBdXG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqL1xuXHRcdFwic0RlZmF1bHRDb250ZW50XCI6IG51bGwsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBUaGlzIHBhcmFtZXRlciBpcyBvbmx5IHVzZWQgaW4gRGF0YVRhYmxlcycgc2VydmVyLXNpZGUgcHJvY2Vzc2luZy4gSXQgY2FuXG5cdFx0ICogYmUgZXhjZXB0aW9uYWxseSB1c2VmdWwgdG8ga25vdyB3aGF0IGNvbHVtbnMgYXJlIGJlaW5nIGRpc3BsYXllZCBvbiB0aGVcblx0XHQgKiBjbGllbnQgc2lkZSwgYW5kIHRvIG1hcCB0aGVzZSB0byBkYXRhYmFzZSBmaWVsZHMuIFdoZW4gZGVmaW5lZCwgdGhlIG5hbWVzXG5cdFx0ICogYWxzbyBhbGxvdyBEYXRhVGFibGVzIHRvIHJlb3JkZXIgaW5mb3JtYXRpb24gZnJvbSB0aGUgc2VydmVyIGlmIGl0IGNvbWVzXG5cdFx0ICogYmFjayBpbiBhbiB1bmV4cGVjdGVkIG9yZGVyIChpLmUuIGlmIHlvdSBzd2l0Y2ggeW91ciBjb2x1bW5zIGFyb3VuZCBvbiB0aGVcblx0XHQgKiBjbGllbnQtc2lkZSwgeW91ciBzZXJ2ZXItc2lkZSBjb2RlIGRvZXMgbm90IGFsc28gbmVlZCB1cGRhdGluZykuXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqICBAZGVmYXVsdCA8aT5FbXB0eSBzdHJpbmc8L2k+XG5cdFx0ICpcblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLmNvbHVtbi5uYW1lXG5cdFx0ICogIEBkdG9wdCBDb2x1bW5zXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBVc2luZyBgY29sdW1uRGVmc2Bcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImNvbHVtbkRlZnNcIjogW1xuXHRcdCAqICAgICAgICAgIHsgXCJuYW1lXCI6IFwiZW5naW5lXCIsIFwidGFyZ2V0c1wiOiBbIDAgXSB9LFxuXHRcdCAqICAgICAgICAgIHsgXCJuYW1lXCI6IFwiYnJvd3NlclwiLCBcInRhcmdldHNcIjogWyAxIF0gfSxcblx0XHQgKiAgICAgICAgICB7IFwibmFtZVwiOiBcInBsYXRmb3JtXCIsIFwidGFyZ2V0c1wiOiBbIDIgXSB9LFxuXHRcdCAqICAgICAgICAgIHsgXCJuYW1lXCI6IFwidmVyc2lvblwiLCBcInRhcmdldHNcIjogWyAzIF0gfSxcblx0XHQgKiAgICAgICAgICB7IFwibmFtZVwiOiBcImdyYWRlXCIsIFwidGFyZ2V0c1wiOiBbIDQgXSB9XG5cdFx0ICogICAgICAgIF1cblx0XHQgKiAgICAgIH0gKTtcblx0XHQgKiAgICB9ICk7XG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBVc2luZyBgY29sdW1uc2Bcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImNvbHVtbnNcIjogW1xuXHRcdCAqICAgICAgICAgIHsgXCJuYW1lXCI6IFwiZW5naW5lXCIgfSxcblx0XHQgKiAgICAgICAgICB7IFwibmFtZVwiOiBcImJyb3dzZXJcIiB9LFxuXHRcdCAqICAgICAgICAgIHsgXCJuYW1lXCI6IFwicGxhdGZvcm1cIiB9LFxuXHRcdCAqICAgICAgICAgIHsgXCJuYW1lXCI6IFwidmVyc2lvblwiIH0sXG5cdFx0ICogICAgICAgICAgeyBcIm5hbWVcIjogXCJncmFkZVwiIH1cblx0XHQgKiAgICAgICAgXVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcInNOYW1lXCI6IFwiXCIsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBEZWZpbmVzIGEgZGF0YSBzb3VyY2UgdHlwZSBmb3IgdGhlIG9yZGVyaW5nIHdoaWNoIGNhbiBiZSB1c2VkIHRvIHJlYWRcblx0XHQgKiByZWFsLXRpbWUgaW5mb3JtYXRpb24gZnJvbSB0aGUgdGFibGUgKHVwZGF0aW5nIHRoZSBpbnRlcm5hbGx5IGNhY2hlZFxuXHRcdCAqIHZlcnNpb24pIHByaW9yIHRvIG9yZGVyaW5nLiBUaGlzIGFsbG93cyBvcmRlcmluZyB0byBvY2N1ciBvbiB1c2VyXG5cdFx0ICogZWRpdGFibGUgZWxlbWVudHMgc3VjaCBhcyBmb3JtIGlucHV0cy5cblx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0ICogIEBkZWZhdWx0IHN0ZFxuXHRcdCAqXG5cdFx0ICogIEBuYW1lIERhdGFUYWJsZS5kZWZhdWx0cy5jb2x1bW4ub3JkZXJEYXRhVHlwZVxuXHRcdCAqICBAZHRvcHQgQ29sdW1uc1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgLy8gVXNpbmcgYGNvbHVtbkRlZnNgXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJjb2x1bW5EZWZzXCI6IFtcblx0XHQgKiAgICAgICAgICB7IFwib3JkZXJEYXRhVHlwZVwiOiBcImRvbS10ZXh0XCIsIFwidGFyZ2V0c1wiOiBbIDIsIDMgXSB9LFxuXHRcdCAqICAgICAgICAgIHsgXCJ0eXBlXCI6IFwibnVtZXJpY1wiLCBcInRhcmdldHNcIjogWyAzIF0gfSxcblx0XHQgKiAgICAgICAgICB7IFwib3JkZXJEYXRhVHlwZVwiOiBcImRvbS1zZWxlY3RcIiwgXCJ0YXJnZXRzXCI6IFsgNCBdIH0sXG5cdFx0ICogICAgICAgICAgeyBcIm9yZGVyRGF0YVR5cGVcIjogXCJkb20tY2hlY2tib3hcIiwgXCJ0YXJnZXRzXCI6IFsgNSBdIH1cblx0XHQgKiAgICAgICAgXVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKlxuXHRcdCAqICBAZXhhbXBsZVxuXHRcdCAqICAgIC8vIFVzaW5nIGBjb2x1bW5zYFxuXHRcdCAqICAgICQoZG9jdW1lbnQpLnJlYWR5KCBmdW5jdGlvbigpIHtcblx0XHQgKiAgICAgICQoJyNleGFtcGxlJykuZGF0YVRhYmxlKCB7XG5cdFx0ICogICAgICAgIFwiY29sdW1uc1wiOiBbXG5cdFx0ICogICAgICAgICAgbnVsbCxcblx0XHQgKiAgICAgICAgICBudWxsLFxuXHRcdCAqICAgICAgICAgIHsgXCJvcmRlckRhdGFUeXBlXCI6IFwiZG9tLXRleHRcIiB9LFxuXHRcdCAqICAgICAgICAgIHsgXCJvcmRlckRhdGFUeXBlXCI6IFwiZG9tLXRleHRcIiwgXCJ0eXBlXCI6IFwibnVtZXJpY1wiIH0sXG5cdFx0ICogICAgICAgICAgeyBcIm9yZGVyRGF0YVR5cGVcIjogXCJkb20tc2VsZWN0XCIgfSxcblx0XHQgKiAgICAgICAgICB7IFwib3JkZXJEYXRhVHlwZVwiOiBcImRvbS1jaGVja2JveFwiIH1cblx0XHQgKiAgICAgICAgXVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcInNTb3J0RGF0YVR5cGVcIjogXCJzdGRcIixcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIFRoZSB0aXRsZSBvZiB0aGlzIGNvbHVtbi5cblx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0ICogIEBkZWZhdWx0IG51bGwgPGk+RGVyaXZlZCBmcm9tIHRoZSAnVEgnIHZhbHVlIGZvciB0aGlzIGNvbHVtbiBpbiB0aGVcblx0XHQgKiAgICBvcmlnaW5hbCBIVE1MIHRhYmxlLjwvaT5cblx0XHQgKlxuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuY29sdW1uLnRpdGxlXG5cdFx0ICogIEBkdG9wdCBDb2x1bW5zXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBVc2luZyBgY29sdW1uRGVmc2Bcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImNvbHVtbkRlZnNcIjogW1xuXHRcdCAqICAgICAgICAgIHsgXCJ0aXRsZVwiOiBcIk15IGNvbHVtbiB0aXRsZVwiLCBcInRhcmdldHNcIjogWyAwIF0gfVxuXHRcdCAqICAgICAgICBdXG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgLy8gVXNpbmcgYGNvbHVtbnNgXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJjb2x1bW5zXCI6IFtcblx0XHQgKiAgICAgICAgICB7IFwidGl0bGVcIjogXCJNeSBjb2x1bW4gdGl0bGVcIiB9LFxuXHRcdCAqICAgICAgICAgIG51bGwsXG5cdFx0ICogICAgICAgICAgbnVsbCxcblx0XHQgKiAgICAgICAgICBudWxsLFxuXHRcdCAqICAgICAgICAgIG51bGxcblx0XHQgKiAgICAgICAgXVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcInNUaXRsZVwiOiBudWxsLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogVGhlIHR5cGUgYWxsb3dzIHlvdSB0byBzcGVjaWZ5IGhvdyB0aGUgZGF0YSBmb3IgdGhpcyBjb2x1bW4gd2lsbCBiZVxuXHRcdCAqIG9yZGVyZWQuIEZvdXIgdHlwZXMgKHN0cmluZywgbnVtZXJpYywgZGF0ZSBhbmQgaHRtbCAod2hpY2ggd2lsbCBzdHJpcFxuXHRcdCAqIEhUTUwgdGFncyBiZWZvcmUgb3JkZXJpbmcpKSBhcmUgY3VycmVudGx5IGF2YWlsYWJsZS4gTm90ZSB0aGF0IG9ubHkgZGF0ZVxuXHRcdCAqIGZvcm1hdHMgdW5kZXJzdG9vZCBieSBKYXZhc2NyaXB0J3MgRGF0ZSgpIG9iamVjdCB3aWxsIGJlIGFjY2VwdGVkIGFzIHR5cGVcblx0XHQgKiBkYXRlLiBGb3IgZXhhbXBsZTogXCJNYXIgMjYsIDIwMDggNTowMyBQTVwiLiBNYXkgdGFrZSB0aGUgdmFsdWVzOiAnc3RyaW5nJyxcblx0XHQgKiAnbnVtZXJpYycsICdkYXRlJyBvciAnaHRtbCcgKGJ5IGRlZmF1bHQpLiBGdXJ0aGVyIHR5cGVzIGNhbiBiZSBhZGRpbmdcblx0XHQgKiB0aHJvdWdoIHBsdWctaW5zLlxuXHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHQgKiAgQGRlZmF1bHQgbnVsbCA8aT5BdXRvLWRldGVjdGVkIGZyb20gcmF3IGRhdGE8L2k+XG5cdFx0ICpcblx0XHQgKiAgQG5hbWUgRGF0YVRhYmxlLmRlZmF1bHRzLmNvbHVtbi50eXBlXG5cdFx0ICogIEBkdG9wdCBDb2x1bW5zXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBVc2luZyBgY29sdW1uRGVmc2Bcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImNvbHVtbkRlZnNcIjogW1xuXHRcdCAqICAgICAgICAgIHsgXCJ0eXBlXCI6IFwiaHRtbFwiLCBcInRhcmdldHNcIjogWyAwIF0gfVxuXHRcdCAqICAgICAgICBdXG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgLy8gVXNpbmcgYGNvbHVtbnNgXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJjb2x1bW5zXCI6IFtcblx0XHQgKiAgICAgICAgICB7IFwidHlwZVwiOiBcImh0bWxcIiB9LFxuXHRcdCAqICAgICAgICAgIG51bGwsXG5cdFx0ICogICAgICAgICAgbnVsbCxcblx0XHQgKiAgICAgICAgICBudWxsLFxuXHRcdCAqICAgICAgICAgIG51bGxcblx0XHQgKiAgICAgICAgXVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcInNUeXBlXCI6IG51bGwsXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBEZWZpbmluZyB0aGUgd2lkdGggb2YgdGhlIGNvbHVtbiwgdGhpcyBwYXJhbWV0ZXIgbWF5IHRha2UgYW55IENTUyB2YWx1ZVxuXHRcdCAqICgzZW0sIDIwcHggZXRjKS4gRGF0YVRhYmxlcyBhcHBsaWVzICdzbWFydCcgd2lkdGhzIHRvIGNvbHVtbnMgd2hpY2ggaGF2ZSBub3Rcblx0XHQgKiBiZWVuIGdpdmVuIGEgc3BlY2lmaWMgd2lkdGggdGhyb3VnaCB0aGlzIGludGVyZmFjZSBlbnN1cmluZyB0aGF0IHRoZSB0YWJsZVxuXHRcdCAqIHJlbWFpbnMgcmVhZGFibGUuXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqICBAZGVmYXVsdCBudWxsIDxpPkF1dG9tYXRpYzwvaT5cblx0XHQgKlxuXHRcdCAqICBAbmFtZSBEYXRhVGFibGUuZGVmYXVsdHMuY29sdW1uLndpZHRoXG5cdFx0ICogIEBkdG9wdCBDb2x1bW5zXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBVc2luZyBgY29sdW1uRGVmc2Bcblx0XHQgKiAgICAkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24oKSB7XG5cdFx0ICogICAgICAkKCcjZXhhbXBsZScpLmRhdGFUYWJsZSgge1xuXHRcdCAqICAgICAgICBcImNvbHVtbkRlZnNcIjogW1xuXHRcdCAqICAgICAgICAgIHsgXCJ3aWR0aFwiOiBcIjIwJVwiLCBcInRhcmdldHNcIjogWyAwIF0gfVxuXHRcdCAqICAgICAgICBdXG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfSApO1xuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgLy8gVXNpbmcgYGNvbHVtbnNgXG5cdFx0ICogICAgJChkb2N1bWVudCkucmVhZHkoIGZ1bmN0aW9uKCkge1xuXHRcdCAqICAgICAgJCgnI2V4YW1wbGUnKS5kYXRhVGFibGUoIHtcblx0XHQgKiAgICAgICAgXCJjb2x1bW5zXCI6IFtcblx0XHQgKiAgICAgICAgICB7IFwid2lkdGhcIjogXCIyMCVcIiB9LFxuXHRcdCAqICAgICAgICAgIG51bGwsXG5cdFx0ICogICAgICAgICAgbnVsbCxcblx0XHQgKiAgICAgICAgICBudWxsLFxuXHRcdCAqICAgICAgICAgIG51bGxcblx0XHQgKiAgICAgICAgXVxuXHRcdCAqICAgICAgfSApO1xuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRcInNXaWR0aFwiOiBudWxsXG5cdH07XG5cdFxuXHRfZm5IdW5nYXJpYW5NYXAoIERhdGFUYWJsZS5kZWZhdWx0cy5jb2x1bW4gKTtcblx0XG5cdFxuXHRcblx0LyoqXG5cdCAqIERhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0IC0gdGhpcyBob2xkcyBhbGwgdGhlIGluZm9ybWF0aW9uIG5lZWRlZCBmb3IgYVxuXHQgKiBnaXZlbiB0YWJsZSwgaW5jbHVkaW5nIGNvbmZpZ3VyYXRpb24sIGRhdGEgYW5kIGN1cnJlbnQgYXBwbGljYXRpb24gb2YgdGhlXG5cdCAqIHRhYmxlIG9wdGlvbnMuIERhdGFUYWJsZXMgZG9lcyBub3QgaGF2ZSBhIHNpbmdsZSBpbnN0YW5jZSBmb3IgZWFjaCBEYXRhVGFibGVcblx0ICogd2l0aCB0aGUgc2V0dGluZ3MgYXR0YWNoZWQgdG8gdGhhdCBpbnN0YW5jZSwgYnV0IHJhdGhlciBpbnN0YW5jZXMgb2YgdGhlXG5cdCAqIERhdGFUYWJsZSBcImNsYXNzXCIgYXJlIGNyZWF0ZWQgb24tdGhlLWZseSBhcyBuZWVkZWQgKHR5cGljYWxseSBieSBhXG5cdCAqICQoKS5kYXRhVGFibGUoKSBjYWxsKSBhbmQgdGhlIHNldHRpbmdzIG9iamVjdCBpcyB0aGVuIGFwcGxpZWQgdG8gdGhhdFxuXHQgKiBpbnN0YW5jZS5cblx0ICpcblx0ICogTm90ZSB0aGF0IHRoaXMgb2JqZWN0IGlzIHJlbGF0ZWQgdG8ge0BsaW5rIERhdGFUYWJsZS5kZWZhdWx0c30gYnV0IHRoaXNcblx0ICogb25lIGlzIHRoZSBpbnRlcm5hbCBkYXRhIHN0b3JlIGZvciBEYXRhVGFibGVzJ3MgY2FjaGUgb2YgY29sdW1ucy4gSXQgc2hvdWxkXG5cdCAqIE5PVCBiZSBtYW5pcHVsYXRlZCBvdXRzaWRlIG9mIERhdGFUYWJsZXMuIEFueSBjb25maWd1cmF0aW9uIHNob3VsZCBiZSBkb25lXG5cdCAqIHRocm91Z2ggdGhlIGluaXRpYWxpc2F0aW9uIG9wdGlvbnMuXG5cdCAqICBAbmFtZXNwYWNlXG5cdCAqICBAdG9kbyBSZWFsbHkgc2hvdWxkIGF0dGFjaCB0aGUgc2V0dGluZ3Mgb2JqZWN0IHRvIGluZGl2aWR1YWwgaW5zdGFuY2VzIHNvIHdlXG5cdCAqICAgIGRvbid0IG5lZWQgdG8gY3JlYXRlIG5ldyBpbnN0YW5jZXMgb24gZWFjaCAkKCkuZGF0YVRhYmxlKCkgY2FsbCAoaWYgdGhlXG5cdCAqICAgIHRhYmxlIGFscmVhZHkgZXhpc3RzKS4gSXQgd291bGQgYWxzbyBzYXZlIHBhc3Npbmcgb1NldHRpbmdzIGFyb3VuZCBhbmRcblx0ICogICAgaW50byBldmVyeSBzaW5nbGUgZnVuY3Rpb24uIEhvd2V2ZXIsIHRoaXMgaXMgYSB2ZXJ5IHNpZ25pZmljYW50XG5cdCAqICAgIGFyY2hpdGVjdHVyZSBjaGFuZ2UgZm9yIERhdGFUYWJsZXMgYW5kIHdpbGwgYWxtb3N0IGNlcnRhaW5seSBicmVha1xuXHQgKiAgICBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eSB3aXRoIG9sZGVyIGluc3RhbGxhdGlvbnMuIFRoaXMgaXMgc29tZXRoaW5nIHRoYXRcblx0ICogICAgd2lsbCBiZSBkb25lIGluIDIuMC5cblx0ICovXG5cdERhdGFUYWJsZS5tb2RlbHMub1NldHRpbmdzID0ge1xuXHRcdC8qKlxuXHRcdCAqIFByaW1hcnkgZmVhdHVyZXMgb2YgRGF0YVRhYmxlcyBhbmQgdGhlaXIgZW5hYmxlbWVudCBzdGF0ZS5cblx0XHQgKiAgQG5hbWVzcGFjZVxuXHRcdCAqL1xuXHRcdFwib0ZlYXR1cmVzXCI6IHtcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIEZsYWcgdG8gc2F5IGlmIERhdGFUYWJsZXMgc2hvdWxkIGF1dG9tYXRpY2FsbHkgdHJ5IHRvIGNhbGN1bGF0ZSB0aGVcblx0XHRcdCAqIG9wdGltdW0gdGFibGUgYW5kIGNvbHVtbnMgd2lkdGhzICh0cnVlKSBvciBub3QgKGZhbHNlKS5cblx0XHRcdCAqIE5vdGUgdGhhdCB0aGlzIHBhcmFtZXRlciB3aWxsIGJlIHNldCBieSB0aGUgaW5pdGlhbGlzYXRpb24gcm91dGluZS4gVG9cblx0XHRcdCAqIHNldCBhIGRlZmF1bHQgdXNlIHtAbGluayBEYXRhVGFibGUuZGVmYXVsdHN9LlxuXHRcdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHRcdCAqL1xuXHRcdFx0XCJiQXV0b1dpZHRoXCI6IG51bGwsXG5cdFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBEZWxheSB0aGUgY3JlYXRpb24gb2YgVFIgYW5kIFREIGVsZW1lbnRzIHVudGlsIHRoZXkgYXJlIGFjdHVhbGx5XG5cdFx0XHQgKiBuZWVkZWQgYnkgYSBkcml2ZW4gcGFnZSBkcmF3LiBUaGlzIGNhbiBnaXZlIGEgc2lnbmlmaWNhbnQgc3BlZWRcblx0XHRcdCAqIGluY3JlYXNlIGZvciBBamF4IHNvdXJjZSBhbmQgSmF2YXNjcmlwdCBzb3VyY2UgZGF0YSwgYnV0IG1ha2VzIG5vXG5cdFx0XHQgKiBkaWZmZXJlbmNlIGF0IGFsbCBmb3IgRE9NIGFuZCBzZXJ2ZXItc2lkZSBwcm9jZXNzaW5nIHRhYmxlcy5cblx0XHRcdCAqIE5vdGUgdGhhdCB0aGlzIHBhcmFtZXRlciB3aWxsIGJlIHNldCBieSB0aGUgaW5pdGlhbGlzYXRpb24gcm91dGluZS4gVG9cblx0XHRcdCAqIHNldCBhIGRlZmF1bHQgdXNlIHtAbGluayBEYXRhVGFibGUuZGVmYXVsdHN9LlxuXHRcdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHRcdCAqL1xuXHRcdFx0XCJiRGVmZXJSZW5kZXJcIjogbnVsbCxcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIEVuYWJsZSBmaWx0ZXJpbmcgb24gdGhlIHRhYmxlIG9yIG5vdC4gTm90ZSB0aGF0IGlmIHRoaXMgaXMgZGlzYWJsZWRcblx0XHRcdCAqIHRoZW4gdGhlcmUgaXMgbm8gZmlsdGVyaW5nIGF0IGFsbCBvbiB0aGUgdGFibGUsIGluY2x1ZGluZyBmbkZpbHRlci5cblx0XHRcdCAqIFRvIGp1c3QgcmVtb3ZlIHRoZSBmaWx0ZXJpbmcgaW5wdXQgdXNlIHNEb20gYW5kIHJlbW92ZSB0aGUgJ2YnIG9wdGlvbi5cblx0XHRcdCAqIE5vdGUgdGhhdCB0aGlzIHBhcmFtZXRlciB3aWxsIGJlIHNldCBieSB0aGUgaW5pdGlhbGlzYXRpb24gcm91dGluZS4gVG9cblx0XHRcdCAqIHNldCBhIGRlZmF1bHQgdXNlIHtAbGluayBEYXRhVGFibGUuZGVmYXVsdHN9LlxuXHRcdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHRcdCAqL1xuXHRcdFx0XCJiRmlsdGVyXCI6IG51bGwsXG5cdFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBUYWJsZSBpbmZvcm1hdGlvbiBlbGVtZW50ICh0aGUgJ1Nob3dpbmcgeCBvZiB5IHJlY29yZHMnIGRpdikgZW5hYmxlXG5cdFx0XHQgKiBmbGFnLlxuXHRcdFx0ICogTm90ZSB0aGF0IHRoaXMgcGFyYW1ldGVyIHdpbGwgYmUgc2V0IGJ5IHRoZSBpbml0aWFsaXNhdGlvbiByb3V0aW5lLiBUb1xuXHRcdFx0ICogc2V0IGEgZGVmYXVsdCB1c2Uge0BsaW5rIERhdGFUYWJsZS5kZWZhdWx0c30uXG5cdFx0XHQgKiAgQHR5cGUgYm9vbGVhblxuXHRcdFx0ICovXG5cdFx0XHRcImJJbmZvXCI6IG51bGwsXG5cdFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBQcmVzZW50IGEgdXNlciBjb250cm9sIGFsbG93aW5nIHRoZSBlbmQgdXNlciB0byBjaGFuZ2UgdGhlIHBhZ2Ugc2l6ZVxuXHRcdFx0ICogd2hlbiBwYWdpbmF0aW9uIGlzIGVuYWJsZWQuXG5cdFx0XHQgKiBOb3RlIHRoYXQgdGhpcyBwYXJhbWV0ZXIgd2lsbCBiZSBzZXQgYnkgdGhlIGluaXRpYWxpc2F0aW9uIHJvdXRpbmUuIFRvXG5cdFx0XHQgKiBzZXQgYSBkZWZhdWx0IHVzZSB7QGxpbmsgRGF0YVRhYmxlLmRlZmF1bHRzfS5cblx0XHRcdCAqICBAdHlwZSBib29sZWFuXG5cdFx0XHQgKi9cblx0XHRcdFwiYkxlbmd0aENoYW5nZVwiOiBudWxsLFxuXHRcblx0XHRcdC8qKlxuXHRcdFx0ICogUGFnaW5hdGlvbiBlbmFibGVkIG9yIG5vdC4gTm90ZSB0aGF0IGlmIHRoaXMgaXMgZGlzYWJsZWQgdGhlbiBsZW5ndGhcblx0XHRcdCAqIGNoYW5naW5nIG11c3QgYWxzbyBiZSBkaXNhYmxlZC5cblx0XHRcdCAqIE5vdGUgdGhhdCB0aGlzIHBhcmFtZXRlciB3aWxsIGJlIHNldCBieSB0aGUgaW5pdGlhbGlzYXRpb24gcm91dGluZS4gVG9cblx0XHRcdCAqIHNldCBhIGRlZmF1bHQgdXNlIHtAbGluayBEYXRhVGFibGUuZGVmYXVsdHN9LlxuXHRcdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHRcdCAqL1xuXHRcdFx0XCJiUGFnaW5hdGVcIjogbnVsbCxcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIFByb2Nlc3NpbmcgaW5kaWNhdG9yIGVuYWJsZSBmbGFnIHdoZW5ldmVyIERhdGFUYWJsZXMgaXMgZW5hY3RpbmcgYVxuXHRcdFx0ICogdXNlciByZXF1ZXN0IC0gdHlwaWNhbGx5IGFuIEFqYXggcmVxdWVzdCBmb3Igc2VydmVyLXNpZGUgcHJvY2Vzc2luZy5cblx0XHRcdCAqIE5vdGUgdGhhdCB0aGlzIHBhcmFtZXRlciB3aWxsIGJlIHNldCBieSB0aGUgaW5pdGlhbGlzYXRpb24gcm91dGluZS4gVG9cblx0XHRcdCAqIHNldCBhIGRlZmF1bHQgdXNlIHtAbGluayBEYXRhVGFibGUuZGVmYXVsdHN9LlxuXHRcdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHRcdCAqL1xuXHRcdFx0XCJiUHJvY2Vzc2luZ1wiOiBudWxsLFxuXHRcblx0XHRcdC8qKlxuXHRcdFx0ICogU2VydmVyLXNpZGUgcHJvY2Vzc2luZyBlbmFibGVkIGZsYWcgLSB3aGVuIGVuYWJsZWQgRGF0YVRhYmxlcyB3aWxsXG5cdFx0XHQgKiBnZXQgYWxsIGRhdGEgZnJvbSB0aGUgc2VydmVyIGZvciBldmVyeSBkcmF3IC0gdGhlcmUgaXMgbm8gZmlsdGVyaW5nLFxuXHRcdFx0ICogc29ydGluZyBvciBwYWdpbmcgZG9uZSBvbiB0aGUgY2xpZW50LXNpZGUuXG5cdFx0XHQgKiBOb3RlIHRoYXQgdGhpcyBwYXJhbWV0ZXIgd2lsbCBiZSBzZXQgYnkgdGhlIGluaXRpYWxpc2F0aW9uIHJvdXRpbmUuIFRvXG5cdFx0XHQgKiBzZXQgYSBkZWZhdWx0IHVzZSB7QGxpbmsgRGF0YVRhYmxlLmRlZmF1bHRzfS5cblx0XHRcdCAqICBAdHlwZSBib29sZWFuXG5cdFx0XHQgKi9cblx0XHRcdFwiYlNlcnZlclNpZGVcIjogbnVsbCxcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIFNvcnRpbmcgZW5hYmxlbWVudCBmbGFnLlxuXHRcdFx0ICogTm90ZSB0aGF0IHRoaXMgcGFyYW1ldGVyIHdpbGwgYmUgc2V0IGJ5IHRoZSBpbml0aWFsaXNhdGlvbiByb3V0aW5lLiBUb1xuXHRcdFx0ICogc2V0IGEgZGVmYXVsdCB1c2Uge0BsaW5rIERhdGFUYWJsZS5kZWZhdWx0c30uXG5cdFx0XHQgKiAgQHR5cGUgYm9vbGVhblxuXHRcdFx0ICovXG5cdFx0XHRcImJTb3J0XCI6IG51bGwsXG5cdFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBNdWx0aS1jb2x1bW4gc29ydGluZ1xuXHRcdFx0ICogTm90ZSB0aGF0IHRoaXMgcGFyYW1ldGVyIHdpbGwgYmUgc2V0IGJ5IHRoZSBpbml0aWFsaXNhdGlvbiByb3V0aW5lLiBUb1xuXHRcdFx0ICogc2V0IGEgZGVmYXVsdCB1c2Uge0BsaW5rIERhdGFUYWJsZS5kZWZhdWx0c30uXG5cdFx0XHQgKiAgQHR5cGUgYm9vbGVhblxuXHRcdFx0ICovXG5cdFx0XHRcImJTb3J0TXVsdGlcIjogbnVsbCxcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIEFwcGx5IGEgY2xhc3MgdG8gdGhlIGNvbHVtbnMgd2hpY2ggYXJlIGJlaW5nIHNvcnRlZCB0byBwcm92aWRlIGFcblx0XHRcdCAqIHZpc3VhbCBoaWdobGlnaHQgb3Igbm90LiBUaGlzIGNhbiBzbG93IHRoaW5ncyBkb3duIHdoZW4gZW5hYmxlZCBzaW5jZVxuXHRcdFx0ICogdGhlcmUgaXMgYSBsb3Qgb2YgRE9NIGludGVyYWN0aW9uLlxuXHRcdFx0ICogTm90ZSB0aGF0IHRoaXMgcGFyYW1ldGVyIHdpbGwgYmUgc2V0IGJ5IHRoZSBpbml0aWFsaXNhdGlvbiByb3V0aW5lLiBUb1xuXHRcdFx0ICogc2V0IGEgZGVmYXVsdCB1c2Uge0BsaW5rIERhdGFUYWJsZS5kZWZhdWx0c30uXG5cdFx0XHQgKiAgQHR5cGUgYm9vbGVhblxuXHRcdFx0ICovXG5cdFx0XHRcImJTb3J0Q2xhc3Nlc1wiOiBudWxsLFxuXHRcblx0XHRcdC8qKlxuXHRcdFx0ICogU3RhdGUgc2F2aW5nIGVuYWJsZW1lbnQgZmxhZy5cblx0XHRcdCAqIE5vdGUgdGhhdCB0aGlzIHBhcmFtZXRlciB3aWxsIGJlIHNldCBieSB0aGUgaW5pdGlhbGlzYXRpb24gcm91dGluZS4gVG9cblx0XHRcdCAqIHNldCBhIGRlZmF1bHQgdXNlIHtAbGluayBEYXRhVGFibGUuZGVmYXVsdHN9LlxuXHRcdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHRcdCAqL1xuXHRcdFx0XCJiU3RhdGVTYXZlXCI6IG51bGxcblx0XHR9LFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogU2Nyb2xsaW5nIHNldHRpbmdzIGZvciBhIHRhYmxlLlxuXHRcdCAqICBAbmFtZXNwYWNlXG5cdFx0ICovXG5cdFx0XCJvU2Nyb2xsXCI6IHtcblx0XHRcdC8qKlxuXHRcdFx0ICogV2hlbiB0aGUgdGFibGUgaXMgc2hvcnRlciBpbiBoZWlnaHQgdGhhbiBzU2Nyb2xsWSwgY29sbGFwc2UgdGhlXG5cdFx0XHQgKiB0YWJsZSBjb250YWluZXIgZG93biB0byB0aGUgaGVpZ2h0IG9mIHRoZSB0YWJsZSAod2hlbiB0cnVlKS5cblx0XHRcdCAqIE5vdGUgdGhhdCB0aGlzIHBhcmFtZXRlciB3aWxsIGJlIHNldCBieSB0aGUgaW5pdGlhbGlzYXRpb24gcm91dGluZS4gVG9cblx0XHRcdCAqIHNldCBhIGRlZmF1bHQgdXNlIHtAbGluayBEYXRhVGFibGUuZGVmYXVsdHN9LlxuXHRcdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHRcdCAqL1xuXHRcdFx0XCJiQ29sbGFwc2VcIjogbnVsbCxcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIFdpZHRoIG9mIHRoZSBzY3JvbGxiYXIgZm9yIHRoZSB3ZWItYnJvd3NlcidzIHBsYXRmb3JtLiBDYWxjdWxhdGVkXG5cdFx0XHQgKiBkdXJpbmcgdGFibGUgaW5pdGlhbGlzYXRpb24uXG5cdFx0XHQgKiAgQHR5cGUgaW50XG5cdFx0XHQgKiAgQGRlZmF1bHQgMFxuXHRcdFx0ICovXG5cdFx0XHRcImlCYXJXaWR0aFwiOiAwLFxuXHRcblx0XHRcdC8qKlxuXHRcdFx0ICogVmlld3BvcnQgd2lkdGggZm9yIGhvcml6b250YWwgc2Nyb2xsaW5nLiBIb3Jpem9udGFsIHNjcm9sbGluZyBpc1xuXHRcdFx0ICogZGlzYWJsZWQgaWYgYW4gZW1wdHkgc3RyaW5nLlxuXHRcdFx0ICogTm90ZSB0aGF0IHRoaXMgcGFyYW1ldGVyIHdpbGwgYmUgc2V0IGJ5IHRoZSBpbml0aWFsaXNhdGlvbiByb3V0aW5lLiBUb1xuXHRcdFx0ICogc2V0IGEgZGVmYXVsdCB1c2Uge0BsaW5rIERhdGFUYWJsZS5kZWZhdWx0c30uXG5cdFx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0XHQgKi9cblx0XHRcdFwic1hcIjogbnVsbCxcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIFdpZHRoIHRvIGV4cGFuZCB0aGUgdGFibGUgdG8gd2hlbiB1c2luZyB4LXNjcm9sbGluZy4gVHlwaWNhbGx5IHlvdVxuXHRcdFx0ICogc2hvdWxkIG5vdCBuZWVkIHRvIHVzZSB0aGlzLlxuXHRcdFx0ICogTm90ZSB0aGF0IHRoaXMgcGFyYW1ldGVyIHdpbGwgYmUgc2V0IGJ5IHRoZSBpbml0aWFsaXNhdGlvbiByb3V0aW5lLiBUb1xuXHRcdFx0ICogc2V0IGEgZGVmYXVsdCB1c2Uge0BsaW5rIERhdGFUYWJsZS5kZWZhdWx0c30uXG5cdFx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0XHQgKiAgQGRlcHJlY2F0ZWRcblx0XHRcdCAqL1xuXHRcdFx0XCJzWElubmVyXCI6IG51bGwsXG5cdFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBWaWV3cG9ydCBoZWlnaHQgZm9yIHZlcnRpY2FsIHNjcm9sbGluZy4gVmVydGljYWwgc2Nyb2xsaW5nIGlzIGRpc2FibGVkXG5cdFx0XHQgKiBpZiBhbiBlbXB0eSBzdHJpbmcuXG5cdFx0XHQgKiBOb3RlIHRoYXQgdGhpcyBwYXJhbWV0ZXIgd2lsbCBiZSBzZXQgYnkgdGhlIGluaXRpYWxpc2F0aW9uIHJvdXRpbmUuIFRvXG5cdFx0XHQgKiBzZXQgYSBkZWZhdWx0IHVzZSB7QGxpbmsgRGF0YVRhYmxlLmRlZmF1bHRzfS5cblx0XHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHRcdCAqL1xuXHRcdFx0XCJzWVwiOiBudWxsXG5cdFx0fSxcblx0XG5cdFx0LyoqXG5cdFx0ICogTGFuZ3VhZ2UgaW5mb3JtYXRpb24gZm9yIHRoZSB0YWJsZS5cblx0XHQgKiAgQG5hbWVzcGFjZVxuXHRcdCAqICBAZXh0ZW5kcyBEYXRhVGFibGUuZGVmYXVsdHMub0xhbmd1YWdlXG5cdFx0ICovXG5cdFx0XCJvTGFuZ3VhZ2VcIjoge1xuXHRcdFx0LyoqXG5cdFx0XHQgKiBJbmZvcm1hdGlvbiBjYWxsYmFjayBmdW5jdGlvbi4gU2VlXG5cdFx0XHQgKiB7QGxpbmsgRGF0YVRhYmxlLmRlZmF1bHRzLmZuSW5mb0NhbGxiYWNrfVxuXHRcdFx0ICogIEB0eXBlIGZ1bmN0aW9uXG5cdFx0XHQgKiAgQGRlZmF1bHQgbnVsbFxuXHRcdFx0ICovXG5cdFx0XHRcImZuSW5mb0NhbGxiYWNrXCI6IG51bGxcblx0XHR9LFxuXHRcblx0XHQvKipcblx0XHQgKiBCcm93c2VyIHN1cHBvcnQgcGFyYW1ldGVyc1xuXHRcdCAqICBAbmFtZXNwYWNlXG5cdFx0ICovXG5cdFx0XCJvQnJvd3NlclwiOiB7XG5cdFx0XHQvKipcblx0XHRcdCAqIEluZGljYXRlIGlmIHRoZSBicm93c2VyIGluY29ycmVjdGx5IGNhbGN1bGF0ZXMgd2lkdGg6MTAwJSBpbnNpZGUgYVxuXHRcdFx0ICogc2Nyb2xsaW5nIGVsZW1lbnQgKElFNi83KVxuXHRcdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHRcdCAqICBAZGVmYXVsdCBmYWxzZVxuXHRcdFx0ICovXG5cdFx0XHRcImJTY3JvbGxPdmVyc2l6ZVwiOiBmYWxzZSxcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIERldGVybWluZSBpZiB0aGUgdmVydGljYWwgc2Nyb2xsYmFyIGlzIG9uIHRoZSByaWdodCBvciBsZWZ0IG9mIHRoZVxuXHRcdFx0ICogc2Nyb2xsaW5nIGNvbnRhaW5lciAtIG5lZWRlZCBmb3IgcnRsIGxhbmd1YWdlIGxheW91dCwgYWx0aG91Z2ggbm90XG5cdFx0XHQgKiBhbGwgYnJvd3NlcnMgbW92ZSB0aGUgc2Nyb2xsYmFyIChTYWZhcmkpLlxuXHRcdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHRcdCAqICBAZGVmYXVsdCBmYWxzZVxuXHRcdFx0ICovXG5cdFx0XHRcImJTY3JvbGxiYXJMZWZ0XCI6IGZhbHNlLFxuXHRcblx0XHRcdC8qKlxuXHRcdFx0ICogRmxhZyBmb3IgaWYgYGdldEJvdW5kaW5nQ2xpZW50UmVjdGAgaXMgZnVsbHkgc3VwcG9ydGVkIG9yIG5vdFxuXHRcdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHRcdCAqICBAZGVmYXVsdCBmYWxzZVxuXHRcdFx0ICovXG5cdFx0XHRcImJCb3VuZGluZ1wiOiBmYWxzZSxcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIEJyb3dzZXIgc2Nyb2xsYmFyIHdpZHRoXG5cdFx0XHQgKiAgQHR5cGUgaW50ZWdlclxuXHRcdFx0ICogIEBkZWZhdWx0IDBcblx0XHRcdCAqL1xuXHRcdFx0XCJiYXJXaWR0aFwiOiAwXG5cdFx0fSxcblx0XG5cdFxuXHRcdFwiYWpheFwiOiBudWxsLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogQXJyYXkgcmVmZXJlbmNpbmcgdGhlIG5vZGVzIHdoaWNoIGFyZSB1c2VkIGZvciB0aGUgZmVhdHVyZXMuIFRoZVxuXHRcdCAqIHBhcmFtZXRlcnMgb2YgdGhpcyBvYmplY3QgbWF0Y2ggd2hhdCBpcyBhbGxvd2VkIGJ5IHNEb20gLSBpLmUuXG5cdFx0ICogICA8dWw+XG5cdFx0ICogICAgIDxsaT4nbCcgLSBMZW5ndGggY2hhbmdpbmc8L2xpPlxuXHRcdCAqICAgICA8bGk+J2YnIC0gRmlsdGVyaW5nIGlucHV0PC9saT5cblx0XHQgKiAgICAgPGxpPid0JyAtIFRoZSB0YWJsZSE8L2xpPlxuXHRcdCAqICAgICA8bGk+J2knIC0gSW5mb3JtYXRpb248L2xpPlxuXHRcdCAqICAgICA8bGk+J3AnIC0gUGFnaW5hdGlvbjwvbGk+XG5cdFx0ICogICAgIDxsaT4ncicgLSBwUm9jZXNzaW5nPC9saT5cblx0XHQgKiAgIDwvdWw+XG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICogIEBkZWZhdWx0IFtdXG5cdFx0ICovXG5cdFx0XCJhYW5GZWF0dXJlc1wiOiBbXSxcblx0XG5cdFx0LyoqXG5cdFx0ICogU3RvcmUgZGF0YSBpbmZvcm1hdGlvbiAtIHNlZSB7QGxpbmsgRGF0YVRhYmxlLm1vZGVscy5vUm93fSBmb3IgZGV0YWlsZWRcblx0XHQgKiBpbmZvcm1hdGlvbi5cblx0XHQgKiAgQHR5cGUgYXJyYXlcblx0XHQgKiAgQGRlZmF1bHQgW11cblx0XHQgKi9cblx0XHRcImFvRGF0YVwiOiBbXSxcblx0XG5cdFx0LyoqXG5cdFx0ICogQXJyYXkgb2YgaW5kZXhlcyB3aGljaCBhcmUgaW4gdGhlIGN1cnJlbnQgZGlzcGxheSAoYWZ0ZXIgZmlsdGVyaW5nIGV0Yylcblx0XHQgKiAgQHR5cGUgYXJyYXlcblx0XHQgKiAgQGRlZmF1bHQgW11cblx0XHQgKi9cblx0XHRcImFpRGlzcGxheVwiOiBbXSxcblx0XG5cdFx0LyoqXG5cdFx0ICogQXJyYXkgb2YgaW5kZXhlcyBmb3IgZGlzcGxheSAtIG5vIGZpbHRlcmluZ1xuXHRcdCAqICBAdHlwZSBhcnJheVxuXHRcdCAqICBAZGVmYXVsdCBbXVxuXHRcdCAqL1xuXHRcdFwiYWlEaXNwbGF5TWFzdGVyXCI6IFtdLFxuXHRcblx0XHQvKipcblx0XHQgKiBNYXAgb2Ygcm93IGlkcyB0byBkYXRhIGluZGV4ZXNcblx0XHQgKiAgQHR5cGUgb2JqZWN0XG5cdFx0ICogIEBkZWZhdWx0IHt9XG5cdFx0ICovXG5cdFx0XCJhSWRzXCI6IHt9LFxuXHRcblx0XHQvKipcblx0XHQgKiBTdG9yZSBpbmZvcm1hdGlvbiBhYm91dCBlYWNoIGNvbHVtbiB0aGF0IGlzIGluIHVzZVxuXHRcdCAqICBAdHlwZSBhcnJheVxuXHRcdCAqICBAZGVmYXVsdCBbXVxuXHRcdCAqL1xuXHRcdFwiYW9Db2x1bW5zXCI6IFtdLFxuXHRcblx0XHQvKipcblx0XHQgKiBTdG9yZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgdGFibGUncyBoZWFkZXJcblx0XHQgKiAgQHR5cGUgYXJyYXlcblx0XHQgKiAgQGRlZmF1bHQgW11cblx0XHQgKi9cblx0XHRcImFvSGVhZGVyXCI6IFtdLFxuXHRcblx0XHQvKipcblx0XHQgKiBTdG9yZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgdGFibGUncyBmb290ZXJcblx0XHQgKiAgQHR5cGUgYXJyYXlcblx0XHQgKiAgQGRlZmF1bHQgW11cblx0XHQgKi9cblx0XHRcImFvRm9vdGVyXCI6IFtdLFxuXHRcblx0XHQvKipcblx0XHQgKiBTdG9yZSB0aGUgYXBwbGllZCBnbG9iYWwgc2VhcmNoIGluZm9ybWF0aW9uIGluIGNhc2Ugd2Ugd2FudCB0byBmb3JjZSBhXG5cdFx0ICogcmVzZWFyY2ggb3IgY29tcGFyZSB0aGUgb2xkIHNlYXJjaCB0byBhIG5ldyBvbmUuXG5cdFx0ICogTm90ZSB0aGF0IHRoaXMgcGFyYW1ldGVyIHdpbGwgYmUgc2V0IGJ5IHRoZSBpbml0aWFsaXNhdGlvbiByb3V0aW5lLiBUb1xuXHRcdCAqIHNldCBhIGRlZmF1bHQgdXNlIHtAbGluayBEYXRhVGFibGUuZGVmYXVsdHN9LlxuXHRcdCAqICBAbmFtZXNwYWNlXG5cdFx0ICogIEBleHRlbmRzIERhdGFUYWJsZS5tb2RlbHMub1NlYXJjaFxuXHRcdCAqL1xuXHRcdFwib1ByZXZpb3VzU2VhcmNoXCI6IHt9LFxuXHRcblx0XHQvKipcblx0XHQgKiBTdG9yZSB0aGUgYXBwbGllZCBzZWFyY2ggZm9yIGVhY2ggY29sdW1uIC0gc2VlXG5cdFx0ICoge0BsaW5rIERhdGFUYWJsZS5tb2RlbHMub1NlYXJjaH0gZm9yIHRoZSBmb3JtYXQgdGhhdCBpcyB1c2VkIGZvciB0aGVcblx0XHQgKiBmaWx0ZXJpbmcgaW5mb3JtYXRpb24gZm9yIGVhY2ggY29sdW1uLlxuXHRcdCAqICBAdHlwZSBhcnJheVxuXHRcdCAqICBAZGVmYXVsdCBbXVxuXHRcdCAqL1xuXHRcdFwiYW9QcmVTZWFyY2hDb2xzXCI6IFtdLFxuXHRcblx0XHQvKipcblx0XHQgKiBTb3J0aW5nIHRoYXQgaXMgYXBwbGllZCB0byB0aGUgdGFibGUuIE5vdGUgdGhhdCB0aGUgaW5uZXIgYXJyYXlzIGFyZVxuXHRcdCAqIHVzZWQgaW4gdGhlIGZvbGxvd2luZyBtYW5uZXI6XG5cdFx0ICogPHVsPlxuXHRcdCAqICAgPGxpPkluZGV4IDAgLSBjb2x1bW4gbnVtYmVyPC9saT5cblx0XHQgKiAgIDxsaT5JbmRleCAxIC0gY3VycmVudCBzb3J0aW5nIGRpcmVjdGlvbjwvbGk+XG5cdFx0ICogPC91bD5cblx0XHQgKiBOb3RlIHRoYXQgdGhpcyBwYXJhbWV0ZXIgd2lsbCBiZSBzZXQgYnkgdGhlIGluaXRpYWxpc2F0aW9uIHJvdXRpbmUuIFRvXG5cdFx0ICogc2V0IGEgZGVmYXVsdCB1c2Uge0BsaW5rIERhdGFUYWJsZS5kZWZhdWx0c30uXG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICogIEB0b2RvIFRoZXNlIGlubmVyIGFycmF5cyBzaG91bGQgcmVhbGx5IGJlIG9iamVjdHNcblx0XHQgKi9cblx0XHRcImFhU29ydGluZ1wiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBTb3J0aW5nIHRoYXQgaXMgYWx3YXlzIGFwcGxpZWQgdG8gdGhlIHRhYmxlIChpLmUuIHByZWZpeGVkIGluIGZyb250IG9mXG5cdFx0ICogYWFTb3J0aW5nKS5cblx0XHQgKiBOb3RlIHRoYXQgdGhpcyBwYXJhbWV0ZXIgd2lsbCBiZSBzZXQgYnkgdGhlIGluaXRpYWxpc2F0aW9uIHJvdXRpbmUuIFRvXG5cdFx0ICogc2V0IGEgZGVmYXVsdCB1c2Uge0BsaW5rIERhdGFUYWJsZS5kZWZhdWx0c30uXG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICogIEBkZWZhdWx0IFtdXG5cdFx0ICovXG5cdFx0XCJhYVNvcnRpbmdGaXhlZFwiOiBbXSxcblx0XG5cdFx0LyoqXG5cdFx0ICogQ2xhc3NlcyB0byB1c2UgZm9yIHRoZSBzdHJpcGluZyBvZiBhIHRhYmxlLlxuXHRcdCAqIE5vdGUgdGhhdCB0aGlzIHBhcmFtZXRlciB3aWxsIGJlIHNldCBieSB0aGUgaW5pdGlhbGlzYXRpb24gcm91dGluZS4gVG9cblx0XHQgKiBzZXQgYSBkZWZhdWx0IHVzZSB7QGxpbmsgRGF0YVRhYmxlLmRlZmF1bHRzfS5cblx0XHQgKiAgQHR5cGUgYXJyYXlcblx0XHQgKiAgQGRlZmF1bHQgW11cblx0XHQgKi9cblx0XHRcImFzU3RyaXBlQ2xhc3Nlc1wiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBJZiByZXN0b3JpbmcgYSB0YWJsZSAtIHdlIHNob3VsZCByZXN0b3JlIGl0cyBzdHJpcGluZyBjbGFzc2VzIGFzIHdlbGxcblx0XHQgKiAgQHR5cGUgYXJyYXlcblx0XHQgKiAgQGRlZmF1bHQgW11cblx0XHQgKi9cblx0XHRcImFzRGVzdHJveVN0cmlwZXNcIjogW10sXG5cdFxuXHRcdC8qKlxuXHRcdCAqIElmIHJlc3RvcmluZyBhIHRhYmxlIC0gd2Ugc2hvdWxkIHJlc3RvcmUgaXRzIHdpZHRoXG5cdFx0ICogIEB0eXBlIGludFxuXHRcdCAqICBAZGVmYXVsdCAwXG5cdFx0ICovXG5cdFx0XCJzRGVzdHJveVdpZHRoXCI6IDAsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIENhbGxiYWNrIGZ1bmN0aW9ucyBhcnJheSBmb3IgZXZlcnkgdGltZSBhIHJvdyBpcyBpbnNlcnRlZCAoaS5lLiBvbiBhIGRyYXcpLlxuXHRcdCAqICBAdHlwZSBhcnJheVxuXHRcdCAqICBAZGVmYXVsdCBbXVxuXHRcdCAqL1xuXHRcdFwiYW9Sb3dDYWxsYmFja1wiOiBbXSxcblx0XG5cdFx0LyoqXG5cdFx0ICogQ2FsbGJhY2sgZnVuY3Rpb25zIGZvciB0aGUgaGVhZGVyIG9uIGVhY2ggZHJhdy5cblx0XHQgKiAgQHR5cGUgYXJyYXlcblx0XHQgKiAgQGRlZmF1bHQgW11cblx0XHQgKi9cblx0XHRcImFvSGVhZGVyQ2FsbGJhY2tcIjogW10sXG5cdFxuXHRcdC8qKlxuXHRcdCAqIENhbGxiYWNrIGZ1bmN0aW9uIGZvciB0aGUgZm9vdGVyIG9uIGVhY2ggZHJhdy5cblx0XHQgKiAgQHR5cGUgYXJyYXlcblx0XHQgKiAgQGRlZmF1bHQgW11cblx0XHQgKi9cblx0XHRcImFvRm9vdGVyQ2FsbGJhY2tcIjogW10sXG5cdFxuXHRcdC8qKlxuXHRcdCAqIEFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9ucyBmb3IgZHJhdyBjYWxsYmFjayBmdW5jdGlvbnNcblx0XHQgKiAgQHR5cGUgYXJyYXlcblx0XHQgKiAgQGRlZmF1bHQgW11cblx0XHQgKi9cblx0XHRcImFvRHJhd0NhbGxiYWNrXCI6IFtdLFxuXHRcblx0XHQvKipcblx0XHQgKiBBcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnMgZm9yIHJvdyBjcmVhdGVkIGZ1bmN0aW9uXG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICogIEBkZWZhdWx0IFtdXG5cdFx0ICovXG5cdFx0XCJhb1Jvd0NyZWF0ZWRDYWxsYmFja1wiOiBbXSxcblx0XG5cdFx0LyoqXG5cdFx0ICogQ2FsbGJhY2sgZnVuY3Rpb25zIGZvciBqdXN0IGJlZm9yZSB0aGUgdGFibGUgaXMgcmVkcmF3bi4gQSByZXR1cm4gb2Zcblx0XHQgKiBmYWxzZSB3aWxsIGJlIHVzZWQgdG8gY2FuY2VsIHRoZSBkcmF3LlxuXHRcdCAqICBAdHlwZSBhcnJheVxuXHRcdCAqICBAZGVmYXVsdCBbXVxuXHRcdCAqL1xuXHRcdFwiYW9QcmVEcmF3Q2FsbGJhY2tcIjogW10sXG5cdFxuXHRcdC8qKlxuXHRcdCAqIENhbGxiYWNrIGZ1bmN0aW9ucyBmb3Igd2hlbiB0aGUgdGFibGUgaGFzIGJlZW4gaW5pdGlhbGlzZWQuXG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICogIEBkZWZhdWx0IFtdXG5cdFx0ICovXG5cdFx0XCJhb0luaXRDb21wbGV0ZVwiOiBbXSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIENhbGxiYWNrcyBmb3IgbW9kaWZ5aW5nIHRoZSBzZXR0aW5ncyB0byBiZSBzdG9yZWQgZm9yIHN0YXRlIHNhdmluZywgcHJpb3IgdG9cblx0XHQgKiBzYXZpbmcgc3RhdGUuXG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICogIEBkZWZhdWx0IFtdXG5cdFx0ICovXG5cdFx0XCJhb1N0YXRlU2F2ZVBhcmFtc1wiOiBbXSxcblx0XG5cdFx0LyoqXG5cdFx0ICogQ2FsbGJhY2tzIGZvciBtb2RpZnlpbmcgdGhlIHNldHRpbmdzIHRoYXQgaGF2ZSBiZWVuIHN0b3JlZCBmb3Igc3RhdGUgc2F2aW5nXG5cdFx0ICogcHJpb3IgdG8gdXNpbmcgdGhlIHN0b3JlZCB2YWx1ZXMgdG8gcmVzdG9yZSB0aGUgc3RhdGUuXG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICogIEBkZWZhdWx0IFtdXG5cdFx0ICovXG5cdFx0XCJhb1N0YXRlTG9hZFBhcmFtc1wiOiBbXSxcblx0XG5cdFx0LyoqXG5cdFx0ICogQ2FsbGJhY2tzIGZvciBvcGVyYXRpbmcgb24gdGhlIHNldHRpbmdzIG9iamVjdCBvbmNlIHRoZSBzYXZlZCBzdGF0ZSBoYXMgYmVlblxuXHRcdCAqIGxvYWRlZFxuXHRcdCAqICBAdHlwZSBhcnJheVxuXHRcdCAqICBAZGVmYXVsdCBbXVxuXHRcdCAqL1xuXHRcdFwiYW9TdGF0ZUxvYWRlZFwiOiBbXSxcblx0XG5cdFx0LyoqXG5cdFx0ICogQ2FjaGUgdGhlIHRhYmxlIElEIGZvciBxdWljayBhY2Nlc3Ncblx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0ICogIEBkZWZhdWx0IDxpPkVtcHR5IHN0cmluZzwvaT5cblx0XHQgKi9cblx0XHRcInNUYWJsZUlkXCI6IFwiXCIsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIFRoZSBUQUJMRSBub2RlIGZvciB0aGUgbWFpbiB0YWJsZVxuXHRcdCAqICBAdHlwZSBub2RlXG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKi9cblx0XHRcIm5UYWJsZVwiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBQZXJtYW5lbnQgcmVmIHRvIHRoZSB0aGVhZCBlbGVtZW50XG5cdFx0ICogIEB0eXBlIG5vZGVcblx0XHQgKiAgQGRlZmF1bHQgbnVsbFxuXHRcdCAqL1xuXHRcdFwiblRIZWFkXCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIFBlcm1hbmVudCByZWYgdG8gdGhlIHRmb290IGVsZW1lbnQgLSBpZiBpdCBleGlzdHNcblx0XHQgKiAgQHR5cGUgbm9kZVxuXHRcdCAqICBAZGVmYXVsdCBudWxsXG5cdFx0ICovXG5cdFx0XCJuVEZvb3RcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogUGVybWFuZW50IHJlZiB0byB0aGUgdGJvZHkgZWxlbWVudFxuXHRcdCAqICBAdHlwZSBub2RlXG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKi9cblx0XHRcIm5UQm9keVwiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBDYWNoZSB0aGUgd3JhcHBlciBub2RlIChjb250YWlucyBhbGwgRGF0YVRhYmxlcyBjb250cm9sbGVkIGVsZW1lbnRzKVxuXHRcdCAqICBAdHlwZSBub2RlXG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKi9cblx0XHRcIm5UYWJsZVdyYXBwZXJcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogSW5kaWNhdGUgaWYgd2hlbiB1c2luZyBzZXJ2ZXItc2lkZSBwcm9jZXNzaW5nIHRoZSBsb2FkaW5nIG9mIGRhdGFcblx0XHQgKiBzaG91bGQgYmUgZGVmZXJyZWQgdW50aWwgdGhlIHNlY29uZCBkcmF3LlxuXHRcdCAqIE5vdGUgdGhhdCB0aGlzIHBhcmFtZXRlciB3aWxsIGJlIHNldCBieSB0aGUgaW5pdGlhbGlzYXRpb24gcm91dGluZS4gVG9cblx0XHQgKiBzZXQgYSBkZWZhdWx0IHVzZSB7QGxpbmsgRGF0YVRhYmxlLmRlZmF1bHRzfS5cblx0XHQgKiAgQHR5cGUgYm9vbGVhblxuXHRcdCAqICBAZGVmYXVsdCBmYWxzZVxuXHRcdCAqL1xuXHRcdFwiYkRlZmVyTG9hZGluZ1wiOiBmYWxzZSxcblx0XG5cdFx0LyoqXG5cdFx0ICogSW5kaWNhdGUgaWYgYWxsIHJlcXVpcmVkIGluZm9ybWF0aW9uIGhhcyBiZWVuIHJlYWQgaW5cblx0XHQgKiAgQHR5cGUgYm9vbGVhblxuXHRcdCAqICBAZGVmYXVsdCBmYWxzZVxuXHRcdCAqL1xuXHRcdFwiYkluaXRpYWxpc2VkXCI6IGZhbHNlLFxuXHRcblx0XHQvKipcblx0XHQgKiBJbmZvcm1hdGlvbiBhYm91dCBvcGVuIHJvd3MuIEVhY2ggb2JqZWN0IGluIHRoZSBhcnJheSBoYXMgdGhlIHBhcmFtZXRlcnNcblx0XHQgKiAnblRyJyBhbmQgJ25QYXJlbnQnXG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICogIEBkZWZhdWx0IFtdXG5cdFx0ICovXG5cdFx0XCJhb09wZW5Sb3dzXCI6IFtdLFxuXHRcblx0XHQvKipcblx0XHQgKiBEaWN0YXRlIHRoZSBwb3NpdGlvbmluZyBvZiBEYXRhVGFibGVzJyBjb250cm9sIGVsZW1lbnRzIC0gc2VlXG5cdFx0ICoge0BsaW5rIERhdGFUYWJsZS5tb2RlbC5vSW5pdC5zRG9tfS5cblx0XHQgKiBOb3RlIHRoYXQgdGhpcyBwYXJhbWV0ZXIgd2lsbCBiZSBzZXQgYnkgdGhlIGluaXRpYWxpc2F0aW9uIHJvdXRpbmUuIFRvXG5cdFx0ICogc2V0IGEgZGVmYXVsdCB1c2Uge0BsaW5rIERhdGFUYWJsZS5kZWZhdWx0c30uXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqICBAZGVmYXVsdCBudWxsXG5cdFx0ICovXG5cdFx0XCJzRG9tXCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIFNlYXJjaCBkZWxheSAoaW4gbVMpXG5cdFx0ICogIEB0eXBlIGludGVnZXJcblx0XHQgKiAgQGRlZmF1bHQgbnVsbFxuXHRcdCAqL1xuXHRcdFwic2VhcmNoRGVsYXlcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogV2hpY2ggdHlwZSBvZiBwYWdpbmF0aW9uIHNob3VsZCBiZSB1c2VkLlxuXHRcdCAqIE5vdGUgdGhhdCB0aGlzIHBhcmFtZXRlciB3aWxsIGJlIHNldCBieSB0aGUgaW5pdGlhbGlzYXRpb24gcm91dGluZS4gVG9cblx0XHQgKiBzZXQgYSBkZWZhdWx0IHVzZSB7QGxpbmsgRGF0YVRhYmxlLmRlZmF1bHRzfS5cblx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0ICogIEBkZWZhdWx0IHR3b19idXR0b25cblx0XHQgKi9cblx0XHRcInNQYWdpbmF0aW9uVHlwZVwiOiBcInR3b19idXR0b25cIixcblx0XG5cdFx0LyoqXG5cdFx0ICogVGhlIHN0YXRlIGR1cmF0aW9uIChmb3IgYHN0YXRlU2F2ZWApIGluIHNlY29uZHMuXG5cdFx0ICogTm90ZSB0aGF0IHRoaXMgcGFyYW1ldGVyIHdpbGwgYmUgc2V0IGJ5IHRoZSBpbml0aWFsaXNhdGlvbiByb3V0aW5lLiBUb1xuXHRcdCAqIHNldCBhIGRlZmF1bHQgdXNlIHtAbGluayBEYXRhVGFibGUuZGVmYXVsdHN9LlxuXHRcdCAqICBAdHlwZSBpbnRcblx0XHQgKiAgQGRlZmF1bHQgMFxuXHRcdCAqL1xuXHRcdFwiaVN0YXRlRHVyYXRpb25cIjogMCxcblx0XG5cdFx0LyoqXG5cdFx0ICogQXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zIGZvciBzdGF0ZSBzYXZpbmcuIEVhY2ggYXJyYXkgZWxlbWVudCBpcyBhblxuXHRcdCAqIG9iamVjdCB3aXRoIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVyczpcblx0XHQgKiAgIDx1bD5cblx0XHQgKiAgICAgPGxpPmZ1bmN0aW9uOmZuIC0gZnVuY3Rpb24gdG8gY2FsbC4gVGFrZXMgdHdvIHBhcmFtZXRlcnMsIG9TZXR0aW5nc1xuXHRcdCAqICAgICAgIGFuZCB0aGUgSlNPTiBzdHJpbmcgdG8gc2F2ZSB0aGF0IGhhcyBiZWVuIHRodXMgZmFyIGNyZWF0ZWQuIFJldHVybnNcblx0XHQgKiAgICAgICBhIEpTT04gc3RyaW5nIHRvIGJlIGluc2VydGVkIGludG8gYSBqc29uIG9iamVjdFxuXHRcdCAqICAgICAgIChpLmUuICdcInBhcmFtXCI6IFsgMCwgMSwgMl0nKTwvbGk+XG5cdFx0ICogICAgIDxsaT5zdHJpbmc6c05hbWUgLSBuYW1lIG9mIGNhbGxiYWNrPC9saT5cblx0XHQgKiAgIDwvdWw+XG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICogIEBkZWZhdWx0IFtdXG5cdFx0ICovXG5cdFx0XCJhb1N0YXRlU2F2ZVwiOiBbXSxcblx0XG5cdFx0LyoqXG5cdFx0ICogQXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zIGZvciBzdGF0ZSBsb2FkaW5nLiBFYWNoIGFycmF5IGVsZW1lbnQgaXMgYW5cblx0XHQgKiBvYmplY3Qgd2l0aCB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnM6XG5cdFx0ICogICA8dWw+XG5cdFx0ICogICAgIDxsaT5mdW5jdGlvbjpmbiAtIGZ1bmN0aW9uIHRvIGNhbGwuIFRha2VzIHR3byBwYXJhbWV0ZXJzLCBvU2V0dGluZ3Ncblx0XHQgKiAgICAgICBhbmQgdGhlIG9iamVjdCBzdG9yZWQuIE1heSByZXR1cm4gZmFsc2UgdG8gY2FuY2VsIHN0YXRlIGxvYWRpbmc8L2xpPlxuXHRcdCAqICAgICA8bGk+c3RyaW5nOnNOYW1lIC0gbmFtZSBvZiBjYWxsYmFjazwvbGk+XG5cdFx0ICogICA8L3VsPlxuXHRcdCAqICBAdHlwZSBhcnJheVxuXHRcdCAqICBAZGVmYXVsdCBbXVxuXHRcdCAqL1xuXHRcdFwiYW9TdGF0ZUxvYWRcIjogW10sXG5cdFxuXHRcdC8qKlxuXHRcdCAqIFN0YXRlIHRoYXQgd2FzIHNhdmVkLiBVc2VmdWwgZm9yIGJhY2sgcmVmZXJlbmNlXG5cdFx0ICogIEB0eXBlIG9iamVjdFxuXHRcdCAqICBAZGVmYXVsdCBudWxsXG5cdFx0ICovXG5cdFx0XCJvU2F2ZWRTdGF0ZVwiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBTdGF0ZSB0aGF0IHdhcyBsb2FkZWQuIFVzZWZ1bCBmb3IgYmFjayByZWZlcmVuY2Vcblx0XHQgKiAgQHR5cGUgb2JqZWN0XG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKi9cblx0XHRcIm9Mb2FkZWRTdGF0ZVwiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBTb3VyY2UgdXJsIGZvciBBSkFYIGRhdGEgZm9yIHRoZSB0YWJsZS5cblx0XHQgKiBOb3RlIHRoYXQgdGhpcyBwYXJhbWV0ZXIgd2lsbCBiZSBzZXQgYnkgdGhlIGluaXRpYWxpc2F0aW9uIHJvdXRpbmUuIFRvXG5cdFx0ICogc2V0IGEgZGVmYXVsdCB1c2Uge0BsaW5rIERhdGFUYWJsZS5kZWZhdWx0c30uXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqICBAZGVmYXVsdCBudWxsXG5cdFx0ICovXG5cdFx0XCJzQWpheFNvdXJjZVwiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBQcm9wZXJ0eSBmcm9tIGEgZ2l2ZW4gb2JqZWN0IGZyb20gd2hpY2ggdG8gcmVhZCB0aGUgdGFibGUgZGF0YSBmcm9tLiBUaGlzXG5cdFx0ICogY2FuIGJlIGFuIGVtcHR5IHN0cmluZyAod2hlbiBub3Qgc2VydmVyLXNpZGUgcHJvY2Vzc2luZyksIGluIHdoaWNoIGNhc2Vcblx0XHQgKiBpdCBpcyAgYXNzdW1lZCBhbiBhbiBhcnJheSBpcyBnaXZlbiBkaXJlY3RseS5cblx0XHQgKiBOb3RlIHRoYXQgdGhpcyBwYXJhbWV0ZXIgd2lsbCBiZSBzZXQgYnkgdGhlIGluaXRpYWxpc2F0aW9uIHJvdXRpbmUuIFRvXG5cdFx0ICogc2V0IGEgZGVmYXVsdCB1c2Uge0BsaW5rIERhdGFUYWJsZS5kZWZhdWx0c30uXG5cdFx0ICogIEB0eXBlIHN0cmluZ1xuXHRcdCAqL1xuXHRcdFwic0FqYXhEYXRhUHJvcFwiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBUaGUgbGFzdCBqUXVlcnkgWEhSIG9iamVjdCB0aGF0IHdhcyB1c2VkIGZvciBzZXJ2ZXItc2lkZSBkYXRhIGdhdGhlcmluZy5cblx0XHQgKiBUaGlzIGNhbiBiZSB1c2VkIGZvciB3b3JraW5nIHdpdGggdGhlIFhIUiBpbmZvcm1hdGlvbiBpbiBvbmUgb2YgdGhlXG5cdFx0ICogY2FsbGJhY2tzXG5cdFx0ICogIEB0eXBlIG9iamVjdFxuXHRcdCAqICBAZGVmYXVsdCBudWxsXG5cdFx0ICovXG5cdFx0XCJqcVhIUlwiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBKU09OIHJldHVybmVkIGZyb20gdGhlIHNlcnZlciBpbiB0aGUgbGFzdCBBamF4IHJlcXVlc3Rcblx0XHQgKiAgQHR5cGUgb2JqZWN0XG5cdFx0ICogIEBkZWZhdWx0IHVuZGVmaW5lZFxuXHRcdCAqL1xuXHRcdFwianNvblwiOiB1bmRlZmluZWQsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIERhdGEgc3VibWl0dGVkIGFzIHBhcnQgb2YgdGhlIGxhc3QgQWpheCByZXF1ZXN0XG5cdFx0ICogIEB0eXBlIG9iamVjdFxuXHRcdCAqICBAZGVmYXVsdCB1bmRlZmluZWRcblx0XHQgKi9cblx0XHRcIm9BamF4RGF0YVwiOiB1bmRlZmluZWQsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIEZ1bmN0aW9uIHRvIGdldCB0aGUgc2VydmVyLXNpZGUgZGF0YS5cblx0XHQgKiBOb3RlIHRoYXQgdGhpcyBwYXJhbWV0ZXIgd2lsbCBiZSBzZXQgYnkgdGhlIGluaXRpYWxpc2F0aW9uIHJvdXRpbmUuIFRvXG5cdFx0ICogc2V0IGEgZGVmYXVsdCB1c2Uge0BsaW5rIERhdGFUYWJsZS5kZWZhdWx0c30uXG5cdFx0ICogIEB0eXBlIGZ1bmN0aW9uXG5cdFx0ICovXG5cdFx0XCJmblNlcnZlckRhdGFcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogRnVuY3Rpb25zIHdoaWNoIGFyZSBjYWxsZWQgcHJpb3IgdG8gc2VuZGluZyBhbiBBamF4IHJlcXVlc3Qgc28gZXh0cmFcblx0XHQgKiBwYXJhbWV0ZXJzIGNhbiBlYXNpbHkgYmUgc2VudCB0byB0aGUgc2VydmVyXG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICogIEBkZWZhdWx0IFtdXG5cdFx0ICovXG5cdFx0XCJhb1NlcnZlclBhcmFtc1wiOiBbXSxcblx0XG5cdFx0LyoqXG5cdFx0ICogU2VuZCB0aGUgWEhSIEhUVFAgbWV0aG9kIC0gR0VUIG9yIFBPU1QgKGNvdWxkIGJlIFBVVCBvciBERUxFVEUgaWZcblx0XHQgKiByZXF1aXJlZCkuXG5cdFx0ICogTm90ZSB0aGF0IHRoaXMgcGFyYW1ldGVyIHdpbGwgYmUgc2V0IGJ5IHRoZSBpbml0aWFsaXNhdGlvbiByb3V0aW5lLiBUb1xuXHRcdCAqIHNldCBhIGRlZmF1bHQgdXNlIHtAbGluayBEYXRhVGFibGUuZGVmYXVsdHN9LlxuXHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHQgKi9cblx0XHRcInNTZXJ2ZXJNZXRob2RcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogRm9ybWF0IG51bWJlcnMgZm9yIGRpc3BsYXkuXG5cdFx0ICogTm90ZSB0aGF0IHRoaXMgcGFyYW1ldGVyIHdpbGwgYmUgc2V0IGJ5IHRoZSBpbml0aWFsaXNhdGlvbiByb3V0aW5lLiBUb1xuXHRcdCAqIHNldCBhIGRlZmF1bHQgdXNlIHtAbGluayBEYXRhVGFibGUuZGVmYXVsdHN9LlxuXHRcdCAqICBAdHlwZSBmdW5jdGlvblxuXHRcdCAqL1xuXHRcdFwiZm5Gb3JtYXROdW1iZXJcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogTGlzdCBvZiBvcHRpb25zIHRoYXQgY2FuIGJlIHVzZWQgZm9yIHRoZSB1c2VyIHNlbGVjdGFibGUgbGVuZ3RoIG1lbnUuXG5cdFx0ICogTm90ZSB0aGF0IHRoaXMgcGFyYW1ldGVyIHdpbGwgYmUgc2V0IGJ5IHRoZSBpbml0aWFsaXNhdGlvbiByb3V0aW5lLiBUb1xuXHRcdCAqIHNldCBhIGRlZmF1bHQgdXNlIHtAbGluayBEYXRhVGFibGUuZGVmYXVsdHN9LlxuXHRcdCAqICBAdHlwZSBhcnJheVxuXHRcdCAqICBAZGVmYXVsdCBbXVxuXHRcdCAqL1xuXHRcdFwiYUxlbmd0aE1lbnVcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogQ291bnRlciBmb3IgdGhlIGRyYXdzIHRoYXQgdGhlIHRhYmxlIGRvZXMuIEFsc28gdXNlZCBhcyBhIHRyYWNrZXIgZm9yXG5cdFx0ICogc2VydmVyLXNpZGUgcHJvY2Vzc2luZ1xuXHRcdCAqICBAdHlwZSBpbnRcblx0XHQgKiAgQGRlZmF1bHQgMFxuXHRcdCAqL1xuXHRcdFwiaURyYXdcIjogMCxcblx0XG5cdFx0LyoqXG5cdFx0ICogSW5kaWNhdGUgaWYgYSByZWRyYXcgaXMgYmVpbmcgZG9uZSAtIHVzZWZ1bCBmb3IgQWpheFxuXHRcdCAqICBAdHlwZSBib29sZWFuXG5cdFx0ICogIEBkZWZhdWx0IGZhbHNlXG5cdFx0ICovXG5cdFx0XCJiRHJhd2luZ1wiOiBmYWxzZSxcblx0XG5cdFx0LyoqXG5cdFx0ICogRHJhdyBpbmRleCAoaURyYXcpIG9mIHRoZSBsYXN0IGVycm9yIHdoZW4gcGFyc2luZyB0aGUgcmV0dXJuZWQgZGF0YVxuXHRcdCAqICBAdHlwZSBpbnRcblx0XHQgKiAgQGRlZmF1bHQgLTFcblx0XHQgKi9cblx0XHRcImlEcmF3RXJyb3JcIjogLTEsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIFBhZ2luZyBkaXNwbGF5IGxlbmd0aFxuXHRcdCAqICBAdHlwZSBpbnRcblx0XHQgKiAgQGRlZmF1bHQgMTBcblx0XHQgKi9cblx0XHRcIl9pRGlzcGxheUxlbmd0aFwiOiAxMCxcblx0XG5cdFx0LyoqXG5cdFx0ICogUGFnaW5nIHN0YXJ0IHBvaW50IC0gYWlEaXNwbGF5IGluZGV4XG5cdFx0ICogIEB0eXBlIGludFxuXHRcdCAqICBAZGVmYXVsdCAwXG5cdFx0ICovXG5cdFx0XCJfaURpc3BsYXlTdGFydFwiOiAwLFxuXHRcblx0XHQvKipcblx0XHQgKiBTZXJ2ZXItc2lkZSBwcm9jZXNzaW5nIC0gbnVtYmVyIG9mIHJlY29yZHMgaW4gdGhlIHJlc3VsdCBzZXRcblx0XHQgKiAoaS5lLiBiZWZvcmUgZmlsdGVyaW5nKSwgVXNlIGZuUmVjb3Jkc1RvdGFsIHJhdGhlciB0aGFuXG5cdFx0ICogdGhpcyBwcm9wZXJ0eSB0byBnZXQgdGhlIHZhbHVlIG9mIHRoZSBudW1iZXIgb2YgcmVjb3JkcywgcmVnYXJkbGVzcyBvZlxuXHRcdCAqIHRoZSBzZXJ2ZXItc2lkZSBwcm9jZXNzaW5nIHNldHRpbmcuXG5cdFx0ICogIEB0eXBlIGludFxuXHRcdCAqICBAZGVmYXVsdCAwXG5cdFx0ICogIEBwcml2YXRlXG5cdFx0ICovXG5cdFx0XCJfaVJlY29yZHNUb3RhbFwiOiAwLFxuXHRcblx0XHQvKipcblx0XHQgKiBTZXJ2ZXItc2lkZSBwcm9jZXNzaW5nIC0gbnVtYmVyIG9mIHJlY29yZHMgaW4gdGhlIGN1cnJlbnQgZGlzcGxheSBzZXRcblx0XHQgKiAoaS5lLiBhZnRlciBmaWx0ZXJpbmcpLiBVc2UgZm5SZWNvcmRzRGlzcGxheSByYXRoZXIgdGhhblxuXHRcdCAqIHRoaXMgcHJvcGVydHkgdG8gZ2V0IHRoZSB2YWx1ZSBvZiB0aGUgbnVtYmVyIG9mIHJlY29yZHMsIHJlZ2FyZGxlc3Mgb2Zcblx0XHQgKiB0aGUgc2VydmVyLXNpZGUgcHJvY2Vzc2luZyBzZXR0aW5nLlxuXHRcdCAqICBAdHlwZSBib29sZWFuXG5cdFx0ICogIEBkZWZhdWx0IDBcblx0XHQgKiAgQHByaXZhdGVcblx0XHQgKi9cblx0XHRcIl9pUmVjb3Jkc0Rpc3BsYXlcIjogMCxcblx0XG5cdFx0LyoqXG5cdFx0ICogVGhlIGNsYXNzZXMgdG8gdXNlIGZvciB0aGUgdGFibGVcblx0XHQgKiAgQHR5cGUgb2JqZWN0XG5cdFx0ICogIEBkZWZhdWx0IHt9XG5cdFx0ICovXG5cdFx0XCJvQ2xhc3Nlc1wiOiB7fSxcblx0XG5cdFx0LyoqXG5cdFx0ICogRmxhZyBhdHRhY2hlZCB0byB0aGUgc2V0dGluZ3Mgb2JqZWN0IHNvIHlvdSBjYW4gY2hlY2sgaW4gdGhlIGRyYXdcblx0XHQgKiBjYWxsYmFjayBpZiBmaWx0ZXJpbmcgaGFzIGJlZW4gZG9uZSBpbiB0aGUgZHJhdy4gRGVwcmVjYXRlZCBpbiBmYXZvdXIgb2Zcblx0XHQgKiBldmVudHMuXG5cdFx0ICogIEB0eXBlIGJvb2xlYW5cblx0XHQgKiAgQGRlZmF1bHQgZmFsc2Vcblx0XHQgKiAgQGRlcHJlY2F0ZWRcblx0XHQgKi9cblx0XHRcImJGaWx0ZXJlZFwiOiBmYWxzZSxcblx0XG5cdFx0LyoqXG5cdFx0ICogRmxhZyBhdHRhY2hlZCB0byB0aGUgc2V0dGluZ3Mgb2JqZWN0IHNvIHlvdSBjYW4gY2hlY2sgaW4gdGhlIGRyYXdcblx0XHQgKiBjYWxsYmFjayBpZiBzb3J0aW5nIGhhcyBiZWVuIGRvbmUgaW4gdGhlIGRyYXcuIERlcHJlY2F0ZWQgaW4gZmF2b3VyIG9mXG5cdFx0ICogZXZlbnRzLlxuXHRcdCAqICBAdHlwZSBib29sZWFuXG5cdFx0ICogIEBkZWZhdWx0IGZhbHNlXG5cdFx0ICogIEBkZXByZWNhdGVkXG5cdFx0ICovXG5cdFx0XCJiU29ydGVkXCI6IGZhbHNlLFxuXHRcblx0XHQvKipcblx0XHQgKiBJbmRpY2F0ZSB0aGF0IGlmIG11bHRpcGxlIHJvd3MgYXJlIGluIHRoZSBoZWFkZXIgYW5kIHRoZXJlIGlzIG1vcmUgdGhhblxuXHRcdCAqIG9uZSB1bmlxdWUgY2VsbCBwZXIgY29sdW1uLCBpZiB0aGUgdG9wIG9uZSAodHJ1ZSkgb3IgYm90dG9tIG9uZSAoZmFsc2UpXG5cdFx0ICogc2hvdWxkIGJlIHVzZWQgZm9yIHNvcnRpbmcgLyB0aXRsZSBieSBEYXRhVGFibGVzLlxuXHRcdCAqIE5vdGUgdGhhdCB0aGlzIHBhcmFtZXRlciB3aWxsIGJlIHNldCBieSB0aGUgaW5pdGlhbGlzYXRpb24gcm91dGluZS4gVG9cblx0XHQgKiBzZXQgYSBkZWZhdWx0IHVzZSB7QGxpbmsgRGF0YVRhYmxlLmRlZmF1bHRzfS5cblx0XHQgKiAgQHR5cGUgYm9vbGVhblxuXHRcdCAqL1xuXHRcdFwiYlNvcnRDZWxsc1RvcFwiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBJbml0aWFsaXNhdGlvbiBvYmplY3QgdGhhdCBpcyB1c2VkIGZvciB0aGUgdGFibGVcblx0XHQgKiAgQHR5cGUgb2JqZWN0XG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKi9cblx0XHRcIm9Jbml0XCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIERlc3Ryb3kgY2FsbGJhY2sgZnVuY3Rpb25zIC0gZm9yIHBsdWctaW5zIHRvIGF0dGFjaCB0aGVtc2VsdmVzIHRvIHRoZVxuXHRcdCAqIGRlc3Ryb3kgc28gdGhleSBjYW4gY2xlYW4gdXAgbWFya3VwIGFuZCBldmVudHMuXG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICogIEBkZWZhdWx0IFtdXG5cdFx0ICovXG5cdFx0XCJhb0Rlc3Ryb3lDYWxsYmFja1wiOiBbXSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIEdldCB0aGUgbnVtYmVyIG9mIHJlY29yZHMgaW4gdGhlIGN1cnJlbnQgcmVjb3JkIHNldCwgYmVmb3JlIGZpbHRlcmluZ1xuXHRcdCAqICBAdHlwZSBmdW5jdGlvblxuXHRcdCAqL1xuXHRcdFwiZm5SZWNvcmRzVG90YWxcIjogZnVuY3Rpb24gKClcblx0XHR7XG5cdFx0XHRyZXR1cm4gX2ZuRGF0YVNvdXJjZSggdGhpcyApID09ICdzc3AnID9cblx0XHRcdFx0dGhpcy5faVJlY29yZHNUb3RhbCAqIDEgOlxuXHRcdFx0XHR0aGlzLmFpRGlzcGxheU1hc3Rlci5sZW5ndGg7XG5cdFx0fSxcblx0XG5cdFx0LyoqXG5cdFx0ICogR2V0IHRoZSBudW1iZXIgb2YgcmVjb3JkcyBpbiB0aGUgY3VycmVudCByZWNvcmQgc2V0LCBhZnRlciBmaWx0ZXJpbmdcblx0XHQgKiAgQHR5cGUgZnVuY3Rpb25cblx0XHQgKi9cblx0XHRcImZuUmVjb3Jkc0Rpc3BsYXlcIjogZnVuY3Rpb24gKClcblx0XHR7XG5cdFx0XHRyZXR1cm4gX2ZuRGF0YVNvdXJjZSggdGhpcyApID09ICdzc3AnID9cblx0XHRcdFx0dGhpcy5faVJlY29yZHNEaXNwbGF5ICogMSA6XG5cdFx0XHRcdHRoaXMuYWlEaXNwbGF5Lmxlbmd0aDtcblx0XHR9LFxuXHRcblx0XHQvKipcblx0XHQgKiBHZXQgdGhlIGRpc3BsYXkgZW5kIHBvaW50IC0gYWlEaXNwbGF5IGluZGV4XG5cdFx0ICogIEB0eXBlIGZ1bmN0aW9uXG5cdFx0ICovXG5cdFx0XCJmbkRpc3BsYXlFbmRcIjogZnVuY3Rpb24gKClcblx0XHR7XG5cdFx0XHR2YXJcblx0XHRcdFx0bGVuICAgICAgPSB0aGlzLl9pRGlzcGxheUxlbmd0aCxcblx0XHRcdFx0c3RhcnQgICAgPSB0aGlzLl9pRGlzcGxheVN0YXJ0LFxuXHRcdFx0XHRjYWxjICAgICA9IHN0YXJ0ICsgbGVuLFxuXHRcdFx0XHRyZWNvcmRzICA9IHRoaXMuYWlEaXNwbGF5Lmxlbmd0aCxcblx0XHRcdFx0ZmVhdHVyZXMgPSB0aGlzLm9GZWF0dXJlcyxcblx0XHRcdFx0cGFnaW5hdGUgPSBmZWF0dXJlcy5iUGFnaW5hdGU7XG5cdFxuXHRcdFx0aWYgKCBmZWF0dXJlcy5iU2VydmVyU2lkZSApIHtcblx0XHRcdFx0cmV0dXJuIHBhZ2luYXRlID09PSBmYWxzZSB8fCBsZW4gPT09IC0xID9cblx0XHRcdFx0XHRzdGFydCArIHJlY29yZHMgOlxuXHRcdFx0XHRcdE1hdGgubWluKCBzdGFydCtsZW4sIHRoaXMuX2lSZWNvcmRzRGlzcGxheSApO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSB7XG5cdFx0XHRcdHJldHVybiAhIHBhZ2luYXRlIHx8IGNhbGM+cmVjb3JkcyB8fCBsZW49PT0tMSA/XG5cdFx0XHRcdFx0cmVjb3JkcyA6XG5cdFx0XHRcdFx0Y2FsYztcblx0XHRcdH1cblx0XHR9LFxuXHRcblx0XHQvKipcblx0XHQgKiBUaGUgRGF0YVRhYmxlcyBvYmplY3QgZm9yIHRoaXMgdGFibGVcblx0XHQgKiAgQHR5cGUgb2JqZWN0XG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKi9cblx0XHRcIm9JbnN0YW5jZVwiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiBVbmlxdWUgaWRlbnRpZmllciBmb3IgZWFjaCBpbnN0YW5jZSBvZiB0aGUgRGF0YVRhYmxlcyBvYmplY3QuIElmIHRoZXJlXG5cdFx0ICogaXMgYW4gSUQgb24gdGhlIHRhYmxlIG5vZGUsIHRoZW4gaXQgdGFrZXMgdGhhdCB2YWx1ZSwgb3RoZXJ3aXNlIGFuXG5cdFx0ICogaW5jcmVtZW50aW5nIGludGVybmFsIGNvdW50ZXIgaXMgdXNlZC5cblx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHQgKi9cblx0XHRcInNJbnN0YW5jZVwiOiBudWxsLFxuXHRcblx0XHQvKipcblx0XHQgKiB0YWJpbmRleCBhdHRyaWJ1dGUgdmFsdWUgdGhhdCBpcyBhZGRlZCB0byBEYXRhVGFibGVzIGNvbnRyb2wgZWxlbWVudHMsIGFsbG93aW5nXG5cdFx0ICoga2V5Ym9hcmQgbmF2aWdhdGlvbiBvZiB0aGUgdGFibGUgYW5kIGl0cyBjb250cm9scy5cblx0XHQgKi9cblx0XHRcImlUYWJJbmRleFwiOiAwLFxuXHRcblx0XHQvKipcblx0XHQgKiBESVYgY29udGFpbmVyIGZvciB0aGUgZm9vdGVyIHNjcm9sbGluZyB0YWJsZSBpZiBzY3JvbGxpbmdcblx0XHQgKi9cblx0XHRcIm5TY3JvbGxIZWFkXCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIERJViBjb250YWluZXIgZm9yIHRoZSBmb290ZXIgc2Nyb2xsaW5nIHRhYmxlIGlmIHNjcm9sbGluZ1xuXHRcdCAqL1xuXHRcdFwiblNjcm9sbEZvb3RcIjogbnVsbCxcblx0XG5cdFx0LyoqXG5cdFx0ICogTGFzdCBhcHBsaWVkIHNvcnRcblx0XHQgKiAgQHR5cGUgYXJyYXlcblx0XHQgKiAgQGRlZmF1bHQgW11cblx0XHQgKi9cblx0XHRcImFMYXN0U29ydFwiOiBbXSxcblx0XG5cdFx0LyoqXG5cdFx0ICogU3RvcmVkIHBsdWctaW4gaW5zdGFuY2VzXG5cdFx0ICogIEB0eXBlIG9iamVjdFxuXHRcdCAqICBAZGVmYXVsdCB7fVxuXHRcdCAqL1xuXHRcdFwib1BsdWdpbnNcIjoge30sXG5cdFxuXHRcdC8qKlxuXHRcdCAqIEZ1bmN0aW9uIHVzZWQgdG8gZ2V0IGEgcm93J3MgaWQgZnJvbSB0aGUgcm93J3MgZGF0YVxuXHRcdCAqICBAdHlwZSBmdW5jdGlvblxuXHRcdCAqICBAZGVmYXVsdCBudWxsXG5cdFx0ICovXG5cdFx0XCJyb3dJZEZuXCI6IG51bGwsXG5cdFxuXHRcdC8qKlxuXHRcdCAqIERhdGEgbG9jYXRpb24gd2hlcmUgdG8gc3RvcmUgYSByb3cncyBpZFxuXHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHQgKiAgQGRlZmF1bHQgbnVsbFxuXHRcdCAqL1xuXHRcdFwicm93SWRcIjogbnVsbFxuXHR9O1xuXG5cdC8qKlxuXHQgKiBFeHRlbnNpb24gb2JqZWN0IGZvciBEYXRhVGFibGVzIHRoYXQgaXMgdXNlZCB0byBwcm92aWRlIGFsbCBleHRlbnNpb25cblx0ICogb3B0aW9ucy5cblx0ICpcblx0ICogTm90ZSB0aGF0IHRoZSBgRGF0YVRhYmxlLmV4dGAgb2JqZWN0IGlzIGF2YWlsYWJsZSB0aHJvdWdoXG5cdCAqIGBqUXVlcnkuZm4uZGF0YVRhYmxlLmV4dGAgd2hlcmUgaXQgbWF5IGJlIGFjY2Vzc2VkIGFuZCBtYW5pcHVsYXRlZC4gSXQgaXNcblx0ICogYWxzbyBhbGlhc2VkIHRvIGBqUXVlcnkuZm4uZGF0YVRhYmxlRXh0YCBmb3IgaGlzdG9yaWMgcmVhc29ucy5cblx0ICogIEBuYW1lc3BhY2Vcblx0ICogIEBleHRlbmRzIERhdGFUYWJsZS5tb2RlbHMuZXh0XG5cdCAqL1xuXHRcblx0XG5cdC8qKlxuXHQgKiBEYXRhVGFibGVzIGV4dGVuc2lvbnNcblx0ICogXG5cdCAqIFRoaXMgbmFtZXNwYWNlIGFjdHMgYXMgYSBjb2xsZWN0aW9uIGFyZWEgZm9yIHBsdWctaW5zIHRoYXQgY2FuIGJlIHVzZWQgdG9cblx0ICogZXh0ZW5kIERhdGFUYWJsZXMgY2FwYWJpbGl0aWVzLiBJbmRlZWQgbWFueSBvZiB0aGUgYnVpbGQgaW4gbWV0aG9kc1xuXHQgKiB1c2UgdGhpcyBtZXRob2QgdG8gcHJvdmlkZSB0aGVpciBvd24gY2FwYWJpbGl0aWVzIChzb3J0aW5nIG1ldGhvZHMgZm9yXG5cdCAqIGV4YW1wbGUpLlxuXHQgKlxuXHQgKiBOb3RlIHRoYXQgdGhpcyBuYW1lc3BhY2UgaXMgYWxpYXNlZCB0byBgalF1ZXJ5LmZuLmRhdGFUYWJsZUV4dGAgZm9yIGxlZ2FjeVxuXHQgKiByZWFzb25zXG5cdCAqXG5cdCAqICBAbmFtZXNwYWNlXG5cdCAqL1xuXHREYXRhVGFibGUuZXh0ID0gX2V4dCA9IHtcblx0XHQvKipcblx0XHQgKiBCdXR0b25zLiBGb3IgdXNlIHdpdGggdGhlIEJ1dHRvbnMgZXh0ZW5zaW9uIGZvciBEYXRhVGFibGVzLiBUaGlzIGlzXG5cdFx0ICogZGVmaW5lZCBoZXJlIHNvIG90aGVyIGV4dGVuc2lvbnMgY2FuIGRlZmluZSBidXR0b25zIHJlZ2FyZGxlc3Mgb2YgbG9hZFxuXHRcdCAqIG9yZGVyLiBJdCBpcyBfbm90XyB1c2VkIGJ5IERhdGFUYWJsZXMgY29yZS5cblx0XHQgKlxuXHRcdCAqICBAdHlwZSBvYmplY3Rcblx0XHQgKiAgQGRlZmF1bHQge31cblx0XHQgKi9cblx0XHRidXR0b25zOiB7fSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIEVsZW1lbnQgY2xhc3MgbmFtZXNcblx0XHQgKlxuXHRcdCAqICBAdHlwZSBvYmplY3Rcblx0XHQgKiAgQGRlZmF1bHQge31cblx0XHQgKi9cblx0XHRjbGFzc2VzOiB7fSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIERhdGFUYWJsZXMgYnVpbGQgdHlwZSAoZXhwYW5kZWQgYnkgdGhlIGRvd25sb2FkIGJ1aWxkZXIpXG5cdFx0ICpcblx0XHQgKiAgQHR5cGUgc3RyaW5nXG5cdFx0ICovXG5cdFx0YnVpbGRlcjogXCItc291cmNlLVwiLFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogRXJyb3IgcmVwb3J0aW5nLlxuXHRcdCAqIFxuXHRcdCAqIEhvdyBzaG91bGQgRGF0YVRhYmxlcyByZXBvcnQgYW4gZXJyb3IuIENhbiB0YWtlIHRoZSB2YWx1ZSAnYWxlcnQnLFxuXHRcdCAqICd0aHJvdycsICdub25lJyBvciBhIGZ1bmN0aW9uLlxuXHRcdCAqXG5cdFx0ICogIEB0eXBlIHN0cmluZ3xmdW5jdGlvblxuXHRcdCAqICBAZGVmYXVsdCBhbGVydFxuXHRcdCAqL1xuXHRcdGVyck1vZGU6IFwiYWxlcnRcIixcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIEZlYXR1cmUgcGx1Zy1pbnMuXG5cdFx0ICogXG5cdFx0ICogVGhpcyBpcyBhbiBhcnJheSBvZiBvYmplY3RzIHdoaWNoIGRlc2NyaWJlIHRoZSBmZWF0dXJlIHBsdWctaW5zIHRoYXQgYXJlXG5cdFx0ICogYXZhaWxhYmxlIHRvIERhdGFUYWJsZXMuIFRoZXNlIGZlYXR1cmUgcGx1Zy1pbnMgYXJlIHRoZW4gYXZhaWxhYmxlIGZvclxuXHRcdCAqIHVzZSB0aHJvdWdoIHRoZSBgZG9tYCBpbml0aWFsaXNhdGlvbiBvcHRpb24uXG5cdFx0ICogXG5cdFx0ICogRWFjaCBmZWF0dXJlIHBsdWctaW4gaXMgZGVzY3JpYmVkIGJ5IGFuIG9iamVjdCB3aGljaCBtdXN0IGhhdmUgdGhlXG5cdFx0ICogZm9sbG93aW5nIHByb3BlcnRpZXM6XG5cdFx0ICogXG5cdFx0ICogKiBgZm5Jbml0YCAtIGZ1bmN0aW9uIHRoYXQgaXMgdXNlZCB0byBpbml0aWFsaXNlIHRoZSBwbHVnLWluLFxuXHRcdCAqICogYGNGZWF0dXJlYCAtIGEgY2hhcmFjdGVyIHNvIHRoZSBmZWF0dXJlIGNhbiBiZSBlbmFibGVkIGJ5IHRoZSBgZG9tYFxuXHRcdCAqICAgaW5zdGlsbGF0aW9uIG9wdGlvbi4gVGhpcyBpcyBjYXNlIHNlbnNpdGl2ZS5cblx0XHQgKlxuXHRcdCAqIFRoZSBgZm5Jbml0YCBmdW5jdGlvbiBoYXMgdGhlIGZvbGxvd2luZyBpbnB1dCBwYXJhbWV0ZXJzOlxuXHRcdCAqXG5cdFx0ICogMS4gYHtvYmplY3R9YCBEYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdDogc2VlXG5cdFx0ICogICAge0BsaW5rIERhdGFUYWJsZS5tb2RlbHMub1NldHRpbmdzfVxuXHRcdCAqXG5cdFx0ICogQW5kIHRoZSBmb2xsb3dpbmcgcmV0dXJuIGlzIGV4cGVjdGVkOlxuXHRcdCAqIFxuXHRcdCAqICoge25vZGV8bnVsbH0gVGhlIGVsZW1lbnQgd2hpY2ggY29udGFpbnMgeW91ciBmZWF0dXJlLiBOb3RlIHRoYXQgdGhlXG5cdFx0ICogICByZXR1cm4gbWF5IGFsc28gYmUgdm9pZCBpZiB5b3VyIHBsdWctaW4gZG9lcyBub3QgcmVxdWlyZSB0byBpbmplY3QgYW55XG5cdFx0ICogICBET00gZWxlbWVudHMgaW50byBEYXRhVGFibGVzIGNvbnRyb2wgKGBkb21gKSAtIGZvciBleGFtcGxlIHRoaXMgbWlnaHRcblx0XHQgKiAgIGJlIHVzZWZ1bCB3aGVuIGRldmVsb3BpbmcgYSBwbHVnLWluIHdoaWNoIGFsbG93cyB0YWJsZSBjb250cm9sIHZpYVxuXHRcdCAqICAga2V5Ym9hcmQgZW50cnlcblx0XHQgKlxuXHRcdCAqICBAdHlwZSBhcnJheVxuXHRcdCAqXG5cdFx0ICogIEBleGFtcGxlXG5cdFx0ICogICAgJC5mbi5kYXRhVGFibGUuZXh0LmZlYXR1cmVzLnB1c2goIHtcblx0XHQgKiAgICAgIFwiZm5Jbml0XCI6IGZ1bmN0aW9uKCBvU2V0dGluZ3MgKSB7XG5cdFx0ICogICAgICAgIHJldHVybiBuZXcgVGFibGVUb29scyggeyBcIm9EVFNldHRpbmdzXCI6IG9TZXR0aW5ncyB9ICk7XG5cdFx0ICogICAgICB9LFxuXHRcdCAqICAgICAgXCJjRmVhdHVyZVwiOiBcIlRcIlxuXHRcdCAqICAgIH0gKTtcblx0XHQgKi9cblx0XHRmZWF0dXJlOiBbXSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIFJvdyBzZWFyY2hpbmcuXG5cdFx0ICogXG5cdFx0ICogVGhpcyBtZXRob2Qgb2Ygc2VhcmNoaW5nIGlzIGNvbXBsaW1lbnRhcnkgdG8gdGhlIGRlZmF1bHQgdHlwZSBiYXNlZFxuXHRcdCAqIHNlYXJjaGluZywgYW5kIGEgbG90IG1vcmUgY29tcHJlaGVuc2l2ZSBhcyBpdCBhbGxvd3MgeW91IGNvbXBsZXRlIGNvbnRyb2xcblx0XHQgKiBvdmVyIHRoZSBzZWFyY2hpbmcgbG9naWMuIEVhY2ggZWxlbWVudCBpbiB0aGlzIGFycmF5IGlzIGEgZnVuY3Rpb25cblx0XHQgKiAocGFyYW1ldGVycyBkZXNjcmliZWQgYmVsb3cpIHRoYXQgaXMgY2FsbGVkIGZvciBldmVyeSByb3cgaW4gdGhlIHRhYmxlLFxuXHRcdCAqIGFuZCB5b3VyIGxvZ2ljIGRlY2lkZXMgaWYgaXQgc2hvdWxkIGJlIGluY2x1ZGVkIGluIHRoZSBzZWFyY2hpbmcgZGF0YSBzZXRcblx0XHQgKiBvciBub3QuXG5cdFx0ICpcblx0XHQgKiBTZWFyY2hpbmcgZnVuY3Rpb25zIGhhdmUgdGhlIGZvbGxvd2luZyBpbnB1dCBwYXJhbWV0ZXJzOlxuXHRcdCAqXG5cdFx0ICogMS4gYHtvYmplY3R9YCBEYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdDogc2VlXG5cdFx0ICogICAge0BsaW5rIERhdGFUYWJsZS5tb2RlbHMub1NldHRpbmdzfVxuXHRcdCAqIDIuIGB7YXJyYXl8b2JqZWN0fWAgRGF0YSBmb3IgdGhlIHJvdyB0byBiZSBwcm9jZXNzZWQgKHNhbWUgYXMgdGhlXG5cdFx0ICogICAgb3JpZ2luYWwgZm9ybWF0IHRoYXQgd2FzIHBhc3NlZCBpbiBhcyB0aGUgZGF0YSBzb3VyY2UsIG9yIGFuIGFycmF5XG5cdFx0ICogICAgZnJvbSBhIERPTSBkYXRhIHNvdXJjZVxuXHRcdCAqIDMuIGB7aW50fWAgUm93IGluZGV4ICh7QGxpbmsgRGF0YVRhYmxlLm1vZGVscy5vU2V0dGluZ3MuYW9EYXRhfSksIHdoaWNoXG5cdFx0ICogICAgY2FuIGJlIHVzZWZ1bCB0byByZXRyaWV2ZSB0aGUgYFRSYCBlbGVtZW50IGlmIHlvdSBuZWVkIERPTSBpbnRlcmFjdGlvbi5cblx0XHQgKlxuXHRcdCAqIEFuZCB0aGUgZm9sbG93aW5nIHJldHVybiBpcyBleHBlY3RlZDpcblx0XHQgKlxuXHRcdCAqICoge2Jvb2xlYW59IEluY2x1ZGUgdGhlIHJvdyBpbiB0aGUgc2VhcmNoZWQgcmVzdWx0IHNldCAodHJ1ZSkgb3Igbm90XG5cdFx0ICogICAoZmFsc2UpXG5cdFx0ICpcblx0XHQgKiBOb3RlIHRoYXQgYXMgd2l0aCB0aGUgbWFpbiBzZWFyY2ggYWJpbGl0eSBpbiBEYXRhVGFibGVzLCB0ZWNobmljYWxseSB0aGlzXG5cdFx0ICogaXMgXCJmaWx0ZXJpbmdcIiwgc2luY2UgaXQgaXMgc3VidHJhY3RpdmUuIEhvd2V2ZXIsIGZvciBjb25zaXN0ZW5jeSBpblxuXHRcdCAqIG5hbWluZyB3ZSBjYWxsIGl0IHNlYXJjaGluZyBoZXJlLlxuXHRcdCAqXG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICogIEBkZWZhdWx0IFtdXG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBUaGUgZm9sbG93aW5nIGV4YW1wbGUgc2hvd3MgY3VzdG9tIHNlYXJjaCBiZWluZyBhcHBsaWVkIHRvIHRoZVxuXHRcdCAqICAgIC8vIGZvdXJ0aCBjb2x1bW4gKGkuZS4gdGhlIGRhdGFbM10gaW5kZXgpIGJhc2VkIG9uIHR3byBpbnB1dCB2YWx1ZXNcblx0XHQgKiAgICAvLyBmcm9tIHRoZSBlbmQtdXNlciwgbWF0Y2hpbmcgdGhlIGRhdGEgaW4gYSBjZXJ0YWluIHJhbmdlLlxuXHRcdCAqICAgICQuZm4uZGF0YVRhYmxlLmV4dC5zZWFyY2gucHVzaChcblx0XHQgKiAgICAgIGZ1bmN0aW9uKCBzZXR0aW5ncywgZGF0YSwgZGF0YUluZGV4ICkge1xuXHRcdCAqICAgICAgICB2YXIgbWluID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ21pbicpLnZhbHVlICogMTtcblx0XHQgKiAgICAgICAgdmFyIG1heCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdtYXgnKS52YWx1ZSAqIDE7XG5cdFx0ICogICAgICAgIHZhciB2ZXJzaW9uID0gZGF0YVszXSA9PSBcIi1cIiA/IDAgOiBkYXRhWzNdKjE7XG5cdFx0ICpcblx0XHQgKiAgICAgICAgaWYgKCBtaW4gPT0gXCJcIiAmJiBtYXggPT0gXCJcIiApIHtcblx0XHQgKiAgICAgICAgICByZXR1cm4gdHJ1ZTtcblx0XHQgKiAgICAgICAgfVxuXHRcdCAqICAgICAgICBlbHNlIGlmICggbWluID09IFwiXCIgJiYgdmVyc2lvbiA8IG1heCApIHtcblx0XHQgKiAgICAgICAgICByZXR1cm4gdHJ1ZTtcblx0XHQgKiAgICAgICAgfVxuXHRcdCAqICAgICAgICBlbHNlIGlmICggbWluIDwgdmVyc2lvbiAmJiBcIlwiID09IG1heCApIHtcblx0XHQgKiAgICAgICAgICByZXR1cm4gdHJ1ZTtcblx0XHQgKiAgICAgICAgfVxuXHRcdCAqICAgICAgICBlbHNlIGlmICggbWluIDwgdmVyc2lvbiAmJiB2ZXJzaW9uIDwgbWF4ICkge1xuXHRcdCAqICAgICAgICAgIHJldHVybiB0cnVlO1xuXHRcdCAqICAgICAgICB9XG5cdFx0ICogICAgICAgIHJldHVybiBmYWxzZTtcblx0XHQgKiAgICAgIH1cblx0XHQgKiAgICApO1xuXHRcdCAqL1xuXHRcdHNlYXJjaDogW10sXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBTZWxlY3RvciBleHRlbnNpb25zXG5cdFx0ICpcblx0XHQgKiBUaGUgYHNlbGVjdG9yYCBvcHRpb24gY2FuIGJlIHVzZWQgdG8gZXh0ZW5kIHRoZSBvcHRpb25zIGF2YWlsYWJsZSBmb3IgdGhlXG5cdFx0ICogc2VsZWN0b3IgbW9kaWZpZXIgb3B0aW9ucyAoYHNlbGVjdG9yLW1vZGlmaWVyYCBvYmplY3QgZGF0YSB0eXBlKSB0aGF0XG5cdFx0ICogZWFjaCBvZiB0aGUgdGhyZWUgYnVpbHQgaW4gc2VsZWN0b3IgdHlwZXMgb2ZmZXIgKHJvdywgY29sdW1uIGFuZCBjZWxsICtcblx0XHQgKiB0aGVpciBwbHVyYWwgY291bnRlcnBhcnRzKS4gRm9yIGV4YW1wbGUgdGhlIFNlbGVjdCBleHRlbnNpb24gdXNlcyB0aGlzXG5cdFx0ICogbWVjaGFuaXNtIHRvIHByb3ZpZGUgYW4gb3B0aW9uIHRvIHNlbGVjdCBvbmx5IHJvd3MsIGNvbHVtbnMgYW5kIGNlbGxzXG5cdFx0ICogdGhhdCBoYXZlIGJlZW4gbWFya2VkIGFzIHNlbGVjdGVkIGJ5IHRoZSBlbmQgdXNlciAoYHtzZWxlY3RlZDogdHJ1ZX1gKSxcblx0XHQgKiB3aGljaCBjYW4gYmUgdXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIHRoZSBleGlzdGluZyBidWlsdCBpbiBzZWxlY3RvclxuXHRcdCAqIG9wdGlvbnMuXG5cdFx0ICpcblx0XHQgKiBFYWNoIHByb3BlcnR5IGlzIGFuIGFycmF5IHRvIHdoaWNoIGZ1bmN0aW9ucyBjYW4gYmUgcHVzaGVkLiBUaGUgZnVuY3Rpb25zXG5cdFx0ICogdGFrZSB0aHJlZSBhdHRyaWJ1dGVzOlxuXHRcdCAqXG5cdFx0ICogKiBTZXR0aW5ncyBvYmplY3QgZm9yIHRoZSBob3N0IHRhYmxlXG5cdFx0ICogKiBPcHRpb25zIG9iamVjdCAoYHNlbGVjdG9yLW1vZGlmaWVyYCBvYmplY3QgdHlwZSlcblx0XHQgKiAqIEFycmF5IG9mIHNlbGVjdGVkIGl0ZW0gaW5kZXhlc1xuXHRcdCAqXG5cdFx0ICogVGhlIHJldHVybiBpcyBhbiBhcnJheSBvZiB0aGUgcmVzdWx0aW5nIGl0ZW0gaW5kZXhlcyBhZnRlciB0aGUgY3VzdG9tXG5cdFx0ICogc2VsZWN0b3IgaGFzIGJlZW4gYXBwbGllZC5cblx0XHQgKlxuXHRcdCAqICBAdHlwZSBvYmplY3Rcblx0XHQgKi9cblx0XHRzZWxlY3Rvcjoge1xuXHRcdFx0Y2VsbDogW10sXG5cdFx0XHRjb2x1bW46IFtdLFxuXHRcdFx0cm93OiBbXVxuXHRcdH0sXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBJbnRlcm5hbCBmdW5jdGlvbnMsIGV4cG9zZWQgZm9yIHVzZWQgaW4gcGx1Zy1pbnMuXG5cdFx0ICogXG5cdFx0ICogUGxlYXNlIG5vdGUgdGhhdCB5b3Ugc2hvdWxkIG5vdCBuZWVkIHRvIHVzZSB0aGUgaW50ZXJuYWwgbWV0aG9kcyBmb3Jcblx0XHQgKiBhbnl0aGluZyBvdGhlciB0aGFuIGEgcGx1Zy1pbiAoYW5kIGV2ZW4gdGhlbiwgdHJ5IHRvIGF2b2lkIGlmIHBvc3NpYmxlKS5cblx0XHQgKiBUaGUgaW50ZXJuYWwgZnVuY3Rpb24gbWF5IGNoYW5nZSBiZXR3ZWVuIHJlbGVhc2VzLlxuXHRcdCAqXG5cdFx0ICogIEB0eXBlIG9iamVjdFxuXHRcdCAqICBAZGVmYXVsdCB7fVxuXHRcdCAqL1xuXHRcdGludGVybmFsOiB7fSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIExlZ2FjeSBjb25maWd1cmF0aW9uIG9wdGlvbnMuIEVuYWJsZSBhbmQgZGlzYWJsZSBsZWdhY3kgb3B0aW9ucyB0aGF0XG5cdFx0ICogYXJlIGF2YWlsYWJsZSBpbiBEYXRhVGFibGVzLlxuXHRcdCAqXG5cdFx0ICogIEB0eXBlIG9iamVjdFxuXHRcdCAqL1xuXHRcdGxlZ2FjeToge1xuXHRcdFx0LyoqXG5cdFx0XHQgKiBFbmFibGUgLyBkaXNhYmxlIERhdGFUYWJsZXMgMS45IGNvbXBhdGlibGUgc2VydmVyLXNpZGUgcHJvY2Vzc2luZ1xuXHRcdFx0ICogcmVxdWVzdHNcblx0XHRcdCAqXG5cdFx0XHQgKiAgQHR5cGUgYm9vbGVhblxuXHRcdFx0ICogIEBkZWZhdWx0IG51bGxcblx0XHRcdCAqL1xuXHRcdFx0YWpheDogbnVsbFxuXHRcdH0sXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBQYWdpbmF0aW9uIHBsdWctaW4gbWV0aG9kcy5cblx0XHQgKiBcblx0XHQgKiBFYWNoIGVudHJ5IGluIHRoaXMgb2JqZWN0IGlzIGEgZnVuY3Rpb24gYW5kIGRlZmluZXMgd2hpY2ggYnV0dG9ucyBzaG91bGRcblx0XHQgKiBiZSBzaG93biBieSB0aGUgcGFnaW5hdGlvbiByZW5kZXJpbmcgbWV0aG9kIHRoYXQgaXMgdXNlZCBmb3IgdGhlIHRhYmxlOlxuXHRcdCAqIHtAbGluayBEYXRhVGFibGUuZXh0LnJlbmRlcmVyLnBhZ2VCdXR0b259LiBUaGUgcmVuZGVyZXIgYWRkcmVzc2VzIGhvdyB0aGVcblx0XHQgKiBidXR0b25zIGFyZSBkaXNwbGF5ZWQgaW4gdGhlIGRvY3VtZW50LCB3aGlsZSB0aGUgZnVuY3Rpb25zIGhlcmUgdGVsbCBpdFxuXHRcdCAqIHdoYXQgYnV0dG9ucyB0byBkaXNwbGF5LiBUaGlzIGlzIGRvbmUgYnkgcmV0dXJuaW5nIGFuIGFycmF5IG9mIGJ1dHRvblxuXHRcdCAqIGRlc2NyaXB0aW9ucyAod2hhdCBlYWNoIGJ1dHRvbiB3aWxsIGRvKS5cblx0XHQgKlxuXHRcdCAqIFBhZ2luYXRpb24gdHlwZXMgKHRoZSBmb3VyIGJ1aWx0IGluIG9wdGlvbnMgYW5kIGFueSBhZGRpdGlvbmFsIHBsdWctaW5cblx0XHQgKiBvcHRpb25zIGRlZmluZWQgaGVyZSkgY2FuIGJlIHVzZWQgdGhyb3VnaCB0aGUgYHBhZ2luYXRpb25UeXBlYFxuXHRcdCAqIGluaXRpYWxpc2F0aW9uIHBhcmFtZXRlci5cblx0XHQgKlxuXHRcdCAqIFRoZSBmdW5jdGlvbnMgZGVmaW5lZCB0YWtlIHR3byBwYXJhbWV0ZXJzOlxuXHRcdCAqXG5cdFx0ICogMS4gYHtpbnR9IHBhZ2VgIFRoZSBjdXJyZW50IHBhZ2UgaW5kZXhcblx0XHQgKiAyLiBge2ludH0gcGFnZXNgIFRoZSBudW1iZXIgb2YgcGFnZXMgaW4gdGhlIHRhYmxlXG5cdFx0ICpcblx0XHQgKiBFYWNoIGZ1bmN0aW9uIGlzIGV4cGVjdGVkIHRvIHJldHVybiBhbiBhcnJheSB3aGVyZSBlYWNoIGVsZW1lbnQgb2YgdGhlXG5cdFx0ICogYXJyYXkgY2FuIGJlIG9uZSBvZjpcblx0XHQgKlxuXHRcdCAqICogYGZpcnN0YCAtIEp1bXAgdG8gZmlyc3QgcGFnZSB3aGVuIGFjdGl2YXRlZFxuXHRcdCAqICogYGxhc3RgIC0gSnVtcCB0byBsYXN0IHBhZ2Ugd2hlbiBhY3RpdmF0ZWRcblx0XHQgKiAqIGBwcmV2aW91c2AgLSBTaG93IHByZXZpb3VzIHBhZ2Ugd2hlbiBhY3RpdmF0ZWRcblx0XHQgKiAqIGBuZXh0YCAtIFNob3cgbmV4dCBwYWdlIHdoZW4gYWN0aXZhdGVkXG5cdFx0ICogKiBge2ludH1gIC0gU2hvdyBwYWdlIG9mIHRoZSBpbmRleCBnaXZlblxuXHRcdCAqICogYHthcnJheX1gIC0gQSBuZXN0ZWQgYXJyYXkgY29udGFpbmluZyB0aGUgYWJvdmUgZWxlbWVudHMgdG8gYWRkIGFcblx0XHQgKiAgIGNvbnRhaW5pbmcgJ0RJVicgZWxlbWVudCAobWlnaHQgYmUgdXNlZnVsIGZvciBzdHlsaW5nKS5cblx0XHQgKlxuXHRcdCAqIE5vdGUgdGhhdCBEYXRhVGFibGVzIHYxLjktIHVzZWQgdGhpcyBvYmplY3Qgc2xpZ2h0bHkgZGlmZmVyZW50bHkgd2hlcmVieVxuXHRcdCAqIGFuIG9iamVjdCB3aXRoIHR3byBmdW5jdGlvbnMgd291bGQgYmUgZGVmaW5lZCBmb3IgZWFjaCBwbHVnLWluLiBUaGF0XG5cdFx0ICogYWJpbGl0eSBpcyBzdGlsbCBzdXBwb3J0ZWQgYnkgRGF0YVRhYmxlcyAxLjEwKyB0byBwcm92aWRlIGJhY2t3YXJkc1xuXHRcdCAqIGNvbXBhdGliaWxpdHksIGJ1dCB0aGlzIG9wdGlvbiBvZiB1c2UgaXMgbm93IGRlY3JlbWVudGVkIGFuZCBubyBsb25nZXJcblx0XHQgKiBkb2N1bWVudGVkIGluIERhdGFUYWJsZXMgMS4xMCsuXG5cdFx0ICpcblx0XHQgKiAgQHR5cGUgb2JqZWN0XG5cdFx0ICogIEBkZWZhdWx0IHt9XG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBTaG93IHByZXZpb3VzLCBuZXh0IGFuZCBjdXJyZW50IHBhZ2UgYnV0dG9ucyBvbmx5XG5cdFx0ICogICAgJC5mbi5kYXRhVGFibGVFeHQub1BhZ2luYXRpb24uY3VycmVudCA9IGZ1bmN0aW9uICggcGFnZSwgcGFnZXMgKSB7XG5cdFx0ICogICAgICByZXR1cm4gWyAncHJldmlvdXMnLCBwYWdlLCAnbmV4dCcgXTtcblx0XHQgKiAgICB9O1xuXHRcdCAqL1xuXHRcdHBhZ2VyOiB7fSxcblx0XG5cdFxuXHRcdHJlbmRlcmVyOiB7XG5cdFx0XHRwYWdlQnV0dG9uOiB7fSxcblx0XHRcdGhlYWRlcjoge31cblx0XHR9LFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogT3JkZXJpbmcgcGx1Zy1pbnMgLSBjdXN0b20gZGF0YSBzb3VyY2Vcblx0XHQgKiBcblx0XHQgKiBUaGUgZXh0ZW5zaW9uIG9wdGlvbnMgZm9yIG9yZGVyaW5nIG9mIGRhdGEgYXZhaWxhYmxlIGhlcmUgaXMgY29tcGxpbWVudGFyeVxuXHRcdCAqIHRvIHRoZSBkZWZhdWx0IHR5cGUgYmFzZWQgb3JkZXJpbmcgdGhhdCBEYXRhVGFibGVzIHR5cGljYWxseSB1c2VzLiBJdFxuXHRcdCAqIGFsbG93cyBtdWNoIGdyZWF0ZXIgY29udHJvbCBvdmVyIHRoZSB0aGUgZGF0YSB0aGF0IGlzIGJlaW5nIHVzZWQgdG9cblx0XHQgKiBvcmRlciBhIGNvbHVtbiwgYnV0IGlzIG5lY2Vzc2FyaWx5IHRoZXJlZm9yZSBtb3JlIGNvbXBsZXguXG5cdFx0ICogXG5cdFx0ICogVGhpcyB0eXBlIG9mIG9yZGVyaW5nIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBkbyBvcmRlcmluZyBiYXNlZCBvbiBkYXRhXG5cdFx0ICogbGl2ZSBmcm9tIHRoZSBET00gKGZvciBleGFtcGxlIHRoZSBjb250ZW50cyBvZiBhbiAnaW5wdXQnIGVsZW1lbnQpIHJhdGhlclxuXHRcdCAqIHRoYW4ganVzdCB0aGUgc3RhdGljIHN0cmluZyB0aGF0IERhdGFUYWJsZXMga25vd3Mgb2YuXG5cdFx0ICogXG5cdFx0ICogVGhlIHdheSB0aGVzZSBwbHVnLWlucyB3b3JrIGlzIHRoYXQgeW91IGNyZWF0ZSBhbiBhcnJheSBvZiB0aGUgdmFsdWVzIHlvdVxuXHRcdCAqIHdpc2ggdG8gYmUgb3JkZXJpbmcgZm9yIHRoZSBjb2x1bW4gaW4gcXVlc3Rpb24gYW5kIHRoZW4gcmV0dXJuIHRoYXRcblx0XHQgKiBhcnJheS4gVGhlIGRhdGEgaW4gdGhlIGFycmF5IG11Y2ggYmUgaW4gdGhlIGluZGV4IG9yZGVyIG9mIHRoZSByb3dzIGluXG5cdFx0ICogdGhlIHRhYmxlIChub3QgdGhlIGN1cnJlbnRseSBvcmRlcmluZyBvcmRlciEpLiBXaGljaCBvcmRlciBkYXRhIGdhdGhlcmluZ1xuXHRcdCAqIGZ1bmN0aW9uIGlzIHJ1biBoZXJlIGRlcGVuZHMgb24gdGhlIGBkdC1pbml0IGNvbHVtbnMub3JkZXJEYXRhVHlwZWBcblx0XHQgKiBwYXJhbWV0ZXIgdGhhdCBpcyB1c2VkIGZvciB0aGUgY29sdW1uIChpZiBhbnkpLlxuXHRcdCAqXG5cdFx0ICogVGhlIGZ1bmN0aW9ucyBkZWZpbmVkIHRha2UgdHdvIHBhcmFtZXRlcnM6XG5cdFx0ICpcblx0XHQgKiAxLiBge29iamVjdH1gIERhdGFUYWJsZXMgc2V0dGluZ3Mgb2JqZWN0OiBzZWVcblx0XHQgKiAgICB7QGxpbmsgRGF0YVRhYmxlLm1vZGVscy5vU2V0dGluZ3N9XG5cdFx0ICogMi4gYHtpbnR9YCBUYXJnZXQgY29sdW1uIGluZGV4XG5cdFx0ICpcblx0XHQgKiBFYWNoIGZ1bmN0aW9uIGlzIGV4cGVjdGVkIHRvIHJldHVybiBhbiBhcnJheTpcblx0XHQgKlxuXHRcdCAqICogYHthcnJheX1gIERhdGEgZm9yIHRoZSBjb2x1bW4gdG8gYmUgb3JkZXJpbmcgdXBvblxuXHRcdCAqXG5cdFx0ICogIEB0eXBlIGFycmF5XG5cdFx0ICpcblx0XHQgKiAgQGV4YW1wbGVcblx0XHQgKiAgICAvLyBPcmRlcmluZyB1c2luZyBgaW5wdXRgIG5vZGUgdmFsdWVzXG5cdFx0ICogICAgJC5mbi5kYXRhVGFibGUuZXh0Lm9yZGVyWydkb20tdGV4dCddID0gZnVuY3Rpb24gICggc2V0dGluZ3MsIGNvbCApXG5cdFx0ICogICAge1xuXHRcdCAqICAgICAgcmV0dXJuIHRoaXMuYXBpKCkuY29sdW1uKCBjb2wsIHtvcmRlcjonaW5kZXgnfSApLm5vZGVzKCkubWFwKCBmdW5jdGlvbiAoIHRkLCBpICkge1xuXHRcdCAqICAgICAgICByZXR1cm4gJCgnaW5wdXQnLCB0ZCkudmFsKCk7XG5cdFx0ICogICAgICB9ICk7XG5cdFx0ICogICAgfVxuXHRcdCAqL1xuXHRcdG9yZGVyOiB7fSxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIFR5cGUgYmFzZWQgcGx1Zy1pbnMuXG5cdFx0ICpcblx0XHQgKiBFYWNoIGNvbHVtbiBpbiBEYXRhVGFibGVzIGhhcyBhIHR5cGUgYXNzaWduZWQgdG8gaXQsIGVpdGhlciBieSBhdXRvbWF0aWNcblx0XHQgKiBkZXRlY3Rpb24gb3IgYnkgZGlyZWN0IGFzc2lnbm1lbnQgdXNpbmcgdGhlIGB0eXBlYCBvcHRpb24gZm9yIHRoZSBjb2x1bW4uXG5cdFx0ICogVGhlIHR5cGUgb2YgYSBjb2x1bW4gd2lsbCBlZmZlY3QgaG93IGl0IGlzIG9yZGVyaW5nIGFuZCBzZWFyY2ggKHBsdWctaW5zXG5cdFx0ICogY2FuIGFsc28gbWFrZSB1c2Ugb2YgdGhlIGNvbHVtbiB0eXBlIGlmIHJlcXVpcmVkKS5cblx0XHQgKlxuXHRcdCAqIEBuYW1lc3BhY2Vcblx0XHQgKi9cblx0XHR0eXBlOiB7XG5cdFx0XHQvKipcblx0XHRcdCAqIFR5cGUgZGV0ZWN0aW9uIGZ1bmN0aW9ucy5cblx0XHRcdCAqXG5cdFx0XHQgKiBUaGUgZnVuY3Rpb25zIGRlZmluZWQgaW4gdGhpcyBvYmplY3QgYXJlIHVzZWQgdG8gYXV0b21hdGljYWxseSBkZXRlY3Rcblx0XHRcdCAqIGEgY29sdW1uJ3MgdHlwZSwgbWFraW5nIGluaXRpYWxpc2F0aW9uIG9mIERhdGFUYWJsZXMgc3VwZXIgZWFzeSwgZXZlblxuXHRcdFx0ICogd2hlbiBjb21wbGV4IGRhdGEgaXMgaW4gdGhlIHRhYmxlLlxuXHRcdFx0ICpcblx0XHRcdCAqIFRoZSBmdW5jdGlvbnMgZGVmaW5lZCB0YWtlIHR3byBwYXJhbWV0ZXJzOlxuXHRcdFx0ICpcblx0XHQgICAgICogIDEuIGB7Kn1gIERhdGEgZnJvbSB0aGUgY29sdW1uIGNlbGwgdG8gYmUgYW5hbHlzZWRcblx0XHQgICAgICogIDIuIGB7c2V0dGluZ3N9YCBEYXRhVGFibGVzIHNldHRpbmdzIG9iamVjdC4gVGhpcyBjYW4gYmUgdXNlZCB0b1xuXHRcdCAgICAgKiAgICAgcGVyZm9ybSBjb250ZXh0IHNwZWNpZmljIHR5cGUgZGV0ZWN0aW9uIC0gZm9yIGV4YW1wbGUgZGV0ZWN0aW9uXG5cdFx0ICAgICAqICAgICBiYXNlZCBvbiBsYW5ndWFnZSBzZXR0aW5ncyBzdWNoIGFzIHVzaW5nIGEgY29tbWEgZm9yIGEgZGVjaW1hbFxuXHRcdCAgICAgKiAgICAgcGxhY2UuIEdlbmVyYWxseSBzcGVha2luZyB0aGUgb3B0aW9ucyBmcm9tIHRoZSBzZXR0aW5ncyB3aWxsIG5vdFxuXHRcdCAgICAgKiAgICAgYmUgcmVxdWlyZWRcblx0XHRcdCAqXG5cdFx0XHQgKiBFYWNoIGZ1bmN0aW9uIGlzIGV4cGVjdGVkIHRvIHJldHVybjpcblx0XHRcdCAqXG5cdFx0XHQgKiAqIGB7c3RyaW5nfG51bGx9YCBEYXRhIHR5cGUgZGV0ZWN0ZWQsIG9yIG51bGwgaWYgdW5rbm93biAoYW5kIHRodXNcblx0XHRcdCAqICAgcGFzcyBpdCBvbiB0byB0aGUgb3RoZXIgdHlwZSBkZXRlY3Rpb24gZnVuY3Rpb25zLlxuXHRcdFx0ICpcblx0XHRcdCAqICBAdHlwZSBhcnJheVxuXHRcdFx0ICpcblx0XHRcdCAqICBAZXhhbXBsZVxuXHRcdFx0ICogICAgLy8gQ3VycmVuY3kgdHlwZSBkZXRlY3Rpb24gcGx1Zy1pbjpcblx0XHRcdCAqICAgICQuZm4uZGF0YVRhYmxlLmV4dC50eXBlLmRldGVjdC5wdXNoKFxuXHRcdFx0ICogICAgICBmdW5jdGlvbiAoIGRhdGEsIHNldHRpbmdzICkge1xuXHRcdFx0ICogICAgICAgIC8vIENoZWNrIHRoZSBudW1lcmljIHBhcnRcblx0XHRcdCAqICAgICAgICBpZiAoICEgZGF0YS5zdWJzdHJpbmcoMSkubWF0Y2goL1swLTldLykgKSB7XG5cdFx0XHQgKiAgICAgICAgICByZXR1cm4gbnVsbDtcblx0XHRcdCAqICAgICAgICB9XG5cdFx0XHQgKlxuXHRcdFx0ICogICAgICAgIC8vIENoZWNrIHByZWZpeGVkIGJ5IGN1cnJlbmN5XG5cdFx0XHQgKiAgICAgICAgaWYgKCBkYXRhLmNoYXJBdCgwKSA9PSAnJCcgfHwgZGF0YS5jaGFyQXQoMCkgPT0gJyZwb3VuZDsnICkge1xuXHRcdFx0ICogICAgICAgICAgcmV0dXJuICdjdXJyZW5jeSc7XG5cdFx0XHQgKiAgICAgICAgfVxuXHRcdFx0ICogICAgICAgIHJldHVybiBudWxsO1xuXHRcdFx0ICogICAgICB9XG5cdFx0XHQgKiAgICApO1xuXHRcdFx0ICovXG5cdFx0XHRkZXRlY3Q6IFtdLFxuXHRcblx0XG5cdFx0XHQvKipcblx0XHRcdCAqIFR5cGUgYmFzZWQgc2VhcmNoIGZvcm1hdHRpbmcuXG5cdFx0XHQgKlxuXHRcdFx0ICogVGhlIHR5cGUgYmFzZWQgc2VhcmNoaW5nIGZ1bmN0aW9ucyBjYW4gYmUgdXNlZCB0byBwcmUtZm9ybWF0IHRoZVxuXHRcdFx0ICogZGF0YSB0byBiZSBzZWFyY2ggb24uIEZvciBleGFtcGxlLCBpdCBjYW4gYmUgdXNlZCB0byBzdHJpcCBIVE1MXG5cdFx0XHQgKiB0YWdzIG9yIHRvIGRlLWZvcm1hdCB0ZWxlcGhvbmUgbnVtYmVycyBmb3IgbnVtZXJpYyBvbmx5IHNlYXJjaGluZy5cblx0XHRcdCAqXG5cdFx0XHQgKiBOb3RlIHRoYXQgaXMgYSBzZWFyY2ggaXMgbm90IGRlZmluZWQgZm9yIGEgY29sdW1uIG9mIGEgZ2l2ZW4gdHlwZSxcblx0XHRcdCAqIG5vIHNlYXJjaCBmb3JtYXR0aW5nIHdpbGwgYmUgcGVyZm9ybWVkLlxuXHRcdFx0ICogXG5cdFx0XHQgKiBQcmUtcHJvY2Vzc2luZyBvZiBzZWFyY2hpbmcgZGF0YSBwbHVnLWlucyAtIFdoZW4geW91IGFzc2lnbiB0aGUgc1R5cGVcblx0XHRcdCAqIGZvciBhIGNvbHVtbiAob3IgaGF2ZSBpdCBhdXRvbWF0aWNhbGx5IGRldGVjdGVkIGZvciB5b3UgYnkgRGF0YVRhYmxlc1xuXHRcdFx0ICogb3IgYSB0eXBlIGRldGVjdGlvbiBwbHVnLWluKSwgeW91IHdpbGwgdHlwaWNhbGx5IGJlIHVzaW5nIHRoaXMgZm9yXG5cdFx0XHQgKiBjdXN0b20gc29ydGluZywgYnV0IGl0IGNhbiBhbHNvIGJlIHVzZWQgdG8gcHJvdmlkZSBjdXN0b20gc2VhcmNoaW5nXG5cdFx0XHQgKiBieSBhbGxvd2luZyB5b3UgdG8gcHJlLXByb2Nlc3NpbmcgdGhlIGRhdGEgYW5kIHJldHVybmluZyB0aGUgZGF0YSBpblxuXHRcdFx0ICogdGhlIGZvcm1hdCB0aGF0IHNob3VsZCBiZSBzZWFyY2hlZCB1cG9uLiBUaGlzIGlzIGRvbmUgYnkgYWRkaW5nXG5cdFx0XHQgKiBmdW5jdGlvbnMgdGhpcyBvYmplY3Qgd2l0aCBhIHBhcmFtZXRlciBuYW1lIHdoaWNoIG1hdGNoZXMgdGhlIHNUeXBlXG5cdFx0XHQgKiBmb3IgdGhhdCB0YXJnZXQgY29sdW1uLiBUaGlzIGlzIHRoZSBjb3JvbGxhcnkgb2YgPGk+YWZuU29ydERhdGE8L2k+XG5cdFx0XHQgKiBmb3Igc2VhcmNoaW5nIGRhdGEuXG5cdFx0XHQgKlxuXHRcdFx0ICogVGhlIGZ1bmN0aW9ucyBkZWZpbmVkIHRha2UgYSBzaW5nbGUgcGFyYW1ldGVyOlxuXHRcdFx0ICpcblx0XHQgICAgICogIDEuIGB7Kn1gIERhdGEgZnJvbSB0aGUgY29sdW1uIGNlbGwgdG8gYmUgcHJlcGFyZWQgZm9yIHNlYXJjaGluZ1xuXHRcdFx0ICpcblx0XHRcdCAqIEVhY2ggZnVuY3Rpb24gaXMgZXhwZWN0ZWQgdG8gcmV0dXJuOlxuXHRcdFx0ICpcblx0XHRcdCAqICogYHtzdHJpbmd8bnVsbH1gIEZvcm1hdHRlZCBzdHJpbmcgdGhhdCB3aWxsIGJlIHVzZWQgZm9yIHRoZSBzZWFyY2hpbmcuXG5cdFx0XHQgKlxuXHRcdFx0ICogIEB0eXBlIG9iamVjdFxuXHRcdFx0ICogIEBkZWZhdWx0IHt9XG5cdFx0XHQgKlxuXHRcdFx0ICogIEBleGFtcGxlXG5cdFx0XHQgKiAgICAkLmZuLmRhdGFUYWJsZS5leHQudHlwZS5zZWFyY2hbJ3RpdGxlLW51bWVyaWMnXSA9IGZ1bmN0aW9uICggZCApIHtcblx0XHRcdCAqICAgICAgcmV0dXJuIGQucmVwbGFjZSgvXFxuL2csXCIgXCIpLnJlcGxhY2UoIC88Lio/Pi9nLCBcIlwiICk7XG5cdFx0XHQgKiAgICB9XG5cdFx0XHQgKi9cblx0XHRcdHNlYXJjaDoge30sXG5cdFxuXHRcblx0XHRcdC8qKlxuXHRcdFx0ICogVHlwZSBiYXNlZCBvcmRlcmluZy5cblx0XHRcdCAqXG5cdFx0XHQgKiBUaGUgY29sdW1uIHR5cGUgdGVsbHMgRGF0YVRhYmxlcyB3aGF0IG9yZGVyaW5nIHRvIGFwcGx5IHRvIHRoZSB0YWJsZVxuXHRcdFx0ICogd2hlbiBhIGNvbHVtbiBpcyBzb3J0ZWQgdXBvbi4gVGhlIG9yZGVyIGZvciBlYWNoIHR5cGUgdGhhdCBpcyBkZWZpbmVkLFxuXHRcdFx0ICogaXMgZGVmaW5lZCBieSB0aGUgZnVuY3Rpb25zIGF2YWlsYWJsZSBpbiB0aGlzIG9iamVjdC5cblx0XHRcdCAqXG5cdFx0XHQgKiBFYWNoIG9yZGVyaW5nIG9wdGlvbiBjYW4gYmUgZGVzY3JpYmVkIGJ5IHRocmVlIHByb3BlcnRpZXMgYWRkZWQgdG9cblx0XHRcdCAqIHRoaXMgb2JqZWN0OlxuXHRcdFx0ICpcblx0XHRcdCAqICogYHt0eXBlfS1wcmVgIC0gUHJlLWZvcm1hdHRpbmcgZnVuY3Rpb25cblx0XHRcdCAqICogYHt0eXBlfS1hc2NgIC0gQXNjZW5kaW5nIG9yZGVyIGZ1bmN0aW9uXG5cdFx0XHQgKiAqIGB7dHlwZX0tZGVzY2AgLSBEZXNjZW5kaW5nIG9yZGVyIGZ1bmN0aW9uXG5cdFx0XHQgKlxuXHRcdFx0ICogQWxsIHRocmVlIGNhbiBiZSB1c2VkIHRvZ2V0aGVyLCBvbmx5IGB7dHlwZX0tcHJlYCBvciBvbmx5XG5cdFx0XHQgKiBge3R5cGV9LWFzY2AgYW5kIGB7dHlwZX0tZGVzY2AgdG9nZXRoZXIuIEl0IGlzIGdlbmVyYWxseSByZWNvbW1lbmRlZFxuXHRcdFx0ICogdGhhdCBvbmx5IGB7dHlwZX0tcHJlYCBpcyB1c2VkLCBhcyB0aGlzIHByb3ZpZGVzIHRoZSBvcHRpbWFsXG5cdFx0XHQgKiBpbXBsZW1lbnRhdGlvbiBpbiB0ZXJtcyBvZiBzcGVlZCwgYWx0aG91Z2ggdGhlIG90aGVycyBhcmUgcHJvdmlkZWRcblx0XHRcdCAqIGZvciBjb21wYXRpYmlsaXR5IHdpdGggZXhpc3RpbmcgSmF2YXNjcmlwdCBzb3J0IGZ1bmN0aW9ucy5cblx0XHRcdCAqXG5cdFx0XHQgKiBge3R5cGV9LXByZWA6IEZ1bmN0aW9ucyBkZWZpbmVkIHRha2UgYSBzaW5nbGUgcGFyYW1ldGVyOlxuXHRcdFx0ICpcblx0XHQgICAgICogIDEuIGB7Kn1gIERhdGEgZnJvbSB0aGUgY29sdW1uIGNlbGwgdG8gYmUgcHJlcGFyZWQgZm9yIG9yZGVyaW5nXG5cdFx0XHQgKlxuXHRcdFx0ICogQW5kIHJldHVybjpcblx0XHRcdCAqXG5cdFx0XHQgKiAqIGB7Kn1gIERhdGEgdG8gYmUgc29ydGVkIHVwb25cblx0XHRcdCAqXG5cdFx0XHQgKiBge3R5cGV9LWFzY2AgYW5kIGB7dHlwZX0tZGVzY2A6IEZ1bmN0aW9ucyBhcmUgdHlwaWNhbCBKYXZhc2NyaXB0IHNvcnRcblx0XHRcdCAqIGZ1bmN0aW9ucywgdGFraW5nIHR3byBwYXJhbWV0ZXJzOlxuXHRcdFx0ICpcblx0XHQgICAgICogIDEuIGB7Kn1gIERhdGEgdG8gY29tcGFyZSB0byB0aGUgc2Vjb25kIHBhcmFtZXRlclxuXHRcdCAgICAgKiAgMi4gYHsqfWAgRGF0YSB0byBjb21wYXJlIHRvIHRoZSBmaXJzdCBwYXJhbWV0ZXJcblx0XHRcdCAqXG5cdFx0XHQgKiBBbmQgcmV0dXJuaW5nOlxuXHRcdFx0ICpcblx0XHRcdCAqICogYHsqfWAgT3JkZXJpbmcgbWF0Y2g6IDwwIGlmIGZpcnN0IHBhcmFtZXRlciBzaG91bGQgYmUgc29ydGVkIGxvd2VyXG5cdFx0XHQgKiAgIHRoYW4gdGhlIHNlY29uZCBwYXJhbWV0ZXIsID09PTAgaWYgdGhlIHR3byBwYXJhbWV0ZXJzIGFyZSBlcXVhbCBhbmRcblx0XHRcdCAqICAgPjAgaWYgdGhlIGZpcnN0IHBhcmFtZXRlciBzaG91bGQgYmUgc29ydGVkIGhlaWdodCB0aGFuIHRoZSBzZWNvbmRcblx0XHRcdCAqICAgcGFyYW1ldGVyLlxuXHRcdFx0ICogXG5cdFx0XHQgKiAgQHR5cGUgb2JqZWN0XG5cdFx0XHQgKiAgQGRlZmF1bHQge31cblx0XHRcdCAqXG5cdFx0XHQgKiAgQGV4YW1wbGVcblx0XHRcdCAqICAgIC8vIE51bWVyaWMgb3JkZXJpbmcgb2YgZm9ybWF0dGVkIG51bWJlcnMgd2l0aCBhIHByZS1mb3JtYXR0ZXJcblx0XHRcdCAqICAgICQuZXh0ZW5kKCAkLmZuLmRhdGFUYWJsZS5leHQudHlwZS5vcmRlciwge1xuXHRcdFx0ICogICAgICBcInN0cmluZy1wcmVcIjogZnVuY3Rpb24oeCkge1xuXHRcdFx0ICogICAgICAgIGEgPSAoYSA9PT0gXCItXCIgfHwgYSA9PT0gXCJcIikgPyAwIDogYS5yZXBsYWNlKCAvW15cXGRcXC1cXC5dL2csIFwiXCIgKTtcblx0XHRcdCAqICAgICAgICByZXR1cm4gcGFyc2VGbG9hdCggYSApO1xuXHRcdFx0ICogICAgICB9XG5cdFx0XHQgKiAgICB9ICk7XG5cdFx0XHQgKlxuXHRcdFx0ICogIEBleGFtcGxlXG5cdFx0XHQgKiAgICAvLyBDYXNlLXNlbnNpdGl2ZSBzdHJpbmcgb3JkZXJpbmcsIHdpdGggbm8gcHJlLWZvcm1hdHRpbmcgbWV0aG9kXG5cdFx0XHQgKiAgICAkLmV4dGVuZCggJC5mbi5kYXRhVGFibGUuZXh0Lm9yZGVyLCB7XG5cdFx0XHQgKiAgICAgIFwic3RyaW5nLWNhc2UtYXNjXCI6IGZ1bmN0aW9uKHgseSkge1xuXHRcdFx0ICogICAgICAgIHJldHVybiAoKHggPCB5KSA/IC0xIDogKCh4ID4geSkgPyAxIDogMCkpO1xuXHRcdFx0ICogICAgICB9LFxuXHRcdFx0ICogICAgICBcInN0cmluZy1jYXNlLWRlc2NcIjogZnVuY3Rpb24oeCx5KSB7XG5cdFx0XHQgKiAgICAgICAgcmV0dXJuICgoeCA8IHkpID8gMSA6ICgoeCA+IHkpID8gLTEgOiAwKSk7XG5cdFx0XHQgKiAgICAgIH1cblx0XHRcdCAqICAgIH0gKTtcblx0XHRcdCAqL1xuXHRcdFx0b3JkZXI6IHt9XG5cdFx0fSxcblx0XG5cdFx0LyoqXG5cdFx0ICogVW5pcXVlIERhdGFUYWJsZXMgaW5zdGFuY2UgY291bnRlclxuXHRcdCAqXG5cdFx0ICogQHR5cGUgaW50XG5cdFx0ICogQHByaXZhdGVcblx0XHQgKi9cblx0XHRfdW5pcXVlOiAwLFxuXHRcblx0XG5cdFx0Ly9cblx0XHQvLyBEZXByZWNpYXRlZFxuXHRcdC8vIFRoZSBmb2xsb3dpbmcgcHJvcGVydGllcyBhcmUgcmV0YWluZWQgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5IG9ubHkuXG5cdFx0Ly8gVGhlIHNob3VsZCBub3QgYmUgdXNlZCBpbiBuZXcgcHJvamVjdHMgYW5kIHdpbGwgYmUgcmVtb3ZlZCBpbiBhIGZ1dHVyZVxuXHRcdC8vIHZlcnNpb25cblx0XHQvL1xuXHRcblx0XHQvKipcblx0XHQgKiBWZXJzaW9uIGNoZWNrIGZ1bmN0aW9uLlxuXHRcdCAqICBAdHlwZSBmdW5jdGlvblxuXHRcdCAqICBAZGVwcmVjaWF0ZWQgU2luY2UgMS4xMFxuXHRcdCAqL1xuXHRcdGZuVmVyc2lvbkNoZWNrOiBEYXRhVGFibGUuZm5WZXJzaW9uQ2hlY2ssXG5cdFxuXHRcblx0XHQvKipcblx0XHQgKiBJbmRleCBmb3Igd2hhdCAndGhpcycgaW5kZXggQVBJIGZ1bmN0aW9ucyBzaG91bGQgdXNlXG5cdFx0ICogIEB0eXBlIGludFxuXHRcdCAqICBAZGVwcmVjYXRlZCBTaW5jZSB2MS4xMFxuXHRcdCAqL1xuXHRcdGlBcGlJbmRleDogMCxcblx0XG5cdFxuXHRcdC8qKlxuXHRcdCAqIGpRdWVyeSBVSSBjbGFzcyBjb250YWluZXJcblx0XHQgKiAgQHR5cGUgb2JqZWN0XG5cdFx0ICogIEBkZXByZWNhdGVkIFNpbmNlIHYxLjEwXG5cdFx0ICovXG5cdFx0b0pVSUNsYXNzZXM6IHt9LFxuXHRcblx0XG5cdFx0LyoqXG5cdFx0ICogU29mdHdhcmUgdmVyc2lvblxuXHRcdCAqICBAdHlwZSBzdHJpbmdcblx0XHQgKiAgQGRlcHJlY2F0ZWQgU2luY2UgdjEuMTBcblx0XHQgKi9cblx0XHRzVmVyc2lvbjogRGF0YVRhYmxlLnZlcnNpb25cblx0fTtcblx0XG5cdFxuXHQvL1xuXHQvLyBCYWNrd2FyZHMgY29tcGF0aWJpbGl0eS4gQWxpYXMgdG8gcHJlIDEuMTAgSHVuZ2FyaWFuIG5vdGF0aW9uIGNvdW50ZXIgcGFydHNcblx0Ly9cblx0JC5leHRlbmQoIF9leHQsIHtcblx0XHRhZm5GaWx0ZXJpbmc6IF9leHQuc2VhcmNoLFxuXHRcdGFUeXBlczogICAgICAgX2V4dC50eXBlLmRldGVjdCxcblx0XHRvZm5TZWFyY2g6ICAgIF9leHQudHlwZS5zZWFyY2gsXG5cdFx0b1NvcnQ6ICAgICAgICBfZXh0LnR5cGUub3JkZXIsXG5cdFx0YWZuU29ydERhdGE6ICBfZXh0Lm9yZGVyLFxuXHRcdGFvRmVhdHVyZXM6ICAgX2V4dC5mZWF0dXJlLFxuXHRcdG9BcGk6ICAgICAgICAgX2V4dC5pbnRlcm5hbCxcblx0XHRvU3RkQ2xhc3NlczogIF9leHQuY2xhc3Nlcyxcblx0XHRvUGFnaW5hdGlvbjogIF9leHQucGFnZXJcblx0fSApO1xuXHRcblx0XG5cdCQuZXh0ZW5kKCBEYXRhVGFibGUuZXh0LmNsYXNzZXMsIHtcblx0XHRcInNUYWJsZVwiOiBcImRhdGFUYWJsZVwiLFxuXHRcdFwic05vRm9vdGVyXCI6IFwibm8tZm9vdGVyXCIsXG5cdFxuXHRcdC8qIFBhZ2luZyBidXR0b25zICovXG5cdFx0XCJzUGFnZUJ1dHRvblwiOiBcInBhZ2luYXRlX2J1dHRvblwiLFxuXHRcdFwic1BhZ2VCdXR0b25BY3RpdmVcIjogXCJjdXJyZW50XCIsXG5cdFx0XCJzUGFnZUJ1dHRvbkRpc2FibGVkXCI6IFwiZGlzYWJsZWRcIixcblx0XG5cdFx0LyogU3RyaXBpbmcgY2xhc3NlcyAqL1xuXHRcdFwic1N0cmlwZU9kZFwiOiBcIm9kZFwiLFxuXHRcdFwic1N0cmlwZUV2ZW5cIjogXCJldmVuXCIsXG5cdFxuXHRcdC8qIEVtcHR5IHJvdyAqL1xuXHRcdFwic1Jvd0VtcHR5XCI6IFwiZGF0YVRhYmxlc19lbXB0eVwiLFxuXHRcblx0XHQvKiBGZWF0dXJlcyAqL1xuXHRcdFwic1dyYXBwZXJcIjogXCJkYXRhVGFibGVzX3dyYXBwZXJcIixcblx0XHRcInNGaWx0ZXJcIjogXCJkYXRhVGFibGVzX2ZpbHRlclwiLFxuXHRcdFwic0luZm9cIjogXCJkYXRhVGFibGVzX2luZm9cIixcblx0XHRcInNQYWdpbmdcIjogXCJkYXRhVGFibGVzX3BhZ2luYXRlIHBhZ2luZ19cIiwgLyogTm90ZSB0aGF0IHRoZSB0eXBlIGlzIHBvc3RmaXhlZCAqL1xuXHRcdFwic0xlbmd0aFwiOiBcImRhdGFUYWJsZXNfbGVuZ3RoXCIsXG5cdFx0XCJzUHJvY2Vzc2luZ1wiOiBcImRhdGFUYWJsZXNfcHJvY2Vzc2luZ1wiLFxuXHRcblx0XHQvKiBTb3J0aW5nICovXG5cdFx0XCJzU29ydEFzY1wiOiBcInNvcnRpbmdfYXNjXCIsXG5cdFx0XCJzU29ydERlc2NcIjogXCJzb3J0aW5nX2Rlc2NcIixcblx0XHRcInNTb3J0YWJsZVwiOiBcInNvcnRpbmdcIiwgLyogU29ydGFibGUgaW4gYm90aCBkaXJlY3Rpb25zICovXG5cdFx0XCJzU29ydGFibGVBc2NcIjogXCJzb3J0aW5nX2Rlc2NfZGlzYWJsZWRcIixcblx0XHRcInNTb3J0YWJsZURlc2NcIjogXCJzb3J0aW5nX2FzY19kaXNhYmxlZFwiLFxuXHRcdFwic1NvcnRhYmxlTm9uZVwiOiBcInNvcnRpbmdfZGlzYWJsZWRcIixcblx0XHRcInNTb3J0Q29sdW1uXCI6IFwic29ydGluZ19cIiwgLyogTm90ZSB0aGF0IGFuIGludCBpcyBwb3N0Zml4ZWQgZm9yIHRoZSBzb3J0aW5nIG9yZGVyICovXG5cdFxuXHRcdC8qIEZpbHRlcmluZyAqL1xuXHRcdFwic0ZpbHRlcklucHV0XCI6IFwiXCIsXG5cdFxuXHRcdC8qIFBhZ2UgbGVuZ3RoICovXG5cdFx0XCJzTGVuZ3RoU2VsZWN0XCI6IFwiXCIsXG5cdFxuXHRcdC8qIFNjcm9sbGluZyAqL1xuXHRcdFwic1Njcm9sbFdyYXBwZXJcIjogXCJkYXRhVGFibGVzX3Njcm9sbFwiLFxuXHRcdFwic1Njcm9sbEhlYWRcIjogXCJkYXRhVGFibGVzX3Njcm9sbEhlYWRcIixcblx0XHRcInNTY3JvbGxIZWFkSW5uZXJcIjogXCJkYXRhVGFibGVzX3Njcm9sbEhlYWRJbm5lclwiLFxuXHRcdFwic1Njcm9sbEJvZHlcIjogXCJkYXRhVGFibGVzX3Njcm9sbEJvZHlcIixcblx0XHRcInNTY3JvbGxGb290XCI6IFwiZGF0YVRhYmxlc19zY3JvbGxGb290XCIsXG5cdFx0XCJzU2Nyb2xsRm9vdElubmVyXCI6IFwiZGF0YVRhYmxlc19zY3JvbGxGb290SW5uZXJcIixcblx0XG5cdFx0LyogTWlzYyAqL1xuXHRcdFwic0hlYWRlclRIXCI6IFwiXCIsXG5cdFx0XCJzRm9vdGVyVEhcIjogXCJcIixcblx0XG5cdFx0Ly8gRGVwcmVjYXRlZFxuXHRcdFwic1NvcnRKVUlBc2NcIjogXCJcIixcblx0XHRcInNTb3J0SlVJRGVzY1wiOiBcIlwiLFxuXHRcdFwic1NvcnRKVUlcIjogXCJcIixcblx0XHRcInNTb3J0SlVJQXNjQWxsb3dlZFwiOiBcIlwiLFxuXHRcdFwic1NvcnRKVUlEZXNjQWxsb3dlZFwiOiBcIlwiLFxuXHRcdFwic1NvcnRKVUlXcmFwcGVyXCI6IFwiXCIsXG5cdFx0XCJzU29ydEljb25cIjogXCJcIixcblx0XHRcInNKVUlIZWFkZXJcIjogXCJcIixcblx0XHRcInNKVUlGb290ZXJcIjogXCJcIlxuXHR9ICk7XG5cdFxuXHRcblx0dmFyIGV4dFBhZ2luYXRpb24gPSBEYXRhVGFibGUuZXh0LnBhZ2VyO1xuXHRcblx0ZnVuY3Rpb24gX251bWJlcnMgKCBwYWdlLCBwYWdlcyApIHtcblx0XHR2YXJcblx0XHRcdG51bWJlcnMgPSBbXSxcblx0XHRcdGJ1dHRvbnMgPSBleHRQYWdpbmF0aW9uLm51bWJlcnNfbGVuZ3RoLFxuXHRcdFx0aGFsZiA9IE1hdGguZmxvb3IoIGJ1dHRvbnMgLyAyICksXG5cdFx0XHRpID0gMTtcblx0XG5cdFx0aWYgKCBwYWdlcyA8PSBidXR0b25zICkge1xuXHRcdFx0bnVtYmVycyA9IF9yYW5nZSggMCwgcGFnZXMgKTtcblx0XHR9XG5cdFx0ZWxzZSBpZiAoIHBhZ2UgPD0gaGFsZiApIHtcblx0XHRcdG51bWJlcnMgPSBfcmFuZ2UoIDAsIGJ1dHRvbnMtMiApO1xuXHRcdFx0bnVtYmVycy5wdXNoKCAnZWxsaXBzaXMnICk7XG5cdFx0XHRudW1iZXJzLnB1c2goIHBhZ2VzLTEgKTtcblx0XHR9XG5cdFx0ZWxzZSBpZiAoIHBhZ2UgPj0gcGFnZXMgLSAxIC0gaGFsZiApIHtcblx0XHRcdG51bWJlcnMgPSBfcmFuZ2UoIHBhZ2VzLShidXR0b25zLTIpLCBwYWdlcyApO1xuXHRcdFx0bnVtYmVycy5zcGxpY2UoIDAsIDAsICdlbGxpcHNpcycgKTsgLy8gbm8gdW5zaGlmdCBpbiBpZTZcblx0XHRcdG51bWJlcnMuc3BsaWNlKCAwLCAwLCAwICk7XG5cdFx0fVxuXHRcdGVsc2Uge1xuXHRcdFx0bnVtYmVycyA9IF9yYW5nZSggcGFnZS1oYWxmKzIsIHBhZ2UraGFsZi0xICk7XG5cdFx0XHRudW1iZXJzLnB1c2goICdlbGxpcHNpcycgKTtcblx0XHRcdG51bWJlcnMucHVzaCggcGFnZXMtMSApO1xuXHRcdFx0bnVtYmVycy5zcGxpY2UoIDAsIDAsICdlbGxpcHNpcycgKTtcblx0XHRcdG51bWJlcnMuc3BsaWNlKCAwLCAwLCAwICk7XG5cdFx0fVxuXHRcblx0XHRudW1iZXJzLkRUX2VsID0gJ3NwYW4nO1xuXHRcdHJldHVybiBudW1iZXJzO1xuXHR9XG5cdFxuXHRcblx0JC5leHRlbmQoIGV4dFBhZ2luYXRpb24sIHtcblx0XHRzaW1wbGU6IGZ1bmN0aW9uICggcGFnZSwgcGFnZXMgKSB7XG5cdFx0XHRyZXR1cm4gWyAncHJldmlvdXMnLCAnbmV4dCcgXTtcblx0XHR9LFxuXHRcblx0XHRmdWxsOiBmdW5jdGlvbiAoIHBhZ2UsIHBhZ2VzICkge1xuXHRcdFx0cmV0dXJuIFsgICdmaXJzdCcsICdwcmV2aW91cycsICduZXh0JywgJ2xhc3QnIF07XG5cdFx0fSxcblx0XG5cdFx0bnVtYmVyczogZnVuY3Rpb24gKCBwYWdlLCBwYWdlcyApIHtcblx0XHRcdHJldHVybiBbIF9udW1iZXJzKHBhZ2UsIHBhZ2VzKSBdO1xuXHRcdH0sXG5cdFxuXHRcdHNpbXBsZV9udW1iZXJzOiBmdW5jdGlvbiAoIHBhZ2UsIHBhZ2VzICkge1xuXHRcdFx0cmV0dXJuIFsgJ3ByZXZpb3VzJywgX251bWJlcnMocGFnZSwgcGFnZXMpLCAnbmV4dCcgXTtcblx0XHR9LFxuXHRcblx0XHRmdWxsX251bWJlcnM6IGZ1bmN0aW9uICggcGFnZSwgcGFnZXMgKSB7XG5cdFx0XHRyZXR1cm4gWyAnZmlyc3QnLCAncHJldmlvdXMnLCBfbnVtYmVycyhwYWdlLCBwYWdlcyksICduZXh0JywgJ2xhc3QnIF07XG5cdFx0fSxcblx0XHRcblx0XHRmaXJzdF9sYXN0X251bWJlcnM6IGZ1bmN0aW9uIChwYWdlLCBwYWdlcykge1xuXHQgXHRcdHJldHVybiBbJ2ZpcnN0JywgX251bWJlcnMocGFnZSwgcGFnZXMpLCAnbGFzdCddO1xuXHQgXHR9LFxuXHRcblx0XHQvLyBGb3IgdGVzdGluZyBhbmQgcGx1Zy1pbnMgdG8gdXNlXG5cdFx0X251bWJlcnM6IF9udW1iZXJzLFxuXHRcblx0XHQvLyBOdW1iZXIgb2YgbnVtYmVyIGJ1dHRvbnMgKGluY2x1ZGluZyBlbGxpcHNpcykgdG8gc2hvdy4gX011c3QgYmUgb2RkIV9cblx0XHRudW1iZXJzX2xlbmd0aDogN1xuXHR9ICk7XG5cdFxuXHRcblx0JC5leHRlbmQoIHRydWUsIERhdGFUYWJsZS5leHQucmVuZGVyZXIsIHtcblx0XHRwYWdlQnV0dG9uOiB7XG5cdFx0XHRfOiBmdW5jdGlvbiAoIHNldHRpbmdzLCBob3N0LCBpZHgsIGJ1dHRvbnMsIHBhZ2UsIHBhZ2VzICkge1xuXHRcdFx0XHR2YXIgY2xhc3NlcyA9IHNldHRpbmdzLm9DbGFzc2VzO1xuXHRcdFx0XHR2YXIgbGFuZyA9IHNldHRpbmdzLm9MYW5ndWFnZS5vUGFnaW5hdGU7XG5cdFx0XHRcdHZhciBhcmlhID0gc2V0dGluZ3Mub0xhbmd1YWdlLm9BcmlhLnBhZ2luYXRlIHx8IHt9O1xuXHRcdFx0XHR2YXIgYnRuRGlzcGxheSwgYnRuQ2xhc3MsIGNvdW50ZXI9MDtcblx0XG5cdFx0XHRcdHZhciBhdHRhY2ggPSBmdW5jdGlvbiggY29udGFpbmVyLCBidXR0b25zICkge1xuXHRcdFx0XHRcdHZhciBpLCBpZW4sIG5vZGUsIGJ1dHRvbiwgdGFiSW5kZXg7XG5cdFx0XHRcdFx0dmFyIGRpc2FibGVkQ2xhc3MgPSBjbGFzc2VzLnNQYWdlQnV0dG9uRGlzYWJsZWQ7XG5cdFx0XHRcdFx0dmFyIGNsaWNrSGFuZGxlciA9IGZ1bmN0aW9uICggZSApIHtcblx0XHRcdFx0XHRcdF9mblBhZ2VDaGFuZ2UoIHNldHRpbmdzLCBlLmRhdGEuYWN0aW9uLCB0cnVlICk7XG5cdFx0XHRcdFx0fTtcblx0XG5cdFx0XHRcdFx0Zm9yICggaT0wLCBpZW49YnV0dG9ucy5sZW5ndGggOyBpPGllbiA7IGkrKyApIHtcblx0XHRcdFx0XHRcdGJ1dHRvbiA9IGJ1dHRvbnNbaV07XG5cdFxuXHRcdFx0XHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCBidXR0b24gKSApIHtcblx0XHRcdFx0XHRcdFx0dmFyIGlubmVyID0gJCggJzwnKyhidXR0b24uRFRfZWwgfHwgJ2RpdicpKycvPicgKVxuXHRcdFx0XHRcdFx0XHRcdC5hcHBlbmRUbyggY29udGFpbmVyICk7XG5cdFx0XHRcdFx0XHRcdGF0dGFjaCggaW5uZXIsIGJ1dHRvbiApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRcdGJ0bkRpc3BsYXkgPSBudWxsO1xuXHRcdFx0XHRcdFx0XHRidG5DbGFzcyA9IGJ1dHRvbjtcblx0XHRcdFx0XHRcdFx0dGFiSW5kZXggPSBzZXR0aW5ncy5pVGFiSW5kZXg7XG5cdFxuXHRcdFx0XHRcdFx0XHRzd2l0Y2ggKCBidXR0b24gKSB7XG5cdFx0XHRcdFx0XHRcdFx0Y2FzZSAnZWxsaXBzaXMnOlxuXHRcdFx0XHRcdFx0XHRcdFx0Y29udGFpbmVyLmFwcGVuZCgnPHNwYW4gY2xhc3M9XCJlbGxpcHNpc1wiPiYjeDIwMjY7PC9zcGFuPicpO1xuXHRcdFx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFxuXHRcdFx0XHRcdFx0XHRcdGNhc2UgJ2ZpcnN0Jzpcblx0XHRcdFx0XHRcdFx0XHRcdGJ0bkRpc3BsYXkgPSBsYW5nLnNGaXJzdDtcblx0XG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAoIHBhZ2UgPT09IDAgKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHRhYkluZGV4ID0gLTE7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGJ0bkNsYXNzICs9ICcgJyArIGRpc2FibGVkQ2xhc3M7XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0XHRicmVhaztcblx0XG5cdFx0XHRcdFx0XHRcdFx0Y2FzZSAncHJldmlvdXMnOlxuXHRcdFx0XHRcdFx0XHRcdFx0YnRuRGlzcGxheSA9IGxhbmcuc1ByZXZpb3VzO1xuXHRcblx0XHRcdFx0XHRcdFx0XHRcdGlmICggcGFnZSA9PT0gMCApIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0dGFiSW5kZXggPSAtMTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0YnRuQ2xhc3MgKz0gJyAnICsgZGlzYWJsZWRDbGFzcztcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcblx0XHRcdFx0XHRcdFx0XHRjYXNlICduZXh0Jzpcblx0XHRcdFx0XHRcdFx0XHRcdGJ0bkRpc3BsYXkgPSBsYW5nLnNOZXh0O1xuXHRcblx0XHRcdFx0XHRcdFx0XHRcdGlmICggcGFnZXMgPT09IDAgfHwgcGFnZSA9PT0gcGFnZXMtMSApIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0dGFiSW5kZXggPSAtMTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0YnRuQ2xhc3MgKz0gJyAnICsgZGlzYWJsZWRDbGFzcztcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcblx0XHRcdFx0XHRcdFx0XHRjYXNlICdsYXN0Jzpcblx0XHRcdFx0XHRcdFx0XHRcdGJ0bkRpc3BsYXkgPSBsYW5nLnNMYXN0O1xuXHRcblx0XHRcdFx0XHRcdFx0XHRcdGlmICggcGFnZXMgPT09IDAgfHwgcGFnZSA9PT0gcGFnZXMtMSApIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0dGFiSW5kZXggPSAtMTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0YnRuQ2xhc3MgKz0gJyAnICsgZGlzYWJsZWRDbGFzcztcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcblx0XHRcdFx0XHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdFx0XHRcdFx0YnRuRGlzcGxheSA9IHNldHRpbmdzLmZuRm9ybWF0TnVtYmVyKCBidXR0b24gKyAxICk7XG5cdFx0XHRcdFx0XHRcdFx0XHRidG5DbGFzcyA9IHBhZ2UgPT09IGJ1dHRvbiA/XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGNsYXNzZXMuc1BhZ2VCdXR0b25BY3RpdmUgOiAnJztcblx0XHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFxuXHRcdFx0XHRcdFx0XHRpZiAoIGJ0bkRpc3BsYXkgIT09IG51bGwgKSB7XG5cdFx0XHRcdFx0XHRcdFx0bm9kZSA9ICQoJzxhPicsIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0J2NsYXNzJzogY2xhc3Nlcy5zUGFnZUJ1dHRvbisnICcrYnRuQ2xhc3MsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdCdhcmlhLWNvbnRyb2xzJzogc2V0dGluZ3Muc1RhYmxlSWQsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdCdhcmlhLWxhYmVsJzogYXJpYVsgYnV0dG9uIF0sXG5cdFx0XHRcdFx0XHRcdFx0XHRcdCdkYXRhLWR0LWlkeCc6IGNvdW50ZXIsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdCd0YWJpbmRleCc6IHRhYkluZGV4LFxuXHRcdFx0XHRcdFx0XHRcdFx0XHQnaWQnOiBpZHggPT09IDAgJiYgdHlwZW9mIGJ1dHRvbiA9PT0gJ3N0cmluZycgP1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHNldHRpbmdzLnNUYWJsZUlkICsnXycrIGJ1dHRvbiA6XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0bnVsbFxuXHRcdFx0XHRcdFx0XHRcdFx0fSApXG5cdFx0XHRcdFx0XHRcdFx0XHQuaHRtbCggYnRuRGlzcGxheSApXG5cdFx0XHRcdFx0XHRcdFx0XHQuYXBwZW5kVG8oIGNvbnRhaW5lciApO1xuXHRcblx0XHRcdFx0XHRcdFx0XHRfZm5CaW5kQWN0aW9uKFxuXHRcdFx0XHRcdFx0XHRcdFx0bm9kZSwge2FjdGlvbjogYnV0dG9ufSwgY2xpY2tIYW5kbGVyXG5cdFx0XHRcdFx0XHRcdFx0KTtcblx0XG5cdFx0XHRcdFx0XHRcdFx0Y291bnRlcisrO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9O1xuXHRcblx0XHRcdFx0Ly8gSUU5IHRocm93cyBhbiAndW5rbm93biBlcnJvcicgaWYgZG9jdW1lbnQuYWN0aXZlRWxlbWVudCBpcyB1c2VkXG5cdFx0XHRcdC8vIGluc2lkZSBhbiBpZnJhbWUgb3IgZnJhbWUuIFRyeSAvIGNhdGNoIHRoZSBlcnJvci4gTm90IGdvb2QgZm9yXG5cdFx0XHRcdC8vIGFjY2Vzc2liaWxpdHksIGJ1dCBuZWl0aGVyIGFyZSBmcmFtZXMuXG5cdFx0XHRcdHZhciBhY3RpdmVFbDtcblx0XG5cdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0Ly8gQmVjYXVzZSB0aGlzIGFwcHJvYWNoIGlzIGRlc3Ryb3lpbmcgYW5kIHJlY3JlYXRpbmcgdGhlIHBhZ2luZ1xuXHRcdFx0XHRcdC8vIGVsZW1lbnRzLCBmb2N1cyBpcyBsb3N0IG9uIHRoZSBzZWxlY3QgYnV0dG9uIHdoaWNoIGlzIGJhZCBmb3Jcblx0XHRcdFx0XHQvLyBhY2Nlc3NpYmlsaXR5LiBTbyB3ZSB3YW50IHRvIHJlc3RvcmUgZm9jdXMgb25jZSB0aGUgZHJhdyBoYXNcblx0XHRcdFx0XHQvLyBjb21wbGV0ZWRcblx0XHRcdFx0XHRhY3RpdmVFbCA9ICQoaG9zdCkuZmluZChkb2N1bWVudC5hY3RpdmVFbGVtZW50KS5kYXRhKCdkdC1pZHgnKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRjYXRjaCAoZSkge31cblx0XG5cdFx0XHRcdGF0dGFjaCggJChob3N0KS5lbXB0eSgpLCBidXR0b25zICk7XG5cdFxuXHRcdFx0XHRpZiAoIGFjdGl2ZUVsICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0JChob3N0KS5maW5kKCAnW2RhdGEtZHQtaWR4PScrYWN0aXZlRWwrJ10nICkudHJpZ2dlcignZm9jdXMnKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fSApO1xuXHRcblx0XG5cdFxuXHQvLyBCdWlsdCBpbiB0eXBlIGRldGVjdGlvbi4gU2VlIG1vZGVsLmV4dC5hVHlwZXMgZm9yIGluZm9ybWF0aW9uIGFib3V0XG5cdC8vIHdoYXQgaXMgcmVxdWlyZWQgZnJvbSB0aGlzIG1ldGhvZHMuXG5cdCQuZXh0ZW5kKCBEYXRhVGFibGUuZXh0LnR5cGUuZGV0ZWN0LCBbXG5cdFx0Ly8gUGxhaW4gbnVtYmVycyAtIGZpcnN0IHNpbmNlIFY4IGRldGVjdHMgc29tZSBwbGFpbiBudW1iZXJzIGFzIGRhdGVzXG5cdFx0Ly8gZS5nLiBEYXRlLnBhcnNlKCc1NScpIChidXQgbm90IGFsbCwgZS5nLiBEYXRlLnBhcnNlKCcyMicpLi4uKS5cblx0XHRmdW5jdGlvbiAoIGQsIHNldHRpbmdzIClcblx0XHR7XG5cdFx0XHR2YXIgZGVjaW1hbCA9IHNldHRpbmdzLm9MYW5ndWFnZS5zRGVjaW1hbDtcblx0XHRcdHJldHVybiBfaXNOdW1iZXIoIGQsIGRlY2ltYWwgKSA/ICdudW0nK2RlY2ltYWwgOiBudWxsO1xuXHRcdH0sXG5cdFxuXHRcdC8vIERhdGVzIChvbmx5IHRob3NlIHJlY29nbmlzZWQgYnkgdGhlIGJyb3dzZXIncyBEYXRlLnBhcnNlKVxuXHRcdGZ1bmN0aW9uICggZCwgc2V0dGluZ3MgKVxuXHRcdHtcblx0XHRcdC8vIFY4IHRyaWVzIF92ZXJ5XyBoYXJkIHRvIG1ha2UgYSBzdHJpbmcgcGFzc2VkIGludG8gYERhdGUucGFyc2UoKWBcblx0XHRcdC8vIHZhbGlkLCBzbyB3ZSBuZWVkIHRvIHVzZSBhIHJlZ2V4IHRvIHJlc3RyaWN0IGRhdGUgZm9ybWF0cy4gVXNlIGFcblx0XHRcdC8vIHBsdWctaW4gZm9yIGFueXRoaW5nIG90aGVyIHRoYW4gSVNPODYwMSBzdHlsZSBzdHJpbmdzXG5cdFx0XHRpZiAoIGQgJiYgIShkIGluc3RhbmNlb2YgRGF0ZSkgJiYgISBfcmVfZGF0ZS50ZXN0KGQpICkge1xuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblx0XHRcdH1cblx0XHRcdHZhciBwYXJzZWQgPSBEYXRlLnBhcnNlKGQpO1xuXHRcdFx0cmV0dXJuIChwYXJzZWQgIT09IG51bGwgJiYgIWlzTmFOKHBhcnNlZCkpIHx8IF9lbXB0eShkKSA/ICdkYXRlJyA6IG51bGw7XG5cdFx0fSxcblx0XG5cdFx0Ly8gRm9ybWF0dGVkIG51bWJlcnNcblx0XHRmdW5jdGlvbiAoIGQsIHNldHRpbmdzIClcblx0XHR7XG5cdFx0XHR2YXIgZGVjaW1hbCA9IHNldHRpbmdzLm9MYW5ndWFnZS5zRGVjaW1hbDtcblx0XHRcdHJldHVybiBfaXNOdW1iZXIoIGQsIGRlY2ltYWwsIHRydWUgKSA/ICdudW0tZm10JytkZWNpbWFsIDogbnVsbDtcblx0XHR9LFxuXHRcblx0XHQvLyBIVE1MIG51bWVyaWNcblx0XHRmdW5jdGlvbiAoIGQsIHNldHRpbmdzIClcblx0XHR7XG5cdFx0XHR2YXIgZGVjaW1hbCA9IHNldHRpbmdzLm9MYW5ndWFnZS5zRGVjaW1hbDtcblx0XHRcdHJldHVybiBfaHRtbE51bWVyaWMoIGQsIGRlY2ltYWwgKSA/ICdodG1sLW51bScrZGVjaW1hbCA6IG51bGw7XG5cdFx0fSxcblx0XG5cdFx0Ly8gSFRNTCBudW1lcmljLCBmb3JtYXR0ZWRcblx0XHRmdW5jdGlvbiAoIGQsIHNldHRpbmdzIClcblx0XHR7XG5cdFx0XHR2YXIgZGVjaW1hbCA9IHNldHRpbmdzLm9MYW5ndWFnZS5zRGVjaW1hbDtcblx0XHRcdHJldHVybiBfaHRtbE51bWVyaWMoIGQsIGRlY2ltYWwsIHRydWUgKSA/ICdodG1sLW51bS1mbXQnK2RlY2ltYWwgOiBudWxsO1xuXHRcdH0sXG5cdFxuXHRcdC8vIEhUTUwgKHRoaXMgaXMgc3RyaWN0IGNoZWNraW5nIC0gdGhlcmUgbXVzdCBiZSBodG1sKVxuXHRcdGZ1bmN0aW9uICggZCwgc2V0dGluZ3MgKVxuXHRcdHtcblx0XHRcdHJldHVybiBfZW1wdHkoIGQgKSB8fCAodHlwZW9mIGQgPT09ICdzdHJpbmcnICYmIGQuaW5kZXhPZignPCcpICE9PSAtMSkgP1xuXHRcdFx0XHQnaHRtbCcgOiBudWxsO1xuXHRcdH1cblx0XSApO1xuXHRcblx0XG5cdFxuXHQvLyBGaWx0ZXIgZm9ybWF0dGluZyBmdW5jdGlvbnMuIFNlZSBtb2RlbC5leHQub2ZuU2VhcmNoIGZvciBpbmZvcm1hdGlvbiBhYm91dFxuXHQvLyB3aGF0IGlzIHJlcXVpcmVkIGZyb20gdGhlc2UgbWV0aG9kcy5cblx0Ly8gXG5cdC8vIE5vdGUgdGhhdCBhZGRpdGlvbmFsIHNlYXJjaCBtZXRob2RzIGFyZSBhZGRlZCBmb3IgdGhlIGh0bWwgbnVtYmVycyBhbmRcblx0Ly8gaHRtbCBmb3JtYXR0ZWQgbnVtYmVycyBieSBgX2FkZE51bWVyaWNTb3J0KClgIHdoZW4gd2Uga25vdyB3aGF0IHRoZSBkZWNpbWFsXG5cdC8vIHBsYWNlIGlzXG5cdFxuXHRcblx0JC5leHRlbmQoIERhdGFUYWJsZS5leHQudHlwZS5zZWFyY2gsIHtcblx0XHRodG1sOiBmdW5jdGlvbiAoIGRhdGEgKSB7XG5cdFx0XHRyZXR1cm4gX2VtcHR5KGRhdGEpID9cblx0XHRcdFx0ZGF0YSA6XG5cdFx0XHRcdHR5cGVvZiBkYXRhID09PSAnc3RyaW5nJyA/XG5cdFx0XHRcdFx0ZGF0YVxuXHRcdFx0XHRcdFx0LnJlcGxhY2UoIF9yZV9uZXdfbGluZXMsIFwiIFwiIClcblx0XHRcdFx0XHRcdC5yZXBsYWNlKCBfcmVfaHRtbCwgXCJcIiApIDpcblx0XHRcdFx0XHQnJztcblx0XHR9LFxuXHRcblx0XHRzdHJpbmc6IGZ1bmN0aW9uICggZGF0YSApIHtcblx0XHRcdHJldHVybiBfZW1wdHkoZGF0YSkgP1xuXHRcdFx0XHRkYXRhIDpcblx0XHRcdFx0dHlwZW9mIGRhdGEgPT09ICdzdHJpbmcnID9cblx0XHRcdFx0XHRkYXRhLnJlcGxhY2UoIF9yZV9uZXdfbGluZXMsIFwiIFwiICkgOlxuXHRcdFx0XHRcdGRhdGE7XG5cdFx0fVxuXHR9ICk7XG5cdFxuXHRcblx0XG5cdHZhciBfX251bWVyaWNSZXBsYWNlID0gZnVuY3Rpb24gKCBkLCBkZWNpbWFsUGxhY2UsIHJlMSwgcmUyICkge1xuXHRcdGlmICggZCAhPT0gMCAmJiAoIWQgfHwgZCA9PT0gJy0nKSApIHtcblx0XHRcdHJldHVybiAtSW5maW5pdHk7XG5cdFx0fVxuXHRcblx0XHQvLyBJZiBhIGRlY2ltYWwgcGxhY2Ugb3RoZXIgdGhhbiBgLmAgaXMgdXNlZCwgaXQgbmVlZHMgdG8gYmUgZ2l2ZW4gdG8gdGhlXG5cdFx0Ly8gZnVuY3Rpb24gc28gd2UgY2FuIGRldGVjdCBpdCBhbmQgcmVwbGFjZSB3aXRoIGEgYC5gIHdoaWNoIGlzIHRoZSBvbmx5XG5cdFx0Ly8gZGVjaW1hbCBwbGFjZSBKYXZhc2NyaXB0IHJlY29nbmlzZXMgLSBpdCBpcyBub3QgbG9jYWxlIGF3YXJlLlxuXHRcdGlmICggZGVjaW1hbFBsYWNlICkge1xuXHRcdFx0ZCA9IF9udW1Ub0RlY2ltYWwoIGQsIGRlY2ltYWxQbGFjZSApO1xuXHRcdH1cblx0XG5cdFx0aWYgKCBkLnJlcGxhY2UgKSB7XG5cdFx0XHRpZiAoIHJlMSApIHtcblx0XHRcdFx0ZCA9IGQucmVwbGFjZSggcmUxLCAnJyApO1xuXHRcdFx0fVxuXHRcblx0XHRcdGlmICggcmUyICkge1xuXHRcdFx0XHRkID0gZC5yZXBsYWNlKCByZTIsICcnICk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcblx0XHRyZXR1cm4gZCAqIDE7XG5cdH07XG5cdFxuXHRcblx0Ly8gQWRkIHRoZSBudW1lcmljICdkZWZvcm1hdHRpbmcnIGZ1bmN0aW9ucyBmb3Igc29ydGluZyBhbmQgc2VhcmNoLiBUaGlzIGlzIGRvbmVcblx0Ly8gaW4gYSBmdW5jdGlvbiB0byBwcm92aWRlIGFuIGVhc3kgYWJpbGl0eSBmb3IgdGhlIGxhbmd1YWdlIG9wdGlvbnMgdG8gYWRkXG5cdC8vIGFkZGl0aW9uYWwgbWV0aG9kcyBpZiBhIG5vbi1wZXJpb2QgZGVjaW1hbCBwbGFjZSBpcyB1c2VkLlxuXHRmdW5jdGlvbiBfYWRkTnVtZXJpY1NvcnQgKCBkZWNpbWFsUGxhY2UgKSB7XG5cdFx0JC5lYWNoKFxuXHRcdFx0e1xuXHRcdFx0XHQvLyBQbGFpbiBudW1iZXJzXG5cdFx0XHRcdFwibnVtXCI6IGZ1bmN0aW9uICggZCApIHtcblx0XHRcdFx0XHRyZXR1cm4gX19udW1lcmljUmVwbGFjZSggZCwgZGVjaW1hbFBsYWNlICk7XG5cdFx0XHRcdH0sXG5cdFxuXHRcdFx0XHQvLyBGb3JtYXR0ZWQgbnVtYmVyc1xuXHRcdFx0XHRcIm51bS1mbXRcIjogZnVuY3Rpb24gKCBkICkge1xuXHRcdFx0XHRcdHJldHVybiBfX251bWVyaWNSZXBsYWNlKCBkLCBkZWNpbWFsUGxhY2UsIF9yZV9mb3JtYXR0ZWRfbnVtZXJpYyApO1xuXHRcdFx0XHR9LFxuXHRcblx0XHRcdFx0Ly8gSFRNTCBudW1lcmljXG5cdFx0XHRcdFwiaHRtbC1udW1cIjogZnVuY3Rpb24gKCBkICkge1xuXHRcdFx0XHRcdHJldHVybiBfX251bWVyaWNSZXBsYWNlKCBkLCBkZWNpbWFsUGxhY2UsIF9yZV9odG1sICk7XG5cdFx0XHRcdH0sXG5cdFxuXHRcdFx0XHQvLyBIVE1MIG51bWVyaWMsIGZvcm1hdHRlZFxuXHRcdFx0XHRcImh0bWwtbnVtLWZtdFwiOiBmdW5jdGlvbiAoIGQgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIF9fbnVtZXJpY1JlcGxhY2UoIGQsIGRlY2ltYWxQbGFjZSwgX3JlX2h0bWwsIF9yZV9mb3JtYXR0ZWRfbnVtZXJpYyApO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0ZnVuY3Rpb24gKCBrZXksIGZuICkge1xuXHRcdFx0XHQvLyBBZGQgdGhlIG9yZGVyaW5nIG1ldGhvZFxuXHRcdFx0XHRfZXh0LnR5cGUub3JkZXJbIGtleStkZWNpbWFsUGxhY2UrJy1wcmUnIF0gPSBmbjtcblx0XG5cdFx0XHRcdC8vIEZvciBIVE1MIHR5cGVzIGFkZCBhIHNlYXJjaCBmb3JtYXR0ZXIgdGhhdCB3aWxsIHN0cmlwIHRoZSBIVE1MXG5cdFx0XHRcdGlmICgga2V5Lm1hdGNoKC9eaHRtbFxcLS8pICkge1xuXHRcdFx0XHRcdF9leHQudHlwZS5zZWFyY2hbIGtleStkZWNpbWFsUGxhY2UgXSA9IF9leHQudHlwZS5zZWFyY2guaHRtbDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdCk7XG5cdH1cblx0XG5cdFxuXHQvLyBEZWZhdWx0IHNvcnQgbWV0aG9kc1xuXHQkLmV4dGVuZCggX2V4dC50eXBlLm9yZGVyLCB7XG5cdFx0Ly8gRGF0ZXNcblx0XHRcImRhdGUtcHJlXCI6IGZ1bmN0aW9uICggZCApIHtcblx0XHRcdHZhciB0cyA9IERhdGUucGFyc2UoIGQgKTtcblx0XHRcdHJldHVybiBpc05hTih0cykgPyAtSW5maW5pdHkgOiB0cztcblx0XHR9LFxuXHRcblx0XHQvLyBodG1sXG5cdFx0XCJodG1sLXByZVwiOiBmdW5jdGlvbiAoIGEgKSB7XG5cdFx0XHRyZXR1cm4gX2VtcHR5KGEpID9cblx0XHRcdFx0JycgOlxuXHRcdFx0XHRhLnJlcGxhY2UgP1xuXHRcdFx0XHRcdGEucmVwbGFjZSggLzwuKj8+L2csIFwiXCIgKS50b0xvd2VyQ2FzZSgpIDpcblx0XHRcdFx0XHRhKycnO1xuXHRcdH0sXG5cdFxuXHRcdC8vIHN0cmluZ1xuXHRcdFwic3RyaW5nLXByZVwiOiBmdW5jdGlvbiAoIGEgKSB7XG5cdFx0XHQvLyBUaGlzIGlzIGEgbGl0dGxlIGNvbXBsZXgsIGJ1dCBmYXN0ZXIgdGhhbiBhbHdheXMgY2FsbGluZyB0b1N0cmluZyxcblx0XHRcdC8vIGh0dHA6Ly9qc3BlcmYuY29tL3Rvc3RyaW5nLXYtY2hlY2tcblx0XHRcdHJldHVybiBfZW1wdHkoYSkgP1xuXHRcdFx0XHQnJyA6XG5cdFx0XHRcdHR5cGVvZiBhID09PSAnc3RyaW5nJyA/XG5cdFx0XHRcdFx0YS50b0xvd2VyQ2FzZSgpIDpcblx0XHRcdFx0XHQhIGEudG9TdHJpbmcgP1xuXHRcdFx0XHRcdFx0JycgOlxuXHRcdFx0XHRcdFx0YS50b1N0cmluZygpO1xuXHRcdH0sXG5cdFxuXHRcdC8vIHN0cmluZy1hc2MgYW5kIC1kZXNjIGFyZSByZXRhaW5lZCBvbmx5IGZvciBjb21wYXRpYmlsaXR5IHdpdGggdGhlIG9sZFxuXHRcdC8vIHNvcnQgbWV0aG9kc1xuXHRcdFwic3RyaW5nLWFzY1wiOiBmdW5jdGlvbiAoIHgsIHkgKSB7XG5cdFx0XHRyZXR1cm4gKCh4IDwgeSkgPyAtMSA6ICgoeCA+IHkpID8gMSA6IDApKTtcblx0XHR9LFxuXHRcblx0XHRcInN0cmluZy1kZXNjXCI6IGZ1bmN0aW9uICggeCwgeSApIHtcblx0XHRcdHJldHVybiAoKHggPCB5KSA/IDEgOiAoKHggPiB5KSA/IC0xIDogMCkpO1xuXHRcdH1cblx0fSApO1xuXHRcblx0XG5cdC8vIE51bWVyaWMgc29ydGluZyB0eXBlcyAtIG9yZGVyIGRvZXNuJ3QgbWF0dGVyIGhlcmVcblx0X2FkZE51bWVyaWNTb3J0KCAnJyApO1xuXHRcblx0XG5cdCQuZXh0ZW5kKCB0cnVlLCBEYXRhVGFibGUuZXh0LnJlbmRlcmVyLCB7XG5cdFx0aGVhZGVyOiB7XG5cdFx0XHRfOiBmdW5jdGlvbiAoIHNldHRpbmdzLCBjZWxsLCBjb2x1bW4sIGNsYXNzZXMgKSB7XG5cdFx0XHRcdC8vIE5vIGFkZGl0aW9uYWwgbWFyay11cCByZXF1aXJlZFxuXHRcdFx0XHQvLyBBdHRhY2ggYSBzb3J0IGxpc3RlbmVyIHRvIHVwZGF0ZSBvbiBzb3J0IC0gbm90ZSB0aGF0IHVzaW5nIHRoZVxuXHRcdFx0XHQvLyBgRFRgIG5hbWVzcGFjZSB3aWxsIGFsbG93IHRoZSBldmVudCB0byBiZSByZW1vdmVkIGF1dG9tYXRpY2FsbHlcblx0XHRcdFx0Ly8gb24gZGVzdHJveSwgd2hpbGUgdGhlIGBkdGAgbmFtZXNwYWNlZCBldmVudCBpcyB0aGUgb25lIHdlIGFyZVxuXHRcdFx0XHQvLyBsaXN0ZW5pbmcgZm9yXG5cdFx0XHRcdCQoc2V0dGluZ3MublRhYmxlKS5vbiggJ29yZGVyLmR0LkRUJywgZnVuY3Rpb24gKCBlLCBjdHgsIHNvcnRpbmcsIGNvbHVtbnMgKSB7XG5cdFx0XHRcdFx0aWYgKCBzZXR0aW5ncyAhPT0gY3R4ICkgeyAvLyBuZWVkIHRvIGNoZWNrIHRoaXMgdGhpcyBpcyB0aGUgaG9zdFxuXHRcdFx0XHRcdFx0cmV0dXJuOyAgICAgICAgICAgICAgIC8vIHRhYmxlLCBub3QgYSBuZXN0ZWQgb25lXG5cdFx0XHRcdFx0fVxuXHRcblx0XHRcdFx0XHR2YXIgY29sSWR4ID0gY29sdW1uLmlkeDtcblx0XG5cdFx0XHRcdFx0Y2VsbFxuXHRcdFx0XHRcdFx0LnJlbW92ZUNsYXNzKFxuXHRcdFx0XHRcdFx0XHRjbGFzc2VzLnNTb3J0QXNjICsnICcrXG5cdFx0XHRcdFx0XHRcdGNsYXNzZXMuc1NvcnREZXNjXG5cdFx0XHRcdFx0XHQpXG5cdFx0XHRcdFx0XHQuYWRkQ2xhc3MoIGNvbHVtbnNbIGNvbElkeCBdID09ICdhc2MnID9cblx0XHRcdFx0XHRcdFx0Y2xhc3Nlcy5zU29ydEFzYyA6IGNvbHVtbnNbIGNvbElkeCBdID09ICdkZXNjJyA/XG5cdFx0XHRcdFx0XHRcdFx0Y2xhc3Nlcy5zU29ydERlc2MgOlxuXHRcdFx0XHRcdFx0XHRcdGNvbHVtbi5zU29ydGluZ0NsYXNzXG5cdFx0XHRcdFx0XHQpO1xuXHRcdFx0XHR9ICk7XG5cdFx0XHR9LFxuXHRcblx0XHRcdGpxdWVyeXVpOiBmdW5jdGlvbiAoIHNldHRpbmdzLCBjZWxsLCBjb2x1bW4sIGNsYXNzZXMgKSB7XG5cdFx0XHRcdCQoJzxkaXYvPicpXG5cdFx0XHRcdFx0LmFkZENsYXNzKCBjbGFzc2VzLnNTb3J0SlVJV3JhcHBlciApXG5cdFx0XHRcdFx0LmFwcGVuZCggY2VsbC5jb250ZW50cygpIClcblx0XHRcdFx0XHQuYXBwZW5kKCAkKCc8c3Bhbi8+Jylcblx0XHRcdFx0XHRcdC5hZGRDbGFzcyggY2xhc3Nlcy5zU29ydEljb24rJyAnK2NvbHVtbi5zU29ydGluZ0NsYXNzSlVJIClcblx0XHRcdFx0XHQpXG5cdFx0XHRcdFx0LmFwcGVuZFRvKCBjZWxsICk7XG5cdFxuXHRcdFx0XHQvLyBBdHRhY2ggYSBzb3J0IGxpc3RlbmVyIHRvIHVwZGF0ZSBvbiBzb3J0XG5cdFx0XHRcdCQoc2V0dGluZ3MublRhYmxlKS5vbiggJ29yZGVyLmR0LkRUJywgZnVuY3Rpb24gKCBlLCBjdHgsIHNvcnRpbmcsIGNvbHVtbnMgKSB7XG5cdFx0XHRcdFx0aWYgKCBzZXR0aW5ncyAhPT0gY3R4ICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdH1cblx0XG5cdFx0XHRcdFx0dmFyIGNvbElkeCA9IGNvbHVtbi5pZHg7XG5cdFxuXHRcdFx0XHRcdGNlbGxcblx0XHRcdFx0XHRcdC5yZW1vdmVDbGFzcyggY2xhc3Nlcy5zU29ydEFzYyArXCIgXCIrY2xhc3Nlcy5zU29ydERlc2MgKVxuXHRcdFx0XHRcdFx0LmFkZENsYXNzKCBjb2x1bW5zWyBjb2xJZHggXSA9PSAnYXNjJyA/XG5cdFx0XHRcdFx0XHRcdGNsYXNzZXMuc1NvcnRBc2MgOiBjb2x1bW5zWyBjb2xJZHggXSA9PSAnZGVzYycgP1xuXHRcdFx0XHRcdFx0XHRcdGNsYXNzZXMuc1NvcnREZXNjIDpcblx0XHRcdFx0XHRcdFx0XHRjb2x1bW4uc1NvcnRpbmdDbGFzc1xuXHRcdFx0XHRcdFx0KTtcblx0XG5cdFx0XHRcdFx0Y2VsbFxuXHRcdFx0XHRcdFx0LmZpbmQoICdzcGFuLicrY2xhc3Nlcy5zU29ydEljb24gKVxuXHRcdFx0XHRcdFx0LnJlbW92ZUNsYXNzKFxuXHRcdFx0XHRcdFx0XHRjbGFzc2VzLnNTb3J0SlVJQXNjICtcIiBcIitcblx0XHRcdFx0XHRcdFx0Y2xhc3Nlcy5zU29ydEpVSURlc2MgK1wiIFwiK1xuXHRcdFx0XHRcdFx0XHRjbGFzc2VzLnNTb3J0SlVJICtcIiBcIitcblx0XHRcdFx0XHRcdFx0Y2xhc3Nlcy5zU29ydEpVSUFzY0FsbG93ZWQgK1wiIFwiK1xuXHRcdFx0XHRcdFx0XHRjbGFzc2VzLnNTb3J0SlVJRGVzY0FsbG93ZWRcblx0XHRcdFx0XHRcdClcblx0XHRcdFx0XHRcdC5hZGRDbGFzcyggY29sdW1uc1sgY29sSWR4IF0gPT0gJ2FzYycgP1xuXHRcdFx0XHRcdFx0XHRjbGFzc2VzLnNTb3J0SlVJQXNjIDogY29sdW1uc1sgY29sSWR4IF0gPT0gJ2Rlc2MnID9cblx0XHRcdFx0XHRcdFx0XHRjbGFzc2VzLnNTb3J0SlVJRGVzYyA6XG5cdFx0XHRcdFx0XHRcdFx0Y29sdW1uLnNTb3J0aW5nQ2xhc3NKVUlcblx0XHRcdFx0XHRcdCk7XG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHR9XG5cdH0gKTtcblx0XG5cdC8qXG5cdCAqIFB1YmxpYyBoZWxwZXIgZnVuY3Rpb25zLiBUaGVzZSBhcmVuJ3QgdXNlZCBpbnRlcm5hbGx5IGJ5IERhdGFUYWJsZXMsIG9yXG5cdCAqIGNhbGxlZCBieSBhbnkgb2YgdGhlIG9wdGlvbnMgcGFzc2VkIGludG8gRGF0YVRhYmxlcywgYnV0IHRoZXkgY2FuIGJlIHVzZWRcblx0ICogZXh0ZXJuYWxseSBieSBkZXZlbG9wZXJzIHdvcmtpbmcgd2l0aCBEYXRhVGFibGVzLiBUaGV5IGFyZSBoZWxwZXIgZnVuY3Rpb25zXG5cdCAqIHRvIG1ha2Ugd29ya2luZyB3aXRoIERhdGFUYWJsZXMgYSBsaXR0bGUgYml0IGVhc2llci5cblx0ICovXG5cdFxuXHR2YXIgX19odG1sRXNjYXBlRW50aXRpZXMgPSBmdW5jdGlvbiAoIGQgKSB7XG5cdFx0aWYgKEFycmF5LmlzQXJyYXkoZCkpIHtcblx0XHRcdGQgPSBkLmpvaW4oJywnKTtcblx0XHR9XG5cdFxuXHRcdHJldHVybiB0eXBlb2YgZCA9PT0gJ3N0cmluZycgP1xuXHRcdFx0ZFxuXHRcdFx0XHQucmVwbGFjZSgvJi9nLCAnJmFtcDsnKVxuXHRcdFx0XHQucmVwbGFjZSgvPC9nLCAnJmx0OycpXG5cdFx0XHRcdC5yZXBsYWNlKC8+L2csICcmZ3Q7Jylcblx0XHRcdFx0LnJlcGxhY2UoL1wiL2csICcmcXVvdDsnKSA6XG5cdFx0XHRkO1xuXHR9O1xuXHRcblx0LyoqXG5cdCAqIEhlbHBlcnMgZm9yIGBjb2x1bW5zLnJlbmRlcmAuXG5cdCAqXG5cdCAqIFRoZSBvcHRpb25zIGRlZmluZWQgaGVyZSBjYW4gYmUgdXNlZCB3aXRoIHRoZSBgY29sdW1ucy5yZW5kZXJgIGluaXRpYWxpc2F0aW9uXG5cdCAqIG9wdGlvbiB0byBwcm92aWRlIGEgZGlzcGxheSByZW5kZXJlci4gVGhlIGZvbGxvd2luZyBmdW5jdGlvbnMgYXJlIGRlZmluZWQ6XG5cdCAqXG5cdCAqICogYG51bWJlcmAgLSBXaWxsIGZvcm1hdCBudW1lcmljIGRhdGEgKGRlZmluZWQgYnkgYGNvbHVtbnMuZGF0YWApIGZvclxuXHQgKiAgIGRpc3BsYXksIHJldGFpbmluZyB0aGUgb3JpZ2luYWwgdW5mb3JtYXR0ZWQgZGF0YSBmb3Igc29ydGluZyBhbmQgZmlsdGVyaW5nLlxuXHQgKiAgIEl0IHRha2VzIDUgcGFyYW1ldGVyczpcblx0ICogICAqIGBzdHJpbmdgIC0gVGhvdXNhbmRzIGdyb3VwaW5nIHNlcGFyYXRvclxuXHQgKiAgICogYHN0cmluZ2AgLSBEZWNpbWFsIHBvaW50IGluZGljYXRvclxuXHQgKiAgICogYGludGVnZXJgIC0gTnVtYmVyIG9mIGRlY2ltYWwgcG9pbnRzIHRvIHNob3dcblx0ICogICAqIGBzdHJpbmdgIChvcHRpb25hbCkgLSBQcmVmaXguXG5cdCAqICAgKiBgc3RyaW5nYCAob3B0aW9uYWwpIC0gUG9zdGZpeCAoL3N1ZmZpeCkuXG5cdCAqICogYHRleHRgIC0gRXNjYXBlIEhUTUwgdG8gaGVscCBwcmV2ZW50IFhTUyBhdHRhY2tzLiBJdCBoYXMgbm8gb3B0aW9uYWxcblx0ICogICBwYXJhbWV0ZXJzLlxuXHQgKlxuXHQgKiBAZXhhbXBsZVxuXHQgKiAgIC8vIENvbHVtbiBkZWZpbml0aW9uIHVzaW5nIHRoZSBudW1iZXIgcmVuZGVyZXJcblx0ICogICB7XG5cdCAqICAgICBkYXRhOiBcInNhbGFyeVwiLFxuXHQgKiAgICAgcmVuZGVyOiAkLmZuLmRhdGFUYWJsZS5yZW5kZXIubnVtYmVyKCAnXFwnJywgJy4nLCAwLCAnJCcgKVxuXHQgKiAgIH1cblx0ICpcblx0ICogQG5hbWVzcGFjZVxuXHQgKi9cblx0RGF0YVRhYmxlLnJlbmRlciA9IHtcblx0XHRudW1iZXI6IGZ1bmN0aW9uICggdGhvdXNhbmRzLCBkZWNpbWFsLCBwcmVjaXNpb24sIHByZWZpeCwgcG9zdGZpeCApIHtcblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdGRpc3BsYXk6IGZ1bmN0aW9uICggZCApIHtcblx0XHRcdFx0XHRpZiAoIHR5cGVvZiBkICE9PSAnbnVtYmVyJyAmJiB0eXBlb2YgZCAhPT0gJ3N0cmluZycgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZDtcblx0XHRcdFx0XHR9XG5cdFxuXHRcdFx0XHRcdHZhciBuZWdhdGl2ZSA9IGQgPCAwID8gJy0nIDogJyc7XG5cdFx0XHRcdFx0dmFyIGZsbyA9IHBhcnNlRmxvYXQoIGQgKTtcblx0XG5cdFx0XHRcdFx0Ly8gSWYgTmFOIHRoZW4gdGhlcmUgaXNuJ3QgbXVjaCBmb3JtYXR0aW5nIHRoYXQgd2UgY2FuIGRvIC0ganVzdFxuXHRcdFx0XHRcdC8vIHJldHVybiBpbW1lZGlhdGVseSwgZXNjYXBpbmcgYW55IEhUTUwgKHRoaXMgd2FzIHN1cHBvc2VkIHRvXG5cdFx0XHRcdFx0Ly8gYmUgYSBudW1iZXIgYWZ0ZXIgYWxsKVxuXHRcdFx0XHRcdGlmICggaXNOYU4oIGZsbyApICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIF9faHRtbEVzY2FwZUVudGl0aWVzKCBkICk7XG5cdFx0XHRcdFx0fVxuXHRcblx0XHRcdFx0XHRmbG8gPSBmbG8udG9GaXhlZCggcHJlY2lzaW9uICk7XG5cdFx0XHRcdFx0ZCA9IE1hdGguYWJzKCBmbG8gKTtcblx0XG5cdFx0XHRcdFx0dmFyIGludFBhcnQgPSBwYXJzZUludCggZCwgMTAgKTtcblx0XHRcdFx0XHR2YXIgZmxvYXRQYXJ0ID0gcHJlY2lzaW9uID9cblx0XHRcdFx0XHRcdGRlY2ltYWwrKGQgLSBpbnRQYXJ0KS50b0ZpeGVkKCBwcmVjaXNpb24gKS5zdWJzdHJpbmcoIDIgKTpcblx0XHRcdFx0XHRcdCcnO1xuXHRcblx0XHRcdFx0XHQvLyBJZiB6ZXJvLCB0aGVuIGNhbid0IGhhdmUgYSBuZWdhdGl2ZSBwcmVmaXhcblx0XHRcdFx0XHRpZiAoaW50UGFydCA9PT0gMCAmJiBwYXJzZUZsb2F0KGZsb2F0UGFydCkgPT09IDApIHtcblx0XHRcdFx0XHRcdG5lZ2F0aXZlID0gJyc7XG5cdFx0XHRcdFx0fVxuXHRcblx0XHRcdFx0XHRyZXR1cm4gbmVnYXRpdmUgKyAocHJlZml4fHwnJykgK1xuXHRcdFx0XHRcdFx0aW50UGFydC50b1N0cmluZygpLnJlcGxhY2UoXG5cdFx0XHRcdFx0XHRcdC9cXEIoPz0oXFxkezN9KSsoPyFcXGQpKS9nLCB0aG91c2FuZHNcblx0XHRcdFx0XHRcdCkgK1xuXHRcdFx0XHRcdFx0ZmxvYXRQYXJ0ICtcblx0XHRcdFx0XHRcdChwb3N0Zml4fHwnJyk7XG5cdFx0XHRcdH1cblx0XHRcdH07XG5cdFx0fSxcblx0XG5cdFx0dGV4dDogZnVuY3Rpb24gKCkge1xuXHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0ZGlzcGxheTogX19odG1sRXNjYXBlRW50aXRpZXMsXG5cdFx0XHRcdGZpbHRlcjogX19odG1sRXNjYXBlRW50aXRpZXNcblx0XHRcdH07XG5cdFx0fVxuXHR9O1xuXHRcblx0XG5cdC8qXG5cdCAqIFRoaXMgaXMgcmVhbGx5IGEgZ29vZCBiaXQgcnViYmlzaCB0aGlzIG1ldGhvZCBvZiBleHBvc2luZyB0aGUgaW50ZXJuYWwgbWV0aG9kc1xuXHQgKiBwdWJsaWNseS4uLiAtIFRvIGJlIGZpeGVkIGluIDIuMCB1c2luZyBtZXRob2RzIG9uIHRoZSBwcm90b3R5cGVcblx0ICovXG5cdFxuXHRcblx0LyoqXG5cdCAqIENyZWF0ZSBhIHdyYXBwZXIgZnVuY3Rpb24gZm9yIGV4cG9ydGluZyBhbiBpbnRlcm5hbCBmdW5jdGlvbnMgdG8gYW4gZXh0ZXJuYWwgQVBJLlxuXHQgKiAgQHBhcmFtIHtzdHJpbmd9IGZuIEFQSSBmdW5jdGlvbiBuYW1lXG5cdCAqICBAcmV0dXJucyB7ZnVuY3Rpb259IHdyYXBwZWQgZnVuY3Rpb25cblx0ICogIEBtZW1iZXJvZiBEYXRhVGFibGUjaW50ZXJuYWxcblx0ICovXG5cdGZ1bmN0aW9uIF9mbkV4dGVybkFwaUZ1bmMgKGZuKVxuXHR7XG5cdFx0cmV0dXJuIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGFyZ3MgPSBbX2ZuU2V0dGluZ3NGcm9tTm9kZSggdGhpc1tEYXRhVGFibGUuZXh0LmlBcGlJbmRleF0gKV0uY29uY2F0KFxuXHRcdFx0XHRBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpXG5cdFx0XHQpO1xuXHRcdFx0cmV0dXJuIERhdGFUYWJsZS5leHQuaW50ZXJuYWxbZm5dLmFwcGx5KCB0aGlzLCBhcmdzICk7XG5cdFx0fTtcblx0fVxuXHRcblx0XG5cdC8qKlxuXHQgKiBSZWZlcmVuY2UgdG8gaW50ZXJuYWwgZnVuY3Rpb25zIGZvciB1c2UgYnkgcGx1Zy1pbiBkZXZlbG9wZXJzLiBOb3RlIHRoYXRcblx0ICogdGhlc2UgbWV0aG9kcyBhcmUgcmVmZXJlbmNlcyB0byBpbnRlcm5hbCBmdW5jdGlvbnMgYW5kIGFyZSBjb25zaWRlcmVkIHRvIGJlXG5cdCAqIHByaXZhdGUuIElmIHlvdSB1c2UgdGhlc2UgbWV0aG9kcywgYmUgYXdhcmUgdGhhdCB0aGV5IGFyZSBsaWFibGUgdG8gY2hhbmdlXG5cdCAqIGJldHdlZW4gdmVyc2lvbnMuXG5cdCAqICBAbmFtZXNwYWNlXG5cdCAqL1xuXHQkLmV4dGVuZCggRGF0YVRhYmxlLmV4dC5pbnRlcm5hbCwge1xuXHRcdF9mbkV4dGVybkFwaUZ1bmM6IF9mbkV4dGVybkFwaUZ1bmMsXG5cdFx0X2ZuQnVpbGRBamF4OiBfZm5CdWlsZEFqYXgsXG5cdFx0X2ZuQWpheFVwZGF0ZTogX2ZuQWpheFVwZGF0ZSxcblx0XHRfZm5BamF4UGFyYW1ldGVyczogX2ZuQWpheFBhcmFtZXRlcnMsXG5cdFx0X2ZuQWpheFVwZGF0ZURyYXc6IF9mbkFqYXhVcGRhdGVEcmF3LFxuXHRcdF9mbkFqYXhEYXRhU3JjOiBfZm5BamF4RGF0YVNyYyxcblx0XHRfZm5BZGRDb2x1bW46IF9mbkFkZENvbHVtbixcblx0XHRfZm5Db2x1bW5PcHRpb25zOiBfZm5Db2x1bW5PcHRpb25zLFxuXHRcdF9mbkFkanVzdENvbHVtblNpemluZzogX2ZuQWRqdXN0Q29sdW1uU2l6aW5nLFxuXHRcdF9mblZpc2libGVUb0NvbHVtbkluZGV4OiBfZm5WaXNpYmxlVG9Db2x1bW5JbmRleCxcblx0XHRfZm5Db2x1bW5JbmRleFRvVmlzaWJsZTogX2ZuQ29sdW1uSW5kZXhUb1Zpc2libGUsXG5cdFx0X2ZuVmlzYmxlQ29sdW1uczogX2ZuVmlzYmxlQ29sdW1ucyxcblx0XHRfZm5HZXRDb2x1bW5zOiBfZm5HZXRDb2x1bW5zLFxuXHRcdF9mbkNvbHVtblR5cGVzOiBfZm5Db2x1bW5UeXBlcyxcblx0XHRfZm5BcHBseUNvbHVtbkRlZnM6IF9mbkFwcGx5Q29sdW1uRGVmcyxcblx0XHRfZm5IdW5nYXJpYW5NYXA6IF9mbkh1bmdhcmlhbk1hcCxcblx0XHRfZm5DYW1lbFRvSHVuZ2FyaWFuOiBfZm5DYW1lbFRvSHVuZ2FyaWFuLFxuXHRcdF9mbkxhbmd1YWdlQ29tcGF0OiBfZm5MYW5ndWFnZUNvbXBhdCxcblx0XHRfZm5Ccm93c2VyRGV0ZWN0OiBfZm5Ccm93c2VyRGV0ZWN0LFxuXHRcdF9mbkFkZERhdGE6IF9mbkFkZERhdGEsXG5cdFx0X2ZuQWRkVHI6IF9mbkFkZFRyLFxuXHRcdF9mbk5vZGVUb0RhdGFJbmRleDogX2ZuTm9kZVRvRGF0YUluZGV4LFxuXHRcdF9mbk5vZGVUb0NvbHVtbkluZGV4OiBfZm5Ob2RlVG9Db2x1bW5JbmRleCxcblx0XHRfZm5HZXRDZWxsRGF0YTogX2ZuR2V0Q2VsbERhdGEsXG5cdFx0X2ZuU2V0Q2VsbERhdGE6IF9mblNldENlbGxEYXRhLFxuXHRcdF9mblNwbGl0T2JqTm90YXRpb246IF9mblNwbGl0T2JqTm90YXRpb24sXG5cdFx0X2ZuR2V0T2JqZWN0RGF0YUZuOiBfZm5HZXRPYmplY3REYXRhRm4sXG5cdFx0X2ZuU2V0T2JqZWN0RGF0YUZuOiBfZm5TZXRPYmplY3REYXRhRm4sXG5cdFx0X2ZuR2V0RGF0YU1hc3RlcjogX2ZuR2V0RGF0YU1hc3Rlcixcblx0XHRfZm5DbGVhclRhYmxlOiBfZm5DbGVhclRhYmxlLFxuXHRcdF9mbkRlbGV0ZUluZGV4OiBfZm5EZWxldGVJbmRleCxcblx0XHRfZm5JbnZhbGlkYXRlOiBfZm5JbnZhbGlkYXRlLFxuXHRcdF9mbkdldFJvd0VsZW1lbnRzOiBfZm5HZXRSb3dFbGVtZW50cyxcblx0XHRfZm5DcmVhdGVUcjogX2ZuQ3JlYXRlVHIsXG5cdFx0X2ZuQnVpbGRIZWFkOiBfZm5CdWlsZEhlYWQsXG5cdFx0X2ZuRHJhd0hlYWQ6IF9mbkRyYXdIZWFkLFxuXHRcdF9mbkRyYXc6IF9mbkRyYXcsXG5cdFx0X2ZuUmVEcmF3OiBfZm5SZURyYXcsXG5cdFx0X2ZuQWRkT3B0aW9uc0h0bWw6IF9mbkFkZE9wdGlvbnNIdG1sLFxuXHRcdF9mbkRldGVjdEhlYWRlcjogX2ZuRGV0ZWN0SGVhZGVyLFxuXHRcdF9mbkdldFVuaXF1ZVRoczogX2ZuR2V0VW5pcXVlVGhzLFxuXHRcdF9mbkZlYXR1cmVIdG1sRmlsdGVyOiBfZm5GZWF0dXJlSHRtbEZpbHRlcixcblx0XHRfZm5GaWx0ZXJDb21wbGV0ZTogX2ZuRmlsdGVyQ29tcGxldGUsXG5cdFx0X2ZuRmlsdGVyQ3VzdG9tOiBfZm5GaWx0ZXJDdXN0b20sXG5cdFx0X2ZuRmlsdGVyQ29sdW1uOiBfZm5GaWx0ZXJDb2x1bW4sXG5cdFx0X2ZuRmlsdGVyOiBfZm5GaWx0ZXIsXG5cdFx0X2ZuRmlsdGVyQ3JlYXRlU2VhcmNoOiBfZm5GaWx0ZXJDcmVhdGVTZWFyY2gsXG5cdFx0X2ZuRXNjYXBlUmVnZXg6IF9mbkVzY2FwZVJlZ2V4LFxuXHRcdF9mbkZpbHRlckRhdGE6IF9mbkZpbHRlckRhdGEsXG5cdFx0X2ZuRmVhdHVyZUh0bWxJbmZvOiBfZm5GZWF0dXJlSHRtbEluZm8sXG5cdFx0X2ZuVXBkYXRlSW5mbzogX2ZuVXBkYXRlSW5mbyxcblx0XHRfZm5JbmZvTWFjcm9zOiBfZm5JbmZvTWFjcm9zLFxuXHRcdF9mbkluaXRpYWxpc2U6IF9mbkluaXRpYWxpc2UsXG5cdFx0X2ZuSW5pdENvbXBsZXRlOiBfZm5Jbml0Q29tcGxldGUsXG5cdFx0X2ZuTGVuZ3RoQ2hhbmdlOiBfZm5MZW5ndGhDaGFuZ2UsXG5cdFx0X2ZuRmVhdHVyZUh0bWxMZW5ndGg6IF9mbkZlYXR1cmVIdG1sTGVuZ3RoLFxuXHRcdF9mbkZlYXR1cmVIdG1sUGFnaW5hdGU6IF9mbkZlYXR1cmVIdG1sUGFnaW5hdGUsXG5cdFx0X2ZuUGFnZUNoYW5nZTogX2ZuUGFnZUNoYW5nZSxcblx0XHRfZm5GZWF0dXJlSHRtbFByb2Nlc3Npbmc6IF9mbkZlYXR1cmVIdG1sUHJvY2Vzc2luZyxcblx0XHRfZm5Qcm9jZXNzaW5nRGlzcGxheTogX2ZuUHJvY2Vzc2luZ0Rpc3BsYXksXG5cdFx0X2ZuRmVhdHVyZUh0bWxUYWJsZTogX2ZuRmVhdHVyZUh0bWxUYWJsZSxcblx0XHRfZm5TY3JvbGxEcmF3OiBfZm5TY3JvbGxEcmF3LFxuXHRcdF9mbkFwcGx5VG9DaGlsZHJlbjogX2ZuQXBwbHlUb0NoaWxkcmVuLFxuXHRcdF9mbkNhbGN1bGF0ZUNvbHVtbldpZHRoczogX2ZuQ2FsY3VsYXRlQ29sdW1uV2lkdGhzLFxuXHRcdF9mblRocm90dGxlOiBfZm5UaHJvdHRsZSxcblx0XHRfZm5Db252ZXJ0VG9XaWR0aDogX2ZuQ29udmVydFRvV2lkdGgsXG5cdFx0X2ZuR2V0V2lkZXN0Tm9kZTogX2ZuR2V0V2lkZXN0Tm9kZSxcblx0XHRfZm5HZXRNYXhMZW5TdHJpbmc6IF9mbkdldE1heExlblN0cmluZyxcblx0XHRfZm5TdHJpbmdUb0NzczogX2ZuU3RyaW5nVG9Dc3MsXG5cdFx0X2ZuU29ydEZsYXR0ZW46IF9mblNvcnRGbGF0dGVuLFxuXHRcdF9mblNvcnQ6IF9mblNvcnQsXG5cdFx0X2ZuU29ydEFyaWE6IF9mblNvcnRBcmlhLFxuXHRcdF9mblNvcnRMaXN0ZW5lcjogX2ZuU29ydExpc3RlbmVyLFxuXHRcdF9mblNvcnRBdHRhY2hMaXN0ZW5lcjogX2ZuU29ydEF0dGFjaExpc3RlbmVyLFxuXHRcdF9mblNvcnRpbmdDbGFzc2VzOiBfZm5Tb3J0aW5nQ2xhc3Nlcyxcblx0XHRfZm5Tb3J0RGF0YTogX2ZuU29ydERhdGEsXG5cdFx0X2ZuU2F2ZVN0YXRlOiBfZm5TYXZlU3RhdGUsXG5cdFx0X2ZuTG9hZFN0YXRlOiBfZm5Mb2FkU3RhdGUsXG5cdFx0X2ZuSW1wbGVtZW50U3RhdGU6IF9mbkltcGxlbWVudFN0YXRlLFxuXHRcdF9mblNldHRpbmdzRnJvbU5vZGU6IF9mblNldHRpbmdzRnJvbU5vZGUsXG5cdFx0X2ZuTG9nOiBfZm5Mb2csXG5cdFx0X2ZuTWFwOiBfZm5NYXAsXG5cdFx0X2ZuQmluZEFjdGlvbjogX2ZuQmluZEFjdGlvbixcblx0XHRfZm5DYWxsYmFja1JlZzogX2ZuQ2FsbGJhY2tSZWcsXG5cdFx0X2ZuQ2FsbGJhY2tGaXJlOiBfZm5DYWxsYmFja0ZpcmUsXG5cdFx0X2ZuTGVuZ3RoT3ZlcmZsb3c6IF9mbkxlbmd0aE92ZXJmbG93LFxuXHRcdF9mblJlbmRlcmVyOiBfZm5SZW5kZXJlcixcblx0XHRfZm5EYXRhU291cmNlOiBfZm5EYXRhU291cmNlLFxuXHRcdF9mblJvd0F0dHJpYnV0ZXM6IF9mblJvd0F0dHJpYnV0ZXMsXG5cdFx0X2ZuRXh0ZW5kOiBfZm5FeHRlbmQsXG5cdFx0X2ZuQ2FsY3VsYXRlRW5kOiBmdW5jdGlvbiAoKSB7fSAvLyBVc2VkIGJ5IGEgbG90IG9mIHBsdWctaW5zLCBidXQgcmVkdW5kYW50XG5cdFx0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpbiAxLjEwLCBzbyB0aGlzIGRlYWQtZW5kIGZ1bmN0aW9uIGlzXG5cdFx0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhZGRlZCB0byBwcmV2ZW50IGVycm9yc1xuXHR9ICk7XG5cdFxuXG5cdC8vIGpRdWVyeSBhY2Nlc3Ncblx0JC5mbi5kYXRhVGFibGUgPSBEYXRhVGFibGU7XG5cblx0Ly8gUHJvdmlkZSBhY2Nlc3MgdG8gdGhlIGhvc3QgalF1ZXJ5IG9iamVjdCAoY2lyY3VsYXIgcmVmZXJlbmNlKVxuXHREYXRhVGFibGUuJCA9ICQ7XG5cblx0Ly8gTGVnYWN5IGFsaWFzZXNcblx0JC5mbi5kYXRhVGFibGVTZXR0aW5ncyA9IERhdGFUYWJsZS5zZXR0aW5ncztcblx0JC5mbi5kYXRhVGFibGVFeHQgPSBEYXRhVGFibGUuZXh0O1xuXG5cdC8vIFdpdGggYSBjYXBpdGFsIGBEYCB3ZSByZXR1cm4gYSBEYXRhVGFibGVzIEFQSSBpbnN0YW5jZSByYXRoZXIgdGhhbiBhXG5cdC8vIGpRdWVyeSBvYmplY3Rcblx0JC5mbi5EYXRhVGFibGUgPSBmdW5jdGlvbiAoIG9wdHMgKSB7XG5cdFx0cmV0dXJuICQodGhpcykuZGF0YVRhYmxlKCBvcHRzICkuYXBpKCk7XG5cdH07XG5cblx0Ly8gQWxsIHByb3BlcnRpZXMgdGhhdCBhcmUgYXZhaWxhYmxlIHRvICQuZm4uZGF0YVRhYmxlIHNob3VsZCBhbHNvIGJlXG5cdC8vIGF2YWlsYWJsZSBvbiAkLmZuLkRhdGFUYWJsZVxuXHQkLmVhY2goIERhdGFUYWJsZSwgZnVuY3Rpb24gKCBwcm9wLCB2YWwgKSB7XG5cdFx0JC5mbi5EYXRhVGFibGVbIHByb3AgXSA9IHZhbDtcblx0fSApO1xuXG5cdHJldHVybiBEYXRhVGFibGU7XG59KSk7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/datatables.net/js/jquery.dataTables.js\n");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./node_modules/jquery-confirm/dist/jquery-confirm.min.js":
|
|
/*!****************************************************************!*\
|
|
!*** ./node_modules/jquery-confirm/dist/jquery-confirm.min.js ***!
|
|
\****************************************************************/
|
|
/***/ ((module, exports, __webpack_require__) => {
|
|
|
|
eval("var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!\r\n * jquery-confirm v3.3.4 (http://craftpip.github.io/jquery-confirm/)\r\n * Author: Boniface Pereira\r\n * Website: www.craftpip.com\r\n * Contact: hey@craftpip.com\r\n *\r\n * Copyright 2013-2019 jquery-confirm\r\n * Licensed under MIT (https://github.com/craftpip/jquery-confirm/blob/master/LICENSE)\r\n */\r\n(function(factory){if(true){!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\")], __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__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),\n\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));}else{}}(function($){var w=window;$.fn.confirm=function(options,option2){if(typeof options===\"undefined\"){options={};}if(typeof options===\"string\"){options={content:options,title:(option2)?option2:false};}$(this).each(function(){var $this=$(this);if($this.attr(\"jc-attached\")){console.warn(\"jConfirm has already been attached to this element \",$this[0]);return;}$this.on(\"click\",function(e){e.preventDefault();var jcOption=$.extend({},options);if($this.attr(\"data-title\")){jcOption.title=$this.attr(\"data-title\");}if($this.attr(\"data-content\")){jcOption.content=$this.attr(\"data-content\");}if(typeof jcOption.buttons===\"undefined\"){jcOption.buttons={};}jcOption[\"$target\"]=$this;if($this.attr(\"href\")&&Object.keys(jcOption.buttons).length===0){var buttons=$.extend(true,{},w.jconfirm.pluginDefaults.defaultButtons,(w.jconfirm.defaults||{}).defaultButtons||{});var firstBtn=Object.keys(buttons)[0];jcOption.buttons=buttons;jcOption.buttons[firstBtn].action=function(){location.href=$this.attr(\"href\");};}jcOption.closeIcon=false;var instance=$.confirm(jcOption);});$this.attr(\"jc-attached\",true);});return $(this);};$.confirm=function(options,option2){if(typeof options===\"undefined\"){options={};}if(typeof options===\"string\"){options={content:options,title:(option2)?option2:false};}var putDefaultButtons=!(options.buttons===false);if(typeof options.buttons!==\"object\"){options.buttons={};}if(Object.keys(options.buttons).length===0&&putDefaultButtons){var buttons=$.extend(true,{},w.jconfirm.pluginDefaults.defaultButtons,(w.jconfirm.defaults||{}).defaultButtons||{});options.buttons=buttons;}return w.jconfirm(options);};$.alert=function(options,option2){if(typeof options===\"undefined\"){options={};}if(typeof options===\"string\"){options={content:options,title:(option2)?option2:false};}var putDefaultButtons=!(options.buttons===false);if(typeof options.buttons!==\"object\"){options.buttons={};}if(Object.keys(options.buttons).length===0&&putDefaultButtons){var buttons=$.extend(true,{},w.jconfirm.pluginDefaults.defaultButtons,(w.jconfirm.defaults||{}).defaultButtons||{});var firstBtn=Object.keys(buttons)[0];options.buttons[firstBtn]=buttons[firstBtn];}return w.jconfirm(options);};$.dialog=function(options,option2){if(typeof options===\"undefined\"){options={};}if(typeof options===\"string\"){options={content:options,title:(option2)?option2:false,closeIcon:function(){}};}options.buttons={};if(typeof options.closeIcon===\"undefined\"){options.closeIcon=function(){};}options.confirmKeys=[13];return w.jconfirm(options);};w.jconfirm=function(options){if(typeof options===\"undefined\"){options={};}var pluginOptions=$.extend(true,{},w.jconfirm.pluginDefaults);if(w.jconfirm.defaults){pluginOptions=$.extend(true,pluginOptions,w.jconfirm.defaults);}pluginOptions=$.extend(true,{},pluginOptions,options);var instance=new w.Jconfirm(pluginOptions);w.jconfirm.instances.push(instance);return instance;};w.Jconfirm=function(options){$.extend(this,options);this._init();};w.Jconfirm.prototype={_init:function(){var that=this;if(!w.jconfirm.instances.length){w.jconfirm.lastFocused=$(\"body\").find(\":focus\");}this._id=Math.round(Math.random()*99999);this.contentParsed=$(document.createElement(\"div\"));if(!this.lazyOpen){setTimeout(function(){that.open();},0);}},_buildHTML:function(){var that=this;this._parseAnimation(this.animation,\"o\");this._parseAnimation(this.closeAnimation,\"c\");this._parseBgDismissAnimation(this.backgroundDismissAnimation);this._parseColumnClass(this.columnClass);this._parseTheme(this.theme);this._parseType(this.type);var template=$(this.template);template.find(\".jconfirm-box\").addClass(this.animationParsed).addClass(this.backgroundDismissAnimationParsed).addClass(this.typeParsed);if(this.typeAnimated){template.find(\".jconfirm-box\").addClass(\"jconfirm-type-animated\");}if(this.useBootstrap){template.find(\".jc-bs3-row\").addClass(this.bootstrapClasses.row);template.find(\".jc-bs3-row\").addClass(\"justify-content-md-center justify-content-sm-center justify-content-xs-center justify-content-lg-center\");template.find(\".jconfirm-box-container\").addClass(this.columnClassParsed);if(this.containerFluid){template.find(\".jc-bs3-container\").addClass(this.bootstrapClasses.containerFluid);}else{template.find(\".jc-bs3-container\").addClass(this.bootstrapClasses.container);}}else{template.find(\".jconfirm-box\").css(\"width\",this.boxWidth);}if(this.titleClass){template.find(\".jconfirm-title-c\").addClass(this.titleClass);}template.addClass(this.themeParsed);var ariaLabel=\"jconfirm-box\"+this._id;template.find(\".jconfirm-box\").attr(\"aria-labelledby\",ariaLabel).attr(\"tabindex\",-1);template.find(\".jconfirm-content\").attr(\"id\",ariaLabel);if(this.bgOpacity!==null){template.find(\".jconfirm-bg\").css(\"opacity\",this.bgOpacity);}if(this.rtl){template.addClass(\"jconfirm-rtl\");}this.$el=template.appendTo(this.container);this.$jconfirmBoxContainer=this.$el.find(\".jconfirm-box-container\");this.$jconfirmBox=this.$body=this.$el.find(\".jconfirm-box\");this.$jconfirmBg=this.$el.find(\".jconfirm-bg\");this.$title=this.$el.find(\".jconfirm-title\");this.$titleContainer=this.$el.find(\".jconfirm-title-c\");this.$content=this.$el.find(\"div.jconfirm-content\");this.$contentPane=this.$el.find(\".jconfirm-content-pane\");this.$icon=this.$el.find(\".jconfirm-icon-c\");this.$closeIcon=this.$el.find(\".jconfirm-closeIcon\");this.$holder=this.$el.find(\".jconfirm-holder\");this.$btnc=this.$el.find(\".jconfirm-buttons\");this.$scrollPane=this.$el.find(\".jconfirm-scrollpane\");that.setStartingPoint();this._contentReady=$.Deferred();this._modalReady=$.Deferred();this.$holder.css({\"padding-top\":this.offsetTop,\"padding-bottom\":this.offsetBottom,});this.setTitle();this.setIcon();this._setButtons();this._parseContent();this.initDraggable();if(this.isAjax){this.showLoading(false);}$.when(this._contentReady,this._modalReady).then(function(){if(that.isAjaxLoading){setTimeout(function(){that.isAjaxLoading=false;that.setContent();that.setTitle();that.setIcon();setTimeout(function(){that.hideLoading(false);that._updateContentMaxHeight();},100);if(typeof that.onContentReady===\"function\"){that.onContentReady();}},50);}else{that._updateContentMaxHeight();that.setTitle();that.setIcon();if(typeof that.onContentReady===\"function\"){that.onContentReady();}}if(that.autoClose){that._startCountDown();}}).then(function(){that._watchContent();});if(this.animation===\"none\"){this.animationSpeed=1;this.animationBounce=1;}this.$body.css(this._getCSS(this.animationSpeed,this.animationBounce));this.$contentPane.css(this._getCSS(this.animationSpeed,1));this.$jconfirmBg.css(this._getCSS(this.animationSpeed,1));this.$jconfirmBoxContainer.css(this._getCSS(this.animationSpeed,1));},_typePrefix:\"jconfirm-type-\",typeParsed:\"\",_parseType:function(type){this.typeParsed=this._typePrefix+type;},setType:function(type){var oldClass=this.typeParsed;this._parseType(type);this.$jconfirmBox.removeClass(oldClass).addClass(this.typeParsed);},themeParsed:\"\",_themePrefix:\"jconfirm-\",setTheme:function(theme){var previous=this.theme;this.theme=theme||this.theme;this._parseTheme(this.theme);if(previous){this.$el.removeClass(previous);}this.$el.addClass(this.themeParsed);this.theme=theme;},_parseTheme:function(theme){var that=this;theme=theme.split(\",\");$.each(theme,function(k,a){if(a.indexOf(that._themePrefix)===-1){theme[k]=that._themePrefix+$.trim(a);}});this.themeParsed=theme.join(\" \").toLowerCase();},backgroundDismissAnimationParsed:\"\",_bgDismissPrefix:\"jconfirm-hilight-\",_parseBgDismissAnimation:function(bgDismissAnimation){var animation=bgDismissAnimation.split(\",\");var that=this;$.each(animation,function(k,a){if(a.indexOf(that._bgDismissPrefix)===-1){animation[k]=that._bgDismissPrefix+$.trim(a);}});this.backgroundDismissAnimationParsed=animation.join(\" \").toLowerCase();},animationParsed:\"\",closeAnimationParsed:\"\",_animationPrefix:\"jconfirm-animation-\",setAnimation:function(animation){this.animation=animation||this.animation;this._parseAnimation(this.animation,\"o\");},_parseAnimation:function(animation,which){which=which||\"o\";var animations=animation.split(\",\");var that=this;$.each(animations,function(k,a){if(a.indexOf(that._animationPrefix)===-1){animations[k]=that._animationPrefix+$.trim(a);}});var a_string=animations.join(\" \").toLowerCase();if(which===\"o\"){this.animationParsed=a_string;}else{this.closeAnimationParsed=a_string;}return a_string;},setCloseAnimation:function(closeAnimation){this.closeAnimation=closeAnimation||this.closeAnimation;this._parseAnimation(this.closeAnimation,\"c\");},setAnimationSpeed:function(speed){this.animationSpeed=speed||this.animationSpeed;},columnClassParsed:\"\",setColumnClass:function(colClass){if(!this.useBootstrap){console.warn(\"cannot set columnClass, useBootstrap is set to false\");return;}this.columnClass=colClass||this.columnClass;this._parseColumnClass(this.columnClass);this.$jconfirmBoxContainer.addClass(this.columnClassParsed);},_updateContentMaxHeight:function(){var height=$(window).height()-(this.$jconfirmBox.outerHeight()-this.$contentPane.outerHeight())-(this.offsetTop+this.offsetBottom);this.$contentPane.css({\"max-height\":height+\"px\"});},setBoxWidth:function(width){if(this.useBootstrap){console.warn(\"cannot set boxWidth, useBootstrap is set to true\");return;}this.boxWidth=width;this.$jconfirmBox.css(\"width\",width);},_parseColumnClass:function(colClass){colClass=colClass.toLowerCase();var p;switch(colClass){case\"xl\":case\"xlarge\":p=\"col-md-12\";break;case\"l\":case\"large\":p=\"col-md-8 col-md-offset-2\";break;case\"m\":case\"medium\":p=\"col-md-6 col-md-offset-3\";break;case\"s\":case\"small\":p=\"col-md-4 col-md-offset-4\";break;case\"xs\":case\"xsmall\":p=\"col-md-2 col-md-offset-5\";break;default:p=colClass;}this.columnClassParsed=p;},initDraggable:function(){var that=this;var $t=this.$titleContainer;this.resetDrag();if(this.draggable){$t.on(\"mousedown\",function(e){$t.addClass(\"jconfirm-hand\");that.mouseX=e.clientX;that.mouseY=e.clientY;that.isDrag=true;});$(window).on(\"mousemove.\"+this._id,function(e){if(that.isDrag){that.movingX=e.clientX-that.mouseX+that.initialX;that.movingY=e.clientY-that.mouseY+that.initialY;that.setDrag();}});$(window).on(\"mouseup.\"+this._id,function(){$t.removeClass(\"jconfirm-hand\");if(that.isDrag){that.isDrag=false;that.initialX=that.movingX;that.initialY=that.movingY;}});}},resetDrag:function(){this.isDrag=false;this.initialX=0;this.initialY=0;this.movingX=0;this.movingY=0;this.mouseX=0;this.mouseY=0;this.$jconfirmBoxContainer.css(\"transform\",\"translate(\"+0+\"px, \"+0+\"px)\");},setDrag:function(){if(!this.draggable){return;}this.alignMiddle=false;var boxWidth=this.$jconfirmBox.outerWidth();var boxHeight=this.$jconfirmBox.outerHeight();var windowWidth=$(window).width();var windowHeight=$(window).height();var that=this;var dragUpdate=1;if(that.movingX%dragUpdate===0||that.movingY%dragUpdate===0){if(that.dragWindowBorder){var leftDistance=(windowWidth/2)-boxWidth/2;var topDistance=(windowHeight/2)-boxHeight/2;topDistance-=that.dragWindowGap;leftDistance-=that.dragWindowGap;if(leftDistance+that.movingX<0){that.movingX=-leftDistance;}else{if(leftDistance-that.movingX<0){that.movingX=leftDistance;}}if(topDistance+that.movingY<0){that.movingY=-topDistance;}else{if(topDistance-that.movingY<0){that.movingY=topDistance;}}}that.$jconfirmBoxContainer.css(\"transform\",\"translate(\"+that.movingX+\"px, \"+that.movingY+\"px)\");}},_scrollTop:function(){if(typeof pageYOffset!==\"undefined\"){return pageYOffset;}else{var B=document.body;var D=document.documentElement;D=(D.clientHeight)?D:B;return D.scrollTop;}},_watchContent:function(){var that=this;if(this._timer){clearInterval(this._timer);}var prevContentHeight=0;this._timer=setInterval(function(){if(that.smoothContent){var contentHeight=that.$content.outerHeight()||0;if(contentHeight!==prevContentHeight){prevContentHeight=contentHeight;}var wh=$(window).height();var total=that.offsetTop+that.offsetBottom+that.$jconfirmBox.height()-that.$contentPane.height()+that.$content.height();if(total<wh){that.$contentPane.addClass(\"no-scroll\");}else{that.$contentPane.removeClass(\"no-scroll\");}}},this.watchInterval);},_overflowClass:\"jconfirm-overflow\",_hilightAnimating:false,highlight:function(){this.hiLightModal();},hiLightModal:function(){var that=this;if(this._hilightAnimating){return;}that.$body.addClass(\"hilight\");var duration=parseFloat(that.$body.css(\"animation-duration\"))||2;this._hilightAnimating=true;setTimeout(function(){that._hilightAnimating=false;that.$body.removeClass(\"hilight\");},duration*1000);},_bindEvents:function(){var that=this;this.boxClicked=false;this.$scrollPane.click(function(e){if(!that.boxClicked){var buttonName=false;var shouldClose=false;var str;if(typeof that.backgroundDismiss===\"function\"){str=that.backgroundDismiss();}else{str=that.backgroundDismiss;}if(typeof str===\"string\"&&typeof that.buttons[str]!==\"undefined\"){buttonName=str;shouldClose=false;}else{if(typeof str===\"undefined\"||!!(str)===true){shouldClose=true;}else{shouldClose=false;}}if(buttonName){var btnResponse=that.buttons[buttonName].action.apply(that);shouldClose=(typeof btnResponse===\"undefined\")||!!(btnResponse);}if(shouldClose){that.close();}else{that.hiLightModal();}}that.boxClicked=false;});this.$jconfirmBox.click(function(e){that.boxClicked=true;});var isKeyDown=false;$(window).on(\"jcKeyDown.\"+that._id,function(e){if(!isKeyDown){isKeyDown=true;}});$(window).on(\"keyup.\"+that._id,function(e){if(isKeyDown){that.reactOnKey(e);isKeyDown=false;}});$(window).on(\"resize.\"+this._id,function(){that._updateContentMaxHeight();setTimeout(function(){that.resetDrag();},100);});},_cubic_bezier:\"0.36, 0.55, 0.19\",_getCSS:function(speed,bounce){return{\"-webkit-transition-duration\":speed/1000+\"s\",\"transition-duration\":speed/1000+\"s\",\"-webkit-transition-timing-function\":\"cubic-bezier(\"+this._cubic_bezier+\", \"+bounce+\")\",\"transition-timing-function\":\"cubic-bezier(\"+this._cubic_bezier+\", \"+bounce+\")\"};},_setButtons:function(){var that=this;var total_buttons=0;if(typeof this.buttons!==\"object\"){this.buttons={};}$.each(this.buttons,function(key,button){total_buttons+=1;if(typeof button===\"function\"){that.buttons[key]=button={action:button};}that.buttons[key].text=button.text||key;that.buttons[key].btnClass=button.btnClass||\"btn-default\";that.buttons[key].action=button.action||function(){};that.buttons[key].keys=button.keys||[];that.buttons[key].isHidden=button.isHidden||false;that.buttons[key].isDisabled=button.isDisabled||false;$.each(that.buttons[key].keys,function(i,a){that.buttons[key].keys[i]=a.toLowerCase();});var button_element=$('<button type=\"button\" class=\"btn\"></button>').html(that.buttons[key].text).addClass(that.buttons[key].btnClass).prop(\"disabled\",that.buttons[key].isDisabled).css(\"display\",that.buttons[key].isHidden?\"none\":\"\").click(function(e){e.preventDefault();var res=that.buttons[key].action.apply(that,[that.buttons[key]]);that.onAction.apply(that,[key,that.buttons[key]]);that._stopCountDown();if(typeof res===\"undefined\"||res){that.close();}});that.buttons[key].el=button_element;that.buttons[key].setText=function(text){button_element.html(text);};that.buttons[key].addClass=function(className){button_element.addClass(className);};that.buttons[key].removeClass=function(className){button_element.removeClass(className);};that.buttons[key].disable=function(){that.buttons[key].isDisabled=true;button_element.prop(\"disabled\",true);};that.buttons[key].enable=function(){that.buttons[key].isDisabled=false;button_element.prop(\"disabled\",false);};that.buttons[key].show=function(){that.buttons[key].isHidden=false;button_element.css(\"display\",\"\");};that.buttons[key].hide=function(){that.buttons[key].isHidden=true;button_element.css(\"display\",\"none\");};that[\"$_\"+key]=that[\"$$\"+key]=button_element;that.$btnc.append(button_element);});if(total_buttons===0){this.$btnc.hide();}if(this.closeIcon===null&&total_buttons===0){this.closeIcon=true;}if(this.closeIcon){if(this.closeIconClass){var closeHtml='<i class=\"'+this.closeIconClass+'\"></i>';this.$closeIcon.html(closeHtml);}this.$closeIcon.click(function(e){e.preventDefault();var buttonName=false;var shouldClose=false;var str;if(typeof that.closeIcon===\"function\"){str=that.closeIcon();}else{str=that.closeIcon;}if(typeof str===\"string\"&&typeof that.buttons[str]!==\"undefined\"){buttonName=str;shouldClose=false;}else{if(typeof str===\"undefined\"||!!(str)===true){shouldClose=true;}else{shouldClose=false;}}if(buttonName){var btnResponse=that.buttons[buttonName].action.apply(that);shouldClose=(typeof btnResponse===\"undefined\")||!!(btnResponse);}if(shouldClose){that.close();}});this.$closeIcon.show();}else{this.$closeIcon.hide();}},setTitle:function(string,force){force=force||false;if(typeof string!==\"undefined\"){if(typeof string===\"string\"){this.title=string;}else{if(typeof string===\"function\"){if(typeof string.promise===\"function\"){console.error(\"Promise was returned from title function, this is not supported.\");}var response=string();if(typeof response===\"string\"){this.title=response;}else{this.title=false;}}else{this.title=false;}}}if(this.isAjaxLoading&&!force){return;}this.$title.html(this.title||\"\");this.updateTitleContainer();},setIcon:function(iconClass,force){force=force||false;if(typeof iconClass!==\"undefined\"){if(typeof iconClass===\"string\"){this.icon=iconClass;}else{if(typeof iconClass===\"function\"){var response=iconClass();if(typeof response===\"string\"){this.icon=response;}else{this.icon=false;}}else{this.icon=false;}}}if(this.isAjaxLoading&&!force){return;}this.$icon.html(this.icon?'<i class=\"'+this.icon+'\"></i>':\"\");this.updateTitleContainer();},updateTitleContainer:function(){if(!this.title&&!this.icon){this.$titleContainer.hide();}else{this.$titleContainer.show();}},setContentPrepend:function(content,force){if(!content){return;}this.contentParsed.prepend(content);},setContentAppend:function(content){if(!content){return;}this.contentParsed.append(content);},setContent:function(content,force){force=!!force;var that=this;if(content){this.contentParsed.html(\"\").append(content);}if(this.isAjaxLoading&&!force){return;}this.$content.html(\"\");this.$content.append(this.contentParsed);setTimeout(function(){that.$body.find(\"input[autofocus]:visible:first\").focus();},100);},loadingSpinner:false,showLoading:function(disableButtons){this.loadingSpinner=true;this.$jconfirmBox.addClass(\"loading\");if(disableButtons){this.$btnc.find(\"button\").prop(\"disabled\",true);}},hideLoading:function(enableButtons){this.loadingSpinner=false;this.$jconfirmBox.removeClass(\"loading\");if(enableButtons){this.$btnc.find(\"button\").prop(\"disabled\",false);}},ajaxResponse:false,contentParsed:\"\",isAjax:false,isAjaxLoading:false,_parseContent:function(){var that=this;var e=\" \";if(typeof this.content===\"function\"){var res=this.content.apply(this);if(typeof res===\"string\"){this.content=res;}else{if(typeof res===\"object\"&&typeof res.always===\"function\"){this.isAjax=true;this.isAjaxLoading=true;res.always(function(data,status,xhr){that.ajaxResponse={data:data,status:status,xhr:xhr};that._contentReady.resolve(data,status,xhr);if(typeof that.contentLoaded===\"function\"){that.contentLoaded(data,status,xhr);}});this.content=e;}else{this.content=e;}}}if(typeof this.content===\"string\"&&this.content.substr(0,4).toLowerCase()===\"url:\"){this.isAjax=true;this.isAjaxLoading=true;var u=this.content.substring(4,this.content.length);$.get(u).done(function(html){that.contentParsed.html(html);}).always(function(data,status,xhr){that.ajaxResponse={data:data,status:status,xhr:xhr};that._contentReady.resolve(data,status,xhr);if(typeof that.contentLoaded===\"function\"){that.contentLoaded(data,status,xhr);}});}if(!this.content){this.content=e;}if(!this.isAjax){this.contentParsed.html(this.content);this.setContent();that._contentReady.resolve();}},_stopCountDown:function(){clearInterval(this.autoCloseInterval);if(this.$cd){this.$cd.remove();}},_startCountDown:function(){var that=this;var opt=this.autoClose.split(\"|\");if(opt.length!==2){console.error(\"Invalid option for autoClose. example 'close|10000'\");return false;}var button_key=opt[0];var time=parseInt(opt[1]);if(typeof this.buttons[button_key]===\"undefined\"){console.error(\"Invalid button key '\"+button_key+\"' for autoClose\");return false;}var seconds=Math.ceil(time/1000);this.$cd=$('<span class=\"countdown\"> ('+seconds+\")</span>\").appendTo(this[\"$_\"+button_key]);this.autoCloseInterval=setInterval(function(){that.$cd.html(\" (\"+(seconds-=1)+\") \");if(seconds<=0){that[\"$$\"+button_key].trigger(\"click\");that._stopCountDown();}},1000);},_getKey:function(key){switch(key){case 192:return\"tilde\";case 13:return\"enter\";case 16:return\"shift\";case 9:return\"tab\";case 20:return\"capslock\";case 17:return\"ctrl\";case 91:return\"win\";case 18:return\"alt\";case 27:return\"esc\";case 32:return\"space\";}var initial=String.fromCharCode(key);if(/^[A-z0-9]+$/.test(initial)){return initial.toLowerCase();}else{return false;}},reactOnKey:function(e){var that=this;var a=$(\".jconfirm\");if(a.eq(a.length-1)[0]!==this.$el[0]){return false;}var key=e.which;if(this.$content.find(\":input\").is(\":focus\")&&/13|32/.test(key)){return false;}var keyChar=this._getKey(key);if(keyChar===\"esc\"&&this.escapeKey){if(this.escapeKey===true){this.$scrollPane.trigger(\"click\");}else{if(typeof this.escapeKey===\"string\"||typeof this.escapeKey===\"function\"){var buttonKey;if(typeof this.escapeKey===\"function\"){buttonKey=this.escapeKey();}else{buttonKey=this.escapeKey;}if(buttonKey){if(typeof this.buttons[buttonKey]===\"undefined\"){console.warn(\"Invalid escapeKey, no buttons found with key \"+buttonKey);}else{this[\"$_\"+buttonKey].trigger(\"click\");}}}}}$.each(this.buttons,function(key,button){if(button.keys.indexOf(keyChar)!==-1){that[\"$_\"+key].trigger(\"click\");}});},setDialogCenter:function(){console.info(\"setDialogCenter is deprecated, dialogs are centered with CSS3 tables\");},_unwatchContent:function(){clearInterval(this._timer);},close:function(onClosePayload){var that=this;if(typeof this.onClose===\"function\"){this.onClose(onClosePayload);}this._unwatchContent();$(window).unbind(\"resize.\"+this._id);$(window).unbind(\"keyup.\"+this._id);$(window).unbind(\"jcKeyDown.\"+this._id);if(this.draggable){$(window).unbind(\"mousemove.\"+this._id);$(window).unbind(\"mouseup.\"+this._id);this.$titleContainer.unbind(\"mousedown\");}that.$el.removeClass(that.loadedClass);$(\"body\").removeClass(\"jconfirm-no-scroll-\"+that._id);that.$jconfirmBoxContainer.removeClass(\"jconfirm-no-transition\");setTimeout(function(){that.$body.addClass(that.closeAnimationParsed);that.$jconfirmBg.addClass(\"jconfirm-bg-h\");var closeTimer=(that.closeAnimation===\"none\")?1:that.animationSpeed;setTimeout(function(){that.$el.remove();var l=w.jconfirm.instances;var i=w.jconfirm.instances.length-1;for(i;i>=0;i--){if(w.jconfirm.instances[i]._id===that._id){w.jconfirm.instances.splice(i,1);}}if(!w.jconfirm.instances.length){if(that.scrollToPreviousElement&&w.jconfirm.lastFocused&&w.jconfirm.lastFocused.length&&$.contains(document,w.jconfirm.lastFocused[0])){var $lf=w.jconfirm.lastFocused;if(that.scrollToPreviousElementAnimate){var st=$(window).scrollTop();var ot=w.jconfirm.lastFocused.offset().top;var wh=$(window).height();if(!(ot>st&&ot<(st+wh))){var scrollTo=(ot-Math.round((wh/3)));$(\"html, body\").animate({scrollTop:scrollTo},that.animationSpeed,\"swing\",function(){$lf.focus();});}else{$lf.focus();}}else{$lf.focus();}w.jconfirm.lastFocused=false;}}if(typeof that.onDestroy===\"function\"){that.onDestroy();}},closeTimer*0.4);},50);return true;},open:function(){if(this.isOpen()){return false;}this._buildHTML();this._bindEvents();this._open();return true;},setStartingPoint:function(){var el=false;if(this.animateFromElement!==true&&this.animateFromElement){el=this.animateFromElement;w.jconfirm.lastClicked=false;}else{if(w.jconfirm.lastClicked&&this.animateFromElement===true){el=w.jconfirm.lastClicked;w.jconfirm.lastClicked=false;}else{return false;}}if(!el){return false;}var offset=el.offset();var iTop=el.outerHeight()/2;var iLeft=el.outerWidth()/2;iTop-=this.$jconfirmBox.outerHeight()/2;iLeft-=this.$jconfirmBox.outerWidth()/2;var sourceTop=offset.top+iTop;sourceTop=sourceTop-this._scrollTop();var sourceLeft=offset.left+iLeft;var wh=$(window).height()/2;var ww=$(window).width()/2;var targetH=wh-this.$jconfirmBox.outerHeight()/2;var targetW=ww-this.$jconfirmBox.outerWidth()/2;sourceTop-=targetH;sourceLeft-=targetW;if(Math.abs(sourceTop)>wh||Math.abs(sourceLeft)>ww){return false;}this.$jconfirmBoxContainer.css(\"transform\",\"translate(\"+sourceLeft+\"px, \"+sourceTop+\"px)\");},_open:function(){var that=this;if(typeof that.onOpenBefore===\"function\"){that.onOpenBefore();}this.$body.removeClass(this.animationParsed);this.$jconfirmBg.removeClass(\"jconfirm-bg-h\");this.$body.focus();that.$jconfirmBoxContainer.css(\"transform\",\"translate(\"+0+\"px, \"+0+\"px)\");setTimeout(function(){that.$body.css(that._getCSS(that.animationSpeed,1));that.$body.css({\"transition-property\":that.$body.css(\"transition-property\")+\", margin\"});that.$jconfirmBoxContainer.addClass(\"jconfirm-no-transition\");that._modalReady.resolve();if(typeof that.onOpen===\"function\"){that.onOpen();}that.$el.addClass(that.loadedClass);},this.animationSpeed);},loadedClass:\"jconfirm-open\",isClosed:function(){return !this.$el||this.$el.parent().length===0;},isOpen:function(){return !this.isClosed();},toggle:function(){if(!this.isOpen()){this.open();}else{this.close();}}};w.jconfirm.instances=[];w.jconfirm.lastFocused=false;w.jconfirm.pluginDefaults={template:'<div class=\"jconfirm\"><div class=\"jconfirm-bg jconfirm-bg-h\"></div><div class=\"jconfirm-scrollpane\"><div class=\"jconfirm-row\"><div class=\"jconfirm-cell\"><div class=\"jconfirm-holder\"><div class=\"jc-bs3-container\"><div class=\"jc-bs3-row\"><div class=\"jconfirm-box-container jconfirm-animated\"><div class=\"jconfirm-box\" role=\"dialog\" aria-labelledby=\"labelled\" tabindex=\"-1\"><div class=\"jconfirm-closeIcon\">×</div><div class=\"jconfirm-title-c\"><span class=\"jconfirm-icon-c\"></span><span class=\"jconfirm-title\"></span></div><div class=\"jconfirm-content-pane\"><div class=\"jconfirm-content\"></div></div><div class=\"jconfirm-buttons\"></div><div class=\"jconfirm-clear\"></div></div></div></div></div></div></div></div></div></div>',title:\"Hello\",titleClass:\"\",type:\"default\",typeAnimated:true,draggable:true,dragWindowGap:15,dragWindowBorder:true,animateFromElement:true,alignMiddle:true,smoothContent:true,content:\"Are you sure to continue?\",buttons:{},defaultButtons:{ok:{action:function(){}},close:{action:function(){}}},contentLoaded:function(){},icon:\"\",lazyOpen:false,bgOpacity:null,theme:\"light\",animation:\"scale\",closeAnimation:\"scale\",animationSpeed:400,animationBounce:1,escapeKey:true,rtl:false,container:\"body\",containerFluid:false,backgroundDismiss:false,backgroundDismissAnimation:\"shake\",autoClose:false,closeIcon:null,closeIconClass:false,watchInterval:100,columnClass:\"col-md-4 col-md-offset-4 col-sm-6 col-sm-offset-3 col-xs-10 col-xs-offset-1\",boxWidth:\"50%\",scrollToPreviousElement:true,scrollToPreviousElementAnimate:true,useBootstrap:true,offsetTop:40,offsetBottom:40,bootstrapClasses:{container:\"container\",containerFluid:\"container-fluid\",row:\"row\"},onContentReady:function(){},onOpenBefore:function(){},onOpen:function(){},onClose:function(){},onDestroy:function(){},onAction:function(){}};var keyDown=false;$(window).on(\"keydown\",function(e){if(!keyDown){var $target=$(e.target);var pass=false;if($target.closest(\".jconfirm-box\").length){pass=true;}if(pass){$(window).trigger(\"jcKeyDown\");}keyDown=true;}});$(window).on(\"keyup\",function(){keyDown=false;});w.jconfirm.lastClicked=false;$(document).on(\"mousedown\",\"button, a, [jc-source]\",function(){w.jconfirm.lastClicked=$(this);});}));//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvanF1ZXJ5LWNvbmZpcm0vZGlzdC9qcXVlcnktY29uZmlybS5taW4uanMuanMiLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CLEdBQUcsSUFBc0MsRUFBRSxpQ0FBTyxDQUFDLHlFQUFRLENBQUMsb0NBQUMsT0FBTztBQUFBO0FBQUE7QUFBQSxrR0FBQyxFQUFFLElBQUksRUFBa1EsQ0FBQyxhQUFhLGFBQWEsdUNBQXVDLGlDQUFpQyxZQUFZLDhCQUE4QixTQUFTLGdEQUFnRCx3QkFBd0Isa0JBQWtCLDhCQUE4Qiw2RUFBNkUsUUFBUSw2QkFBNkIsbUJBQW1CLHdCQUF3QixVQUFVLDZCQUE2Qix5Q0FBeUMsK0JBQStCLDZDQUE2QywwQ0FBMEMscUJBQXFCLDBCQUEwQixpRUFBaUUsNEJBQTRCLGtFQUFrRSxvQkFBb0IsRUFBRSxxQ0FBcUMseUJBQXlCLDZDQUE2QyxvQ0FBb0MseUJBQXlCLGtDQUFrQyxFQUFFLGdDQUFnQyxFQUFFLGlCQUFpQixvQ0FBb0MsaUNBQWlDLFlBQVksOEJBQThCLFNBQVMsZ0RBQWdELGlEQUFpRCxzQ0FBc0Msb0JBQW9CLCtEQUErRCw0QkFBNEIsa0VBQWtFLG9CQUFvQixFQUFFLHlCQUF5Qiw2QkFBNkIsa0NBQWtDLGlDQUFpQyxZQUFZLDhCQUE4QixTQUFTLGdEQUFnRCxpREFBaUQsc0NBQXNDLG9CQUFvQiwrREFBK0QsNEJBQTRCLGtFQUFrRSxvQkFBb0IsRUFBRSxxQ0FBcUMsNkNBQTZDLDZCQUE2QixtQ0FBbUMsaUNBQWlDLFlBQVksOEJBQThCLFNBQVMsdUVBQXVFLG1CQUFtQiwyQ0FBMkMsZ0NBQWdDLHlCQUF5Qiw2QkFBNkIsNkJBQTZCLGlDQUFpQyxZQUFZLGtDQUFrQyw0QkFBNEIsd0JBQXdCLGdFQUFnRSw4QkFBOEIsd0JBQXdCLDJDQUEyQyxvQ0FBb0Msa0JBQWtCLDZCQUE2Qix1QkFBdUIsZUFBZSxzQkFBc0IsaUJBQWlCLGNBQWMsaUNBQWlDLGlEQUFpRCx5Q0FBeUMsb0RBQW9ELG1CQUFtQixzQkFBc0IsYUFBYSxNQUFNLHVCQUF1QixjQUFjLHlDQUF5Qyw4Q0FBOEMsK0RBQStELHlDQUF5Qyw2QkFBNkIsMkJBQTJCLDhCQUE4Qix3SUFBd0ksc0JBQXNCLG1FQUFtRSxzQkFBc0IsaUVBQWlFLGlKQUFpSiwwRUFBMEUsd0JBQXdCLG1GQUFtRixLQUFLLCtFQUErRSxLQUFLLDJEQUEyRCxvQkFBb0IsOERBQThELG9DQUFvQyxzQ0FBc0MscUZBQXFGLHdEQUF3RCwwQkFBMEIsNkRBQTZELGFBQWEsbUNBQW1DLDJDQUEyQyxvRUFBb0UsNERBQTRELCtDQUErQyw2Q0FBNkMsd0RBQXdELG9EQUFvRCwwREFBMEQsNkNBQTZDLHFEQUFxRCwrQ0FBK0MsOENBQThDLHVEQUF1RCx3QkFBd0IsZ0NBQWdDLDhCQUE4QixrQkFBa0IsaUVBQWlFLEVBQUUsZ0JBQWdCLGVBQWUsbUJBQW1CLHFCQUFxQixxQkFBcUIsZ0JBQWdCLHlCQUF5Qiw0REFBNEQsdUJBQXVCLHNCQUFzQix5QkFBeUIsa0JBQWtCLGdCQUFnQixlQUFlLHNCQUFzQix3QkFBd0IsZ0NBQWdDLE1BQU0sNENBQTRDLHdCQUF3QixNQUFNLEtBQUssK0JBQStCLGdCQUFnQixlQUFlLDRDQUE0Qyx3QkFBd0IsbUJBQW1CLHlCQUF5QixrQkFBa0Isc0JBQXNCLEVBQUUsNEJBQTRCLHNCQUFzQix3QkFBd0IsdUVBQXVFLDJEQUEyRCwwREFBMEQscUVBQXFFLHNFQUFzRSx1Q0FBdUMsd0JBQXdCLDZCQUE2QixzQkFBc0IsbUVBQW1FLGtFQUFrRSx3QkFBd0IsNkJBQTZCLDZCQUE2QixhQUFhLGdDQUFnQyxvQ0FBb0Msa0JBQWtCLDZCQUE2QixjQUFjLHVCQUF1QiwyQkFBMkIsc0NBQXNDLHVDQUF1QyxFQUFFLGdEQUFnRCxnSUFBZ0ksNENBQTRDLGNBQWMsK0JBQStCLDBDQUEwQywrQ0FBK0MsRUFBRSx5RUFBeUUsb0hBQW9ILHlDQUF5QywwQ0FBMEMsMkNBQTJDLGlCQUFpQixvQ0FBb0MsY0FBYyxnQ0FBZ0MsMENBQTBDLGdEQUFnRCxFQUFFLGdEQUFnRCxnQkFBZ0IsK0JBQStCLEtBQUssb0NBQW9DLGlCQUFpQiw0Q0FBNEMsd0RBQXdELCtDQUErQyxtQ0FBbUMsZ0RBQWdELHdEQUF3RCx1QkFBdUIscUVBQXFFLFFBQVEsNENBQTRDLHlDQUF5Qyw2REFBNkQsb0NBQW9DLG1JQUFtSSx1QkFBdUIseUJBQXlCLEdBQUcsNkJBQTZCLHNCQUFzQixpRUFBaUUsUUFBUSxvQkFBb0Isc0NBQXNDLHNDQUFzQyxnQ0FBZ0MsTUFBTSxpQkFBaUIsb0NBQW9DLE1BQU0saURBQWlELE1BQU0sa0RBQWtELE1BQU0saURBQWlELE1BQU0sbURBQW1ELE1BQU0sb0JBQW9CLDBCQUEwQiwwQkFBMEIsY0FBYyw0QkFBNEIsaUJBQWlCLG1CQUFtQiw4QkFBOEIsNkJBQTZCLHNCQUFzQixzQkFBc0Isa0JBQWtCLEVBQUUsK0NBQStDLGdCQUFnQixpREFBaUQsaURBQWlELGlCQUFpQixFQUFFLDRDQUE0QyxnQ0FBZ0MsZ0JBQWdCLGtCQUFrQiwyQkFBMkIsNkJBQTZCLElBQUksc0JBQXNCLGtCQUFrQixnQkFBZ0IsZ0JBQWdCLGVBQWUsZUFBZSxjQUFjLGNBQWMsMkVBQTJFLG9CQUFvQixvQkFBb0IsUUFBUSx1QkFBdUIsNENBQTRDLDhDQUE4QyxrQ0FBa0Msb0NBQW9DLGNBQWMsaUJBQWlCLDZEQUE2RCwwQkFBMEIsNENBQTRDLDZDQUE2QyxnQ0FBZ0MsaUNBQWlDLGdDQUFnQyw0QkFBNEIsS0FBSyxnQ0FBZ0MsNEJBQTRCLCtCQUErQiwyQkFBMkIsS0FBSywrQkFBK0IsNEJBQTRCLGtHQUFrRyx1QkFBdUIscUNBQXFDLG9CQUFvQixLQUFLLG9CQUFvQiwrQkFBK0IsdUJBQXVCLHFCQUFxQiwwQkFBMEIsY0FBYyxnQkFBZ0IsNEJBQTRCLHdCQUF3QixtQ0FBbUMsdUJBQXVCLGlEQUFpRCxzQ0FBc0MsaUNBQWlDLDBCQUEwQix3SEFBd0gsYUFBYSx5Q0FBeUMsS0FBSyw4Q0FBOEMsc0JBQXNCLGlGQUFpRixxQkFBcUIseUJBQXlCLGNBQWMsMkJBQTJCLFFBQVEsK0JBQStCLGlFQUFpRSw0QkFBNEIsc0JBQXNCLDZCQUE2QixtQ0FBbUMsaUJBQWlCLHdCQUF3QixjQUFjLHNCQUFzQixtQ0FBbUMscUJBQXFCLHFCQUFxQixzQkFBc0IsUUFBUSwrQ0FBK0MsOEJBQThCLEtBQUssNEJBQTRCLGtFQUFrRSxlQUFlLG1CQUFtQixLQUFLLDZDQUE2QyxrQkFBa0IsS0FBSyxvQkFBb0IsZUFBZSw0REFBNEQsaUVBQWlFLGdCQUFnQixjQUFjLEtBQUssc0JBQXNCLHVCQUF1QixFQUFFLG9DQUFvQyxzQkFBc0IsRUFBRSxvQkFBb0IsK0NBQStDLGVBQWUsaUJBQWlCLEVBQUUsMkNBQTJDLGNBQWMsbUJBQW1CLGtCQUFrQixFQUFFLDJDQUEyQywrQkFBK0Isc0JBQXNCLGtCQUFrQixPQUFPLEdBQUcsaUVBQWlFLE9BQU8sNFBBQTRQLHdCQUF3QixjQUFjLG9CQUFvQixtQ0FBbUMsaUJBQWlCLHlDQUF5QyxpQkFBaUIsK0JBQStCLDBCQUEwQixnQkFBZ0Isd0NBQXdDLDBEQUEwRCxxREFBcUQsdUNBQXVDLGtEQUFrRCxzREFBc0QsNENBQTRDLDJDQUEyQyxFQUFFLDBQQUEwUCxtQkFBbUIsaUVBQWlFLGtEQUFrRCxzQkFBc0Isa0NBQWtDLGVBQWUsRUFBRSxvQ0FBb0MseUNBQXlDLDRCQUE0QiwrQ0FBK0MscUNBQXFDLGtEQUFrRCx3Q0FBd0MscUNBQXFDLGtDQUFrQyx1Q0FBdUMsb0NBQW9DLG1DQUFtQyx3Q0FBd0Msa0NBQWtDLGlDQUFpQyxtQ0FBbUMsa0NBQWtDLGdDQUFnQyx1Q0FBdUMsNkNBQTZDLG1DQUFtQyxFQUFFLHNCQUFzQixtQkFBbUIsNkNBQTZDLHFCQUFxQixtQkFBbUIsd0JBQXdCLHdEQUF3RCxpQ0FBaUMsa0NBQWtDLG1CQUFtQixxQkFBcUIsc0JBQXNCLFFBQVEsdUNBQXVDLHNCQUFzQixLQUFLLG9CQUFvQixrRUFBa0UsZUFBZSxtQkFBbUIsS0FBSyw2Q0FBNkMsa0JBQWtCLEtBQUssb0JBQW9CLGVBQWUsNERBQTRELGlFQUFpRSxnQkFBZ0IsZUFBZSxFQUFFLHdCQUF3QixLQUFLLHlCQUF5QixpQ0FBaUMsbUJBQW1CLGdDQUFnQyw2QkFBNkIsbUJBQW1CLEtBQUssK0JBQStCLHVDQUF1QyxtRkFBbUYsc0JBQXNCLCtCQUErQixxQkFBcUIsS0FBSyxtQkFBbUIsS0FBSyxvQkFBb0IsK0JBQStCLFFBQVEsaUNBQWlDLDZCQUE2QixtQ0FBbUMsbUJBQW1CLG1DQUFtQyxnQ0FBZ0MscUJBQXFCLEtBQUssa0NBQWtDLHlCQUF5QiwrQkFBK0Isb0JBQW9CLEtBQUssa0JBQWtCLEtBQUssbUJBQW1CLCtCQUErQixRQUFRLDhEQUE4RCw2QkFBNkIsaUNBQWlDLDRCQUE0Qiw2QkFBNkIsS0FBSyw4QkFBOEIsMkNBQTJDLGFBQWEsUUFBUSxxQ0FBcUMsb0NBQW9DLGFBQWEsUUFBUSxvQ0FBb0Msb0NBQW9DLGNBQWMsY0FBYyxZQUFZLDZDQUE2QywrQkFBK0IsUUFBUSx1QkFBdUIseUNBQXlDLHNCQUFzQiwyREFBMkQsT0FBTywyREFBMkQseUJBQXlCLHNDQUFzQyxtQkFBbUIsa0RBQWtELHFDQUFxQywwQkFBMEIseUNBQXlDLGtCQUFrQixtREFBbUQsK0ZBQStGLGNBQWMsYUFBYSxFQUFFLHFDQUFxQyxpQ0FBaUMsMEJBQTBCLGtCQUFrQixLQUFLLDBEQUEwRCxpQkFBaUIsd0JBQXdCLHFDQUFxQyxtQkFBbUIsaUNBQWlDLDRDQUE0QywyQ0FBMkMsc0NBQXNDLEVBQUUsZ0JBQWdCLEtBQUssa0JBQWtCLG9GQUFvRixpQkFBaUIsd0JBQXdCLG9EQUFvRCw2QkFBNkIsK0JBQStCLG1DQUFtQyxtQkFBbUIsaUNBQWlDLDRDQUE0QywyQ0FBMkMsc0NBQXNDLEdBQUcsa0JBQWtCLGdCQUFnQixpQkFBaUIsc0NBQXNDLGtCQUFrQiwrQkFBK0IsMkJBQTJCLHNDQUFzQyxhQUFhLG9CQUFvQiw0QkFBNEIsY0FBYyxrQ0FBa0MsbUJBQW1CLHFFQUFxRSxjQUFjLHNCQUFzQiwwQkFBMEIsa0RBQWtELG1FQUFtRSxjQUFjLGlDQUFpQyw0RkFBNEYsOENBQThDLHNDQUFzQyxlQUFlLHVDQUF1Qyx3QkFBd0IsUUFBUSx1QkFBdUIsWUFBWSx1QkFBdUIsc0JBQXNCLHNCQUFzQixtQkFBbUIseUJBQXlCLHFCQUFxQixvQkFBb0Isb0JBQW9CLG9CQUFvQix1QkFBdUIscUNBQXFDLGdDQUFnQyw4QkFBOEIsS0FBSyxlQUFlLHdCQUF3QixjQUFjLHFCQUFxQixzQ0FBc0MsY0FBYyxnQkFBZ0IsaUVBQWlFLGNBQWMsOEJBQThCLG9DQUFvQywwQkFBMEIsbUNBQW1DLEtBQUsseUVBQXlFLGNBQWMsdUNBQXVDLDRCQUE0QixLQUFLLDBCQUEwQixjQUFjLGlEQUFpRCx5RUFBeUUsS0FBSywyQ0FBMkMseUNBQXlDLHNDQUFzQyxrQ0FBa0MsR0FBRyw0QkFBNEIsc0ZBQXNGLDRCQUE0Qiw0QkFBNEIsZ0NBQWdDLGNBQWMscUNBQXFDLDhCQUE4Qix1QkFBdUIscUNBQXFDLG9DQUFvQyx3Q0FBd0MsbUJBQW1CLHdDQUF3QyxzQ0FBc0MsMENBQTBDLHVDQUF1QyxzREFBc0QsaUVBQWlFLHNCQUFzQiwrQ0FBK0MsMkNBQTJDLG9FQUFvRSxzQkFBc0Isa0JBQWtCLDJCQUEyQixvQ0FBb0MsTUFBTSxLQUFLLEtBQUssMkNBQTJDLG1DQUFtQyxpQ0FBaUMsd0lBQXdJLCtCQUErQix3Q0FBd0MsNkJBQTZCLDJDQUEyQywwQkFBMEIseUJBQXlCLHFDQUFxQyx5QkFBeUIsbUJBQW1CLHdDQUF3QyxhQUFhLEdBQUcsS0FBSyxjQUFjLEtBQUssYUFBYSwrQkFBK0IsdUNBQXVDLG1CQUFtQixrQkFBa0IsS0FBSyxhQUFhLGlCQUFpQixrQkFBa0IsY0FBYyxrQkFBa0IsbUJBQW1CLGFBQWEsYUFBYSw2QkFBNkIsYUFBYSw0REFBNEQsMkJBQTJCLDhCQUE4QixLQUFLLDJEQUEyRCwwQkFBMEIsOEJBQThCLEtBQUssZUFBZSxRQUFRLGNBQWMsdUJBQXVCLDRCQUE0Qiw0QkFBNEIsd0NBQXdDLHdDQUF3Qyw4QkFBOEIsc0NBQXNDLGlDQUFpQyw0QkFBNEIsMkJBQTJCLGlEQUFpRCxnREFBZ0QsbUJBQW1CLG9CQUFvQixvREFBb0QsY0FBYyw0RkFBNEYsa0JBQWtCLGNBQWMsMENBQTBDLHFCQUFxQiw2Q0FBNkMsOENBQThDLG1CQUFtQiwwRUFBMEUsc0JBQXNCLG9EQUFvRCxnQkFBZ0IsdUVBQXVFLEVBQUUsOERBQThELDJCQUEyQixvQ0FBb0MsZUFBZSxxQ0FBcUMsdUJBQXVCLGlEQUFpRCxnREFBZ0QsbUJBQW1CLHlCQUF5QixtQkFBbUIsbUJBQW1CLGFBQWEsS0FBSyxpQkFBaUIsd0JBQXdCLDZCQUE2QiwyQkFBMkIsb2FBQW9hLDJoQkFBMmhCLGlCQUFpQixJQUFJLG9CQUFvQixRQUFRLHFCQUFxQiwyQkFBMkIsOGlCQUE4aUIsaUVBQWlFLDRCQUE0QiwwQkFBMEIsb0JBQW9CLHFCQUFxQix1QkFBdUIsd0JBQXdCLGtCQUFrQixtQ0FBbUMsYUFBYSx3QkFBd0IsZUFBZSw0Q0FBNEMsV0FBVyxTQUFTLGdDQUFnQyxlQUFlLEVBQUUsZ0NBQWdDLGVBQWUsRUFBRSw2QkFBNkIsK0RBQStELGdDQUFnQyxHQUFHIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL2pxdWVyeS1jb25maXJtL2Rpc3QvanF1ZXJ5LWNvbmZpcm0ubWluLmpzP2YyYTEiXSwic291cmNlc0NvbnRlbnQiOlsiLyohXHJcbiAqIGpxdWVyeS1jb25maXJtIHYzLjMuNCAoaHR0cDovL2NyYWZ0cGlwLmdpdGh1Yi5pby9qcXVlcnktY29uZmlybS8pXHJcbiAqIEF1dGhvcjogQm9uaWZhY2UgUGVyZWlyYVxyXG4gKiBXZWJzaXRlOiB3d3cuY3JhZnRwaXAuY29tXHJcbiAqIENvbnRhY3Q6IGhleUBjcmFmdHBpcC5jb21cclxuICpcclxuICogQ29weXJpZ2h0IDIwMTMtMjAxOSBqcXVlcnktY29uZmlybVxyXG4gKiBMaWNlbnNlZCB1bmRlciBNSVQgKGh0dHBzOi8vZ2l0aHViLmNvbS9jcmFmdHBpcC9qcXVlcnktY29uZmlybS9ibG9iL21hc3Rlci9MSUNFTlNFKVxyXG4gKi9cclxuKGZ1bmN0aW9uKGZhY3Rvcnkpe2lmKHR5cGVvZiBkZWZpbmU9PT1cImZ1bmN0aW9uXCImJmRlZmluZS5hbWQpe2RlZmluZShbXCJqcXVlcnlcIl0sZmFjdG9yeSk7fWVsc2V7aWYodHlwZW9mIG1vZHVsZT09PVwib2JqZWN0XCImJm1vZHVsZS5leHBvcnRzKXttb2R1bGUuZXhwb3J0cz1mdW5jdGlvbihyb290LGpRdWVyeSl7aWYoalF1ZXJ5PT09dW5kZWZpbmVkKXtpZih0eXBlb2Ygd2luZG93IT09XCJ1bmRlZmluZWRcIil7alF1ZXJ5PXJlcXVpcmUoXCJqcXVlcnlcIik7fWVsc2V7alF1ZXJ5PXJlcXVpcmUoXCJqcXVlcnlcIikocm9vdCk7fX1mYWN0b3J5KGpRdWVyeSk7cmV0dXJuIGpRdWVyeTt9O31lbHNle2ZhY3RvcnkoalF1ZXJ5KTt9fX0oZnVuY3Rpb24oJCl7dmFyIHc9d2luZG93OyQuZm4uY29uZmlybT1mdW5jdGlvbihvcHRpb25zLG9wdGlvbjIpe2lmKHR5cGVvZiBvcHRpb25zPT09XCJ1bmRlZmluZWRcIil7b3B0aW9ucz17fTt9aWYodHlwZW9mIG9wdGlvbnM9PT1cInN0cmluZ1wiKXtvcHRpb25zPXtjb250ZW50Om9wdGlvbnMsdGl0bGU6KG9wdGlvbjIpP29wdGlvbjI6ZmFsc2V9O30kKHRoaXMpLmVhY2goZnVuY3Rpb24oKXt2YXIgJHRoaXM9JCh0aGlzKTtpZigkdGhpcy5hdHRyKFwiamMtYXR0YWNoZWRcIikpe2NvbnNvbGUud2FybihcImpDb25maXJtIGhhcyBhbHJlYWR5IGJlZW4gYXR0YWNoZWQgdG8gdGhpcyBlbGVtZW50IFwiLCR0aGlzWzBdKTtyZXR1cm47fSR0aGlzLm9uKFwiY2xpY2tcIixmdW5jdGlvbihlKXtlLnByZXZlbnREZWZhdWx0KCk7dmFyIGpjT3B0aW9uPSQuZXh0ZW5kKHt9LG9wdGlvbnMpO2lmKCR0aGlzLmF0dHIoXCJkYXRhLXRpdGxlXCIpKXtqY09wdGlvbi50aXRsZT0kdGhpcy5hdHRyKFwiZGF0YS10aXRsZVwiKTt9aWYoJHRoaXMuYXR0cihcImRhdGEtY29udGVudFwiKSl7amNPcHRpb24uY29udGVudD0kdGhpcy5hdHRyKFwiZGF0YS1jb250ZW50XCIpO31pZih0eXBlb2YgamNPcHRpb24uYnV0dG9ucz09PVwidW5kZWZpbmVkXCIpe2pjT3B0aW9uLmJ1dHRvbnM9e307fWpjT3B0aW9uW1wiJHRhcmdldFwiXT0kdGhpcztpZigkdGhpcy5hdHRyKFwiaHJlZlwiKSYmT2JqZWN0LmtleXMoamNPcHRpb24uYnV0dG9ucykubGVuZ3RoPT09MCl7dmFyIGJ1dHRvbnM9JC5leHRlbmQodHJ1ZSx7fSx3Lmpjb25maXJtLnBsdWdpbkRlZmF1bHRzLmRlZmF1bHRCdXR0b25zLCh3Lmpjb25maXJtLmRlZmF1bHRzfHx7fSkuZGVmYXVsdEJ1dHRvbnN8fHt9KTt2YXIgZmlyc3RCdG49T2JqZWN0LmtleXMoYnV0dG9ucylbMF07amNPcHRpb24uYnV0dG9ucz1idXR0b25zO2pjT3B0aW9uLmJ1dHRvbnNbZmlyc3RCdG5dLmFjdGlvbj1mdW5jdGlvbigpe2xvY2F0aW9uLmhyZWY9JHRoaXMuYXR0cihcImhyZWZcIik7fTt9amNPcHRpb24uY2xvc2VJY29uPWZhbHNlO3ZhciBpbnN0YW5jZT0kLmNvbmZpcm0oamNPcHRpb24pO30pOyR0aGlzLmF0dHIoXCJqYy1hdHRhY2hlZFwiLHRydWUpO30pO3JldHVybiAkKHRoaXMpO307JC5jb25maXJtPWZ1bmN0aW9uKG9wdGlvbnMsb3B0aW9uMil7aWYodHlwZW9mIG9wdGlvbnM9PT1cInVuZGVmaW5lZFwiKXtvcHRpb25zPXt9O31pZih0eXBlb2Ygb3B0aW9ucz09PVwic3RyaW5nXCIpe29wdGlvbnM9e2NvbnRlbnQ6b3B0aW9ucyx0aXRsZToob3B0aW9uMik/b3B0aW9uMjpmYWxzZX07fXZhciBwdXREZWZhdWx0QnV0dG9ucz0hKG9wdGlvbnMuYnV0dG9ucz09PWZhbHNlKTtpZih0eXBlb2Ygb3B0aW9ucy5idXR0b25zIT09XCJvYmplY3RcIil7b3B0aW9ucy5idXR0b25zPXt9O31pZihPYmplY3Qua2V5cyhvcHRpb25zLmJ1dHRvbnMpLmxlbmd0aD09PTAmJnB1dERlZmF1bHRCdXR0b25zKXt2YXIgYnV0dG9ucz0kLmV4dGVuZCh0cnVlLHt9LHcuamNvbmZpcm0ucGx1Z2luRGVmYXVsdHMuZGVmYXVsdEJ1dHRvbnMsKHcuamNvbmZpcm0uZGVmYXVsdHN8fHt9KS5kZWZhdWx0QnV0dG9uc3x8e30pO29wdGlvbnMuYnV0dG9ucz1idXR0b25zO31yZXR1cm4gdy5qY29uZmlybShvcHRpb25zKTt9OyQuYWxlcnQ9ZnVuY3Rpb24ob3B0aW9ucyxvcHRpb24yKXtpZih0eXBlb2Ygb3B0aW9ucz09PVwidW5kZWZpbmVkXCIpe29wdGlvbnM9e307fWlmKHR5cGVvZiBvcHRpb25zPT09XCJzdHJpbmdcIil7b3B0aW9ucz17Y29udGVudDpvcHRpb25zLHRpdGxlOihvcHRpb24yKT9vcHRpb24yOmZhbHNlfTt9dmFyIHB1dERlZmF1bHRCdXR0b25zPSEob3B0aW9ucy5idXR0b25zPT09ZmFsc2UpO2lmKHR5cGVvZiBvcHRpb25zLmJ1dHRvbnMhPT1cIm9iamVjdFwiKXtvcHRpb25zLmJ1dHRvbnM9e307fWlmKE9iamVjdC5rZXlzKG9wdGlvbnMuYnV0dG9ucykubGVuZ3RoPT09MCYmcHV0RGVmYXVsdEJ1dHRvbnMpe3ZhciBidXR0b25zPSQuZXh0ZW5kKHRydWUse30sdy5qY29uZmlybS5wbHVnaW5EZWZhdWx0cy5kZWZhdWx0QnV0dG9ucywody5qY29uZmlybS5kZWZhdWx0c3x8e30pLmRlZmF1bHRCdXR0b25zfHx7fSk7dmFyIGZpcnN0QnRuPU9iamVjdC5rZXlzKGJ1dHRvbnMpWzBdO29wdGlvbnMuYnV0dG9uc1tmaXJzdEJ0bl09YnV0dG9uc1tmaXJzdEJ0bl07fXJldHVybiB3Lmpjb25maXJtKG9wdGlvbnMpO307JC5kaWFsb2c9ZnVuY3Rpb24ob3B0aW9ucyxvcHRpb24yKXtpZih0eXBlb2Ygb3B0aW9ucz09PVwidW5kZWZpbmVkXCIpe29wdGlvbnM9e307fWlmKHR5cGVvZiBvcHRpb25zPT09XCJzdHJpbmdcIil7b3B0aW9ucz17Y29udGVudDpvcHRpb25zLHRpdGxlOihvcHRpb24yKT9vcHRpb24yOmZhbHNlLGNsb3NlSWNvbjpmdW5jdGlvbigpe319O31vcHRpb25zLmJ1dHRvbnM9e307aWYodHlwZW9mIG9wdGlvbnMuY2xvc2VJY29uPT09XCJ1bmRlZmluZWRcIil7b3B0aW9ucy5jbG9zZUljb249ZnVuY3Rpb24oKXt9O31vcHRpb25zLmNvbmZpcm1LZXlzPVsxM107cmV0dXJuIHcuamNvbmZpcm0ob3B0aW9ucyk7fTt3Lmpjb25maXJtPWZ1bmN0aW9uKG9wdGlvbnMpe2lmKHR5cGVvZiBvcHRpb25zPT09XCJ1bmRlZmluZWRcIil7b3B0aW9ucz17fTt9dmFyIHBsdWdpbk9wdGlvbnM9JC5leHRlbmQodHJ1ZSx7fSx3Lmpjb25maXJtLnBsdWdpbkRlZmF1bHRzKTtpZih3Lmpjb25maXJtLmRlZmF1bHRzKXtwbHVnaW5PcHRpb25zPSQuZXh0ZW5kKHRydWUscGx1Z2luT3B0aW9ucyx3Lmpjb25maXJtLmRlZmF1bHRzKTt9cGx1Z2luT3B0aW9ucz0kLmV4dGVuZCh0cnVlLHt9LHBsdWdpbk9wdGlvbnMsb3B0aW9ucyk7dmFyIGluc3RhbmNlPW5ldyB3Lkpjb25maXJtKHBsdWdpbk9wdGlvbnMpO3cuamNvbmZpcm0uaW5zdGFuY2VzLnB1c2goaW5zdGFuY2UpO3JldHVybiBpbnN0YW5jZTt9O3cuSmNvbmZpcm09ZnVuY3Rpb24ob3B0aW9ucyl7JC5leHRlbmQodGhpcyxvcHRpb25zKTt0aGlzLl9pbml0KCk7fTt3Lkpjb25maXJtLnByb3RvdHlwZT17X2luaXQ6ZnVuY3Rpb24oKXt2YXIgdGhhdD10aGlzO2lmKCF3Lmpjb25maXJtLmluc3RhbmNlcy5sZW5ndGgpe3cuamNvbmZpcm0ubGFzdEZvY3VzZWQ9JChcImJvZHlcIikuZmluZChcIjpmb2N1c1wiKTt9dGhpcy5faWQ9TWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpKjk5OTk5KTt0aGlzLmNvbnRlbnRQYXJzZWQ9JChkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpKTtpZighdGhpcy5sYXp5T3Blbil7c2V0VGltZW91dChmdW5jdGlvbigpe3RoYXQub3BlbigpO30sMCk7fX0sX2J1aWxkSFRNTDpmdW5jdGlvbigpe3ZhciB0aGF0PXRoaXM7dGhpcy5fcGFyc2VBbmltYXRpb24odGhpcy5hbmltYXRpb24sXCJvXCIpO3RoaXMuX3BhcnNlQW5pbWF0aW9uKHRoaXMuY2xvc2VBbmltYXRpb24sXCJjXCIpO3RoaXMuX3BhcnNlQmdEaXNtaXNzQW5pbWF0aW9uKHRoaXMuYmFja2dyb3VuZERpc21pc3NBbmltYXRpb24pO3RoaXMuX3BhcnNlQ29sdW1uQ2xhc3ModGhpcy5jb2x1bW5DbGFzcyk7dGhpcy5fcGFyc2VUaGVtZSh0aGlzLnRoZW1lKTt0aGlzLl9wYXJzZVR5cGUodGhpcy50eXBlKTt2YXIgdGVtcGxhdGU9JCh0aGlzLnRlbXBsYXRlKTt0ZW1wbGF0ZS5maW5kKFwiLmpjb25maXJtLWJveFwiKS5hZGRDbGFzcyh0aGlzLmFuaW1hdGlvblBhcnNlZCkuYWRkQ2xhc3ModGhpcy5iYWNrZ3JvdW5kRGlzbWlzc0FuaW1hdGlvblBhcnNlZCkuYWRkQ2xhc3ModGhpcy50eXBlUGFyc2VkKTtpZih0aGlzLnR5cGVBbmltYXRlZCl7dGVtcGxhdGUuZmluZChcIi5qY29uZmlybS1ib3hcIikuYWRkQ2xhc3MoXCJqY29uZmlybS10eXBlLWFuaW1hdGVkXCIpO31pZih0aGlzLnVzZUJvb3RzdHJhcCl7dGVtcGxhdGUuZmluZChcIi5qYy1iczMtcm93XCIpLmFkZENsYXNzKHRoaXMuYm9vdHN0cmFwQ2xhc3Nlcy5yb3cpO3RlbXBsYXRlLmZpbmQoXCIuamMtYnMzLXJvd1wiKS5hZGRDbGFzcyhcImp1c3RpZnktY29udGVudC1tZC1jZW50ZXIganVzdGlmeS1jb250ZW50LXNtLWNlbnRlciBqdXN0aWZ5LWNvbnRlbnQteHMtY2VudGVyIGp1c3RpZnktY29udGVudC1sZy1jZW50ZXJcIik7dGVtcGxhdGUuZmluZChcIi5qY29uZmlybS1ib3gtY29udGFpbmVyXCIpLmFkZENsYXNzKHRoaXMuY29sdW1uQ2xhc3NQYXJzZWQpO2lmKHRoaXMuY29udGFpbmVyRmx1aWQpe3RlbXBsYXRlLmZpbmQoXCIuamMtYnMzLWNvbnRhaW5lclwiKS5hZGRDbGFzcyh0aGlzLmJvb3RzdHJhcENsYXNzZXMuY29udGFpbmVyRmx1aWQpO31lbHNle3RlbXBsYXRlLmZpbmQoXCIuamMtYnMzLWNvbnRhaW5lclwiKS5hZGRDbGFzcyh0aGlzLmJvb3RzdHJhcENsYXNzZXMuY29udGFpbmVyKTt9fWVsc2V7dGVtcGxhdGUuZmluZChcIi5qY29uZmlybS1ib3hcIikuY3NzKFwid2lkdGhcIix0aGlzLmJveFdpZHRoKTt9aWYodGhpcy50aXRsZUNsYXNzKXt0ZW1wbGF0ZS5maW5kKFwiLmpjb25maXJtLXRpdGxlLWNcIikuYWRkQ2xhc3ModGhpcy50aXRsZUNsYXNzKTt9dGVtcGxhdGUuYWRkQ2xhc3ModGhpcy50aGVtZVBhcnNlZCk7dmFyIGFyaWFMYWJlbD1cImpjb25maXJtLWJveFwiK3RoaXMuX2lkO3RlbXBsYXRlLmZpbmQoXCIuamNvbmZpcm0tYm94XCIpLmF0dHIoXCJhcmlhLWxhYmVsbGVkYnlcIixhcmlhTGFiZWwpLmF0dHIoXCJ0YWJpbmRleFwiLC0xKTt0ZW1wbGF0ZS5maW5kKFwiLmpjb25maXJtLWNvbnRlbnRcIikuYXR0cihcImlkXCIsYXJpYUxhYmVsKTtpZih0aGlzLmJnT3BhY2l0eSE9PW51bGwpe3RlbXBsYXRlLmZpbmQoXCIuamNvbmZpcm0tYmdcIikuY3NzKFwib3BhY2l0eVwiLHRoaXMuYmdPcGFjaXR5KTt9aWYodGhpcy5ydGwpe3RlbXBsYXRlLmFkZENsYXNzKFwiamNvbmZpcm0tcnRsXCIpO310aGlzLiRlbD10ZW1wbGF0ZS5hcHBlbmRUbyh0aGlzLmNvbnRhaW5lcik7dGhpcy4kamNvbmZpcm1Cb3hDb250YWluZXI9dGhpcy4kZWwuZmluZChcIi5qY29uZmlybS1ib3gtY29udGFpbmVyXCIpO3RoaXMuJGpjb25maXJtQm94PXRoaXMuJGJvZHk9dGhpcy4kZWwuZmluZChcIi5qY29uZmlybS1ib3hcIik7dGhpcy4kamNvbmZpcm1CZz10aGlzLiRlbC5maW5kKFwiLmpjb25maXJtLWJnXCIpO3RoaXMuJHRpdGxlPXRoaXMuJGVsLmZpbmQoXCIuamNvbmZpcm0tdGl0bGVcIik7dGhpcy4kdGl0bGVDb250YWluZXI9dGhpcy4kZWwuZmluZChcIi5qY29uZmlybS10aXRsZS1jXCIpO3RoaXMuJGNvbnRlbnQ9dGhpcy4kZWwuZmluZChcImRpdi5qY29uZmlybS1jb250ZW50XCIpO3RoaXMuJGNvbnRlbnRQYW5lPXRoaXMuJGVsLmZpbmQoXCIuamNvbmZpcm0tY29udGVudC1wYW5lXCIpO3RoaXMuJGljb249dGhpcy4kZWwuZmluZChcIi5qY29uZmlybS1pY29uLWNcIik7dGhpcy4kY2xvc2VJY29uPXRoaXMuJGVsLmZpbmQoXCIuamNvbmZpcm0tY2xvc2VJY29uXCIpO3RoaXMuJGhvbGRlcj10aGlzLiRlbC5maW5kKFwiLmpjb25maXJtLWhvbGRlclwiKTt0aGlzLiRidG5jPXRoaXMuJGVsLmZpbmQoXCIuamNvbmZpcm0tYnV0dG9uc1wiKTt0aGlzLiRzY3JvbGxQYW5lPXRoaXMuJGVsLmZpbmQoXCIuamNvbmZpcm0tc2Nyb2xscGFuZVwiKTt0aGF0LnNldFN0YXJ0aW5nUG9pbnQoKTt0aGlzLl9jb250ZW50UmVhZHk9JC5EZWZlcnJlZCgpO3RoaXMuX21vZGFsUmVhZHk9JC5EZWZlcnJlZCgpO3RoaXMuJGhvbGRlci5jc3Moe1wicGFkZGluZy10b3BcIjp0aGlzLm9mZnNldFRvcCxcInBhZGRpbmctYm90dG9tXCI6dGhpcy5vZmZzZXRCb3R0b20sfSk7dGhpcy5zZXRUaXRsZSgpO3RoaXMuc2V0SWNvbigpO3RoaXMuX3NldEJ1dHRvbnMoKTt0aGlzLl9wYXJzZUNvbnRlbnQoKTt0aGlzLmluaXREcmFnZ2FibGUoKTtpZih0aGlzLmlzQWpheCl7dGhpcy5zaG93TG9hZGluZyhmYWxzZSk7fSQud2hlbih0aGlzLl9jb250ZW50UmVhZHksdGhpcy5fbW9kYWxSZWFkeSkudGhlbihmdW5jdGlvbigpe2lmKHRoYXQuaXNBamF4TG9hZGluZyl7c2V0VGltZW91dChmdW5jdGlvbigpe3RoYXQuaXNBamF4TG9hZGluZz1mYWxzZTt0aGF0LnNldENvbnRlbnQoKTt0aGF0LnNldFRpdGxlKCk7dGhhdC5zZXRJY29uKCk7c2V0VGltZW91dChmdW5jdGlvbigpe3RoYXQuaGlkZUxvYWRpbmcoZmFsc2UpO3RoYXQuX3VwZGF0ZUNvbnRlbnRNYXhIZWlnaHQoKTt9LDEwMCk7aWYodHlwZW9mIHRoYXQub25Db250ZW50UmVhZHk9PT1cImZ1bmN0aW9uXCIpe3RoYXQub25Db250ZW50UmVhZHkoKTt9fSw1MCk7fWVsc2V7dGhhdC5fdXBkYXRlQ29udGVudE1heEhlaWdodCgpO3RoYXQuc2V0VGl0bGUoKTt0aGF0LnNldEljb24oKTtpZih0eXBlb2YgdGhhdC5vbkNvbnRlbnRSZWFkeT09PVwiZnVuY3Rpb25cIil7dGhhdC5vbkNvbnRlbnRSZWFkeSgpO319aWYodGhhdC5hdXRvQ2xvc2Upe3RoYXQuX3N0YXJ0Q291bnREb3duKCk7fX0pLnRoZW4oZnVuY3Rpb24oKXt0aGF0Ll93YXRjaENvbnRlbnQoKTt9KTtpZih0aGlzLmFuaW1hdGlvbj09PVwibm9uZVwiKXt0aGlzLmFuaW1hdGlvblNwZWVkPTE7dGhpcy5hbmltYXRpb25Cb3VuY2U9MTt9dGhpcy4kYm9keS5jc3ModGhpcy5fZ2V0Q1NTKHRoaXMuYW5pbWF0aW9uU3BlZWQsdGhpcy5hbmltYXRpb25Cb3VuY2UpKTt0aGlzLiRjb250ZW50UGFuZS5jc3ModGhpcy5fZ2V0Q1NTKHRoaXMuYW5pbWF0aW9uU3BlZWQsMSkpO3RoaXMuJGpjb25maXJtQmcuY3NzKHRoaXMuX2dldENTUyh0aGlzLmFuaW1hdGlvblNwZWVkLDEpKTt0aGlzLiRqY29uZmlybUJveENvbnRhaW5lci5jc3ModGhpcy5fZ2V0Q1NTKHRoaXMuYW5pbWF0aW9uU3BlZWQsMSkpO30sX3R5cGVQcmVmaXg6XCJqY29uZmlybS10eXBlLVwiLHR5cGVQYXJzZWQ6XCJcIixfcGFyc2VUeXBlOmZ1bmN0aW9uKHR5cGUpe3RoaXMudHlwZVBhcnNlZD10aGlzLl90eXBlUHJlZml4K3R5cGU7fSxzZXRUeXBlOmZ1bmN0aW9uKHR5cGUpe3ZhciBvbGRDbGFzcz10aGlzLnR5cGVQYXJzZWQ7dGhpcy5fcGFyc2VUeXBlKHR5cGUpO3RoaXMuJGpjb25maXJtQm94LnJlbW92ZUNsYXNzKG9sZENsYXNzKS5hZGRDbGFzcyh0aGlzLnR5cGVQYXJzZWQpO30sdGhlbWVQYXJzZWQ6XCJcIixfdGhlbWVQcmVmaXg6XCJqY29uZmlybS1cIixzZXRUaGVtZTpmdW5jdGlvbih0aGVtZSl7dmFyIHByZXZpb3VzPXRoaXMudGhlbWU7dGhpcy50aGVtZT10aGVtZXx8dGhpcy50aGVtZTt0aGlzLl9wYXJzZVRoZW1lKHRoaXMudGhlbWUpO2lmKHByZXZpb3VzKXt0aGlzLiRlbC5yZW1vdmVDbGFzcyhwcmV2aW91cyk7fXRoaXMuJGVsLmFkZENsYXNzKHRoaXMudGhlbWVQYXJzZWQpO3RoaXMudGhlbWU9dGhlbWU7fSxfcGFyc2VUaGVtZTpmdW5jdGlvbih0aGVtZSl7dmFyIHRoYXQ9dGhpczt0aGVtZT10aGVtZS5zcGxpdChcIixcIik7JC5lYWNoKHRoZW1lLGZ1bmN0aW9uKGssYSl7aWYoYS5pbmRleE9mKHRoYXQuX3RoZW1lUHJlZml4KT09PS0xKXt0aGVtZVtrXT10aGF0Ll90aGVtZVByZWZpeCskLnRyaW0oYSk7fX0pO3RoaXMudGhlbWVQYXJzZWQ9dGhlbWUuam9pbihcIiBcIikudG9Mb3dlckNhc2UoKTt9LGJhY2tncm91bmREaXNtaXNzQW5pbWF0aW9uUGFyc2VkOlwiXCIsX2JnRGlzbWlzc1ByZWZpeDpcImpjb25maXJtLWhpbGlnaHQtXCIsX3BhcnNlQmdEaXNtaXNzQW5pbWF0aW9uOmZ1bmN0aW9uKGJnRGlzbWlzc0FuaW1hdGlvbil7dmFyIGFuaW1hdGlvbj1iZ0Rpc21pc3NBbmltYXRpb24uc3BsaXQoXCIsXCIpO3ZhciB0aGF0PXRoaXM7JC5lYWNoKGFuaW1hdGlvbixmdW5jdGlvbihrLGEpe2lmKGEuaW5kZXhPZih0aGF0Ll9iZ0Rpc21pc3NQcmVmaXgpPT09LTEpe2FuaW1hdGlvbltrXT10aGF0Ll9iZ0Rpc21pc3NQcmVmaXgrJC50cmltKGEpO319KTt0aGlzLmJhY2tncm91bmREaXNtaXNzQW5pbWF0aW9uUGFyc2VkPWFuaW1hdGlvbi5qb2luKFwiIFwiKS50b0xvd2VyQ2FzZSgpO30sYW5pbWF0aW9uUGFyc2VkOlwiXCIsY2xvc2VBbmltYXRpb25QYXJzZWQ6XCJcIixfYW5pbWF0aW9uUHJlZml4OlwiamNvbmZpcm0tYW5pbWF0aW9uLVwiLHNldEFuaW1hdGlvbjpmdW5jdGlvbihhbmltYXRpb24pe3RoaXMuYW5pbWF0aW9uPWFuaW1hdGlvbnx8dGhpcy5hbmltYXRpb247dGhpcy5fcGFyc2VBbmltYXRpb24odGhpcy5hbmltYXRpb24sXCJvXCIpO30sX3BhcnNlQW5pbWF0aW9uOmZ1bmN0aW9uKGFuaW1hdGlvbix3aGljaCl7d2hpY2g9d2hpY2h8fFwib1wiO3ZhciBhbmltYXRpb25zPWFuaW1hdGlvbi5zcGxpdChcIixcIik7dmFyIHRoYXQ9dGhpczskLmVhY2goYW5pbWF0aW9ucyxmdW5jdGlvbihrLGEpe2lmKGEuaW5kZXhPZih0aGF0Ll9hbmltYXRpb25QcmVmaXgpPT09LTEpe2FuaW1hdGlvbnNba109dGhhdC5fYW5pbWF0aW9uUHJlZml4KyQudHJpbShhKTt9fSk7dmFyIGFfc3RyaW5nPWFuaW1hdGlvbnMuam9pbihcIiBcIikudG9Mb3dlckNhc2UoKTtpZih3aGljaD09PVwib1wiKXt0aGlzLmFuaW1hdGlvblBhcnNlZD1hX3N0cmluZzt9ZWxzZXt0aGlzLmNsb3NlQW5pbWF0aW9uUGFyc2VkPWFfc3RyaW5nO31yZXR1cm4gYV9zdHJpbmc7fSxzZXRDbG9zZUFuaW1hdGlvbjpmdW5jdGlvbihjbG9zZUFuaW1hdGlvbil7dGhpcy5jbG9zZUFuaW1hdGlvbj1jbG9zZUFuaW1hdGlvbnx8dGhpcy5jbG9zZUFuaW1hdGlvbjt0aGlzLl9wYXJzZUFuaW1hdGlvbih0aGlzLmNsb3NlQW5pbWF0aW9uLFwiY1wiKTt9LHNldEFuaW1hdGlvblNwZWVkOmZ1bmN0aW9uKHNwZWVkKXt0aGlzLmFuaW1hdGlvblNwZWVkPXNwZWVkfHx0aGlzLmFuaW1hdGlvblNwZWVkO30sY29sdW1uQ2xhc3NQYXJzZWQ6XCJcIixzZXRDb2x1bW5DbGFzczpmdW5jdGlvbihjb2xDbGFzcyl7aWYoIXRoaXMudXNlQm9vdHN0cmFwKXtjb25zb2xlLndhcm4oXCJjYW5ub3Qgc2V0IGNvbHVtbkNsYXNzLCB1c2VCb290c3RyYXAgaXMgc2V0IHRvIGZhbHNlXCIpO3JldHVybjt9dGhpcy5jb2x1bW5DbGFzcz1jb2xDbGFzc3x8dGhpcy5jb2x1bW5DbGFzczt0aGlzLl9wYXJzZUNvbHVtbkNsYXNzKHRoaXMuY29sdW1uQ2xhc3MpO3RoaXMuJGpjb25maXJtQm94Q29udGFpbmVyLmFkZENsYXNzKHRoaXMuY29sdW1uQ2xhc3NQYXJzZWQpO30sX3VwZGF0ZUNvbnRlbnRNYXhIZWlnaHQ6ZnVuY3Rpb24oKXt2YXIgaGVpZ2h0PSQod2luZG93KS5oZWlnaHQoKS0odGhpcy4kamNvbmZpcm1Cb3gub3V0ZXJIZWlnaHQoKS10aGlzLiRjb250ZW50UGFuZS5vdXRlckhlaWdodCgpKS0odGhpcy5vZmZzZXRUb3ArdGhpcy5vZmZzZXRCb3R0b20pO3RoaXMuJGNvbnRlbnRQYW5lLmNzcyh7XCJtYXgtaGVpZ2h0XCI6aGVpZ2h0K1wicHhcIn0pO30sc2V0Qm94V2lkdGg6ZnVuY3Rpb24od2lkdGgpe2lmKHRoaXMudXNlQm9vdHN0cmFwKXtjb25zb2xlLndhcm4oXCJjYW5ub3Qgc2V0IGJveFdpZHRoLCB1c2VCb290c3RyYXAgaXMgc2V0IHRvIHRydWVcIik7cmV0dXJuO310aGlzLmJveFdpZHRoPXdpZHRoO3RoaXMuJGpjb25maXJtQm94LmNzcyhcIndpZHRoXCIsd2lkdGgpO30sX3BhcnNlQ29sdW1uQ2xhc3M6ZnVuY3Rpb24oY29sQ2xhc3Mpe2NvbENsYXNzPWNvbENsYXNzLnRvTG93ZXJDYXNlKCk7dmFyIHA7c3dpdGNoKGNvbENsYXNzKXtjYXNlXCJ4bFwiOmNhc2VcInhsYXJnZVwiOnA9XCJjb2wtbWQtMTJcIjticmVhaztjYXNlXCJsXCI6Y2FzZVwibGFyZ2VcIjpwPVwiY29sLW1kLTggY29sLW1kLW9mZnNldC0yXCI7YnJlYWs7Y2FzZVwibVwiOmNhc2VcIm1lZGl1bVwiOnA9XCJjb2wtbWQtNiBjb2wtbWQtb2Zmc2V0LTNcIjticmVhaztjYXNlXCJzXCI6Y2FzZVwic21hbGxcIjpwPVwiY29sLW1kLTQgY29sLW1kLW9mZnNldC00XCI7YnJlYWs7Y2FzZVwieHNcIjpjYXNlXCJ4c21hbGxcIjpwPVwiY29sLW1kLTIgY29sLW1kLW9mZnNldC01XCI7YnJlYWs7ZGVmYXVsdDpwPWNvbENsYXNzO310aGlzLmNvbHVtbkNsYXNzUGFyc2VkPXA7fSxpbml0RHJhZ2dhYmxlOmZ1bmN0aW9uKCl7dmFyIHRoYXQ9dGhpczt2YXIgJHQ9dGhpcy4kdGl0bGVDb250YWluZXI7dGhpcy5yZXNldERyYWcoKTtpZih0aGlzLmRyYWdnYWJsZSl7JHQub24oXCJtb3VzZWRvd25cIixmdW5jdGlvbihlKXskdC5hZGRDbGFzcyhcImpjb25maXJtLWhhbmRcIik7dGhhdC5tb3VzZVg9ZS5jbGllbnRYO3RoYXQubW91c2VZPWUuY2xpZW50WTt0aGF0LmlzRHJhZz10cnVlO30pOyQod2luZG93KS5vbihcIm1vdXNlbW92ZS5cIit0aGlzLl9pZCxmdW5jdGlvbihlKXtpZih0aGF0LmlzRHJhZyl7dGhhdC5tb3ZpbmdYPWUuY2xpZW50WC10aGF0Lm1vdXNlWCt0aGF0LmluaXRpYWxYO3RoYXQubW92aW5nWT1lLmNsaWVudFktdGhhdC5tb3VzZVkrdGhhdC5pbml0aWFsWTt0aGF0LnNldERyYWcoKTt9fSk7JCh3aW5kb3cpLm9uKFwibW91c2V1cC5cIit0aGlzLl9pZCxmdW5jdGlvbigpeyR0LnJlbW92ZUNsYXNzKFwiamNvbmZpcm0taGFuZFwiKTtpZih0aGF0LmlzRHJhZyl7dGhhdC5pc0RyYWc9ZmFsc2U7dGhhdC5pbml0aWFsWD10aGF0Lm1vdmluZ1g7dGhhdC5pbml0aWFsWT10aGF0Lm1vdmluZ1k7fX0pO319LHJlc2V0RHJhZzpmdW5jdGlvbigpe3RoaXMuaXNEcmFnPWZhbHNlO3RoaXMuaW5pdGlhbFg9MDt0aGlzLmluaXRpYWxZPTA7dGhpcy5tb3ZpbmdYPTA7dGhpcy5tb3ZpbmdZPTA7dGhpcy5tb3VzZVg9MDt0aGlzLm1vdXNlWT0wO3RoaXMuJGpjb25maXJtQm94Q29udGFpbmVyLmNzcyhcInRyYW5zZm9ybVwiLFwidHJhbnNsYXRlKFwiKzArXCJweCwgXCIrMCtcInB4KVwiKTt9LHNldERyYWc6ZnVuY3Rpb24oKXtpZighdGhpcy5kcmFnZ2FibGUpe3JldHVybjt9dGhpcy5hbGlnbk1pZGRsZT1mYWxzZTt2YXIgYm94V2lkdGg9dGhpcy4kamNvbmZpcm1Cb3gub3V0ZXJXaWR0aCgpO3ZhciBib3hIZWlnaHQ9dGhpcy4kamNvbmZpcm1Cb3gub3V0ZXJIZWlnaHQoKTt2YXIgd2luZG93V2lkdGg9JCh3aW5kb3cpLndpZHRoKCk7dmFyIHdpbmRvd0hlaWdodD0kKHdpbmRvdykuaGVpZ2h0KCk7dmFyIHRoYXQ9dGhpczt2YXIgZHJhZ1VwZGF0ZT0xO2lmKHRoYXQubW92aW5nWCVkcmFnVXBkYXRlPT09MHx8dGhhdC5tb3ZpbmdZJWRyYWdVcGRhdGU9PT0wKXtpZih0aGF0LmRyYWdXaW5kb3dCb3JkZXIpe3ZhciBsZWZ0RGlzdGFuY2U9KHdpbmRvd1dpZHRoLzIpLWJveFdpZHRoLzI7dmFyIHRvcERpc3RhbmNlPSh3aW5kb3dIZWlnaHQvMiktYm94SGVpZ2h0LzI7dG9wRGlzdGFuY2UtPXRoYXQuZHJhZ1dpbmRvd0dhcDtsZWZ0RGlzdGFuY2UtPXRoYXQuZHJhZ1dpbmRvd0dhcDtpZihsZWZ0RGlzdGFuY2UrdGhhdC5tb3ZpbmdYPDApe3RoYXQubW92aW5nWD0tbGVmdERpc3RhbmNlO31lbHNle2lmKGxlZnREaXN0YW5jZS10aGF0Lm1vdmluZ1g8MCl7dGhhdC5tb3ZpbmdYPWxlZnREaXN0YW5jZTt9fWlmKHRvcERpc3RhbmNlK3RoYXQubW92aW5nWTwwKXt0aGF0Lm1vdmluZ1k9LXRvcERpc3RhbmNlO31lbHNle2lmKHRvcERpc3RhbmNlLXRoYXQubW92aW5nWTwwKXt0aGF0Lm1vdmluZ1k9dG9wRGlzdGFuY2U7fX19dGhhdC4kamNvbmZpcm1Cb3hDb250YWluZXIuY3NzKFwidHJhbnNmb3JtXCIsXCJ0cmFuc2xhdGUoXCIrdGhhdC5tb3ZpbmdYK1wicHgsIFwiK3RoYXQubW92aW5nWStcInB4KVwiKTt9fSxfc2Nyb2xsVG9wOmZ1bmN0aW9uKCl7aWYodHlwZW9mIHBhZ2VZT2Zmc2V0IT09XCJ1bmRlZmluZWRcIil7cmV0dXJuIHBhZ2VZT2Zmc2V0O31lbHNle3ZhciBCPWRvY3VtZW50LmJvZHk7dmFyIEQ9ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50O0Q9KEQuY2xpZW50SGVpZ2h0KT9EOkI7cmV0dXJuIEQuc2Nyb2xsVG9wO319LF93YXRjaENvbnRlbnQ6ZnVuY3Rpb24oKXt2YXIgdGhhdD10aGlzO2lmKHRoaXMuX3RpbWVyKXtjbGVhckludGVydmFsKHRoaXMuX3RpbWVyKTt9dmFyIHByZXZDb250ZW50SGVpZ2h0PTA7dGhpcy5fdGltZXI9c2V0SW50ZXJ2YWwoZnVuY3Rpb24oKXtpZih0aGF0LnNtb290aENvbnRlbnQpe3ZhciBjb250ZW50SGVpZ2h0PXRoYXQuJGNvbnRlbnQub3V0ZXJIZWlnaHQoKXx8MDtpZihjb250ZW50SGVpZ2h0IT09cHJldkNvbnRlbnRIZWlnaHQpe3ByZXZDb250ZW50SGVpZ2h0PWNvbnRlbnRIZWlnaHQ7fXZhciB3aD0kKHdpbmRvdykuaGVpZ2h0KCk7dmFyIHRvdGFsPXRoYXQub2Zmc2V0VG9wK3RoYXQub2Zmc2V0Qm90dG9tK3RoYXQuJGpjb25maXJtQm94LmhlaWdodCgpLXRoYXQuJGNvbnRlbnRQYW5lLmhlaWdodCgpK3RoYXQuJGNvbnRlbnQuaGVpZ2h0KCk7aWYodG90YWw8d2gpe3RoYXQuJGNvbnRlbnRQYW5lLmFkZENsYXNzKFwibm8tc2Nyb2xsXCIpO31lbHNle3RoYXQuJGNvbnRlbnRQYW5lLnJlbW92ZUNsYXNzKFwibm8tc2Nyb2xsXCIpO319fSx0aGlzLndhdGNoSW50ZXJ2YWwpO30sX292ZXJmbG93Q2xhc3M6XCJqY29uZmlybS1vdmVyZmxvd1wiLF9oaWxpZ2h0QW5pbWF0aW5nOmZhbHNlLGhpZ2hsaWdodDpmdW5jdGlvbigpe3RoaXMuaGlMaWdodE1vZGFsKCk7fSxoaUxpZ2h0TW9kYWw6ZnVuY3Rpb24oKXt2YXIgdGhhdD10aGlzO2lmKHRoaXMuX2hpbGlnaHRBbmltYXRpbmcpe3JldHVybjt9dGhhdC4kYm9keS5hZGRDbGFzcyhcImhpbGlnaHRcIik7dmFyIGR1cmF0aW9uPXBhcnNlRmxvYXQodGhhdC4kYm9keS5jc3MoXCJhbmltYXRpb24tZHVyYXRpb25cIikpfHwyO3RoaXMuX2hpbGlnaHRBbmltYXRpbmc9dHJ1ZTtzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7dGhhdC5faGlsaWdodEFuaW1hdGluZz1mYWxzZTt0aGF0LiRib2R5LnJlbW92ZUNsYXNzKFwiaGlsaWdodFwiKTt9LGR1cmF0aW9uKjEwMDApO30sX2JpbmRFdmVudHM6ZnVuY3Rpb24oKXt2YXIgdGhhdD10aGlzO3RoaXMuYm94Q2xpY2tlZD1mYWxzZTt0aGlzLiRzY3JvbGxQYW5lLmNsaWNrKGZ1bmN0aW9uKGUpe2lmKCF0aGF0LmJveENsaWNrZWQpe3ZhciBidXR0b25OYW1lPWZhbHNlO3ZhciBzaG91bGRDbG9zZT1mYWxzZTt2YXIgc3RyO2lmKHR5cGVvZiB0aGF0LmJhY2tncm91bmREaXNtaXNzPT09XCJmdW5jdGlvblwiKXtzdHI9dGhhdC5iYWNrZ3JvdW5kRGlzbWlzcygpO31lbHNle3N0cj10aGF0LmJhY2tncm91bmREaXNtaXNzO31pZih0eXBlb2Ygc3RyPT09XCJzdHJpbmdcIiYmdHlwZW9mIHRoYXQuYnV0dG9uc1tzdHJdIT09XCJ1bmRlZmluZWRcIil7YnV0dG9uTmFtZT1zdHI7c2hvdWxkQ2xvc2U9ZmFsc2U7fWVsc2V7aWYodHlwZW9mIHN0cj09PVwidW5kZWZpbmVkXCJ8fCEhKHN0cik9PT10cnVlKXtzaG91bGRDbG9zZT10cnVlO31lbHNle3Nob3VsZENsb3NlPWZhbHNlO319aWYoYnV0dG9uTmFtZSl7dmFyIGJ0blJlc3BvbnNlPXRoYXQuYnV0dG9uc1tidXR0b25OYW1lXS5hY3Rpb24uYXBwbHkodGhhdCk7c2hvdWxkQ2xvc2U9KHR5cGVvZiBidG5SZXNwb25zZT09PVwidW5kZWZpbmVkXCIpfHwhIShidG5SZXNwb25zZSk7fWlmKHNob3VsZENsb3NlKXt0aGF0LmNsb3NlKCk7fWVsc2V7dGhhdC5oaUxpZ2h0TW9kYWwoKTt9fXRoYXQuYm94Q2xpY2tlZD1mYWxzZTt9KTt0aGlzLiRqY29uZmlybUJveC5jbGljayhmdW5jdGlvbihlKXt0aGF0LmJveENsaWNrZWQ9dHJ1ZTt9KTt2YXIgaXNLZXlEb3duPWZhbHNlOyQod2luZG93KS5vbihcImpjS2V5RG93bi5cIit0aGF0Ll9pZCxmdW5jdGlvbihlKXtpZighaXNLZXlEb3duKXtpc0tleURvd249dHJ1ZTt9fSk7JCh3aW5kb3cpLm9uKFwia2V5dXAuXCIrdGhhdC5faWQsZnVuY3Rpb24oZSl7aWYoaXNLZXlEb3duKXt0aGF0LnJlYWN0T25LZXkoZSk7aXNLZXlEb3duPWZhbHNlO319KTskKHdpbmRvdykub24oXCJyZXNpemUuXCIrdGhpcy5faWQsZnVuY3Rpb24oKXt0aGF0Ll91cGRhdGVDb250ZW50TWF4SGVpZ2h0KCk7c2V0VGltZW91dChmdW5jdGlvbigpe3RoYXQucmVzZXREcmFnKCk7fSwxMDApO30pO30sX2N1YmljX2JlemllcjpcIjAuMzYsIDAuNTUsIDAuMTlcIixfZ2V0Q1NTOmZ1bmN0aW9uKHNwZWVkLGJvdW5jZSl7cmV0dXJue1wiLXdlYmtpdC10cmFuc2l0aW9uLWR1cmF0aW9uXCI6c3BlZWQvMTAwMCtcInNcIixcInRyYW5zaXRpb24tZHVyYXRpb25cIjpzcGVlZC8xMDAwK1wic1wiLFwiLXdlYmtpdC10cmFuc2l0aW9uLXRpbWluZy1mdW5jdGlvblwiOlwiY3ViaWMtYmV6aWVyKFwiK3RoaXMuX2N1YmljX2JlemllcitcIiwgXCIrYm91bmNlK1wiKVwiLFwidHJhbnNpdGlvbi10aW1pbmctZnVuY3Rpb25cIjpcImN1YmljLWJlemllcihcIit0aGlzLl9jdWJpY19iZXppZXIrXCIsIFwiK2JvdW5jZStcIilcIn07fSxfc2V0QnV0dG9uczpmdW5jdGlvbigpe3ZhciB0aGF0PXRoaXM7dmFyIHRvdGFsX2J1dHRvbnM9MDtpZih0eXBlb2YgdGhpcy5idXR0b25zIT09XCJvYmplY3RcIil7dGhpcy5idXR0b25zPXt9O30kLmVhY2godGhpcy5idXR0b25zLGZ1bmN0aW9uKGtleSxidXR0b24pe3RvdGFsX2J1dHRvbnMrPTE7aWYodHlwZW9mIGJ1dHRvbj09PVwiZnVuY3Rpb25cIil7dGhhdC5idXR0b25zW2tleV09YnV0dG9uPXthY3Rpb246YnV0dG9ufTt9dGhhdC5idXR0b25zW2tleV0udGV4dD1idXR0b24udGV4dHx8a2V5O3RoYXQuYnV0dG9uc1trZXldLmJ0bkNsYXNzPWJ1dHRvbi5idG5DbGFzc3x8XCJidG4tZGVmYXVsdFwiO3RoYXQuYnV0dG9uc1trZXldLmFjdGlvbj1idXR0b24uYWN0aW9ufHxmdW5jdGlvbigpe307dGhhdC5idXR0b25zW2tleV0ua2V5cz1idXR0b24ua2V5c3x8W107dGhhdC5idXR0b25zW2tleV0uaXNIaWRkZW49YnV0dG9uLmlzSGlkZGVufHxmYWxzZTt0aGF0LmJ1dHRvbnNba2V5XS5pc0Rpc2FibGVkPWJ1dHRvbi5pc0Rpc2FibGVkfHxmYWxzZTskLmVhY2godGhhdC5idXR0b25zW2tleV0ua2V5cyxmdW5jdGlvbihpLGEpe3RoYXQuYnV0dG9uc1trZXldLmtleXNbaV09YS50b0xvd2VyQ2FzZSgpO30pO3ZhciBidXR0b25fZWxlbWVudD0kKCc8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImJ0blwiPjwvYnV0dG9uPicpLmh0bWwodGhhdC5idXR0b25zW2tleV0udGV4dCkuYWRkQ2xhc3ModGhhdC5idXR0b25zW2tleV0uYnRuQ2xhc3MpLnByb3AoXCJkaXNhYmxlZFwiLHRoYXQuYnV0dG9uc1trZXldLmlzRGlzYWJsZWQpLmNzcyhcImRpc3BsYXlcIix0aGF0LmJ1dHRvbnNba2V5XS5pc0hpZGRlbj9cIm5vbmVcIjpcIlwiKS5jbGljayhmdW5jdGlvbihlKXtlLnByZXZlbnREZWZhdWx0KCk7dmFyIHJlcz10aGF0LmJ1dHRvbnNba2V5XS5hY3Rpb24uYXBwbHkodGhhdCxbdGhhdC5idXR0b25zW2tleV1dKTt0aGF0Lm9uQWN0aW9uLmFwcGx5KHRoYXQsW2tleSx0aGF0LmJ1dHRvbnNba2V5XV0pO3RoYXQuX3N0b3BDb3VudERvd24oKTtpZih0eXBlb2YgcmVzPT09XCJ1bmRlZmluZWRcInx8cmVzKXt0aGF0LmNsb3NlKCk7fX0pO3RoYXQuYnV0dG9uc1trZXldLmVsPWJ1dHRvbl9lbGVtZW50O3RoYXQuYnV0dG9uc1trZXldLnNldFRleHQ9ZnVuY3Rpb24odGV4dCl7YnV0dG9uX2VsZW1lbnQuaHRtbCh0ZXh0KTt9O3RoYXQuYnV0dG9uc1trZXldLmFkZENsYXNzPWZ1bmN0aW9uKGNsYXNzTmFtZSl7YnV0dG9uX2VsZW1lbnQuYWRkQ2xhc3MoY2xhc3NOYW1lKTt9O3RoYXQuYnV0dG9uc1trZXldLnJlbW92ZUNsYXNzPWZ1bmN0aW9uKGNsYXNzTmFtZSl7YnV0dG9uX2VsZW1lbnQucmVtb3ZlQ2xhc3MoY2xhc3NOYW1lKTt9O3RoYXQuYnV0dG9uc1trZXldLmRpc2FibGU9ZnVuY3Rpb24oKXt0aGF0LmJ1dHRvbnNba2V5XS5pc0Rpc2FibGVkPXRydWU7YnV0dG9uX2VsZW1lbnQucHJvcChcImRpc2FibGVkXCIsdHJ1ZSk7fTt0aGF0LmJ1dHRvbnNba2V5XS5lbmFibGU9ZnVuY3Rpb24oKXt0aGF0LmJ1dHRvbnNba2V5XS5pc0Rpc2FibGVkPWZhbHNlO2J1dHRvbl9lbGVtZW50LnByb3AoXCJkaXNhYmxlZFwiLGZhbHNlKTt9O3RoYXQuYnV0dG9uc1trZXldLnNob3c9ZnVuY3Rpb24oKXt0aGF0LmJ1dHRvbnNba2V5XS5pc0hpZGRlbj1mYWxzZTtidXR0b25fZWxlbWVudC5jc3MoXCJkaXNwbGF5XCIsXCJcIik7fTt0aGF0LmJ1dHRvbnNba2V5XS5oaWRlPWZ1bmN0aW9uKCl7dGhhdC5idXR0b25zW2tleV0uaXNIaWRkZW49dHJ1ZTtidXR0b25fZWxlbWVudC5jc3MoXCJkaXNwbGF5XCIsXCJub25lXCIpO307dGhhdFtcIiRfXCIra2V5XT10aGF0W1wiJCRcIitrZXldPWJ1dHRvbl9lbGVtZW50O3RoYXQuJGJ0bmMuYXBwZW5kKGJ1dHRvbl9lbGVtZW50KTt9KTtpZih0b3RhbF9idXR0b25zPT09MCl7dGhpcy4kYnRuYy5oaWRlKCk7fWlmKHRoaXMuY2xvc2VJY29uPT09bnVsbCYmdG90YWxfYnV0dG9ucz09PTApe3RoaXMuY2xvc2VJY29uPXRydWU7fWlmKHRoaXMuY2xvc2VJY29uKXtpZih0aGlzLmNsb3NlSWNvbkNsYXNzKXt2YXIgY2xvc2VIdG1sPSc8aSBjbGFzcz1cIicrdGhpcy5jbG9zZUljb25DbGFzcysnXCI+PC9pPic7dGhpcy4kY2xvc2VJY29uLmh0bWwoY2xvc2VIdG1sKTt9dGhpcy4kY2xvc2VJY29uLmNsaWNrKGZ1bmN0aW9uKGUpe2UucHJldmVudERlZmF1bHQoKTt2YXIgYnV0dG9uTmFtZT1mYWxzZTt2YXIgc2hvdWxkQ2xvc2U9ZmFsc2U7dmFyIHN0cjtpZih0eXBlb2YgdGhhdC5jbG9zZUljb249PT1cImZ1bmN0aW9uXCIpe3N0cj10aGF0LmNsb3NlSWNvbigpO31lbHNle3N0cj10aGF0LmNsb3NlSWNvbjt9aWYodHlwZW9mIHN0cj09PVwic3RyaW5nXCImJnR5cGVvZiB0aGF0LmJ1dHRvbnNbc3RyXSE9PVwidW5kZWZpbmVkXCIpe2J1dHRvbk5hbWU9c3RyO3Nob3VsZENsb3NlPWZhbHNlO31lbHNle2lmKHR5cGVvZiBzdHI9PT1cInVuZGVmaW5lZFwifHwhIShzdHIpPT09dHJ1ZSl7c2hvdWxkQ2xvc2U9dHJ1ZTt9ZWxzZXtzaG91bGRDbG9zZT1mYWxzZTt9fWlmKGJ1dHRvbk5hbWUpe3ZhciBidG5SZXNwb25zZT10aGF0LmJ1dHRvbnNbYnV0dG9uTmFtZV0uYWN0aW9uLmFwcGx5KHRoYXQpO3Nob3VsZENsb3NlPSh0eXBlb2YgYnRuUmVzcG9uc2U9PT1cInVuZGVmaW5lZFwiKXx8ISEoYnRuUmVzcG9uc2UpO31pZihzaG91bGRDbG9zZSl7dGhhdC5jbG9zZSgpO319KTt0aGlzLiRjbG9zZUljb24uc2hvdygpO31lbHNle3RoaXMuJGNsb3NlSWNvbi5oaWRlKCk7fX0sc2V0VGl0bGU6ZnVuY3Rpb24oc3RyaW5nLGZvcmNlKXtmb3JjZT1mb3JjZXx8ZmFsc2U7aWYodHlwZW9mIHN0cmluZyE9PVwidW5kZWZpbmVkXCIpe2lmKHR5cGVvZiBzdHJpbmc9PT1cInN0cmluZ1wiKXt0aGlzLnRpdGxlPXN0cmluZzt9ZWxzZXtpZih0eXBlb2Ygc3RyaW5nPT09XCJmdW5jdGlvblwiKXtpZih0eXBlb2Ygc3RyaW5nLnByb21pc2U9PT1cImZ1bmN0aW9uXCIpe2NvbnNvbGUuZXJyb3IoXCJQcm9taXNlIHdhcyByZXR1cm5lZCBmcm9tIHRpdGxlIGZ1bmN0aW9uLCB0aGlzIGlzIG5vdCBzdXBwb3J0ZWQuXCIpO312YXIgcmVzcG9uc2U9c3RyaW5nKCk7aWYodHlwZW9mIHJlc3BvbnNlPT09XCJzdHJpbmdcIil7dGhpcy50aXRsZT1yZXNwb25zZTt9ZWxzZXt0aGlzLnRpdGxlPWZhbHNlO319ZWxzZXt0aGlzLnRpdGxlPWZhbHNlO319fWlmKHRoaXMuaXNBamF4TG9hZGluZyYmIWZvcmNlKXtyZXR1cm47fXRoaXMuJHRpdGxlLmh0bWwodGhpcy50aXRsZXx8XCJcIik7dGhpcy51cGRhdGVUaXRsZUNvbnRhaW5lcigpO30sc2V0SWNvbjpmdW5jdGlvbihpY29uQ2xhc3MsZm9yY2Upe2ZvcmNlPWZvcmNlfHxmYWxzZTtpZih0eXBlb2YgaWNvbkNsYXNzIT09XCJ1bmRlZmluZWRcIil7aWYodHlwZW9mIGljb25DbGFzcz09PVwic3RyaW5nXCIpe3RoaXMuaWNvbj1pY29uQ2xhc3M7fWVsc2V7aWYodHlwZW9mIGljb25DbGFzcz09PVwiZnVuY3Rpb25cIil7dmFyIHJlc3BvbnNlPWljb25DbGFzcygpO2lmKHR5cGVvZiByZXNwb25zZT09PVwic3RyaW5nXCIpe3RoaXMuaWNvbj1yZXNwb25zZTt9ZWxzZXt0aGlzLmljb249ZmFsc2U7fX1lbHNle3RoaXMuaWNvbj1mYWxzZTt9fX1pZih0aGlzLmlzQWpheExvYWRpbmcmJiFmb3JjZSl7cmV0dXJuO310aGlzLiRpY29uLmh0bWwodGhpcy5pY29uPyc8aSBjbGFzcz1cIicrdGhpcy5pY29uKydcIj48L2k+JzpcIlwiKTt0aGlzLnVwZGF0ZVRpdGxlQ29udGFpbmVyKCk7fSx1cGRhdGVUaXRsZUNvbnRhaW5lcjpmdW5jdGlvbigpe2lmKCF0aGlzLnRpdGxlJiYhdGhpcy5pY29uKXt0aGlzLiR0aXRsZUNvbnRhaW5lci5oaWRlKCk7fWVsc2V7dGhpcy4kdGl0bGVDb250YWluZXIuc2hvdygpO319LHNldENvbnRlbnRQcmVwZW5kOmZ1bmN0aW9uKGNvbnRlbnQsZm9yY2Upe2lmKCFjb250ZW50KXtyZXR1cm47fXRoaXMuY29udGVudFBhcnNlZC5wcmVwZW5kKGNvbnRlbnQpO30sc2V0Q29udGVudEFwcGVuZDpmdW5jdGlvbihjb250ZW50KXtpZighY29udGVudCl7cmV0dXJuO310aGlzLmNvbnRlbnRQYXJzZWQuYXBwZW5kKGNvbnRlbnQpO30sc2V0Q29udGVudDpmdW5jdGlvbihjb250ZW50LGZvcmNlKXtmb3JjZT0hIWZvcmNlO3ZhciB0aGF0PXRoaXM7aWYoY29udGVudCl7dGhpcy5jb250ZW50UGFyc2VkLmh0bWwoXCJcIikuYXBwZW5kKGNvbnRlbnQpO31pZih0aGlzLmlzQWpheExvYWRpbmcmJiFmb3JjZSl7cmV0dXJuO310aGlzLiRjb250ZW50Lmh0bWwoXCJcIik7dGhpcy4kY29udGVudC5hcHBlbmQodGhpcy5jb250ZW50UGFyc2VkKTtzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7dGhhdC4kYm9keS5maW5kKFwiaW5wdXRbYXV0b2ZvY3VzXTp2aXNpYmxlOmZpcnN0XCIpLmZvY3VzKCk7fSwxMDApO30sbG9hZGluZ1NwaW5uZXI6ZmFsc2Usc2hvd0xvYWRpbmc6ZnVuY3Rpb24oZGlzYWJsZUJ1dHRvbnMpe3RoaXMubG9hZGluZ1NwaW5uZXI9dHJ1ZTt0aGlzLiRqY29uZmlybUJveC5hZGRDbGFzcyhcImxvYWRpbmdcIik7aWYoZGlzYWJsZUJ1dHRvbnMpe3RoaXMuJGJ0bmMuZmluZChcImJ1dHRvblwiKS5wcm9wKFwiZGlzYWJsZWRcIix0cnVlKTt9fSxoaWRlTG9hZGluZzpmdW5jdGlvbihlbmFibGVCdXR0b25zKXt0aGlzLmxvYWRpbmdTcGlubmVyPWZhbHNlO3RoaXMuJGpjb25maXJtQm94LnJlbW92ZUNsYXNzKFwibG9hZGluZ1wiKTtpZihlbmFibGVCdXR0b25zKXt0aGlzLiRidG5jLmZpbmQoXCJidXR0b25cIikucHJvcChcImRpc2FibGVkXCIsZmFsc2UpO319LGFqYXhSZXNwb25zZTpmYWxzZSxjb250ZW50UGFyc2VkOlwiXCIsaXNBamF4OmZhbHNlLGlzQWpheExvYWRpbmc6ZmFsc2UsX3BhcnNlQ29udGVudDpmdW5jdGlvbigpe3ZhciB0aGF0PXRoaXM7dmFyIGU9XCImbmJzcDtcIjtpZih0eXBlb2YgdGhpcy5jb250ZW50PT09XCJmdW5jdGlvblwiKXt2YXIgcmVzPXRoaXMuY29udGVudC5hcHBseSh0aGlzKTtpZih0eXBlb2YgcmVzPT09XCJzdHJpbmdcIil7dGhpcy5jb250ZW50PXJlczt9ZWxzZXtpZih0eXBlb2YgcmVzPT09XCJvYmplY3RcIiYmdHlwZW9mIHJlcy5hbHdheXM9PT1cImZ1bmN0aW9uXCIpe3RoaXMuaXNBamF4PXRydWU7dGhpcy5pc0FqYXhMb2FkaW5nPXRydWU7cmVzLmFsd2F5cyhmdW5jdGlvbihkYXRhLHN0YXR1cyx4aHIpe3RoYXQuYWpheFJlc3BvbnNlPXtkYXRhOmRhdGEsc3RhdHVzOnN0YXR1cyx4aHI6eGhyfTt0aGF0Ll9jb250ZW50UmVhZHkucmVzb2x2ZShkYXRhLHN0YXR1cyx4aHIpO2lmKHR5cGVvZiB0aGF0LmNvbnRlbnRMb2FkZWQ9PT1cImZ1bmN0aW9uXCIpe3RoYXQuY29udGVudExvYWRlZChkYXRhLHN0YXR1cyx4aHIpO319KTt0aGlzLmNvbnRlbnQ9ZTt9ZWxzZXt0aGlzLmNvbnRlbnQ9ZTt9fX1pZih0eXBlb2YgdGhpcy5jb250ZW50PT09XCJzdHJpbmdcIiYmdGhpcy5jb250ZW50LnN1YnN0cigwLDQpLnRvTG93ZXJDYXNlKCk9PT1cInVybDpcIil7dGhpcy5pc0FqYXg9dHJ1ZTt0aGlzLmlzQWpheExvYWRpbmc9dHJ1ZTt2YXIgdT10aGlzLmNvbnRlbnQuc3Vic3RyaW5nKDQsdGhpcy5jb250ZW50Lmxlbmd0aCk7JC5nZXQodSkuZG9uZShmdW5jdGlvbihodG1sKXt0aGF0LmNvbnRlbnRQYXJzZWQuaHRtbChodG1sKTt9KS5hbHdheXMoZnVuY3Rpb24oZGF0YSxzdGF0dXMseGhyKXt0aGF0LmFqYXhSZXNwb25zZT17ZGF0YTpkYXRhLHN0YXR1czpzdGF0dXMseGhyOnhocn07dGhhdC5fY29udGVudFJlYWR5LnJlc29sdmUoZGF0YSxzdGF0dXMseGhyKTtpZih0eXBlb2YgdGhhdC5jb250ZW50TG9hZGVkPT09XCJmdW5jdGlvblwiKXt0aGF0LmNvbnRlbnRMb2FkZWQoZGF0YSxzdGF0dXMseGhyKTt9fSk7fWlmKCF0aGlzLmNvbnRlbnQpe3RoaXMuY29udGVudD1lO31pZighdGhpcy5pc0FqYXgpe3RoaXMuY29udGVudFBhcnNlZC5odG1sKHRoaXMuY29udGVudCk7dGhpcy5zZXRDb250ZW50KCk7dGhhdC5fY29udGVudFJlYWR5LnJlc29sdmUoKTt9fSxfc3RvcENvdW50RG93bjpmdW5jdGlvbigpe2NsZWFySW50ZXJ2YWwodGhpcy5hdXRvQ2xvc2VJbnRlcnZhbCk7aWYodGhpcy4kY2Qpe3RoaXMuJGNkLnJlbW92ZSgpO319LF9zdGFydENvdW50RG93bjpmdW5jdGlvbigpe3ZhciB0aGF0PXRoaXM7dmFyIG9wdD10aGlzLmF1dG9DbG9zZS5zcGxpdChcInxcIik7aWYob3B0Lmxlbmd0aCE9PTIpe2NvbnNvbGUuZXJyb3IoXCJJbnZhbGlkIG9wdGlvbiBmb3IgYXV0b0Nsb3NlLiBleGFtcGxlICdjbG9zZXwxMDAwMCdcIik7cmV0dXJuIGZhbHNlO312YXIgYnV0dG9uX2tleT1vcHRbMF07dmFyIHRpbWU9cGFyc2VJbnQob3B0WzFdKTtpZih0eXBlb2YgdGhpcy5idXR0b25zW2J1dHRvbl9rZXldPT09XCJ1bmRlZmluZWRcIil7Y29uc29sZS5lcnJvcihcIkludmFsaWQgYnV0dG9uIGtleSAnXCIrYnV0dG9uX2tleStcIicgZm9yIGF1dG9DbG9zZVwiKTtyZXR1cm4gZmFsc2U7fXZhciBzZWNvbmRzPU1hdGguY2VpbCh0aW1lLzEwMDApO3RoaXMuJGNkPSQoJzxzcGFuIGNsYXNzPVwiY291bnRkb3duXCI+ICgnK3NlY29uZHMrXCIpPC9zcGFuPlwiKS5hcHBlbmRUbyh0aGlzW1wiJF9cIitidXR0b25fa2V5XSk7dGhpcy5hdXRvQ2xvc2VJbnRlcnZhbD1zZXRJbnRlcnZhbChmdW5jdGlvbigpe3RoYXQuJGNkLmh0bWwoXCIgKFwiKyhzZWNvbmRzLT0xKStcIikgXCIpO2lmKHNlY29uZHM8PTApe3RoYXRbXCIkJFwiK2J1dHRvbl9rZXldLnRyaWdnZXIoXCJjbGlja1wiKTt0aGF0Ll9zdG9wQ291bnREb3duKCk7fX0sMTAwMCk7fSxfZ2V0S2V5OmZ1bmN0aW9uKGtleSl7c3dpdGNoKGtleSl7Y2FzZSAxOTI6cmV0dXJuXCJ0aWxkZVwiO2Nhc2UgMTM6cmV0dXJuXCJlbnRlclwiO2Nhc2UgMTY6cmV0dXJuXCJzaGlmdFwiO2Nhc2UgOTpyZXR1cm5cInRhYlwiO2Nhc2UgMjA6cmV0dXJuXCJjYXBzbG9ja1wiO2Nhc2UgMTc6cmV0dXJuXCJjdHJsXCI7Y2FzZSA5MTpyZXR1cm5cIndpblwiO2Nhc2UgMTg6cmV0dXJuXCJhbHRcIjtjYXNlIDI3OnJldHVyblwiZXNjXCI7Y2FzZSAzMjpyZXR1cm5cInNwYWNlXCI7fXZhciBpbml0aWFsPVN0cmluZy5mcm9tQ2hhckNvZGUoa2V5KTtpZigvXltBLXowLTldKyQvLnRlc3QoaW5pdGlhbCkpe3JldHVybiBpbml0aWFsLnRvTG93ZXJDYXNlKCk7fWVsc2V7cmV0dXJuIGZhbHNlO319LHJlYWN0T25LZXk6ZnVuY3Rpb24oZSl7dmFyIHRoYXQ9dGhpczt2YXIgYT0kKFwiLmpjb25maXJtXCIpO2lmKGEuZXEoYS5sZW5ndGgtMSlbMF0hPT10aGlzLiRlbFswXSl7cmV0dXJuIGZhbHNlO312YXIga2V5PWUud2hpY2g7aWYodGhpcy4kY29udGVudC5maW5kKFwiOmlucHV0XCIpLmlzKFwiOmZvY3VzXCIpJiYvMTN8MzIvLnRlc3Qoa2V5KSl7cmV0dXJuIGZhbHNlO312YXIga2V5Q2hhcj10aGlzLl9nZXRLZXkoa2V5KTtpZihrZXlDaGFyPT09XCJlc2NcIiYmdGhpcy5lc2NhcGVLZXkpe2lmKHRoaXMuZXNjYXBlS2V5PT09dHJ1ZSl7dGhpcy4kc2Nyb2xsUGFuZS50cmlnZ2VyKFwiY2xpY2tcIik7fWVsc2V7aWYodHlwZW9mIHRoaXMuZXNjYXBlS2V5PT09XCJzdHJpbmdcInx8dHlwZW9mIHRoaXMuZXNjYXBlS2V5PT09XCJmdW5jdGlvblwiKXt2YXIgYnV0dG9uS2V5O2lmKHR5cGVvZiB0aGlzLmVzY2FwZUtleT09PVwiZnVuY3Rpb25cIil7YnV0dG9uS2V5PXRoaXMuZXNjYXBlS2V5KCk7fWVsc2V7YnV0dG9uS2V5PXRoaXMuZXNjYXBlS2V5O31pZihidXR0b25LZXkpe2lmKHR5cGVvZiB0aGlzLmJ1dHRvbnNbYnV0dG9uS2V5XT09PVwidW5kZWZpbmVkXCIpe2NvbnNvbGUud2FybihcIkludmFsaWQgZXNjYXBlS2V5LCBubyBidXR0b25zIGZvdW5kIHdpdGgga2V5IFwiK2J1dHRvbktleSk7fWVsc2V7dGhpc1tcIiRfXCIrYnV0dG9uS2V5XS50cmlnZ2VyKFwiY2xpY2tcIik7fX19fX0kLmVhY2godGhpcy5idXR0b25zLGZ1bmN0aW9uKGtleSxidXR0b24pe2lmKGJ1dHRvbi5rZXlzLmluZGV4T2Yoa2V5Q2hhcikhPT0tMSl7dGhhdFtcIiRfXCIra2V5XS50cmlnZ2VyKFwiY2xpY2tcIik7fX0pO30sc2V0RGlhbG9nQ2VudGVyOmZ1bmN0aW9uKCl7Y29uc29sZS5pbmZvKFwic2V0RGlhbG9nQ2VudGVyIGlzIGRlcHJlY2F0ZWQsIGRpYWxvZ3MgYXJlIGNlbnRlcmVkIHdpdGggQ1NTMyB0YWJsZXNcIik7fSxfdW53YXRjaENvbnRlbnQ6ZnVuY3Rpb24oKXtjbGVhckludGVydmFsKHRoaXMuX3RpbWVyKTt9LGNsb3NlOmZ1bmN0aW9uKG9uQ2xvc2VQYXlsb2FkKXt2YXIgdGhhdD10aGlzO2lmKHR5cGVvZiB0aGlzLm9uQ2xvc2U9PT1cImZ1bmN0aW9uXCIpe3RoaXMub25DbG9zZShvbkNsb3NlUGF5bG9hZCk7fXRoaXMuX3Vud2F0Y2hDb250ZW50KCk7JCh3aW5kb3cpLnVuYmluZChcInJlc2l6ZS5cIit0aGlzLl9pZCk7JCh3aW5kb3cpLnVuYmluZChcImtleXVwLlwiK3RoaXMuX2lkKTskKHdpbmRvdykudW5iaW5kKFwiamNLZXlEb3duLlwiK3RoaXMuX2lkKTtpZih0aGlzLmRyYWdnYWJsZSl7JCh3aW5kb3cpLnVuYmluZChcIm1vdXNlbW92ZS5cIit0aGlzLl9pZCk7JCh3aW5kb3cpLnVuYmluZChcIm1vdXNldXAuXCIrdGhpcy5faWQpO3RoaXMuJHRpdGxlQ29udGFpbmVyLnVuYmluZChcIm1vdXNlZG93blwiKTt9dGhhdC4kZWwucmVtb3ZlQ2xhc3ModGhhdC5sb2FkZWRDbGFzcyk7JChcImJvZHlcIikucmVtb3ZlQ2xhc3MoXCJqY29uZmlybS1uby1zY3JvbGwtXCIrdGhhdC5faWQpO3RoYXQuJGpjb25maXJtQm94Q29udGFpbmVyLnJlbW92ZUNsYXNzKFwiamNvbmZpcm0tbm8tdHJhbnNpdGlvblwiKTtzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7dGhhdC4kYm9keS5hZGRDbGFzcyh0aGF0LmNsb3NlQW5pbWF0aW9uUGFyc2VkKTt0aGF0LiRqY29uZmlybUJnLmFkZENsYXNzKFwiamNvbmZpcm0tYmctaFwiKTt2YXIgY2xvc2VUaW1lcj0odGhhdC5jbG9zZUFuaW1hdGlvbj09PVwibm9uZVwiKT8xOnRoYXQuYW5pbWF0aW9uU3BlZWQ7c2V0VGltZW91dChmdW5jdGlvbigpe3RoYXQuJGVsLnJlbW92ZSgpO3ZhciBsPXcuamNvbmZpcm0uaW5zdGFuY2VzO3ZhciBpPXcuamNvbmZpcm0uaW5zdGFuY2VzLmxlbmd0aC0xO2ZvcihpO2k+PTA7aS0tKXtpZih3Lmpjb25maXJtLmluc3RhbmNlc1tpXS5faWQ9PT10aGF0Ll9pZCl7dy5qY29uZmlybS5pbnN0YW5jZXMuc3BsaWNlKGksMSk7fX1pZighdy5qY29uZmlybS5pbnN0YW5jZXMubGVuZ3RoKXtpZih0aGF0LnNjcm9sbFRvUHJldmlvdXNFbGVtZW50JiZ3Lmpjb25maXJtLmxhc3RGb2N1c2VkJiZ3Lmpjb25maXJtLmxhc3RGb2N1c2VkLmxlbmd0aCYmJC5jb250YWlucyhkb2N1bWVudCx3Lmpjb25maXJtLmxhc3RGb2N1c2VkWzBdKSl7dmFyICRsZj13Lmpjb25maXJtLmxhc3RGb2N1c2VkO2lmKHRoYXQuc2Nyb2xsVG9QcmV2aW91c0VsZW1lbnRBbmltYXRlKXt2YXIgc3Q9JCh3aW5kb3cpLnNjcm9sbFRvcCgpO3ZhciBvdD13Lmpjb25maXJtLmxhc3RGb2N1c2VkLm9mZnNldCgpLnRvcDt2YXIgd2g9JCh3aW5kb3cpLmhlaWdodCgpO2lmKCEob3Q+c3QmJm90PChzdCt3aCkpKXt2YXIgc2Nyb2xsVG89KG90LU1hdGgucm91bmQoKHdoLzMpKSk7JChcImh0bWwsIGJvZHlcIikuYW5pbWF0ZSh7c2Nyb2xsVG9wOnNjcm9sbFRvfSx0aGF0LmFuaW1hdGlvblNwZWVkLFwic3dpbmdcIixmdW5jdGlvbigpeyRsZi5mb2N1cygpO30pO31lbHNleyRsZi5mb2N1cygpO319ZWxzZXskbGYuZm9jdXMoKTt9dy5qY29uZmlybS5sYXN0Rm9jdXNlZD1mYWxzZTt9fWlmKHR5cGVvZiB0aGF0Lm9uRGVzdHJveT09PVwiZnVuY3Rpb25cIil7dGhhdC5vbkRlc3Ryb3koKTt9fSxjbG9zZVRpbWVyKjAuNCk7fSw1MCk7cmV0dXJuIHRydWU7fSxvcGVuOmZ1bmN0aW9uKCl7aWYodGhpcy5pc09wZW4oKSl7cmV0dXJuIGZhbHNlO310aGlzLl9idWlsZEhUTUwoKTt0aGlzLl9iaW5kRXZlbnRzKCk7dGhpcy5fb3BlbigpO3JldHVybiB0cnVlO30sc2V0U3RhcnRpbmdQb2ludDpmdW5jdGlvbigpe3ZhciBlbD1mYWxzZTtpZih0aGlzLmFuaW1hdGVGcm9tRWxlbWVudCE9PXRydWUmJnRoaXMuYW5pbWF0ZUZyb21FbGVtZW50KXtlbD10aGlzLmFuaW1hdGVGcm9tRWxlbWVudDt3Lmpjb25maXJtLmxhc3RDbGlja2VkPWZhbHNlO31lbHNle2lmKHcuamNvbmZpcm0ubGFzdENsaWNrZWQmJnRoaXMuYW5pbWF0ZUZyb21FbGVtZW50PT09dHJ1ZSl7ZWw9dy5qY29uZmlybS5sYXN0Q2xpY2tlZDt3Lmpjb25maXJtLmxhc3RDbGlja2VkPWZhbHNlO31lbHNle3JldHVybiBmYWxzZTt9fWlmKCFlbCl7cmV0dXJuIGZhbHNlO312YXIgb2Zmc2V0PWVsLm9mZnNldCgpO3ZhciBpVG9wPWVsLm91dGVySGVpZ2h0KCkvMjt2YXIgaUxlZnQ9ZWwub3V0ZXJXaWR0aCgpLzI7aVRvcC09dGhpcy4kamNvbmZpcm1Cb3gub3V0ZXJIZWlnaHQoKS8yO2lMZWZ0LT10aGlzLiRqY29uZmlybUJveC5vdXRlcldpZHRoKCkvMjt2YXIgc291cmNlVG9wPW9mZnNldC50b3AraVRvcDtzb3VyY2VUb3A9c291cmNlVG9wLXRoaXMuX3Njcm9sbFRvcCgpO3ZhciBzb3VyY2VMZWZ0PW9mZnNldC5sZWZ0K2lMZWZ0O3ZhciB3aD0kKHdpbmRvdykuaGVpZ2h0KCkvMjt2YXIgd3c9JCh3aW5kb3cpLndpZHRoKCkvMjt2YXIgdGFyZ2V0SD13aC10aGlzLiRqY29uZmlybUJveC5vdXRlckhlaWdodCgpLzI7dmFyIHRhcmdldFc9d3ctdGhpcy4kamNvbmZpcm1Cb3gub3V0ZXJXaWR0aCgpLzI7c291cmNlVG9wLT10YXJnZXRIO3NvdXJjZUxlZnQtPXRhcmdldFc7aWYoTWF0aC5hYnMoc291cmNlVG9wKT53aHx8TWF0aC5hYnMoc291cmNlTGVmdCk+d3cpe3JldHVybiBmYWxzZTt9dGhpcy4kamNvbmZpcm1Cb3hDb250YWluZXIuY3NzKFwidHJhbnNmb3JtXCIsXCJ0cmFuc2xhdGUoXCIrc291cmNlTGVmdCtcInB4LCBcIitzb3VyY2VUb3ArXCJweClcIik7fSxfb3BlbjpmdW5jdGlvbigpe3ZhciB0aGF0PXRoaXM7aWYodHlwZW9mIHRoYXQub25PcGVuQmVmb3JlPT09XCJmdW5jdGlvblwiKXt0aGF0Lm9uT3BlbkJlZm9yZSgpO310aGlzLiRib2R5LnJlbW92ZUNsYXNzKHRoaXMuYW5pbWF0aW9uUGFyc2VkKTt0aGlzLiRqY29uZmlybUJnLnJlbW92ZUNsYXNzKFwiamNvbmZpcm0tYmctaFwiKTt0aGlzLiRib2R5LmZvY3VzKCk7dGhhdC4kamNvbmZpcm1Cb3hDb250YWluZXIuY3NzKFwidHJhbnNmb3JtXCIsXCJ0cmFuc2xhdGUoXCIrMCtcInB4LCBcIiswK1wicHgpXCIpO3NldFRpbWVvdXQoZnVuY3Rpb24oKXt0aGF0LiRib2R5LmNzcyh0aGF0Ll9nZXRDU1ModGhhdC5hbmltYXRpb25TcGVlZCwxKSk7dGhhdC4kYm9keS5jc3Moe1widHJhbnNpdGlvbi1wcm9wZXJ0eVwiOnRoYXQuJGJvZHkuY3NzKFwidHJhbnNpdGlvbi1wcm9wZXJ0eVwiKStcIiwgbWFyZ2luXCJ9KTt0aGF0LiRqY29uZmlybUJveENvbnRhaW5lci5hZGRDbGFzcyhcImpjb25maXJtLW5vLXRyYW5zaXRpb25cIik7dGhhdC5fbW9kYWxSZWFkeS5yZXNvbHZlKCk7aWYodHlwZW9mIHRoYXQub25PcGVuPT09XCJmdW5jdGlvblwiKXt0aGF0Lm9uT3BlbigpO310aGF0LiRlbC5hZGRDbGFzcyh0aGF0LmxvYWRlZENsYXNzKTt9LHRoaXMuYW5pbWF0aW9uU3BlZWQpO30sbG9hZGVkQ2xhc3M6XCJqY29uZmlybS1vcGVuXCIsaXNDbG9zZWQ6ZnVuY3Rpb24oKXtyZXR1cm4gIXRoaXMuJGVsfHx0aGlzLiRlbC5wYXJlbnQoKS5sZW5ndGg9PT0wO30saXNPcGVuOmZ1bmN0aW9uKCl7cmV0dXJuICF0aGlzLmlzQ2xvc2VkKCk7fSx0b2dnbGU6ZnVuY3Rpb24oKXtpZighdGhpcy5pc09wZW4oKSl7dGhpcy5vcGVuKCk7fWVsc2V7dGhpcy5jbG9zZSgpO319fTt3Lmpjb25maXJtLmluc3RhbmNlcz1bXTt3Lmpjb25maXJtLmxhc3RGb2N1c2VkPWZhbHNlO3cuamNvbmZpcm0ucGx1Z2luRGVmYXVsdHM9e3RlbXBsYXRlOic8ZGl2IGNsYXNzPVwiamNvbmZpcm1cIj48ZGl2IGNsYXNzPVwiamNvbmZpcm0tYmcgamNvbmZpcm0tYmctaFwiPjwvZGl2PjxkaXYgY2xhc3M9XCJqY29uZmlybS1zY3JvbGxwYW5lXCI+PGRpdiBjbGFzcz1cImpjb25maXJtLXJvd1wiPjxkaXYgY2xhc3M9XCJqY29uZmlybS1jZWxsXCI+PGRpdiBjbGFzcz1cImpjb25maXJtLWhvbGRlclwiPjxkaXYgY2xhc3M9XCJqYy1iczMtY29udGFpbmVyXCI+PGRpdiBjbGFzcz1cImpjLWJzMy1yb3dcIj48ZGl2IGNsYXNzPVwiamNvbmZpcm0tYm94LWNvbnRhaW5lciBqY29uZmlybS1hbmltYXRlZFwiPjxkaXYgY2xhc3M9XCJqY29uZmlybS1ib3hcIiByb2xlPVwiZGlhbG9nXCIgYXJpYS1sYWJlbGxlZGJ5PVwibGFiZWxsZWRcIiB0YWJpbmRleD1cIi0xXCI+PGRpdiBjbGFzcz1cImpjb25maXJtLWNsb3NlSWNvblwiPiZ0aW1lczs8L2Rpdj48ZGl2IGNsYXNzPVwiamNvbmZpcm0tdGl0bGUtY1wiPjxzcGFuIGNsYXNzPVwiamNvbmZpcm0taWNvbi1jXCI+PC9zcGFuPjxzcGFuIGNsYXNzPVwiamNvbmZpcm0tdGl0bGVcIj48L3NwYW4+PC9kaXY+PGRpdiBjbGFzcz1cImpjb25maXJtLWNvbnRlbnQtcGFuZVwiPjxkaXYgY2xhc3M9XCJqY29uZmlybS1jb250ZW50XCI+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz1cImpjb25maXJtLWJ1dHRvbnNcIj48L2Rpdj48ZGl2IGNsYXNzPVwiamNvbmZpcm0tY2xlYXJcIj48L2Rpdj48L2Rpdj48L2Rpdj48L2Rpdj48L2Rpdj48L2Rpdj48L2Rpdj48L2Rpdj48L2Rpdj48L2Rpdj4nLHRpdGxlOlwiSGVsbG9cIix0aXRsZUNsYXNzOlwiXCIsdHlwZTpcImRlZmF1bHRcIix0eXBlQW5pbWF0ZWQ6dHJ1ZSxkcmFnZ2FibGU6dHJ1ZSxkcmFnV2luZG93R2FwOjE1LGRyYWdXaW5kb3dCb3JkZXI6dHJ1ZSxhbmltYXRlRnJvbUVsZW1lbnQ6dHJ1ZSxhbGlnbk1pZGRsZTp0cnVlLHNtb290aENvbnRlbnQ6dHJ1ZSxjb250ZW50OlwiQXJlIHlvdSBzdXJlIHRvIGNvbnRpbnVlP1wiLGJ1dHRvbnM6e30sZGVmYXVsdEJ1dHRvbnM6e29rOnthY3Rpb246ZnVuY3Rpb24oKXt9fSxjbG9zZTp7YWN0aW9uOmZ1bmN0aW9uKCl7fX19LGNvbnRlbnRMb2FkZWQ6ZnVuY3Rpb24oKXt9LGljb246XCJcIixsYXp5T3BlbjpmYWxzZSxiZ09wYWNpdHk6bnVsbCx0aGVtZTpcImxpZ2h0XCIsYW5pbWF0aW9uOlwic2NhbGVcIixjbG9zZUFuaW1hdGlvbjpcInNjYWxlXCIsYW5pbWF0aW9uU3BlZWQ6NDAwLGFuaW1hdGlvbkJvdW5jZToxLGVzY2FwZUtleTp0cnVlLHJ0bDpmYWxzZSxjb250YWluZXI6XCJib2R5XCIsY29udGFpbmVyRmx1aWQ6ZmFsc2UsYmFja2dyb3VuZERpc21pc3M6ZmFsc2UsYmFja2dyb3VuZERpc21pc3NBbmltYXRpb246XCJzaGFrZVwiLGF1dG9DbG9zZTpmYWxzZSxjbG9zZUljb246bnVsbCxjbG9zZUljb25DbGFzczpmYWxzZSx3YXRjaEludGVydmFsOjEwMCxjb2x1bW5DbGFzczpcImNvbC1tZC00IGNvbC1tZC1vZmZzZXQtNCBjb2wtc20tNiBjb2wtc20tb2Zmc2V0LTMgY29sLXhzLTEwIGNvbC14cy1vZmZzZXQtMVwiLGJveFdpZHRoOlwiNTAlXCIsc2Nyb2xsVG9QcmV2aW91c0VsZW1lbnQ6dHJ1ZSxzY3JvbGxUb1ByZXZpb3VzRWxlbWVudEFuaW1hdGU6dHJ1ZSx1c2VCb290c3RyYXA6dHJ1ZSxvZmZzZXRUb3A6NDAsb2Zmc2V0Qm90dG9tOjQwLGJvb3RzdHJhcENsYXNzZXM6e2NvbnRhaW5lcjpcImNvbnRhaW5lclwiLGNvbnRhaW5lckZsdWlkOlwiY29udGFpbmVyLWZsdWlkXCIscm93Olwicm93XCJ9LG9uQ29udGVudFJlYWR5OmZ1bmN0aW9uKCl7fSxvbk9wZW5CZWZvcmU6ZnVuY3Rpb24oKXt9LG9uT3BlbjpmdW5jdGlvbigpe30sb25DbG9zZTpmdW5jdGlvbigpe30sb25EZXN0cm95OmZ1bmN0aW9uKCl7fSxvbkFjdGlvbjpmdW5jdGlvbigpe319O3ZhciBrZXlEb3duPWZhbHNlOyQod2luZG93KS5vbihcImtleWRvd25cIixmdW5jdGlvbihlKXtpZigha2V5RG93bil7dmFyICR0YXJnZXQ9JChlLnRhcmdldCk7dmFyIHBhc3M9ZmFsc2U7aWYoJHRhcmdldC5jbG9zZXN0KFwiLmpjb25maXJtLWJveFwiKS5sZW5ndGgpe3Bhc3M9dHJ1ZTt9aWYocGFzcyl7JCh3aW5kb3cpLnRyaWdnZXIoXCJqY0tleURvd25cIik7fWtleURvd249dHJ1ZTt9fSk7JCh3aW5kb3cpLm9uKFwia2V5dXBcIixmdW5jdGlvbigpe2tleURvd249ZmFsc2U7fSk7dy5qY29uZmlybS5sYXN0Q2xpY2tlZD1mYWxzZTskKGRvY3VtZW50KS5vbihcIm1vdXNlZG93blwiLFwiYnV0dG9uLCBhLCBbamMtc291cmNlXVwiLGZ1bmN0aW9uKCl7dy5qY29uZmlybS5sYXN0Q2xpY2tlZD0kKHRoaXMpO30pO30pKTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/jquery-confirm/dist/jquery-confirm.min.js\n");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./node_modules/jquery/dist/jquery.js":
|
|
/*!********************************************!*\
|
|
!*** ./node_modules/jquery/dist/jquery.js ***!
|
|
\********************************************/
|
|
/***/ (function(module, exports) {
|
|
|
|
eval("var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!\n * jQuery JavaScript Library v3.6.0\n * https://jquery.com/\n *\n * Includes Sizzle.js\n * https://sizzlejs.com/\n *\n * Copyright OpenJS Foundation and other contributors\n * Released under the MIT license\n * https://jquery.org/license\n *\n * Date: 2021-03-02T17:08Z\n */\n( function( global, factory ) {\n\n\t\"use strict\";\n\n\tif ( true && typeof module.exports === \"object\" ) {\n\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\t// For environments that do not have a `window` with a `document`\n\t\t// (such as Node.js), expose a factory as module.exports.\n\t\t// This accentuates the need for the creation of a real `window`.\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket #14549 for more info.\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n} )( typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1\n// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode\n// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common\n// enough that all such attempts are guarded in a try block.\n\"use strict\";\n\nvar arr = [];\n\nvar getProto = Object.getPrototypeOf;\n\nvar slice = arr.slice;\n\nvar flat = arr.flat ? function( array ) {\n\treturn arr.flat.call( array );\n} : function( array ) {\n\treturn arr.concat.apply( [], array );\n};\n\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar fnToString = hasOwn.toString;\n\nvar ObjectFunctionString = fnToString.call( Object );\n\nvar support = {};\n\nvar isFunction = function isFunction( obj ) {\n\n\t\t// Support: Chrome <=57, Firefox <=52\n\t\t// In some browsers, typeof returns \"function\" for HTML <object> elements\n\t\t// (i.e., `typeof document.createElement( \"object\" ) === \"function\"`).\n\t\t// We don't want to classify *any* DOM node as a function.\n\t\t// Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5\n\t\t// Plus for old WebKit, typeof returns \"function\" for HTML collections\n\t\t// (e.g., `typeof document.getElementsByTagName(\"div\") === \"function\"`). (gh-4756)\n\t\treturn typeof obj === \"function\" && typeof obj.nodeType !== \"number\" &&\n\t\t\ttypeof obj.item !== \"function\";\n\t};\n\n\nvar isWindow = function isWindow( obj ) {\n\t\treturn obj != null && obj === obj.window;\n\t};\n\n\nvar document = window.document;\n\n\n\n\tvar preservedScriptAttributes = {\n\t\ttype: true,\n\t\tsrc: true,\n\t\tnonce: true,\n\t\tnoModule: true\n\t};\n\n\tfunction DOMEval( code, node, doc ) {\n\t\tdoc = doc || document;\n\n\t\tvar i, val,\n\t\t\tscript = doc.createElement( \"script\" );\n\n\t\tscript.text = code;\n\t\tif ( node ) {\n\t\t\tfor ( i in preservedScriptAttributes ) {\n\n\t\t\t\t// Support: Firefox 64+, Edge 18+\n\t\t\t\t// Some browsers don't support the \"nonce\" property on scripts.\n\t\t\t\t// On the other hand, just using `getAttribute` is not enough as\n\t\t\t\t// the `nonce` attribute is reset to an empty string whenever it\n\t\t\t\t// becomes browsing-context connected.\n\t\t\t\t// See https://github.com/whatwg/html/issues/2369\n\t\t\t\t// See https://html.spec.whatwg.org/#nonce-attributes\n\t\t\t\t// The `node.getAttribute` check was added for the sake of\n\t\t\t\t// `jQuery.globalEval` so that it can fake a nonce-containing node\n\t\t\t\t// via an object.\n\t\t\t\tval = node[ i ] || node.getAttribute && node.getAttribute( i );\n\t\t\t\tif ( val ) {\n\t\t\t\t\tscript.setAttribute( i, val );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdoc.head.appendChild( script ).parentNode.removeChild( script );\n\t}\n\n\nfunction toType( obj ) {\n\tif ( obj == null ) {\n\t\treturn obj + \"\";\n\t}\n\n\t// Support: Android <=2.3 only (functionish RegExp)\n\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\tclass2type[ toString.call( obj ) ] || \"object\" :\n\t\ttypeof obj;\n}\n/* global Symbol */\n// Defining this global in .eslintrc.json would create a danger of using the global\n// unguarded in another place, it seems safer to define global only for this module\n\n\n\nvar\n\tversion = \"3.6.0\",\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t};\n\njQuery.fn = jQuery.prototype = {\n\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\n\t\t// Return all the elements in a clean array\n\t\tif ( num == null ) {\n\t\t\treturn slice.call( this );\n\t\t}\n\n\t\t// Return just the one element from the set\n\t\treturn num < 0 ? this[ num + this.length ] : this[ num ];\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\teach: function( callback ) {\n\t\treturn jQuery.each( this, callback );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map( this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t} ) );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teven: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn ( i + 1 ) % 2;\n\t\t} ) );\n\t},\n\n\todd: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn i % 2;\n\t\t} ) );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor();\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: push,\n\tsort: arr.sort,\n\tsplice: arr.splice\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[ 0 ] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !isFunction( target ) ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\n\t\t// Only deal with non-null/undefined values\n\t\tif ( ( options = arguments[ i ] ) != null ) {\n\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent Object.prototype pollution\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( name === \"__proto__\" || target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject( copy ) ||\n\t\t\t\t\t( copyIsArray = Array.isArray( copy ) ) ) ) {\n\t\t\t\t\tsrc = target[ name ];\n\n\t\t\t\t\t// Ensure proper type for the source value\n\t\t\t\t\tif ( copyIsArray && !Array.isArray( src ) ) {\n\t\t\t\t\t\tclone = [];\n\t\t\t\t\t} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {\n\t\t\t\t\t\tclone = {};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src;\n\t\t\t\t\t}\n\t\t\t\t\tcopyIsArray = false;\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend( {\n\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisPlainObject: function( obj ) {\n\t\tvar proto, Ctor;\n\n\t\t// Detect obvious negatives\n\t\t// Use toString instead of jQuery.type to catch host objects\n\t\tif ( !obj || toString.call( obj ) !== \"[object Object]\" ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tproto = getProto( obj );\n\n\t\t// Objects with no prototype (e.g., `Object.create( null )`) are plain\n\t\tif ( !proto ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Objects with prototype are plain iff they were constructed by a global Object function\n\t\tCtor = hasOwn.call( proto, \"constructor\" ) && proto.constructor;\n\t\treturn typeof Ctor === \"function\" && fnToString.call( Ctor ) === ObjectFunctionString;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\t// Evaluates a script in a provided context; falls back to the global one\n\t// if not specified.\n\tglobalEval: function( code, options, doc ) {\n\t\tDOMEval( code, { nonce: options && options.nonce }, doc );\n\t},\n\n\teach: function( obj, callback ) {\n\t\tvar length, i = 0;\n\n\t\tif ( isArrayLike( obj ) ) {\n\t\t\tlength = obj.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( i in obj ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArrayLike( Object( arr ) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t// push.apply(_, arraylike) throws on ancient WebKit\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar length, value,\n\t\t\ti = 0,\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArrayLike( elems ) ) {\n\t\t\tlength = elems.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn flat( ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n} );\n\nif ( typeof Symbol === \"function\" ) {\n\tjQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];\n}\n\n// Populate the class2type map\njQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\n\tfunction( _i, name ) {\n\t\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n\t} );\n\nfunction isArrayLike( obj ) {\n\n\t// Support: real iOS 8.2 only (not reproducible in simulator)\n\t// `in` check used to prevent JIT error (gh-2145)\n\t// hasOwn isn't used here due to false negatives\n\t// regarding Nodelist length in IE\n\tvar length = !!obj && \"length\" in obj && obj.length,\n\t\ttype = toType( obj );\n\n\tif ( isFunction( obj ) || isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\nvar Sizzle =\n/*!\n * Sizzle CSS Selector Engine v2.3.6\n * https://sizzlejs.com/\n *\n * Copyright JS Foundation and other contributors\n * Released under the MIT license\n * https://js.foundation/\n *\n * Date: 2021-02-16\n */\n( function( window ) {\nvar i,\n\tsupport,\n\tExpr,\n\tgetText,\n\tisXML,\n\ttokenize,\n\tcompile,\n\tselect,\n\toutermostContext,\n\tsortInput,\n\thasDuplicate,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsHTML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + 1 * new Date(),\n\tpreferredDoc = window.document,\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\tnonnativeSelectorCache = createCache(),\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn 0;\n\t},\n\n\t// Instance methods\n\thasOwn = ( {} ).hasOwnProperty,\n\tarr = [],\n\tpop = arr.pop,\n\tpushNative = arr.push,\n\tpush = arr.push,\n\tslice = arr.slice,\n\n\t// Use a stripped-down indexOf as it's faster than native\n\t// https://jsperf.com/thor-indexof-vs-for/5\n\tindexOf = function( list, elem ) {\n\t\tvar i = 0,\n\t\t\tlen = list.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( list[ i ] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\tbooleans = \"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|\" +\n\t\t\"ismap|loop|multiple|open|readonly|required|scoped\",\n\n\t// Regular expressions\n\n\t// http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\n\t// https://www.w3.org/TR/css-syntax-3/#ident-token-diagram\n\tidentifier = \"(?:\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace +\n\t\t\"?|\\\\\\\\[^\\\\r\\\\n\\\\f]|[\\\\w-]|[^\\0-\\\\x7f])+\",\n\n\t// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + identifier + \")(?:\" + whitespace +\n\n\t\t// Operator (capture 2)\n\t\t\"*([*^$|!~]?=)\" + whitespace +\n\n\t\t// \"Attribute values must be CSS identifiers [capture 5]\n\t\t// or strings [capture 3 or capture 4]\"\n\t\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" +\n\t\twhitespace + \"*\\\\]\",\n\n\tpseudos = \":(\" + identifier + \")(?:\\\\((\" +\n\n\t\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\n\t\t// 2. simple (capture 6)\n\t\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\n\t\t// 3. anything else (capture 2)\n\t\t\".*\" +\n\t\t\")\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" +\n\t\twhitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([>+~]|\" + whitespace + \")\" + whitespace +\n\t\t\"*\" ),\n\trdescend = new RegExp( whitespace + \"|>\" ),\n\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + identifier + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + identifier + \")\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + identifier + \"|[*])\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" +\n\t\t\twhitespace + \"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" +\n\t\t\twhitespace + \"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t\"bool\": new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace +\n\t\t\t\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" + whitespace +\n\t\t\t\"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trhtml = /HTML$/i,\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trnative = /^[^{]+\\{\\s*\\[native \\w/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trsibling = /[+~]/,\n\n\t// CSS escapes\n\t// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = new RegExp( \"\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace + \"?|\\\\\\\\([^\\\\r\\\\n\\\\f])\", \"g\" ),\n\tfunescape = function( escape, nonHex ) {\n\t\tvar high = \"0x\" + escape.slice( 1 ) - 0x10000;\n\n\t\treturn nonHex ?\n\n\t\t\t// Strip the backslash prefix from a non-hex escape sequence\n\t\t\tnonHex :\n\n\t\t\t// Replace a hexadecimal escape sequence with the encoded Unicode code point\n\t\t\t// Support: IE <=11+\n\t\t\t// For values outside the Basic Multilingual Plane (BMP), manually construct a\n\t\t\t// surrogate pair\n\t\t\thigh < 0 ?\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t},\n\n\t// CSS string/identifier serialization\n\t// https://drafts.csswg.org/cssom/#common-serializing-idioms\n\trcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,\n\tfcssescape = function( ch, asCodePoint ) {\n\t\tif ( asCodePoint ) {\n\n\t\t\t// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\n\t\t\tif ( ch === \"\\0\" ) {\n\t\t\t\treturn \"\\uFFFD\";\n\t\t\t}\n\n\t\t\t// Control characters and (dependent upon position) numbers get escaped as code points\n\t\t\treturn ch.slice( 0, -1 ) + \"\\\\\" +\n\t\t\t\tch.charCodeAt( ch.length - 1 ).toString( 16 ) + \" \";\n\t\t}\n\n\t\t// Other potentially-special ASCII characters get backslash-escaped\n\t\treturn \"\\\\\" + ch;\n\t},\n\n\t// Used for iframes\n\t// See setDocument()\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t},\n\n\tinDisabledFieldset = addCombinator(\n\t\tfunction( elem ) {\n\t\t\treturn elem.disabled === true && elem.nodeName.toLowerCase() === \"fieldset\";\n\t\t},\n\t\t{ dir: \"parentNode\", next: \"legend\" }\n\t);\n\n// Optimize for push.apply( _, NodeList )\ntry {\n\tpush.apply(\n\t\t( arr = slice.call( preferredDoc.childNodes ) ),\n\t\tpreferredDoc.childNodes\n\t);\n\n\t// Support: Android<4.0\n\t// Detect silently failing push.apply\n\t// eslint-disable-next-line no-unused-expressions\n\tarr[ preferredDoc.childNodes.length ].nodeType;\n} catch ( e ) {\n\tpush = { apply: arr.length ?\n\n\t\t// Leverage slice if possible\n\t\tfunction( target, els ) {\n\t\t\tpushNative.apply( target, slice.call( els ) );\n\t\t} :\n\n\t\t// Support: IE<9\n\t\t// Otherwise append directly\n\t\tfunction( target, els ) {\n\t\t\tvar j = target.length,\n\t\t\t\ti = 0;\n\n\t\t\t// Can't trust NodeList.length\n\t\t\twhile ( ( target[ j++ ] = els[ i++ ] ) ) {}\n\t\t\ttarget.length = j - 1;\n\t\t}\n\t};\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar m, i, elem, nid, match, groups, newSelector,\n\t\tnewContext = context && context.ownerDocument,\n\n\t\t// nodeType defaults to 9, since context defaults to document\n\t\tnodeType = context ? context.nodeType : 9;\n\n\tresults = results || [];\n\n\t// Return early from calls with invalid selector or context\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\t// Try to shortcut find operations (as opposed to filters) in HTML documents\n\tif ( !seed ) {\n\t\tsetDocument( context );\n\t\tcontext = context || document;\n\n\t\tif ( documentIsHTML ) {\n\n\t\t\t// If the selector is sufficiently simple, try using a \"get*By*\" DOM method\n\t\t\t// (excepting DocumentFragment context, where the methods don't exist)\n\t\t\tif ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) {\n\n\t\t\t\t// ID selector\n\t\t\t\tif ( ( m = match[ 1 ] ) ) {\n\n\t\t\t\t\t// Document context\n\t\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\t\tif ( ( elem = context.getElementById( m ) ) ) {\n\n\t\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t// Element context\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\tif ( newContext && ( elem = newContext.getElementById( m ) ) &&\n\t\t\t\t\t\t\tcontains( context, elem ) &&\n\t\t\t\t\t\t\telem.id === m ) {\n\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t// Type selector\n\t\t\t\t} else if ( match[ 2 ] ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\t\treturn results;\n\n\t\t\t\t// Class selector\n\t\t\t\t} else if ( ( m = match[ 3 ] ) && support.getElementsByClassName &&\n\t\t\t\t\tcontext.getElementsByClassName ) {\n\n\t\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Take advantage of querySelectorAll\n\t\t\tif ( support.qsa &&\n\t\t\t\t!nonnativeSelectorCache[ selector + \" \" ] &&\n\t\t\t\t( !rbuggyQSA || !rbuggyQSA.test( selector ) ) &&\n\n\t\t\t\t// Support: IE 8 only\n\t\t\t\t// Exclude object elements\n\t\t\t\t( nodeType !== 1 || context.nodeName.toLowerCase() !== \"object\" ) ) {\n\n\t\t\t\tnewSelector = selector;\n\t\t\t\tnewContext = context;\n\n\t\t\t\t// qSA considers elements outside a scoping root when evaluating child or\n\t\t\t\t// descendant combinators, which is not what we want.\n\t\t\t\t// In such cases, we work around the behavior by prefixing every selector in the\n\t\t\t\t// list with an ID selector referencing the scope context.\n\t\t\t\t// The technique has to be used as well when a leading combinator is used\n\t\t\t\t// as such selectors are not recognized by querySelectorAll.\n\t\t\t\t// Thanks to Andrew Dupont for this technique.\n\t\t\t\tif ( nodeType === 1 &&\n\t\t\t\t\t( rdescend.test( selector ) || rcombinators.test( selector ) ) ) {\n\n\t\t\t\t\t// Expand context for sibling selectors\n\t\t\t\t\tnewContext = rsibling.test( selector ) && testContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext;\n\n\t\t\t\t\t// We can use :scope instead of the ID hack if the browser\n\t\t\t\t\t// supports it & if we're not changing the context.\n\t\t\t\t\tif ( newContext !== context || !support.scope ) {\n\n\t\t\t\t\t\t// Capture the context ID, setting it first if necessary\n\t\t\t\t\t\tif ( ( nid = context.getAttribute( \"id\" ) ) ) {\n\t\t\t\t\t\t\tnid = nid.replace( rcssescape, fcssescape );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontext.setAttribute( \"id\", ( nid = expando ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prefix every selector in the list\n\t\t\t\t\tgroups = tokenize( selector );\n\t\t\t\t\ti = groups.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tgroups[ i ] = ( nid ? \"#\" + nid : \":scope\" ) + \" \" +\n\t\t\t\t\t\t\ttoSelector( groups[ i ] );\n\t\t\t\t\t}\n\t\t\t\t\tnewSelector = groups.join( \",\" );\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t);\n\t\t\t\t\treturn results;\n\t\t\t\t} catch ( qsaError ) {\n\t\t\t\t\tnonnativeSelectorCache( selector, true );\n\t\t\t\t} finally {\n\t\t\t\t\tif ( nid === expando ) {\n\t\t\t\t\t\tcontext.removeAttribute( \"id\" );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {function(string, object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key + \" \" ) > Expr.cacheLength ) {\n\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn ( cache[ key + \" \" ] = value );\n\t}\n\treturn cache;\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created element and returns a boolean result\n */\nfunction assert( fn ) {\n\tvar el = document.createElement( \"fieldset\" );\n\n\ttry {\n\t\treturn !!fn( el );\n\t} catch ( e ) {\n\t\treturn false;\n\t} finally {\n\n\t\t// Remove from its parent by default\n\t\tif ( el.parentNode ) {\n\t\t\tel.parentNode.removeChild( el );\n\t\t}\n\n\t\t// release memory in IE\n\t\tel = null;\n\t}\n}\n\n/**\n * Adds the same handler for all of the specified attrs\n * @param {String} attrs Pipe-separated list of attributes\n * @param {Function} handler The method that will be applied\n */\nfunction addHandle( attrs, handler ) {\n\tvar arr = attrs.split( \"|\" ),\n\t\ti = arr.length;\n\n\twhile ( i-- ) {\n\t\tExpr.attrHandle[ arr[ i ] ] = handler;\n\t}\n}\n\n/**\n * Checks document order of two siblings\n * @param {Element} a\n * @param {Element} b\n * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b\n */\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && a.nodeType === 1 && b.nodeType === 1 &&\n\t\t\ta.sourceIndex - b.sourceIndex;\n\n\t// Use IE sourceIndex if available on both nodes\n\tif ( diff ) {\n\t\treturn diff;\n\t}\n\n\t// Check if b follows a\n\tif ( cur ) {\n\t\twhile ( ( cur = cur.nextSibling ) ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn ( name === \"input\" || name === \"button\" ) && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for :enabled/:disabled\n * @param {Boolean} disabled true for :disabled; false for :enabled\n */\nfunction createDisabledPseudo( disabled ) {\n\n\t// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable\n\treturn function( elem ) {\n\n\t\t// Only certain elements can match :enabled or :disabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled\n\t\tif ( \"form\" in elem ) {\n\n\t\t\t// Check for inherited disabledness on relevant non-disabled elements:\n\t\t\t// * listed form-associated elements in a disabled fieldset\n\t\t\t// https://html.spec.whatwg.org/multipage/forms.html#category-listed\n\t\t\t// https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled\n\t\t\t// * option elements in a disabled optgroup\n\t\t\t// https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled\n\t\t\t// All such elements have a \"form\" property.\n\t\t\tif ( elem.parentNode && elem.disabled === false ) {\n\n\t\t\t\t// Option elements defer to a parent optgroup if present\n\t\t\t\tif ( \"label\" in elem ) {\n\t\t\t\t\tif ( \"label\" in elem.parentNode ) {\n\t\t\t\t\t\treturn elem.parentNode.disabled === disabled;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn elem.disabled === disabled;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Support: IE 6 - 11\n\t\t\t\t// Use the isDisabled shortcut property to check for disabled fieldset ancestors\n\t\t\t\treturn elem.isDisabled === disabled ||\n\n\t\t\t\t\t// Where there is no isDisabled, check manually\n\t\t\t\t\t/* jshint -W018 */\n\t\t\t\t\telem.isDisabled !== !disabled &&\n\t\t\t\t\tinDisabledFieldset( elem ) === disabled;\n\t\t\t}\n\n\t\t\treturn elem.disabled === disabled;\n\n\t\t// Try to winnow out elements that can't be disabled before trusting the disabled property.\n\t\t// Some victims get caught in our net (label, legend, menu, track), but it shouldn't\n\t\t// even exist on them, let alone have a boolean value.\n\t\t} else if ( \"label\" in elem ) {\n\t\t\treturn elem.disabled === disabled;\n\t\t}\n\n\t\t// Remaining elements are neither :enabled nor :disabled\n\t\treturn false;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction( function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction( function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ ( j = matchIndexes[ i ] ) ] ) {\n\t\t\t\t\tseed[ j ] = !( matches[ j ] = seed[ j ] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t} );\n}\n\n/**\n * Checks a node for validity as a Sizzle context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Expose support vars for convenience\nsupport = Sizzle.support = {};\n\n/**\n * Detects XML nodes\n * @param {Element|Object} elem An element or a document\n * @returns {Boolean} True iff elem is a non-HTML XML node\n */\nisXML = Sizzle.isXML = function( elem ) {\n\tvar namespace = elem && elem.namespaceURI,\n\t\tdocElem = elem && ( elem.ownerDocument || elem ).documentElement;\n\n\t// Support: IE <=8\n\t// Assume HTML when documentElement doesn't yet exist, such as inside loading iframes\n\t// https://bugs.jquery.com/ticket/4833\n\treturn !rhtml.test( namespace || docElem && docElem.nodeName || \"HTML\" );\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar hasCompare, subWindow,\n\t\tdoc = node ? node.ownerDocument || node : preferredDoc;\n\n\t// Return early if doc is invalid or already selected\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Update global variables\n\tdocument = doc;\n\tdocElem = document.documentElement;\n\tdocumentIsHTML = !isXML( document );\n\n\t// Support: IE 9 - 11+, Edge 12 - 18+\n\t// Accessing iframe documents after unload throws \"permission denied\" errors (jQuery #13936)\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( preferredDoc != document &&\n\t\t( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {\n\n\t\t// Support: IE 11, Edge\n\t\tif ( subWindow.addEventListener ) {\n\t\t\tsubWindow.addEventListener( \"unload\", unloadHandler, false );\n\n\t\t// Support: IE 9 - 10 only\n\t\t} else if ( subWindow.attachEvent ) {\n\t\t\tsubWindow.attachEvent( \"onunload\", unloadHandler );\n\t\t}\n\t}\n\n\t// Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only,\n\t// Safari 4 - 5 only, Opera <=11.6 - 12.x only\n\t// IE/Edge & older browsers don't support the :scope pseudo-class.\n\t// Support: Safari 6.0 only\n\t// Safari 6.0 supports :scope but it's an alias of :root there.\n\tsupport.scope = assert( function( el ) {\n\t\tdocElem.appendChild( el ).appendChild( document.createElement( \"div\" ) );\n\t\treturn typeof el.querySelectorAll !== \"undefined\" &&\n\t\t\t!el.querySelectorAll( \":scope fieldset div\" ).length;\n\t} );\n\n\t/* Attributes\n\t---------------------------------------------------------------------- */\n\n\t// Support: IE<8\n\t// Verify that getAttribute really returns attributes and not properties\n\t// (excepting IE8 booleans)\n\tsupport.attributes = assert( function( el ) {\n\t\tel.className = \"i\";\n\t\treturn !el.getAttribute( \"className\" );\n\t} );\n\n\t/* getElement(s)By*\n\t---------------------------------------------------------------------- */\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.getElementsByTagName = assert( function( el ) {\n\t\tel.appendChild( document.createComment( \"\" ) );\n\t\treturn !el.getElementsByTagName( \"*\" ).length;\n\t} );\n\n\t// Support: IE<9\n\tsupport.getElementsByClassName = rnative.test( document.getElementsByClassName );\n\n\t// Support: IE<10\n\t// Check if getElementById returns elements by name\n\t// The broken getElementById methods don't pick up programmatically-set names,\n\t// so use a roundabout getElementsByName test\n\tsupport.getById = assert( function( el ) {\n\t\tdocElem.appendChild( el ).id = expando;\n\t\treturn !document.getElementsByName || !document.getElementsByName( expando ).length;\n\t} );\n\n\t// ID filter and find\n\tif ( support.getById ) {\n\t\tExpr.filter[ \"ID\" ] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute( \"id\" ) === attrId;\n\t\t\t};\n\t\t};\n\t\tExpr.find[ \"ID\" ] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar elem = context.getElementById( id );\n\t\t\t\treturn elem ? [ elem ] : [];\n\t\t\t}\n\t\t};\n\t} else {\n\t\tExpr.filter[ \"ID\" ] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== \"undefined\" &&\n\t\t\t\t\telem.getAttributeNode( \"id\" );\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\n\t\t// Support: IE 6 - 7 only\n\t\t// getElementById is not reliable as a find shortcut\n\t\tExpr.find[ \"ID\" ] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar node, i, elems,\n\t\t\t\t\telem = context.getElementById( id );\n\n\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t// Verify the id attribute\n\t\t\t\t\tnode = elem.getAttributeNode( \"id\" );\n\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fall back on getElementsByName\n\t\t\t\t\telems = context.getElementsByName( id );\n\t\t\t\t\ti = 0;\n\t\t\t\t\twhile ( ( elem = elems[ i++ ] ) ) {\n\t\t\t\t\t\tnode = elem.getAttributeNode( \"id\" );\n\t\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn [];\n\t\t\t}\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[ \"TAG\" ] = support.getElementsByTagName ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else if ( support.qsa ) {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t} :\n\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\n\t\t\t\t// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\twhile ( ( elem = results[ i++ ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Class\n\tExpr.find[ \"CLASS\" ] = support.getElementsByClassName && function( className, context ) {\n\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && documentIsHTML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t/* QSA/matchesSelector\n\t---------------------------------------------------------------------- */\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21)\n\t// We allow this because of a bug in IE8/9 that throws an error\n\t// whenever `document.activeElement` is accessed on an iframe\n\t// So, we allow :focus to pass through QSA all the time to avoid the IE error\n\t// See https://bugs.jquery.com/ticket/13378\n\trbuggyQSA = [];\n\n\tif ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) {\n\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert( function( el ) {\n\n\t\t\tvar input;\n\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explicitly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// https://bugs.jquery.com/ticket/12359\n\t\t\tdocElem.appendChild( el ).innerHTML = \"<a id='\" + expando + \"'></a>\" +\n\t\t\t\t\"<select id='\" + expando + \"-\\r\\\\' msallowcapture=''>\" +\n\t\t\t\t\"<option selected=''></option></select>\";\n\n\t\t\t// Support: IE8, Opera 11-12.16\n\t\t\t// Nothing should be selected when empty strings follow ^= or $= or *=\n\t\t\t// The test attribute must be unknown in Opera but \"safe\" for WinRT\n\t\t\t// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section\n\t\t\tif ( el.querySelectorAll( \"[msallowcapture^='']\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Support: IE8\n\t\t\t// Boolean attributes and \"value\" are not treated correctly\n\t\t\tif ( !el.querySelectorAll( \"[selected]\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:value|\" + booleans + \")\" );\n\t\t\t}\n\n\t\t\t// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+\n\t\t\tif ( !el.querySelectorAll( \"[id~=\" + expando + \"-]\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"~=\" );\n\t\t\t}\n\n\t\t\t// Support: IE 11+, Edge 15 - 18+\n\t\t\t// IE 11/Edge don't find elements on a `[name='']` query in some cases.\n\t\t\t// Adding a temporary attribute to the document before the selection works\n\t\t\t// around the issue.\n\t\t\t// Interestingly, IE 10 & older don't seem to have the issue.\n\t\t\tinput = document.createElement( \"input\" );\n\t\t\tinput.setAttribute( \"name\", \"\" );\n\t\t\tel.appendChild( input );\n\t\t\tif ( !el.querySelectorAll( \"[name='']\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*name\" + whitespace + \"*=\" +\n\t\t\t\t\twhitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !el.querySelectorAll( \":checked\" ).length ) {\n\t\t\t\trbuggyQSA.push( \":checked\" );\n\t\t\t}\n\n\t\t\t// Support: Safari 8+, iOS 8+\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=136851\n\t\t\t// In-page `selector#id sibling-combinator selector` fails\n\t\t\tif ( !el.querySelectorAll( \"a#\" + expando + \"+*\" ).length ) {\n\t\t\t\trbuggyQSA.push( \".#.+[+~]\" );\n\t\t\t}\n\n\t\t\t// Support: Firefox <=3.6 - 5 only\n\t\t\t// Old Firefox doesn't throw on a badly-escaped identifier.\n\t\t\tel.querySelectorAll( \"\\\\\\f\" );\n\t\t\trbuggyQSA.push( \"[\\\\r\\\\n\\\\f]\" );\n\t\t} );\n\n\t\tassert( function( el ) {\n\t\t\tel.innerHTML = \"<a href='' disabled='disabled'></a>\" +\n\t\t\t\t\"<select disabled='disabled'><option/></select>\";\n\n\t\t\t// Support: Windows 8 Native Apps\n\t\t\t// The type and name attributes are restricted during .innerHTML assignment\n\t\t\tvar input = document.createElement( \"input\" );\n\t\t\tinput.setAttribute( \"type\", \"hidden\" );\n\t\t\tel.appendChild( input ).setAttribute( \"name\", \"D\" );\n\n\t\t\t// Support: IE8\n\t\t\t// Enforce case-sensitivity of name attribute\n\t\t\tif ( el.querySelectorAll( \"[name=d]\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"name\" + whitespace + \"*[*^$|!~]?=\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( el.querySelectorAll( \":enabled\" ).length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Support: IE9-11+\n\t\t\t// IE's :disabled selector does not pick up the children of disabled fieldsets\n\t\t\tdocElem.appendChild( el ).disabled = true;\n\t\t\tif ( el.querySelectorAll( \":disabled\" ).length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Support: Opera 10 - 11 only\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tel.querySelectorAll( \"*,:x\" );\n\t\t\trbuggyQSA.push( \",.*:\" );\n\t\t} );\n\t}\n\n\tif ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches ||\n\t\tdocElem.webkitMatchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector ) ) ) ) {\n\n\t\tassert( function( el ) {\n\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( el, \"*\" );\n\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( el, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t} );\n\t}\n\n\trbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( \"|\" ) );\n\trbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( \"|\" ) );\n\n\t/* Contains\n\t---------------------------------------------------------------------- */\n\thasCompare = rnative.test( docElem.compareDocumentPosition );\n\n\t// Element contains another\n\t// Purposefully self-exclusive\n\t// As in, an element does not contain itself\n\tcontains = hasCompare || rnative.test( docElem.contains ) ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t) );\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( ( b = b.parentNode ) ) {\n\t\t\t\t\tif ( b === a ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t/* Sorting\n\t---------------------------------------------------------------------- */\n\n\t// Document order sorting\n\tsortOrder = hasCompare ?\n\tfunction( a, b ) {\n\n\t\t// Flag for duplicate removal\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Sort on method existence if only one input has compareDocumentPosition\n\t\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\t\tif ( compare ) {\n\t\t\treturn compare;\n\t\t}\n\n\t\t// Calculate position if both inputs belong to the same document\n\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t// two documents; shallow comparisons work.\n\t\t// eslint-disable-next-line eqeqeq\n\t\tcompare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ?\n\t\t\ta.compareDocumentPosition( b ) :\n\n\t\t\t// Otherwise we know they are disconnected\n\t\t\t1;\n\n\t\t// Disconnected nodes\n\t\tif ( compare & 1 ||\n\t\t\t( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) {\n\n\t\t\t// Choose the first element that is related to our preferred document\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\tif ( a == document || a.ownerDocument == preferredDoc &&\n\t\t\t\tcontains( preferredDoc, a ) ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\tif ( b == document || b.ownerDocument == preferredDoc &&\n\t\t\t\tcontains( preferredDoc, b ) ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t// Maintain original order\n\t\t\treturn sortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\t\t}\n\n\t\treturn compare & 4 ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\n\t\t// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\tif ( !aup || !bup ) {\n\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t/* eslint-disable eqeqeq */\n\t\t\treturn a == document ? -1 :\n\t\t\t\tb == document ? 1 :\n\t\t\t\t/* eslint-enable eqeqeq */\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\tsortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( ( cur = cur.parentNode ) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( ( cur = cur.parentNode ) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[ i ] === bp[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[ i ], bp[ i ] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t/* eslint-disable eqeqeq */\n\t\t\tap[ i ] == preferredDoc ? -1 :\n\t\t\tbp[ i ] == preferredDoc ? 1 :\n\t\t\t/* eslint-enable eqeqeq */\n\t\t\t0;\n\t};\n\n\treturn document;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\tsetDocument( elem );\n\n\tif ( support.matchesSelector && documentIsHTML &&\n\t\t!nonnativeSelectorCache[ expr + \" \" ] &&\n\t\t( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&\n\t\t( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\n\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t// fragment in IE 9\n\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch ( e ) {\n\t\t\tnonnativeSelectorCache( expr, true );\n\t\t}\n\t}\n\n\treturn Sizzle( expr, document, null, [ elem ] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\n\t// Set document vars if needed\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( ( context.ownerDocument || context ) != document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\n\t// Set document vars if needed\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( ( elem.ownerDocument || elem ) != document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tvar fn = Expr.attrHandle[ name.toLowerCase() ],\n\n\t\t// Don't get fooled by Object.prototype properties (jQuery #13807)\n\t\tval = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?\n\t\t\tfn( elem, name, !documentIsHTML ) :\n\t\t\tundefined;\n\n\treturn val !== undefined ?\n\t\tval :\n\t\tsupport.attributes || !documentIsHTML ?\n\t\t\telem.getAttribute( name ) :\n\t\t\t( val = elem.getAttributeNode( name ) ) && val.specified ?\n\t\t\t\tval.value :\n\t\t\t\tnull;\n};\n\nSizzle.escape = function( sel ) {\n\treturn ( sel + \"\" ).replace( rcssescape, fcssescape );\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tsortInput = !support.sortStable && results.slice( 0 );\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( ( elem = results[ i++ ] ) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\t// Clear input after sorting to release objects\n\t// See https://github.com/jquery/sizzle/pull/225\n\tsortInput = null;\n\n\treturn results;\n};\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\n\t\t// If no nodeType, this is expected to be an array\n\t\twhile ( ( node = elem[ i++ ] ) ) {\n\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (jQuery #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tattrHandle: {},\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[ 1 ] = match[ 1 ].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[ 3 ] = ( match[ 3 ] || match[ 4 ] ||\n\t\t\t\tmatch[ 5 ] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[ 2 ] === \"~=\" ) {\n\t\t\t\tmatch[ 3 ] = \" \" + match[ 3 ] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[ 1 ] = match[ 1 ].toLowerCase();\n\n\t\t\tif ( match[ 1 ].slice( 0, 3 ) === \"nth\" ) {\n\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[ 3 ] ) {\n\t\t\t\t\tSizzle.error( match[ 0 ] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[ 4 ] = +( match[ 4 ] ?\n\t\t\t\t\tmatch[ 5 ] + ( match[ 6 ] || 1 ) :\n\t\t\t\t\t2 * ( match[ 3 ] === \"even\" || match[ 3 ] === \"odd\" ) );\n\t\t\t\tmatch[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === \"odd\" );\n\n\t\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[ 3 ] ) {\n\t\t\t\tSizzle.error( match[ 0 ] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[ 6 ] && match[ 2 ];\n\n\t\t\tif ( matchExpr[ \"CHILD\" ].test( match[ 0 ] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[ 3 ] ) {\n\t\t\t\tmatch[ 2 ] = match[ 4 ] || match[ 5 ] || \"\";\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t( excess = tokenize( unquoted, true ) ) &&\n\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t( excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length ) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[ 0 ] = match[ 0 ].slice( 0, excess );\n\t\t\t\tmatch[ 2 ] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeNameSelector ) {\n\t\t\tvar nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\t\t\t\tfunction() {\n\t\t\t\t\treturn true;\n\t\t\t\t} :\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t( pattern = new RegExp( \"(^|\" + whitespace +\n\t\t\t\t\t\")\" + className + \"(\" + whitespace + \"|$)\" ) ) && classCache(\n\t\t\t\t\t\tclassName, function( elem ) {\n\t\t\t\t\t\t\treturn pattern.test(\n\t\t\t\t\t\t\t\ttypeof elem.className === \"string\" && elem.className ||\n\t\t\t\t\t\t\t\ttypeof elem.getAttribute !== \"undefined\" &&\n\t\t\t\t\t\t\t\t\telem.getAttribute( \"class\" ) ||\n\t\t\t\t\t\t\t\t\"\"\n\t\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\t/* eslint-disable max-len */\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.slice( -check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t\t/* eslint-enable max-len */\n\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, _argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tvar cache, uniqueCache, outerCache, node, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType,\n\t\t\t\t\t\tdiff = false;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( ( node = node[ dir ] ) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) {\n\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\n\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\tnode = parent;\n\t\t\t\t\t\t\touterCache = node[ expando ] || ( node[ expando ] = {} );\n\n\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t( outerCache[ node.uniqueID ] = {} );\n\n\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\tdiff = nodeIndex && cache[ 2 ];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t\tif ( useCache ) {\n\n\t\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\touterCache = node[ expando ] || ( node[ expando ] = {} );\n\n\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t( outerCache[ node.uniqueID ] = {} );\n\n\t\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\t\tdiff = nodeIndex;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// xml :nth-child(...)\n\t\t\t\t\t\t\t// or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t\tif ( diff === false ) {\n\n\t\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t\tif ( ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) &&\n\t\t\t\t\t\t\t\t\t\t++diff ) {\n\n\t\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t\touterCache = node[ expando ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t( node[ expando ] = {} );\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t( outerCache[ node.uniqueID ] = {} );\n\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\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\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction( function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf( seed, matched[ i ] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[ i ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t} ) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction( function( selector ) {\n\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction( function( seed, matches, _context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\t\t\t\t\tseed[ i ] = !( matches[ i ] = elem );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} ) :\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tinput[ 0 ] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\n\t\t\t\t\t// Don't keep the element (issue #299)\n\t\t\t\t\tinput[ 0 ] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t} ),\n\n\t\t\"has\": markFunction( function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t} ),\n\n\t\t\"contains\": markFunction( function( text ) {\n\t\t\ttext = text.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t} ),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test( lang || \"\" ) ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( ( elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute( \"xml:lang\" ) || elem.getAttribute( \"lang\" ) ) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t} ),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement &&\n\t\t\t\t( !document.hasFocus || document.hasFocus() ) &&\n\t\t\t\t!!( elem.type || elem.href || ~elem.tabIndex );\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": createDisabledPseudo( false ),\n\t\t\"disabled\": createDisabledPseudo( true ),\n\n\t\t\"checked\": function( elem ) {\n\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn ( nodeName === \"input\" && !!elem.checked ) ||\n\t\t\t\t( nodeName === \"option\" && !!elem.selected );\n\t\t},\n\n\t\t\"selected\": function( elem ) {\n\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\t// eslint-disable-next-line no-unused-expressions\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t// but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[ \"empty\" ]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\n\t\t\t\t// Support: IE<8\n\t\t\t\t// New HTML5 attribute values (e.g., \"search\") appear with elem.type === \"text\"\n\t\t\t\t( ( attr = elem.getAttribute( \"type\" ) ) == null ||\n\t\t\t\t\tattr.toLowerCase() === \"text\" );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo( function() {\n\t\t\treturn [ 0 ];\n\t\t} ),\n\n\t\t\"last\": createPositionalPseudo( function( _matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t} ),\n\n\t\t\"eq\": createPositionalPseudo( function( _matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t} ),\n\n\t\t\"even\": createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\t\"odd\": createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\t\"lt\": createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ?\n\t\t\t\targument + length :\n\t\t\t\targument > length ?\n\t\t\t\t\tlength :\n\t\t\t\t\targument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\t\"gt\": createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} )\n\t}\n};\n\nExpr.pseudos[ \"nth\" ] = Expr.pseudos[ \"eq\" ];\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = Expr.filters = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\ntokenize = Sizzle.tokenize = function( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || ( match = rcomma.exec( soFar ) ) ) {\n\t\t\tif ( match ) {\n\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[ 0 ].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( ( tokens = [] ) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( ( match = rcombinators.exec( soFar ) ) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push( {\n\t\t\t\tvalue: matched,\n\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[ 0 ].replace( rtrim, \" \" )\n\t\t\t} );\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] ||\n\t\t\t\t( match = preFilters[ type ]( match ) ) ) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push( {\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t} );\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[ i ].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tskip = combinator.next,\n\t\tkey = skip || dir,\n\t\tcheckNonElements = base && key === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, uniqueCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || ( elem[ expando ] = {} );\n\n\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\tuniqueCache = outerCache[ elem.uniqueID ] ||\n\t\t\t\t\t\t\t( outerCache[ elem.uniqueID ] = {} );\n\n\t\t\t\t\t\tif ( skip && skip === elem.nodeName.toLowerCase() ) {\n\t\t\t\t\t\t\telem = elem[ dir ] || elem;\n\t\t\t\t\t\t} else if ( ( oldCache = uniqueCache[ key ] ) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn ( newCache[ 2 ] = oldCache[ 2 ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\tuniqueCache[ key ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {\n\t\t\t\t\t\t\t\treturn true;\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\t\t\t}\n\t\t\treturn false;\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[ i ]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[ 0 ];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[ i ], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction( function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts(\n\t\t\t\tselector || \"*\",\n\t\t\t\tcontext.nodeType ? [ context ] : context,\n\t\t\t\t[]\n\t\t\t),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( ( elem = temp[ i ] ) ) {\n\t\t\t\t\tmatcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) ) {\n\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( ( matcherIn[ i ] = elem ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, ( matcherOut = [] ), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) &&\n\t\t\t\t\t\t( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) {\n\n\t\t\t\t\t\tseed[ temp ] = !( results[ temp ] = elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t} );\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[ 0 ].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[ \" \" ],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\tvar ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t( checkContext = context ).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\n\t\t\t// Avoid hanging onto element (issue #299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) {\n\t\t\tmatchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[ j ].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\n\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\ttokens\n\t\t\t\t\t\t.slice( 0, i - 1 )\n\t\t\t\t\t\t.concat( { value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" } )\n\t\t\t\t\t).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && Expr.find[ \"TAG\" ]( \"*\", outermost ),\n\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ),\n\t\t\t\tlen = elems.length;\n\n\t\t\tif ( outermost ) {\n\n\t\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\toutermostContext = context == document || context || outermost;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\t// Support: IE<9, Safari\n\t\t\t// Tolerate NodeList properties (IE: \"length\"; Safari: <number>) matching elements by id\n\t\t\tfor ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\n\t\t\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif ( !context && elem.ownerDocument != document ) {\n\t\t\t\t\t\tsetDocument( elem );\n\t\t\t\t\t\txml = !documentIsHTML;\n\t\t\t\t\t}\n\t\t\t\t\twhile ( ( matcher = elementMatchers[ j++ ] ) ) {\n\t\t\t\t\t\tif ( matcher( elem, context || document, xml ) ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( ( elem = !matcher && elem ) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// `i` is now the count of elements visited above, and adding it to `matchedCount`\n\t\t\t// makes the latter nonnegative.\n\t\t\tmatchedCount += i;\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\t// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`\n\t\t\t// equals `i`), unless we didn't visit _any_ elements in the above loop because we have\n\t\t\t// no element matchers and no seed.\n\t\t\t// Incrementing an initially-string \"0\" `i` allows `i` to remain a string only in that\n\t\t\t// case, which will result in a \"00\" `matchedCount` that differs from `i` but is also\n\t\t\t// numerically zero.\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( ( matcher = setMatchers[ j++ ] ) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !( unmatched[ i ] || setMatched[ i ] ) ) {\n\t\t\t\t\t\t\t\tsetMatched[ i ] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[ i ] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache(\n\t\t\tselector,\n\t\t\tmatcherFromGroupMatchers( elementMatchers, setMatchers )\n\t\t);\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n};\n\n/**\n * A low-level selection function that works with Sizzle's compiled\n * selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n * selector function built with Sizzle.compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nselect = Sizzle.select = function( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( ( selector = compiled.selector || selector ) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is only one selector in the list and no seed\n\t// (the latter of which guarantees us context)\n\tif ( match.length === 1 ) {\n\n\t\t// Reduce context if the leading compound selector is an ID\n\t\ttokens = match[ 0 ] = match[ 0 ].slice( 0 );\n\t\tif ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === \"ID\" &&\n\t\t\tcontext.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) {\n\n\t\t\tcontext = ( Expr.find[ \"ID\" ]( token.matches[ 0 ]\n\t\t\t\t.replace( runescape, funescape ), context ) || [] )[ 0 ];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr[ \"needsContext\" ].test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[ i ];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( Expr.relative[ ( type = token.type ) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( ( find = Expr.find[ type ] ) ) {\n\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( ( seed = find(\n\t\t\t\t\ttoken.matches[ 0 ].replace( runescape, funescape ),\n\t\t\t\t\trsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext\n\t\t\t\t) ) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\t!context || rsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n};\n\n// One-time assignments\n\n// Sort stability\nsupport.sortStable = expando.split( \"\" ).sort( sortOrder ).join( \"\" ) === expando;\n\n// Support: Chrome 14-35+\n// Always assume duplicates if they aren't passed to the comparison function\nsupport.detectDuplicates = !!hasDuplicate;\n\n// Initialize against the default document\nsetDocument();\n\n// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)\n// Detached nodes confoundingly follow *each other*\nsupport.sortDetached = assert( function( el ) {\n\n\t// Should return 1, but returns 4 (following)\n\treturn el.compareDocumentPosition( document.createElement( \"fieldset\" ) ) & 1;\n} );\n\n// Support: IE<8\n// Prevent attribute/property \"interpolation\"\n// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !assert( function( el ) {\n\tel.innerHTML = \"<a href='#'></a>\";\n\treturn el.firstChild.getAttribute( \"href\" ) === \"#\";\n} ) ) {\n\taddHandle( \"type|href|height|width\", function( elem, name, isXML ) {\n\t\tif ( !isXML ) {\n\t\t\treturn elem.getAttribute( name, name.toLowerCase() === \"type\" ? 1 : 2 );\n\t\t}\n\t} );\n}\n\n// Support: IE<9\n// Use defaultValue in place of getAttribute(\"value\")\nif ( !support.attributes || !assert( function( el ) {\n\tel.innerHTML = \"<input/>\";\n\tel.firstChild.setAttribute( \"value\", \"\" );\n\treturn el.firstChild.getAttribute( \"value\" ) === \"\";\n} ) ) {\n\taddHandle( \"value\", function( elem, _name, isXML ) {\n\t\tif ( !isXML && elem.nodeName.toLowerCase() === \"input\" ) {\n\t\t\treturn elem.defaultValue;\n\t\t}\n\t} );\n}\n\n// Support: IE<9\n// Use getAttributeNode to fetch booleans when getAttribute lies\nif ( !assert( function( el ) {\n\treturn el.getAttribute( \"disabled\" ) == null;\n} ) ) {\n\taddHandle( booleans, function( elem, name, isXML ) {\n\t\tvar val;\n\t\tif ( !isXML ) {\n\t\t\treturn elem[ name ] === true ? name.toLowerCase() :\n\t\t\t\t( val = elem.getAttributeNode( name ) ) && val.specified ?\n\t\t\t\t\tval.value :\n\t\t\t\t\tnull;\n\t\t}\n\t} );\n}\n\nreturn Sizzle;\n\n} )( window );\n\n\n\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\n\n// Deprecated\njQuery.expr[ \":\" ] = jQuery.expr.pseudos;\njQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\njQuery.escapeSelector = Sizzle.escape;\n\n\n\n\nvar dir = function( elem, dir, until ) {\n\tvar matched = [],\n\t\ttruncate = until !== undefined;\n\n\twhile ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {\n\t\tif ( elem.nodeType === 1 ) {\n\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmatched.push( elem );\n\t\t}\n\t}\n\treturn matched;\n};\n\n\nvar siblings = function( n, elem ) {\n\tvar matched = [];\n\n\tfor ( ; n; n = n.nextSibling ) {\n\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\tmatched.push( n );\n\t\t}\n\t}\n\n\treturn matched;\n};\n\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\n\n\nfunction nodeName( elem, name ) {\n\n\treturn elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\n}\nvar rsingleTag = ( /^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i );\n\n\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( isFunction( qualifier ) ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t} );\n\t}\n\n\t// Single element\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t} );\n\t}\n\n\t// Arraylike of elements (jQuery, arguments, Array)\n\tif ( typeof qualifier !== \"string\" ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( indexOf.call( qualifier, elem ) > -1 ) !== not;\n\t\t} );\n\t}\n\n\t// Filtered directly for both simple and complex selectors\n\treturn jQuery.filter( qualifier, elements, not );\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\tif ( elems.length === 1 && elem.nodeType === 1 ) {\n\t\treturn jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];\n\t}\n\n\treturn jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\treturn elem.nodeType === 1;\n\t} ) );\n};\n\njQuery.fn.extend( {\n\tfind: function( selector ) {\n\t\tvar i, ret,\n\t\t\tlen = this.length,\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter( function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\tret = this.pushStack( [] );\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\treturn len > 1 ? jQuery.uniqueSort( ret ) : ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], false ) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], true ) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n} );\n\n\n// Initialize a jQuery object\n\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\t// Shortcut simple #id case for speed\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/,\n\n\tinit = jQuery.fn.init = function( selector, context, root ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Method init() accepts an alternate rootjQuery\n\t\t// so migrate can support jQuery.sub (gh-2101)\n\t\troot = root || rootjQuery;\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\tif ( selector[ 0 ] === \"<\" &&\n\t\t\t\tselector[ selector.length - 1 ] === \">\" &&\n\t\t\t\tselector.length >= 3 ) {\n\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\tif ( match && ( match[ 1 ] || !context ) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[ 1 ] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[ 0 ] : context;\n\n\t\t\t\t\t// Option to run scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[ 1 ],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[ 2 ] );\n\n\t\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t\t// Inject the element directly into the jQuery object\n\t\t\t\t\t\tthis[ 0 ] = elem;\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || root ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis[ 0 ] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( isFunction( selector ) ) {\n\t\t\treturn root.ready !== undefined ?\n\t\t\t\troot.ready( selector ) :\n\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t};\n\n// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document );\n\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\n\t// Methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.fn.extend( {\n\thas: function( target ) {\n\t\tvar targets = jQuery( target, this ),\n\t\t\tl = targets.length;\n\n\t\treturn this.filter( function() {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[ i ] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\ttargets = typeof selectors !== \"string\" && jQuery( selectors );\n\n\t\t// Positional selectors never match, since there's no _selection_ context\n\t\tif ( !rneedsContext.test( selectors ) ) {\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tfor ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {\n\n\t\t\t\t\t// Always skip document fragments\n\t\t\t\t\tif ( cur.nodeType < 11 && ( targets ?\n\t\t\t\t\t\ttargets.index( cur ) > -1 :\n\n\t\t\t\t\t\t// Don't pass non-elements to Sizzle\n\t\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\t\tjQuery.find.matchesSelector( cur, selectors ) ) ) {\n\n\t\t\t\t\t\tmatched.push( cur );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within the set\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// Index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn indexOf.call( jQuery( elem ), this[ 0 ] );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn indexOf.call( this,\n\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[ 0 ] : elem\n\t\t);\n\t},\n\n\tadd: function( selector, context ) {\n\t\treturn this.pushStack(\n\t\t\tjQuery.uniqueSort(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter( selector )\n\t\t);\n\t}\n} );\n\nfunction sibling( cur, dir ) {\n\twhile ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}\n\treturn cur;\n}\n\njQuery.each( {\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn siblings( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn siblings( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\tif ( elem.contentDocument != null &&\n\n\t\t\t// Support: IE 11+\n\t\t\t// <object> elements with no `data` attribute has an object\n\t\t\t// `contentDocument` with a `null` prototype.\n\t\t\tgetProto( elem.contentDocument ) ) {\n\n\t\t\treturn elem.contentDocument;\n\t\t}\n\n\t\t// Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only\n\t\t// Treat the template element as a regular one in browsers that\n\t\t// don't support it.\n\t\tif ( nodeName( elem, \"template\" ) ) {\n\t\t\telem = elem.content || elem;\n\t\t}\n\n\t\treturn jQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar matched = jQuery.map( this, fn, until );\n\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tmatched = jQuery.filter( selector, matched );\n\t\t}\n\n\t\tif ( this.length > 1 ) {\n\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tjQuery.uniqueSort( matched );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tmatched.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched );\n\t};\n} );\nvar rnothtmlwhite = ( /[^\\x20\\t\\r\\n\\f]+/g );\n\n\n\n// Convert String-formatted options into Object-formatted ones\nfunction createOptions( options ) {\n\tvar object = {};\n\tjQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t} );\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\tcreateOptions( options ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Flag to know if list is currently firing\n\t\tfiring,\n\n\t\t// Last fire value for non-forgettable lists\n\t\tmemory,\n\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\n\t\t// Flag to prevent firing\n\t\tlocked,\n\n\t\t// Actual callback list\n\t\tlist = [],\n\n\t\t// Queue of execution data for repeatable lists\n\t\tqueue = [],\n\n\t\t// Index of currently firing callback (modified by add/remove as needed)\n\t\tfiringIndex = -1,\n\n\t\t// Fire callbacks\n\t\tfire = function() {\n\n\t\t\t// Enforce single-firing\n\t\t\tlocked = locked || options.once;\n\n\t\t\t// Execute callbacks for all pending executions,\n\t\t\t// respecting firingIndex overrides and runtime changes\n\t\t\tfired = firing = true;\n\t\t\tfor ( ; queue.length; firingIndex = -1 ) {\n\t\t\t\tmemory = queue.shift();\n\t\t\t\twhile ( ++firingIndex < list.length ) {\n\n\t\t\t\t\t// Run callback and check for early termination\n\t\t\t\t\tif ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&\n\t\t\t\t\t\toptions.stopOnFalse ) {\n\n\t\t\t\t\t\t// Jump to end and forget the data so .add doesn't re-fire\n\t\t\t\t\t\tfiringIndex = list.length;\n\t\t\t\t\t\tmemory = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Forget the data if we're done with it\n\t\t\tif ( !options.memory ) {\n\t\t\t\tmemory = false;\n\t\t\t}\n\n\t\t\tfiring = false;\n\n\t\t\t// Clean up if we're done firing for good\n\t\t\tif ( locked ) {\n\n\t\t\t\t// Keep an empty list if we have data for future add calls\n\t\t\t\tif ( memory ) {\n\t\t\t\t\tlist = [];\n\n\t\t\t\t// Otherwise, this object is spent\n\t\t\t\t} else {\n\t\t\t\t\tlist = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t// Actual Callbacks object\n\t\tself = {\n\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\n\t\t\t\t\t// If we have memory from a past run, we should fire after adding\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfiringIndex = list.length - 1;\n\t\t\t\t\t\tqueue.push( memory );\n\t\t\t\t\t}\n\n\t\t\t\t\t( function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tif ( isFunction( arg ) ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && toType( arg ) !== \"string\" ) {\n\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t} )( arguments );\n\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\tvar index;\n\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\tlist.splice( index, 1 );\n\n\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ?\n\t\t\t\t\tjQuery.inArray( fn, list ) > -1 :\n\t\t\t\t\tlist.length > 0;\n\t\t\t},\n\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Disable .fire and .add\n\t\t\t// Abort any current/pending executions\n\t\t\t// Clear all callbacks and values\n\t\t\tdisable: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tlist = memory = \"\";\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\n\t\t\t// Disable .fire\n\t\t\t// Also disable .add unless we have memory (since it would have no effect)\n\t\t\t// Abort any pending executions\n\t\t\tlock: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tif ( !memory && !firing ) {\n\t\t\t\t\tlist = memory = \"\";\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tlocked: function() {\n\t\t\t\treturn !!locked;\n\t\t\t},\n\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( !locked ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tqueue.push( args );\n\t\t\t\t\tif ( !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\n\nfunction Identity( v ) {\n\treturn v;\n}\nfunction Thrower( ex ) {\n\tthrow ex;\n}\n\nfunction adoptValue( value, resolve, reject, noValue ) {\n\tvar method;\n\n\ttry {\n\n\t\t// Check for promise aspect first to privilege synchronous behavior\n\t\tif ( value && isFunction( ( method = value.promise ) ) ) {\n\t\t\tmethod.call( value ).done( resolve ).fail( reject );\n\n\t\t// Other thenables\n\t\t} else if ( value && isFunction( ( method = value.then ) ) ) {\n\t\t\tmethod.call( value, resolve, reject );\n\n\t\t// Other non-thenables\n\t\t} else {\n\n\t\t\t// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:\n\t\t\t// * false: [ value ].slice( 0 ) => resolve( value )\n\t\t\t// * true: [ value ].slice( 1 ) => resolve()\n\t\t\tresolve.apply( undefined, [ value ].slice( noValue ) );\n\t\t}\n\n\t// For Promises/A+, convert exceptions into rejections\n\t// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in\n\t// Deferred#then to conditionally suppress rejection.\n\t} catch ( value ) {\n\n\t\t// Support: Android 4.0 only\n\t\t// Strict mode functions invoked without .call/.apply get global-object context\n\t\treject.apply( undefined, [ value ] );\n\t}\n}\n\njQuery.extend( {\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\n\t\t\t\t// action, add listener, callbacks,\n\t\t\t\t// ... .then handlers, argument index, [final state]\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks( \"memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"memory\" ), 2 ],\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 0, \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 1, \"rejected\" ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\t\"catch\": function( fn ) {\n\t\t\t\t\treturn promise.then( null, fn );\n\t\t\t\t},\n\n\t\t\t\t// Keep pipe for back-compat\n\t\t\t\tpipe: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( _i, tuple ) {\n\n\t\t\t\t\t\t\t// Map tuples (progress, done, fail) to arguments (done, fail, progress)\n\t\t\t\t\t\t\tvar fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];\n\n\t\t\t\t\t\t\t// deferred.progress(function() { bind to newDefer or newDefer.notify })\n\t\t\t\t\t\t\t// deferred.done(function() { bind to newDefer or newDefer.resolve })\n\t\t\t\t\t\t\t// deferred.fail(function() { bind to newDefer or newDefer.reject })\n\t\t\t\t\t\t\tdeferred[ tuple[ 1 ] ]( function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify )\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ](\n\t\t\t\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\t\t\t\tfn ? [ returned ] : arguments\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\tfns = null;\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\t\t\t\tthen: function( onFulfilled, onRejected, onProgress ) {\n\t\t\t\t\tvar maxDepth = 0;\n\t\t\t\t\tfunction resolve( depth, deferred, handler, special ) {\n\t\t\t\t\t\treturn function() {\n\t\t\t\t\t\t\tvar that = this,\n\t\t\t\t\t\t\t\targs = arguments,\n\t\t\t\t\t\t\t\tmightThrow = function() {\n\t\t\t\t\t\t\t\t\tvar returned, then;\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.3\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-59\n\t\t\t\t\t\t\t\t\t// Ignore double-resolution attempts\n\t\t\t\t\t\t\t\t\tif ( depth < maxDepth ) {\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturned = handler.apply( that, args );\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.1\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-48\n\t\t\t\t\t\t\t\t\tif ( returned === deferred.promise() ) {\n\t\t\t\t\t\t\t\t\t\tthrow new TypeError( \"Thenable self-resolution\" );\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ sections 2.3.3.1, 3.5\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-54\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-75\n\t\t\t\t\t\t\t\t\t// Retrieve `then` only once\n\t\t\t\t\t\t\t\t\tthen = returned &&\n\n\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.4\n\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-64\n\t\t\t\t\t\t\t\t\t\t// Only check objects and functions for thenability\n\t\t\t\t\t\t\t\t\t\t( typeof returned === \"object\" ||\n\t\t\t\t\t\t\t\t\t\t\ttypeof returned === \"function\" ) &&\n\t\t\t\t\t\t\t\t\t\treturned.then;\n\n\t\t\t\t\t\t\t\t\t// Handle a returned thenable\n\t\t\t\t\t\t\t\t\tif ( isFunction( then ) ) {\n\n\t\t\t\t\t\t\t\t\t\t// Special processors (notify) just wait for resolution\n\t\t\t\t\t\t\t\t\t\tif ( special ) {\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special )\n\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t// Normal processors (resolve) also hook into progress\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\t// ...and disregard older resolution values\n\t\t\t\t\t\t\t\t\t\t\tmaxDepth++;\n\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdeferred.notifyWith )\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Handle all other returned values\n\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\tif ( handler !== Identity ) {\n\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\targs = [ returned ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// Process the value(s)\n\t\t\t\t\t\t\t\t\t\t// Default process is resolve\n\t\t\t\t\t\t\t\t\t\t( special || deferred.resolveWith )( that, args );\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\t\t// Only normal processors (resolve) catch and reject exceptions\n\t\t\t\t\t\t\t\tprocess = special ?\n\t\t\t\t\t\t\t\t\tmightThrow :\n\t\t\t\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tmightThrow();\n\t\t\t\t\t\t\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t\t\t\t\t\t\tif ( jQuery.Deferred.exceptionHook ) {\n\t\t\t\t\t\t\t\t\t\t\t\tjQuery.Deferred.exceptionHook( e,\n\t\t\t\t\t\t\t\t\t\t\t\t\tprocess.stackTrace );\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.4.1\n\t\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-61\n\t\t\t\t\t\t\t\t\t\t\t// Ignore post-resolution exceptions\n\t\t\t\t\t\t\t\t\t\t\tif ( depth + 1 >= maxDepth ) {\n\n\t\t\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\t\t\tif ( handler !== Thrower ) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\targs = [ e ];\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\tdeferred.rejectWith( that, args );\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.1\n\t\t\t\t\t\t\t// https://promisesaplus.com/#point-57\n\t\t\t\t\t\t\t// Re-resolve promises immediately to dodge false rejection from\n\t\t\t\t\t\t\t// subsequent errors\n\t\t\t\t\t\t\tif ( depth ) {\n\t\t\t\t\t\t\t\tprocess();\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// Call an optional hook to record the stack, in case of exception\n\t\t\t\t\t\t\t\t// since it's otherwise lost when execution goes async\n\t\t\t\t\t\t\t\tif ( jQuery.Deferred.getStackHook ) {\n\t\t\t\t\t\t\t\t\tprocess.stackTrace = jQuery.Deferred.getStackHook();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\twindow.setTimeout( process );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\n\t\t\t\t\t\t// progress_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 0 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onProgress ) ?\n\t\t\t\t\t\t\t\t\tonProgress :\n\t\t\t\t\t\t\t\t\tIdentity,\n\t\t\t\t\t\t\t\tnewDefer.notifyWith\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// fulfilled_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 1 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onFulfilled ) ?\n\t\t\t\t\t\t\t\t\tonFulfilled :\n\t\t\t\t\t\t\t\t\tIdentity\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// rejected_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 2 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onRejected ) ?\n\t\t\t\t\t\t\t\t\tonRejected :\n\t\t\t\t\t\t\t\t\tThrower\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 5 ];\n\n\t\t\t// promise.progress = list.add\n\t\t\t// promise.done = list.add\n\t\t\t// promise.fail = list.add\n\t\t\tpromise[ tuple[ 1 ] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(\n\t\t\t\t\tfunction() {\n\n\t\t\t\t\t\t// state = \"resolved\" (i.e., fulfilled)\n\t\t\t\t\t\t// state = \"rejected\"\n\t\t\t\t\t\tstate = stateString;\n\t\t\t\t\t},\n\n\t\t\t\t\t// rejected_callbacks.disable\n\t\t\t\t\t// fulfilled_callbacks.disable\n\t\t\t\t\ttuples[ 3 - i ][ 2 ].disable,\n\n\t\t\t\t\t// rejected_handlers.disable\n\t\t\t\t\t// fulfilled_handlers.disable\n\t\t\t\t\ttuples[ 3 - i ][ 3 ].disable,\n\n\t\t\t\t\t// progress_callbacks.lock\n\t\t\t\t\ttuples[ 0 ][ 2 ].lock,\n\n\t\t\t\t\t// progress_handlers.lock\n\t\t\t\t\ttuples[ 0 ][ 3 ].lock\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// progress_handlers.fire\n\t\t\t// fulfilled_handlers.fire\n\t\t\t// rejected_handlers.fire\n\t\t\tlist.add( tuple[ 3 ].fire );\n\n\t\t\t// deferred.notify = function() { deferred.notifyWith(...) }\n\t\t\t// deferred.resolve = function() { deferred.resolveWith(...) }\n\t\t\t// deferred.reject = function() { deferred.rejectWith(...) }\n\t\t\tdeferred[ tuple[ 0 ] ] = function() {\n\t\t\t\tdeferred[ tuple[ 0 ] + \"With\" ]( this === deferred ? undefined : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\n\t\t\t// deferred.notifyWith = list.fireWith\n\t\t\t// deferred.resolveWith = list.fireWith\n\t\t\t// deferred.rejectWith = list.fireWith\n\t\t\tdeferred[ tuple[ 0 ] + \"With\" ] = list.fireWith;\n\t\t} );\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( singleValue ) {\n\t\tvar\n\n\t\t\t// count of uncompleted subordinates\n\t\t\tremaining = arguments.length,\n\n\t\t\t// count of unprocessed arguments\n\t\t\ti = remaining,\n\n\t\t\t// subordinate fulfillment data\n\t\t\tresolveContexts = Array( i ),\n\t\t\tresolveValues = slice.call( arguments ),\n\n\t\t\t// the primary Deferred\n\t\t\tprimary = jQuery.Deferred(),\n\n\t\t\t// subordinate callback factory\n\t\t\tupdateFunc = function( i ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tresolveContexts[ i ] = this;\n\t\t\t\t\tresolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( !( --remaining ) ) {\n\t\t\t\t\t\tprimary.resolveWith( resolveContexts, resolveValues );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t};\n\n\t\t// Single- and empty arguments are adopted like Promise.resolve\n\t\tif ( remaining <= 1 ) {\n\t\t\tadoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject,\n\t\t\t\t!remaining );\n\n\t\t\t// Use .then() to unwrap secondary thenables (cf. gh-3000)\n\t\t\tif ( primary.state() === \"pending\" ||\n\t\t\t\tisFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {\n\n\t\t\t\treturn primary.then();\n\t\t\t}\n\t\t}\n\n\t\t// Multiple arguments are aggregated like Promise.all array elements\n\t\twhile ( i-- ) {\n\t\t\tadoptValue( resolveValues[ i ], updateFunc( i ), primary.reject );\n\t\t}\n\n\t\treturn primary.promise();\n\t}\n} );\n\n\n// These usually indicate a programmer mistake during development,\n// warn about them ASAP rather than swallowing them by default.\nvar rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;\n\njQuery.Deferred.exceptionHook = function( error, stack ) {\n\n\t// Support: IE 8 - 9 only\n\t// Console exists when dev tools are open, which can happen at any time\n\tif ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {\n\t\twindow.console.warn( \"jQuery.Deferred exception: \" + error.message, error.stack, stack );\n\t}\n};\n\n\n\n\njQuery.readyException = function( error ) {\n\twindow.setTimeout( function() {\n\t\tthrow error;\n\t} );\n};\n\n\n\n\n// The deferred used on DOM ready\nvar readyList = jQuery.Deferred();\n\njQuery.fn.ready = function( fn ) {\n\n\treadyList\n\t\t.then( fn )\n\n\t\t// Wrap jQuery.readyException in a function so that the lookup\n\t\t// happens at the time of error handling instead of callback\n\t\t// registration.\n\t\t.catch( function( error ) {\n\t\t\tjQuery.readyException( error );\n\t\t} );\n\n\treturn this;\n};\n\njQuery.extend( {\n\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\t}\n} );\n\njQuery.ready.then = readyList.then;\n\n// The ready event handler and self cleanup method\nfunction completed() {\n\tdocument.removeEventListener( \"DOMContentLoaded\", completed );\n\twindow.removeEventListener( \"load\", completed );\n\tjQuery.ready();\n}\n\n// Catch cases where $(document).ready() is called\n// after the browser event has already occurred.\n// Support: IE <=9 - 10 only\n// Older IE sometimes signals \"interactive\" too soon\nif ( document.readyState === \"complete\" ||\n\t( document.readyState !== \"loading\" && !document.documentElement.doScroll ) ) {\n\n\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\twindow.setTimeout( jQuery.ready );\n\n} else {\n\n\t// Use the handy event callback\n\tdocument.addEventListener( \"DOMContentLoaded\", completed );\n\n\t// A fallback to window.onload, that will always work\n\twindow.addEventListener( \"load\", completed );\n}\n\n\n\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nvar access = function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( toType( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\taccess( elems, fn, i, key[ i ], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( !isFunction( value ) ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, _key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn(\n\t\t\t\t\telems[ i ], key, raw ?\n\t\t\t\t\t\tvalue :\n\t\t\t\t\t\tvalue.call( elems[ i ], i, fn( elems[ i ], key ) )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( chainable ) {\n\t\treturn elems;\n\t}\n\n\t// Gets\n\tif ( bulk ) {\n\t\treturn fn.call( elems );\n\t}\n\n\treturn len ? fn( elems[ 0 ], key ) : emptyGet;\n};\n\n\n// Matches dashed string for camelizing\nvar rmsPrefix = /^-ms-/,\n\trdashAlpha = /-([a-z])/g;\n\n// Used by camelCase as callback to replace()\nfunction fcamelCase( _all, letter ) {\n\treturn letter.toUpperCase();\n}\n\n// Convert dashed to camelCase; used by the css and data modules\n// Support: IE <=9 - 11, Edge 12 - 15\n// Microsoft forgot to hump their vendor prefix (#9572)\nfunction camelCase( string ) {\n\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n}\nvar acceptData = function( owner ) {\n\n\t// Accepts only:\n\t// - Node\n\t// - Node.ELEMENT_NODE\n\t// - Node.DOCUMENT_NODE\n\t// - Object\n\t// - Any\n\treturn owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n};\n\n\n\n\nfunction Data() {\n\tthis.expando = jQuery.expando + Data.uid++;\n}\n\nData.uid = 1;\n\nData.prototype = {\n\n\tcache: function( owner ) {\n\n\t\t// Check if the owner object already has a cache\n\t\tvar value = owner[ this.expando ];\n\n\t\t// If not, create one\n\t\tif ( !value ) {\n\t\t\tvalue = {};\n\n\t\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t\t// but we should not, see #8335.\n\t\t\t// Always return an empty object.\n\t\t\tif ( acceptData( owner ) ) {\n\n\t\t\t\t// If it is a node unlikely to be stringify-ed or looped over\n\t\t\t\t// use plain assignment\n\t\t\t\tif ( owner.nodeType ) {\n\t\t\t\t\towner[ this.expando ] = value;\n\n\t\t\t\t// Otherwise secure it in a non-enumerable property\n\t\t\t\t// configurable must be true to allow the property to be\n\t\t\t\t// deleted when data is removed\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty( owner, this.expando, {\n\t\t\t\t\t\tvalue: value,\n\t\t\t\t\t\tconfigurable: true\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn value;\n\t},\n\tset: function( owner, data, value ) {\n\t\tvar prop,\n\t\t\tcache = this.cache( owner );\n\n\t\t// Handle: [ owner, key, value ] args\n\t\t// Always use camelCase key (gh-2257)\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tcache[ camelCase( data ) ] = value;\n\n\t\t// Handle: [ owner, { properties } ] args\n\t\t} else {\n\n\t\t\t// Copy the properties one-by-one to the cache object\n\t\t\tfor ( prop in data ) {\n\t\t\t\tcache[ camelCase( prop ) ] = data[ prop ];\n\t\t\t}\n\t\t}\n\t\treturn cache;\n\t},\n\tget: function( owner, key ) {\n\t\treturn key === undefined ?\n\t\t\tthis.cache( owner ) :\n\n\t\t\t// Always use camelCase key (gh-2257)\n\t\t\towner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];\n\t},\n\taccess: function( owner, key, value ) {\n\n\t\t// In cases where either:\n\t\t//\n\t\t// 1. No key was specified\n\t\t// 2. A string key was specified, but no value provided\n\t\t//\n\t\t// Take the \"read\" path and allow the get method to determine\n\t\t// which value to return, respectively either:\n\t\t//\n\t\t// 1. The entire cache object\n\t\t// 2. The data stored at the key\n\t\t//\n\t\tif ( key === undefined ||\n\t\t\t\t( ( key && typeof key === \"string\" ) && value === undefined ) ) {\n\n\t\t\treturn this.get( owner, key );\n\t\t}\n\n\t\t// When the key is not a string, or both a key and value\n\t\t// are specified, set or extend (existing objects) with either:\n\t\t//\n\t\t// 1. An object of properties\n\t\t// 2. A key and value\n\t\t//\n\t\tthis.set( owner, key, value );\n\n\t\t// Since the \"set\" path can have two possible entry points\n\t\t// return the expected data based on which path was taken[*]\n\t\treturn value !== undefined ? value : key;\n\t},\n\tremove: function( owner, key ) {\n\t\tvar i,\n\t\t\tcache = owner[ this.expando ];\n\n\t\tif ( cache === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( key !== undefined ) {\n\n\t\t\t// Support array or space separated string of keys\n\t\t\tif ( Array.isArray( key ) ) {\n\n\t\t\t\t// If key is an array of keys...\n\t\t\t\t// We always set camelCase keys, so remove that.\n\t\t\t\tkey = key.map( camelCase );\n\t\t\t} else {\n\t\t\t\tkey = camelCase( key );\n\n\t\t\t\t// If a key with the spaces exists, use it.\n\t\t\t\t// Otherwise, create an array by matching non-whitespace\n\t\t\t\tkey = key in cache ?\n\t\t\t\t\t[ key ] :\n\t\t\t\t\t( key.match( rnothtmlwhite ) || [] );\n\t\t\t}\n\n\t\t\ti = key.length;\n\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete cache[ key[ i ] ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if there's no more data\n\t\tif ( key === undefined || jQuery.isEmptyObject( cache ) ) {\n\n\t\t\t// Support: Chrome <=35 - 45\n\t\t\t// Webkit & Blink performance suffers when deleting properties\n\t\t\t// from DOM nodes, so set to undefined instead\n\t\t\t// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)\n\t\t\tif ( owner.nodeType ) {\n\t\t\t\towner[ this.expando ] = undefined;\n\t\t\t} else {\n\t\t\t\tdelete owner[ this.expando ];\n\t\t\t}\n\t\t}\n\t},\n\thasData: function( owner ) {\n\t\tvar cache = owner[ this.expando ];\n\t\treturn cache !== undefined && !jQuery.isEmptyObject( cache );\n\t}\n};\nvar dataPriv = new Data();\n\nvar dataUser = new Data();\n\n\n\n//\tImplementation Summary\n//\n//\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n//\t2. Improve the module's maintainability by reducing the storage\n//\t\tpaths to a single mechanism.\n//\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n//\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n//\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n//\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /[A-Z]/g;\n\nfunction getData( data ) {\n\tif ( data === \"true\" ) {\n\t\treturn true;\n\t}\n\n\tif ( data === \"false\" ) {\n\t\treturn false;\n\t}\n\n\tif ( data === \"null\" ) {\n\t\treturn null;\n\t}\n\n\t// Only convert to a number if it doesn't change the string\n\tif ( data === +data + \"\" ) {\n\t\treturn +data;\n\t}\n\n\tif ( rbrace.test( data ) ) {\n\t\treturn JSON.parse( data );\n\t}\n\n\treturn data;\n}\n\nfunction dataAttr( elem, key, data ) {\n\tvar name;\n\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\t\tname = \"data-\" + key.replace( rmultiDash, \"-$&\" ).toLowerCase();\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = getData( data );\n\t\t\t} catch ( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tdataUser.set( elem, key, data );\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\treturn data;\n}\n\njQuery.extend( {\n\thasData: function( elem ) {\n\t\treturn dataUser.hasData( elem ) || dataPriv.hasData( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn dataUser.access( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tdataUser.remove( elem, name );\n\t},\n\n\t// TODO: Now that all calls to _data and _removeData have been replaced\n\t// with direct calls to dataPriv methods, these can be deprecated.\n\t_data: function( elem, name, data ) {\n\t\treturn dataPriv.access( elem, name, data );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\tdataPriv.remove( elem, name );\n\t}\n} );\n\njQuery.fn.extend( {\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[ 0 ],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = dataUser.get( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !dataPriv.get( elem, \"hasDataAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\n\t\t\t\t\t\t// Support: IE 11 only\n\t\t\t\t\t\t// The attrs elements can be null (#14894)\n\t\t\t\t\t\tif ( attrs[ i ] ) {\n\t\t\t\t\t\t\tname = attrs[ i ].name;\n\t\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\t\tname = camelCase( name.slice( 5 ) );\n\t\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\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\tdataPriv.set( elem, \"hasDataAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tdataUser.set( this, key );\n\t\t\t} );\n\t\t}\n\n\t\treturn access( this, function( value ) {\n\t\t\tvar data;\n\n\t\t\t// The calling jQuery object (element matches) is not empty\n\t\t\t// (and therefore has an element appears at this[ 0 ]) and the\n\t\t\t// `value` parameter was not undefined. An empty jQuery object\n\t\t\t// will result in `undefined` for elem = this[ 0 ] which will\n\t\t\t// throw an exception if an attempt to read a data cache is made.\n\t\t\tif ( elem && value === undefined ) {\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// The key will always be camelCased in Data\n\t\t\t\tdata = dataUser.get( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to \"discover\" the data in\n\t\t\t\t// HTML5 custom data-* attrs\n\t\t\t\tdata = dataAttr( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// We tried really hard, but the data doesn't exist.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the data...\n\t\t\tthis.each( function() {\n\n\t\t\t\t// We always store the camelCased key\n\t\t\t\tdataUser.set( this, key, value );\n\t\t\t} );\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each( function() {\n\t\t\tdataUser.remove( this, key );\n\t\t} );\n\t}\n} );\n\n\njQuery.extend( {\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = dataPriv.get( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || Array.isArray( data ) ) {\n\t\t\t\t\tqueue = dataPriv.access( elem, type, jQuery.makeArray( data ) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// Clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// Not public - generate a queueHooks object, or return the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn dataPriv.get( elem, key ) || dataPriv.access( elem, key, {\n\t\t\tempty: jQuery.Callbacks( \"once memory\" ).add( function() {\n\t\t\t\tdataPriv.remove( elem, [ type + \"queue\", key ] );\n\t\t\t} )\n\t\t} );\n\t}\n} );\n\njQuery.fn.extend( {\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[ 0 ], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each( function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// Ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[ 0 ] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t} );\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t} );\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = dataPriv.get( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n} );\nvar pnum = ( /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/ ).source;\n\nvar rcssNum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" );\n\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\nvar documentElement = document.documentElement;\n\n\n\n\tvar isAttached = function( elem ) {\n\t\t\treturn jQuery.contains( elem.ownerDocument, elem );\n\t\t},\n\t\tcomposed = { composed: true };\n\n\t// Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only\n\t// Check attachment across shadow DOM boundaries when possible (gh-3504)\n\t// Support: iOS 10.0-10.2 only\n\t// Early iOS 10 versions support `attachShadow` but not `getRootNode`,\n\t// leading to errors. We need to check for `getRootNode`.\n\tif ( documentElement.getRootNode ) {\n\t\tisAttached = function( elem ) {\n\t\t\treturn jQuery.contains( elem.ownerDocument, elem ) ||\n\t\t\t\telem.getRootNode( composed ) === elem.ownerDocument;\n\t\t};\n\t}\nvar isHiddenWithinTree = function( elem, el ) {\n\n\t\t// isHiddenWithinTree might be called from jQuery#filter function;\n\t\t// in that case, element will be second argument\n\t\telem = el || elem;\n\n\t\t// Inline style trumps all\n\t\treturn elem.style.display === \"none\" ||\n\t\t\telem.style.display === \"\" &&\n\n\t\t\t// Otherwise, check computed style\n\t\t\t// Support: Firefox <=43 - 45\n\t\t\t// Disconnected elements can have computed display: none, so first confirm that elem is\n\t\t\t// in the document.\n\t\t\tisAttached( elem ) &&\n\n\t\t\tjQuery.css( elem, \"display\" ) === \"none\";\n\t};\n\n\n\nfunction adjustCSS( elem, prop, valueParts, tween ) {\n\tvar adjusted, scale,\n\t\tmaxIterations = 20,\n\t\tcurrentValue = tween ?\n\t\t\tfunction() {\n\t\t\t\treturn tween.cur();\n\t\t\t} :\n\t\t\tfunction() {\n\t\t\t\treturn jQuery.css( elem, prop, \"\" );\n\t\t\t},\n\t\tinitial = currentValue(),\n\t\tunit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" ),\n\n\t\t// Starting value computation is required for potential unit mismatches\n\t\tinitialInUnit = elem.nodeType &&\n\t\t\t( jQuery.cssNumber[ prop ] || unit !== \"px\" && +initial ) &&\n\t\t\trcssNum.exec( jQuery.css( elem, prop ) );\n\n\tif ( initialInUnit && initialInUnit[ 3 ] !== unit ) {\n\n\t\t// Support: Firefox <=54\n\t\t// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)\n\t\tinitial = initial / 2;\n\n\t\t// Trust units reported by jQuery.css\n\t\tunit = unit || initialInUnit[ 3 ];\n\n\t\t// Iteratively approximate from a nonzero starting point\n\t\tinitialInUnit = +initial || 1;\n\n\t\twhile ( maxIterations-- ) {\n\n\t\t\t// Evaluate and update our best guess (doubling guesses that zero out).\n\t\t\t// Finish if the scale equals or crosses 1 (making the old*new product non-positive).\n\t\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\t\t\tif ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {\n\t\t\t\tmaxIterations = 0;\n\t\t\t}\n\t\t\tinitialInUnit = initialInUnit / scale;\n\n\t\t}\n\n\t\tinitialInUnit = initialInUnit * 2;\n\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\n\t\t// Make sure we update the tween properties later on\n\t\tvalueParts = valueParts || [];\n\t}\n\n\tif ( valueParts ) {\n\t\tinitialInUnit = +initialInUnit || +initial || 0;\n\n\t\t// Apply relative offset (+=/-=) if specified\n\t\tadjusted = valueParts[ 1 ] ?\n\t\t\tinitialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :\n\t\t\t+valueParts[ 2 ];\n\t\tif ( tween ) {\n\t\t\ttween.unit = unit;\n\t\t\ttween.start = initialInUnit;\n\t\t\ttween.end = adjusted;\n\t\t}\n\t}\n\treturn adjusted;\n}\n\n\nvar defaultDisplayMap = {};\n\nfunction getDefaultDisplay( elem ) {\n\tvar temp,\n\t\tdoc = elem.ownerDocument,\n\t\tnodeName = elem.nodeName,\n\t\tdisplay = defaultDisplayMap[ nodeName ];\n\n\tif ( display ) {\n\t\treturn display;\n\t}\n\n\ttemp = doc.body.appendChild( doc.createElement( nodeName ) );\n\tdisplay = jQuery.css( temp, \"display\" );\n\n\ttemp.parentNode.removeChild( temp );\n\n\tif ( display === \"none\" ) {\n\t\tdisplay = \"block\";\n\t}\n\tdefaultDisplayMap[ nodeName ] = display;\n\n\treturn display;\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\t// Determine new display value for elements that need to change\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\n\t\t\t// Since we force visibility upon cascade-hidden elements, an immediate (and slow)\n\t\t\t// check is required in this first loop unless we have a nonempty display value (either\n\t\t\t// inline or about-to-be-restored)\n\t\t\tif ( display === \"none\" ) {\n\t\t\t\tvalues[ index ] = dataPriv.get( elem, \"display\" ) || null;\n\t\t\t\tif ( !values[ index ] ) {\n\t\t\t\t\telem.style.display = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( elem.style.display === \"\" && isHiddenWithinTree( elem ) ) {\n\t\t\t\tvalues[ index ] = getDefaultDisplay( elem );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( display !== \"none\" ) {\n\t\t\t\tvalues[ index ] = \"none\";\n\n\t\t\t\t// Remember what we're overwriting\n\t\t\t\tdataPriv.set( elem, \"display\", display );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of the elements in a second loop to avoid constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\tif ( values[ index ] != null ) {\n\t\t\telements[ index ].style.display = values[ index ];\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.fn.extend( {\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tif ( isHiddenWithinTree( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t} );\n\t}\n} );\nvar rcheckableType = ( /^(?:checkbox|radio)$/i );\n\nvar rtagName = ( /<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i );\n\nvar rscriptType = ( /^$|^module$|\\/(?:java|ecma)script/i );\n\n\n\n( function() {\n\tvar fragment = document.createDocumentFragment(),\n\t\tdiv = fragment.appendChild( document.createElement( \"div\" ) ),\n\t\tinput = document.createElement( \"input\" );\n\n\t// Support: Android 4.0 - 4.3 only\n\t// Check state lost if the name is set (#11217)\n\t// Support: Windows Web Apps (WWA)\n\t// `name` and `type` must use .setAttribute for WWA (#14901)\n\tinput.setAttribute( \"type\", \"radio\" );\n\tinput.setAttribute( \"checked\", \"checked\" );\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tdiv.appendChild( input );\n\n\t// Support: Android <=4.1 only\n\t// Older WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE <=11 only\n\t// Make sure textarea (and checkbox) defaultValue is properly cloned\n\tdiv.innerHTML = \"<textarea>x</textarea>\";\n\tsupport.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n\n\t// Support: IE <=9 only\n\t// IE <=9 replaces <option> tags with their contents when inserted outside of\n\t// the select element.\n\tdiv.innerHTML = \"<option></option>\";\n\tsupport.option = !!div.lastChild;\n} )();\n\n\n// We have to close these tags to support XHTML (#13200)\nvar wrapMap = {\n\n\t// XHTML parsers do not magically insert elements in the\n\t// same way that tag soup parsers do. So we cannot shorten\n\t// this by omitting <tbody> or other required elements.\n\tthead: [ 1, \"<table>\", \"</table>\" ],\n\tcol: [ 2, \"<table><colgroup>\", \"</colgroup></table>\" ],\n\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t_default: [ 0, \"\", \"\" ]\n};\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n// Support: IE <=9 only\nif ( !support.option ) {\n\twrapMap.optgroup = wrapMap.option = [ 1, \"<select multiple='multiple'>\", \"</select>\" ];\n}\n\n\nfunction getAll( context, tag ) {\n\n\t// Support: IE <=9 - 11 only\n\t// Use typeof to avoid zero-argument method invocation on host objects (#15151)\n\tvar ret;\n\n\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\tret = context.getElementsByTagName( tag || \"*\" );\n\n\t} else if ( typeof context.querySelectorAll !== \"undefined\" ) {\n\t\tret = context.querySelectorAll( tag || \"*\" );\n\n\t} else {\n\t\tret = [];\n\t}\n\n\tif ( tag === undefined || tag && nodeName( context, tag ) ) {\n\t\treturn jQuery.merge( [ context ], ret );\n\t}\n\n\treturn ret;\n}\n\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdataPriv.set(\n\t\t\telems[ i ],\n\t\t\t\"globalEval\",\n\t\t\t!refElements || dataPriv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\n\nvar rhtml = /<|&#?\\w+;/;\n\nfunction buildFragment( elems, context, scripts, selection, ignored ) {\n\tvar elem, tmp, tag, wrap, attached, j,\n\t\tfragment = context.createDocumentFragment(),\n\t\tnodes = [],\n\t\ti = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\telem = elems[ i ];\n\n\t\tif ( elem || elem === 0 ) {\n\n\t\t\t// Add nodes directly\n\t\t\tif ( toType( elem ) === \"object\" ) {\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t// Convert non-html into a text node\n\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t// Convert html into DOM nodes\n\t\t\t} else {\n\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement( \"div\" ) );\n\n\t\t\t\t// Deserialize a standard representation\n\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\t\t\t\ttmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];\n\n\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\tj = wrap[ 0 ];\n\t\t\t\twhile ( j-- ) {\n\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t}\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t// Remember the top-level container\n\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t// Ensure the created nodes are orphaned (#12392)\n\t\t\t\ttmp.textContent = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove wrapper from fragment\n\tfragment.textContent = \"\";\n\n\ti = 0;\n\twhile ( ( elem = nodes[ i++ ] ) ) {\n\n\t\t// Skip elements already in the context collection (trac-4087)\n\t\tif ( selection && jQuery.inArray( elem, selection ) > -1 ) {\n\t\t\tif ( ignored ) {\n\t\t\t\tignored.push( elem );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tattached = isAttached( elem );\n\n\t\t// Append to fragment\n\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t// Preserve script evaluation history\n\t\tif ( attached ) {\n\t\t\tsetGlobalEval( tmp );\n\t\t}\n\n\t\t// Capture executables\n\t\tif ( scripts ) {\n\t\t\tj = 0;\n\t\t\twhile ( ( elem = tmp[ j++ ] ) ) {\n\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\tscripts.push( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fragment;\n}\n\n\nvar rtypenamespace = /^([^.]*)(?:\\.(.+)|)/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\n// Support: IE <=9 - 11+\n// focus() and blur() are asynchronous, except when they are no-op.\n// So expect focus to be synchronous when the element is already active,\n// and blur to be synchronous when the element is not already active.\n// (focus and blur are always synchronous in other supported browsers,\n// this just defines when we can count on it).\nfunction expectSync( elem, type ) {\n\treturn ( elem === safeActiveElement() ) === ( type === \"focus\" );\n}\n\n// Support: IE <=9 only\n// Accessing document.activeElement can throw unexpectedly\n// https://bugs.jquery.com/ticket/13393\nfunction safeActiveElement() {\n\ttry {\n\t\treturn document.activeElement;\n\t} catch ( err ) { }\n}\n\nfunction on( elem, types, selector, data, fn, one ) {\n\tvar origFn, type;\n\n\t// Types can be a map of types/handlers\n\tif ( typeof types === \"object\" ) {\n\n\t\t// ( types-Object, selector, data )\n\t\tif ( typeof selector !== \"string\" ) {\n\n\t\t\t// ( types-Object, data )\n\t\t\tdata = data || selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tfor ( type in types ) {\n\t\t\ton( elem, type, selector, data, types[ type ], one );\n\t\t}\n\t\treturn elem;\n\t}\n\n\tif ( data == null && fn == null ) {\n\n\t\t// ( types, fn )\n\t\tfn = selector;\n\t\tdata = selector = undefined;\n\t} else if ( fn == null ) {\n\t\tif ( typeof selector === \"string\" ) {\n\n\t\t\t// ( types, selector, fn )\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t} else {\n\n\t\t\t// ( types, data, fn )\n\t\t\tfn = data;\n\t\t\tdata = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t}\n\tif ( fn === false ) {\n\t\tfn = returnFalse;\n\t} else if ( !fn ) {\n\t\treturn elem;\n\t}\n\n\tif ( one === 1 ) {\n\t\torigFn = fn;\n\t\tfn = function( event ) {\n\n\t\t\t// Can use an empty set, since event contains the info\n\t\t\tjQuery().off( event );\n\t\t\treturn origFn.apply( this, arguments );\n\t\t};\n\n\t\t// Use same guid so caller can remove using origFn\n\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t}\n\treturn elem.each( function() {\n\t\tjQuery.event.add( this, types, fn, data, selector );\n\t} );\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.get( elem );\n\n\t\t// Only attach events to objects that accept data\n\t\tif ( !acceptData( elem ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Ensure that invalid selectors throw exceptions at attach time\n\t\t// Evaluate against documentElement in case elem is a non-element node (e.g., document)\n\t\tif ( selector ) {\n\t\t\tjQuery.find.matchesSelector( documentElement, selector );\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !( events = elemData.events ) ) {\n\t\t\tevents = elemData.events = Object.create( null );\n\t\t}\n\t\tif ( !( eventHandle = elemData.handle ) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend( {\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join( \".\" )\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !( handlers = events[ type ] ) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup ||\n\t\t\t\t\tspecial.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.hasData( elem ) && dataPriv.get( elem );\n\n\t\tif ( !elemData || !( events = elemData.events ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[ 2 ] &&\n\t\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector ||\n\t\t\t\t\t\tselector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown ||\n\t\t\t\t\tspecial.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove data and the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdataPriv.remove( elem, \"handle events\" );\n\t\t}\n\t},\n\n\tdispatch: function( nativeEvent ) {\n\n\t\tvar i, j, ret, matched, handleObj, handlerQueue,\n\t\t\targs = new Array( arguments.length ),\n\n\t\t\t// Make a writable jQuery.Event from the native event object\n\t\t\tevent = jQuery.event.fix( nativeEvent ),\n\n\t\t\thandlers = (\n\t\t\t\tdataPriv.get( this, \"events\" ) || Object.create( null )\n\t\t\t)[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[ 0 ] = event;\n\n\t\tfor ( i = 1; i < arguments.length; i++ ) {\n\t\t\targs[ i ] = arguments[ i ];\n\t\t}\n\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( ( handleObj = matched.handlers[ j++ ] ) &&\n\t\t\t\t!event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// If the event is namespaced, then each handler is only invoked if it is\n\t\t\t\t// specially universal or its namespaces are a superset of the event's.\n\t\t\t\tif ( !event.rnamespace || handleObj.namespace === false ||\n\t\t\t\t\tevent.rnamespace.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||\n\t\t\t\t\t\thandleObj.handler ).apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( ( event.result = ret ) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, handleObj, sel, matchedHandlers, matchedSelectors,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\tif ( delegateCount &&\n\n\t\t\t// Support: IE <=9\n\t\t\t// Black-hole SVG <use> instance trees (trac-13180)\n\t\t\tcur.nodeType &&\n\n\t\t\t// Support: Firefox <=42\n\t\t\t// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)\n\t\t\t// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click\n\t\t\t// Support: IE 11 only\n\t\t\t// ...but not arrow key \"clicks\" of radio inputs, which can have `button` -1 (gh-2343)\n\t\t\t!( event.type === \"click\" && event.button >= 1 ) ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't check non-elements (#13208)\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.nodeType === 1 && !( event.type === \"click\" && cur.disabled === true ) ) {\n\t\t\t\t\tmatchedHandlers = [];\n\t\t\t\t\tmatchedSelectors = {};\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatchedSelectors[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) > -1 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] ) {\n\t\t\t\t\t\t\tmatchedHandlers.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matchedHandlers.length ) {\n\t\t\t\t\t\thandlerQueue.push( { elem: cur, handlers: matchedHandlers } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tcur = this;\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\taddProp: function( name, hook ) {\n\t\tObject.defineProperty( jQuery.Event.prototype, name, {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\n\t\t\tget: isFunction( hook ) ?\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\treturn hook( this.originalEvent );\n\t\t\t\t\t}\n\t\t\t\t} :\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\treturn this.originalEvent[ name ];\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\tset: function( value ) {\n\t\t\t\tObject.defineProperty( this, name, {\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t\tvalue: value\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t},\n\n\tfix: function( originalEvent ) {\n\t\treturn originalEvent[ jQuery.expando ] ?\n\t\t\toriginalEvent :\n\t\t\tnew jQuery.Event( originalEvent );\n\t},\n\n\tspecial: {\n\t\tload: {\n\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tclick: {\n\n\t\t\t// Utilize native event to ensure correct state for checkable inputs\n\t\t\tsetup: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Claim the first handler\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\t// dataPriv.set( el, \"click\", ... )\n\t\t\t\t\tleverageNative( el, \"click\", returnTrue );\n\t\t\t\t}\n\n\t\t\t\t// Return false to allow normal processing in the caller\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\ttrigger: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Force setup before triggering a click\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\tleverageNative( el, \"click\" );\n\t\t\t\t}\n\n\t\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\t\treturn true;\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, suppress native .click() on links\n\t\t\t// Also prevent it if we're currently inside a leveraged native-event stack\n\t\t\t_default: function( event ) {\n\t\t\t\tvar target = event.target;\n\t\t\t\treturn rcheckableType.test( target.type ) &&\n\t\t\t\t\ttarget.click && nodeName( target, \"input\" ) &&\n\t\t\t\t\tdataPriv.get( target, \"click\" ) ||\n\t\t\t\t\tnodeName( target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Support: Firefox 20+\n\t\t\t\t// Firefox doesn't alert if the returnValue field is not set.\n\t\t\t\tif ( event.result !== undefined && event.originalEvent ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Ensure the presence of an event listener that handles manually-triggered\n// synthetic events by interrupting progress until reinvoked in response to\n// *native* events that it fires directly, ensuring that state changes have\n// already occurred before other listeners are invoked.\nfunction leverageNative( el, type, expectSync ) {\n\n\t// Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add\n\tif ( !expectSync ) {\n\t\tif ( dataPriv.get( el, type ) === undefined ) {\n\t\t\tjQuery.event.add( el, type, returnTrue );\n\t\t}\n\t\treturn;\n\t}\n\n\t// Register the controller as a special universal handler for all event namespaces\n\tdataPriv.set( el, type, false );\n\tjQuery.event.add( el, type, {\n\t\tnamespace: false,\n\t\thandler: function( event ) {\n\t\t\tvar notAsync, result,\n\t\t\t\tsaved = dataPriv.get( this, type );\n\n\t\t\tif ( ( event.isTrigger & 1 ) && this[ type ] ) {\n\n\t\t\t\t// Interrupt processing of the outer synthetic .trigger()ed event\n\t\t\t\t// Saved data should be false in such cases, but might be a leftover capture object\n\t\t\t\t// from an async native handler (gh-4350)\n\t\t\t\tif ( !saved.length ) {\n\n\t\t\t\t\t// Store arguments for use when handling the inner native event\n\t\t\t\t\t// There will always be at least one argument (an event object), so this array\n\t\t\t\t\t// will not be confused with a leftover capture object.\n\t\t\t\t\tsaved = slice.call( arguments );\n\t\t\t\t\tdataPriv.set( this, type, saved );\n\n\t\t\t\t\t// Trigger the native event and capture its result\n\t\t\t\t\t// Support: IE <=9 - 11+\n\t\t\t\t\t// focus() and blur() are asynchronous\n\t\t\t\t\tnotAsync = expectSync( this, type );\n\t\t\t\t\tthis[ type ]();\n\t\t\t\t\tresult = dataPriv.get( this, type );\n\t\t\t\t\tif ( saved !== result || notAsync ) {\n\t\t\t\t\t\tdataPriv.set( this, type, false );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = {};\n\t\t\t\t\t}\n\t\t\t\t\tif ( saved !== result ) {\n\n\t\t\t\t\t\t// Cancel the outer synthetic event\n\t\t\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t\t\t\tevent.preventDefault();\n\n\t\t\t\t\t\t// Support: Chrome 86+\n\t\t\t\t\t\t// In Chrome, if an element having a focusout handler is blurred by\n\t\t\t\t\t\t// clicking outside of it, it invokes the handler synchronously. If\n\t\t\t\t\t\t// that handler calls `.remove()` on the element, the data is cleared,\n\t\t\t\t\t\t// leaving `result` undefined. We need to guard against this.\n\t\t\t\t\t\treturn result && result.value;\n\t\t\t\t\t}\n\n\t\t\t\t// If this is an inner synthetic event for an event with a bubbling surrogate\n\t\t\t\t// (focus or blur), assume that the surrogate already propagated from triggering the\n\t\t\t\t// native event and prevent that from happening again here.\n\t\t\t\t// This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the\n\t\t\t\t// bubbling surrogate propagates *after* the non-bubbling base), but that seems\n\t\t\t\t// less bad than duplication.\n\t\t\t\t} else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t}\n\n\t\t\t// If this is a native event triggered above, everything is now in order\n\t\t\t// Fire an inner synthetic event with the original arguments\n\t\t\t} else if ( saved.length ) {\n\n\t\t\t\t// ...and capture the result\n\t\t\t\tdataPriv.set( this, type, {\n\t\t\t\t\tvalue: jQuery.event.trigger(\n\n\t\t\t\t\t\t// Support: IE <=9 - 11+\n\t\t\t\t\t\t// Extend with the prototype to reset the above stopImmediatePropagation()\n\t\t\t\t\t\tjQuery.extend( saved[ 0 ], jQuery.Event.prototype ),\n\t\t\t\t\t\tsaved.slice( 1 ),\n\t\t\t\t\t\tthis\n\t\t\t\t\t)\n\t\t\t\t} );\n\n\t\t\t\t// Abort handling of the native event\n\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t}\n\t\t}\n\t} );\n}\n\njQuery.removeEvent = function( elem, type, handle ) {\n\n\t// This \"if\" is needed for plain objects\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\n\t// Allow instantiation without the 'new' keyword\n\tif ( !( this instanceof jQuery.Event ) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = src.defaultPrevented ||\n\t\t\t\tsrc.defaultPrevented === undefined &&\n\n\t\t\t\t// Support: Android <=2.3 only\n\t\t\t\tsrc.returnValue === false ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t\t// Create target properties\n\t\t// Support: Safari <=6 - 7 only\n\t\t// Target should not be a text node (#504, #13143)\n\t\tthis.target = ( src.target && src.target.nodeType === 3 ) ?\n\t\t\tsrc.target.parentNode :\n\t\t\tsrc.target;\n\n\t\tthis.currentTarget = src.currentTarget;\n\t\tthis.relatedTarget = src.relatedTarget;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || Date.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tconstructor: jQuery.Event,\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\tisSimulated: false,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Includes all common event props including KeyEvent and MouseEvent specific props\njQuery.each( {\n\taltKey: true,\n\tbubbles: true,\n\tcancelable: true,\n\tchangedTouches: true,\n\tctrlKey: true,\n\tdetail: true,\n\teventPhase: true,\n\tmetaKey: true,\n\tpageX: true,\n\tpageY: true,\n\tshiftKey: true,\n\tview: true,\n\t\"char\": true,\n\tcode: true,\n\tcharCode: true,\n\tkey: true,\n\tkeyCode: true,\n\tbutton: true,\n\tbuttons: true,\n\tclientX: true,\n\tclientY: true,\n\toffsetX: true,\n\toffsetY: true,\n\tpointerId: true,\n\tpointerType: true,\n\tscreenX: true,\n\tscreenY: true,\n\ttargetTouches: true,\n\ttoElement: true,\n\ttouches: true,\n\twhich: true\n}, jQuery.event.addProp );\n\njQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( type, delegateType ) {\n\tjQuery.event.special[ type ] = {\n\n\t\t// Utilize native event if possible so blur/focus sequence is correct\n\t\tsetup: function() {\n\n\t\t\t// Claim the first handler\n\t\t\t// dataPriv.set( this, \"focus\", ... )\n\t\t\t// dataPriv.set( this, \"blur\", ... )\n\t\t\tleverageNative( this, type, expectSync );\n\n\t\t\t// Return false to allow normal processing in the caller\n\t\t\treturn false;\n\t\t},\n\t\ttrigger: function() {\n\n\t\t\t// Force setup before trigger\n\t\t\tleverageNative( this, type );\n\n\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\treturn true;\n\t\t},\n\n\t\t// Suppress native focus or blur as it's already being fired\n\t\t// in leverageNative.\n\t\t_default: function() {\n\t\t\treturn true;\n\t\t},\n\n\t\tdelegateType: delegateType\n\t};\n} );\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// so that event delegation works in jQuery.\n// Do the same for pointerenter/pointerleave and pointerover/pointerout\n//\n// Support: Safari 7 only\n// Safari sends mouseenter too often; see:\n// https://bugs.chromium.org/p/chromium/issues/detail?id=470258\n// for the description of the bug (it existed in older Chrome versions as well).\njQuery.each( {\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\",\n\tpointerenter: \"pointerover\",\n\tpointerleave: \"pointerout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mouseenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n} );\n\njQuery.fn.extend( {\n\n\ton: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn );\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\n\t\t\t// ( event ) dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ?\n\t\t\t\t\thandleObj.origType + \".\" + handleObj.namespace :\n\t\t\t\t\thandleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t} );\n\t}\n} );\n\n\nvar\n\n\t// Support: IE <=10 - 11, Edge 12 - 13 only\n\t// In IE/Edge using regex groups here causes severe slowdowns.\n\t// See https://connect.microsoft.com/IE/feedback/details/1736512/\n\trnoInnerhtml = /<script|<style|<link/i,\n\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;\n\n// Prefer a tbody over its parent table for containing new rows\nfunction manipulationTarget( elem, content ) {\n\tif ( nodeName( elem, \"table\" ) &&\n\t\tnodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ) {\n\n\t\treturn jQuery( elem ).children( \"tbody\" )[ 0 ] || elem;\n\t}\n\n\treturn elem;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = ( elem.getAttribute( \"type\" ) !== null ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tif ( ( elem.type || \"\" ).slice( 0, 5 ) === \"true/\" ) {\n\t\telem.type = elem.type.slice( 5 );\n\t} else {\n\t\telem.removeAttribute( \"type\" );\n\t}\n\n\treturn elem;\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\tvar i, l, type, pdataOld, udataOld, udataCur, events;\n\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// 1. Copy private data: events, handlers, etc.\n\tif ( dataPriv.hasData( src ) ) {\n\t\tpdataOld = dataPriv.get( src );\n\t\tevents = pdataOld.events;\n\n\t\tif ( events ) {\n\t\t\tdataPriv.remove( dest, \"handle events\" );\n\n\t\t\tfor ( type in events ) {\n\t\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. Copy user data\n\tif ( dataUser.hasData( src ) ) {\n\t\tudataOld = dataUser.access( src );\n\t\tudataCur = jQuery.extend( {}, udataOld );\n\n\t\tdataUser.set( dest, udataCur );\n\t}\n}\n\n// Fix IE bugs, see support tests\nfunction fixInput( src, dest ) {\n\tvar nodeName = dest.nodeName.toLowerCase();\n\n\t// Fails to persist the checked state of a cloned checkbox or radio button.\n\tif ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\n\t\tdest.checked = src.checked;\n\n\t// Fails to return the selected option to the default selected state when cloning options\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\nfunction domManip( collection, args, callback, ignored ) {\n\n\t// Flatten any nested arrays\n\targs = flat( args );\n\n\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\ti = 0,\n\t\tl = collection.length,\n\t\tiNoClone = l - 1,\n\t\tvalue = args[ 0 ],\n\t\tvalueIsFunction = isFunction( value );\n\n\t// We can't cloneNode fragments that contain checked, in WebKit\n\tif ( valueIsFunction ||\n\t\t\t( l > 1 && typeof value === \"string\" &&\n\t\t\t\t!support.checkClone && rchecked.test( value ) ) ) {\n\t\treturn collection.each( function( index ) {\n\t\t\tvar self = collection.eq( index );\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\t}\n\t\t\tdomManip( self, args, callback, ignored );\n\t\t} );\n\t}\n\n\tif ( l ) {\n\t\tfragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );\n\t\tfirst = fragment.firstChild;\n\n\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\tfragment = first;\n\t\t}\n\n\t\t// Require either new content or an interest in ignored elements to invoke the callback\n\t\tif ( first || ignored ) {\n\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\thasScripts = scripts.length;\n\n\t\t\t// Use the original fragment for the last item\n\t\t\t// instead of the first because it can end up\n\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tnode = fragment;\n\n\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\tif ( hasScripts ) {\n\n\t\t\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcallback.call( collection[ i ], node, i );\n\t\t\t}\n\n\t\t\tif ( hasScripts ) {\n\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t// Reenable scripts\n\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t!dataPriv.access( node, \"globalEval\" ) &&\n\t\t\t\t\t\tjQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\tif ( node.src && ( node.type || \"\" ).toLowerCase() !== \"module\" ) {\n\n\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\tif ( jQuery._evalUrl && !node.noModule ) {\n\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src, {\n\t\t\t\t\t\t\t\t\tnonce: node.nonce || node.getAttribute( \"nonce\" )\n\t\t\t\t\t\t\t\t}, doc );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tDOMEval( node.textContent.replace( rcleanScript, \"\" ), node, doc );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn collection;\n}\n\nfunction remove( elem, selector, keepData ) {\n\tvar node,\n\t\tnodes = selector ? jQuery.filter( selector, elem ) : elem,\n\t\ti = 0;\n\n\tfor ( ; ( node = nodes[ i ] ) != null; i++ ) {\n\t\tif ( !keepData && node.nodeType === 1 ) {\n\t\t\tjQuery.cleanData( getAll( node ) );\n\t\t}\n\n\t\tif ( node.parentNode ) {\n\t\t\tif ( keepData && isAttached( node ) ) {\n\t\t\t\tsetGlobalEval( getAll( node, \"script\" ) );\n\t\t\t}\n\t\t\tnode.parentNode.removeChild( node );\n\t\t}\n\t}\n\n\treturn elem;\n}\n\njQuery.extend( {\n\thtmlPrefilter: function( html ) {\n\t\treturn html;\n\t},\n\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar i, l, srcElements, destElements,\n\t\t\tclone = elem.cloneNode( true ),\n\t\t\tinPage = isAttached( elem );\n\n\t\t// Fix IE cloning issues\n\t\tif ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&\n\t\t\t\t!jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\tfixInput( srcElements[ i ], destElements[ i ] );\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[ i ], destElements[ i ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, type,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {\n\t\t\tif ( acceptData( elem ) ) {\n\t\t\t\tif ( ( data = elem[ dataPriv.expando ] ) ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataPriv.expando ] = undefined;\n\t\t\t\t}\n\t\t\t\tif ( elem[ dataUser.expando ] ) {\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataUser.expando ] = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n} );\n\njQuery.fn.extend( {\n\tdetach: function( selector ) {\n\t\treturn remove( this, selector, true );\n\t},\n\n\tremove: function( selector ) {\n\t\treturn remove( this, selector );\n\t},\n\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each( function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t} );\n\t},\n\n\tprepend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t} );\n\t},\n\n\tbefore: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t} );\n\t},\n\n\tafter: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t} );\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = this[ i ] ) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function() {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t} );\n\t},\n\n\thtml: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = jQuery.htmlPrefilter( value );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch ( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar ignored = [];\n\n\t\t// Make the changes, replacing each non-ignored context element with the new content\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tvar parent = this.parentNode;\n\n\t\t\tif ( jQuery.inArray( this, ignored ) < 0 ) {\n\t\t\t\tjQuery.cleanData( getAll( this ) );\n\t\t\t\tif ( parent ) {\n\t\t\t\t\tparent.replaceChild( elem, this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Force callback invocation\n\t\t}, ignored );\n\t}\n} );\n\njQuery.each( {\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\n\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t// .get() because push.apply(_, arraylike) throws on ancient WebKit\n\t\t\tpush.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n} );\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar getStyles = function( elem ) {\n\n\t\t// Support: IE <=11 only, Firefox <=30 (#15098, #14150)\n\t\t// IE throws on elements created in popups\n\t\t// FF meanwhile throws on frame elements through \"defaultView.getComputedStyle\"\n\t\tvar view = elem.ownerDocument.defaultView;\n\n\t\tif ( !view || !view.opener ) {\n\t\t\tview = window;\n\t\t}\n\n\t\treturn view.getComputedStyle( elem );\n\t};\n\nvar swap = function( elem, options, callback ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.call( elem );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\nvar rboxStyle = new RegExp( cssExpand.join( \"|\" ), \"i\" );\n\n\n\n( function() {\n\n\t// Executing both pixelPosition & boxSizingReliable tests require only one layout\n\t// so they're executed at the same time to save the second computation.\n\tfunction computeStyleTests() {\n\n\t\t// This is a singleton, we need to execute it only once\n\t\tif ( !div ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcontainer.style.cssText = \"position:absolute;left:-11111px;width:60px;\" +\n\t\t\t\"margin-top:1px;padding:0;border:0\";\n\t\tdiv.style.cssText =\n\t\t\t\"position:relative;display:block;box-sizing:border-box;overflow:scroll;\" +\n\t\t\t\"margin:auto;border:1px;padding:1px;\" +\n\t\t\t\"width:60%;top:1%\";\n\t\tdocumentElement.appendChild( container ).appendChild( div );\n\n\t\tvar divStyle = window.getComputedStyle( div );\n\t\tpixelPositionVal = divStyle.top !== \"1%\";\n\n\t\t// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44\n\t\treliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;\n\n\t\t// Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3\n\t\t// Some styles come back with percentage values, even though they shouldn't\n\t\tdiv.style.right = \"60%\";\n\t\tpixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;\n\n\t\t// Support: IE 9 - 11 only\n\t\t// Detect misreporting of content dimensions for box-sizing:border-box elements\n\t\tboxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;\n\n\t\t// Support: IE 9 only\n\t\t// Detect overflow:scroll screwiness (gh-3699)\n\t\t// Support: Chrome <=64\n\t\t// Don't get tricked when zoom affects offsetWidth (gh-4029)\n\t\tdiv.style.position = \"absolute\";\n\t\tscrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12;\n\n\t\tdocumentElement.removeChild( container );\n\n\t\t// Nullify the div so it wouldn't be stored in the memory and\n\t\t// it will also be a sign that checks already performed\n\t\tdiv = null;\n\t}\n\n\tfunction roundPixelMeasures( measure ) {\n\t\treturn Math.round( parseFloat( measure ) );\n\t}\n\n\tvar pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,\n\t\treliableTrDimensionsVal, reliableMarginLeftVal,\n\t\tcontainer = document.createElement( \"div\" ),\n\t\tdiv = document.createElement( \"div\" );\n\n\t// Finish early in limited (non-browser) environments\n\tif ( !div.style ) {\n\t\treturn;\n\t}\n\n\t// Support: IE <=9 - 11 only\n\t// Style of cloned element affects source element cloned (#8908)\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\tjQuery.extend( support, {\n\t\tboxSizingReliable: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn boxSizingReliableVal;\n\t\t},\n\t\tpixelBoxStyles: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelBoxStylesVal;\n\t\t},\n\t\tpixelPosition: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelPositionVal;\n\t\t},\n\t\treliableMarginLeft: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn reliableMarginLeftVal;\n\t\t},\n\t\tscrollboxSize: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn scrollboxSizeVal;\n\t\t},\n\n\t\t// Support: IE 9 - 11+, Edge 15 - 18+\n\t\t// IE/Edge misreport `getComputedStyle` of table rows with width/height\n\t\t// set in CSS while `offset*` properties report correct values.\n\t\t// Behavior in IE 9 is more subtle than in newer versions & it passes\n\t\t// some versions of this test; make sure not to make it pass there!\n\t\t//\n\t\t// Support: Firefox 70+\n\t\t// Only Firefox includes border widths\n\t\t// in computed dimensions. (gh-4529)\n\t\treliableTrDimensions: function() {\n\t\t\tvar table, tr, trChild, trStyle;\n\t\t\tif ( reliableTrDimensionsVal == null ) {\n\t\t\t\ttable = document.createElement( \"table\" );\n\t\t\t\ttr = document.createElement( \"tr\" );\n\t\t\t\ttrChild = document.createElement( \"div\" );\n\n\t\t\t\ttable.style.cssText = \"position:absolute;left:-11111px;border-collapse:separate\";\n\t\t\t\ttr.style.cssText = \"border:1px solid\";\n\n\t\t\t\t// Support: Chrome 86+\n\t\t\t\t// Height set through cssText does not get applied.\n\t\t\t\t// Computed height then comes back as 0.\n\t\t\t\ttr.style.height = \"1px\";\n\t\t\t\ttrChild.style.height = \"9px\";\n\n\t\t\t\t// Support: Android 8 Chrome 86+\n\t\t\t\t// In our bodyBackground.html iframe,\n\t\t\t\t// display for all div elements is set to \"inline\",\n\t\t\t\t// which causes a problem only in Android 8 Chrome 86.\n\t\t\t\t// Ensuring the div is display: block\n\t\t\t\t// gets around this issue.\n\t\t\t\ttrChild.style.display = \"block\";\n\n\t\t\t\tdocumentElement\n\t\t\t\t\t.appendChild( table )\n\t\t\t\t\t.appendChild( tr )\n\t\t\t\t\t.appendChild( trChild );\n\n\t\t\t\ttrStyle = window.getComputedStyle( tr );\n\t\t\t\treliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) +\n\t\t\t\t\tparseInt( trStyle.borderTopWidth, 10 ) +\n\t\t\t\t\tparseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight;\n\n\t\t\t\tdocumentElement.removeChild( table );\n\t\t\t}\n\t\t\treturn reliableTrDimensionsVal;\n\t\t}\n\t} );\n} )();\n\n\nfunction curCSS( elem, name, computed ) {\n\tvar width, minWidth, maxWidth, ret,\n\n\t\t// Support: Firefox 51+\n\t\t// Retrieving style before computed somehow\n\t\t// fixes an issue with getting wrong values\n\t\t// on detached elements\n\t\tstyle = elem.style;\n\n\tcomputed = computed || getStyles( elem );\n\n\t// getPropertyValue is needed for:\n\t// .css('filter') (IE 9 only, #12537)\n\t// .css('--customProperty) (#3144)\n\tif ( computed ) {\n\t\tret = computed.getPropertyValue( name ) || computed[ name ];\n\n\t\tif ( ret === \"\" && !isAttached( elem ) ) {\n\t\t\tret = jQuery.style( elem, name );\n\t\t}\n\n\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t// Android Browser returns percentage for some values,\n\t\t// but width seems to be reliably pixels.\n\t\t// This is against the CSSOM draft spec:\n\t\t// https://drafts.csswg.org/cssom/#resolved-values\n\t\tif ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\twidth = style.width;\n\t\t\tminWidth = style.minWidth;\n\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\tret = computed.width;\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.width = width;\n\t\t\tstyle.minWidth = minWidth;\n\t\t\tstyle.maxWidth = maxWidth;\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\n\t\t// Support: IE <=9 - 11 only\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\n\nfunction addGetHookIf( conditionFn, hookFn ) {\n\n\t// Define the hook, we'll check on the first run if it's really needed.\n\treturn {\n\t\tget: function() {\n\t\t\tif ( conditionFn() ) {\n\n\t\t\t\t// Hook not needed (or it's not possible to use it due\n\t\t\t\t// to missing dependency), remove it.\n\t\t\t\tdelete this.get;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Hook needed; redefine it so that the support test is not executed again.\n\t\t\treturn ( this.get = hookFn ).apply( this, arguments );\n\t\t}\n\t};\n}\n\n\nvar cssPrefixes = [ \"Webkit\", \"Moz\", \"ms\" ],\n\temptyStyle = document.createElement( \"div\" ).style,\n\tvendorProps = {};\n\n// Return a vendor-prefixed property or undefined\nfunction vendorPropName( name ) {\n\n\t// Check for vendor prefixed names\n\tvar capName = name[ 0 ].toUpperCase() + name.slice( 1 ),\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in emptyStyle ) {\n\t\t\treturn name;\n\t\t}\n\t}\n}\n\n// Return a potentially-mapped jQuery.cssProps or vendor prefixed property\nfunction finalPropName( name ) {\n\tvar final = jQuery.cssProps[ name ] || vendorProps[ name ];\n\n\tif ( final ) {\n\t\treturn final;\n\t}\n\tif ( name in emptyStyle ) {\n\t\treturn name;\n\t}\n\treturn vendorProps[ name ] = vendorPropName( name ) || name;\n}\n\n\nvar\n\n\t// Swappable if display is none or starts with table\n\t// except \"table\", \"table-cell\", or \"table-caption\"\n\t// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\trcustomProp = /^--/,\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: \"0\",\n\t\tfontWeight: \"400\"\n\t};\n\nfunction setPositiveNumber( _elem, value, subtract ) {\n\n\t// Any relative (+/-) values have already been\n\t// normalized at this point\n\tvar matches = rcssNum.exec( value );\n\treturn matches ?\n\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {\n\tvar i = dimension === \"width\" ? 1 : 0,\n\t\textra = 0,\n\t\tdelta = 0;\n\n\t// Adjustment may not be necessary\n\tif ( box === ( isBorderBox ? \"border\" : \"content\" ) ) {\n\t\treturn 0;\n\t}\n\n\tfor ( ; i < 4; i += 2 ) {\n\n\t\t// Both box models exclude margin\n\t\tif ( box === \"margin\" ) {\n\t\t\tdelta += jQuery.css( elem, box + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\t// If we get here with a content-box, we're seeking \"padding\" or \"border\" or \"margin\"\n\t\tif ( !isBorderBox ) {\n\n\t\t\t// Add padding\n\t\t\tdelta += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// For \"border\" or \"margin\", add border\n\t\t\tif ( box !== \"padding\" ) {\n\t\t\t\tdelta += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\n\t\t\t// But still keep track of it otherwise\n\t\t\t} else {\n\t\t\t\textra += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\n\t\t// If we get here with a border-box (content + padding + border), we're seeking \"content\" or\n\t\t// \"padding\" or \"margin\"\n\t\t} else {\n\n\t\t\t// For \"content\", subtract padding\n\t\t\tif ( box === \"content\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// For \"content\" or \"padding\", subtract border\n\t\t\tif ( box !== \"margin\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Account for positive content-box scroll gutter when requested by providing computedVal\n\tif ( !isBorderBox && computedVal >= 0 ) {\n\n\t\t// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border\n\t\t// Assuming integer scroll gutter, subtract the rest and round down\n\t\tdelta += Math.max( 0, Math.ceil(\n\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\tcomputedVal -\n\t\t\tdelta -\n\t\t\textra -\n\t\t\t0.5\n\n\t\t// If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter\n\t\t// Use an explicit zero to avoid NaN (gh-3964)\n\t\t) ) || 0;\n\t}\n\n\treturn delta;\n}\n\nfunction getWidthOrHeight( elem, dimension, extra ) {\n\n\t// Start with computed style\n\tvar styles = getStyles( elem ),\n\n\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).\n\t\t// Fake content-box until we know it's needed to know the true value.\n\t\tboxSizingNeeded = !support.boxSizingReliable() || extra,\n\t\tisBorderBox = boxSizingNeeded &&\n\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\tvalueIsBorderBox = isBorderBox,\n\n\t\tval = curCSS( elem, dimension, styles ),\n\t\toffsetProp = \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );\n\n\t// Support: Firefox <=54\n\t// Return a confounding non-pixel value or feign ignorance, as appropriate.\n\tif ( rnumnonpx.test( val ) ) {\n\t\tif ( !extra ) {\n\t\t\treturn val;\n\t\t}\n\t\tval = \"auto\";\n\t}\n\n\n\t// Support: IE 9 - 11 only\n\t// Use offsetWidth/offsetHeight for when box sizing is unreliable.\n\t// In those cases, the computed value can be trusted to be border-box.\n\tif ( ( !support.boxSizingReliable() && isBorderBox ||\n\n\t\t// Support: IE 10 - 11+, Edge 15 - 18+\n\t\t// IE/Edge misreport `getComputedStyle` of table rows with width/height\n\t\t// set in CSS while `offset*` properties report correct values.\n\t\t// Interestingly, in some cases IE 9 doesn't suffer from this issue.\n\t\t!support.reliableTrDimensions() && nodeName( elem, \"tr\" ) ||\n\n\t\t// Fall back to offsetWidth/offsetHeight when value is \"auto\"\n\t\t// This happens for inline elements with no explicit setting (gh-3571)\n\t\tval === \"auto\" ||\n\n\t\t// Support: Android <=4.1 - 4.3 only\n\t\t// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)\n\t\t!parseFloat( val ) && jQuery.css( elem, \"display\", false, styles ) === \"inline\" ) &&\n\n\t\t// Make sure the element is visible & connected\n\t\telem.getClientRects().length ) {\n\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t\t// Where available, offsetWidth/offsetHeight approximate border box dimensions.\n\t\t// Where not available (e.g., SVG), assume unreliable box-sizing and interpret the\n\t\t// retrieved value as a content box dimension.\n\t\tvalueIsBorderBox = offsetProp in elem;\n\t\tif ( valueIsBorderBox ) {\n\t\t\tval = elem[ offsetProp ];\n\t\t}\n\t}\n\n\t// Normalize \"\" and auto\n\tval = parseFloat( val ) || 0;\n\n\t// Adjust for the element's box model\n\treturn ( val +\n\t\tboxModelAdjustment(\n\t\t\telem,\n\t\t\tdimension,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles,\n\n\t\t\t// Provide the current computed size to request scroll gutter calculation (gh-3589)\n\t\t\tval\n\t\t)\n\t) + \"px\";\n}\n\njQuery.extend( {\n\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Don't automatically add \"px\" to these possibly-unitless properties\n\tcssNumber: {\n\t\t\"animationIterationCount\": true,\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"flexGrow\": true,\n\t\t\"flexShrink\": true,\n\t\t\"fontWeight\": true,\n\t\t\"gridArea\": true,\n\t\t\"gridColumn\": true,\n\t\t\"gridColumnEnd\": true,\n\t\t\"gridColumnStart\": true,\n\t\t\"gridRow\": true,\n\t\t\"gridRowEnd\": true,\n\t\t\"gridRowStart\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"order\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name ),\n\t\t\tstyle = elem.style;\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to query the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Gets hook for the prefixed version, then unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// Convert \"+=\" or \"-=\" to relative numbers (#7345)\n\t\t\tif ( type === \"string\" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {\n\t\t\t\tvalue = adjustCSS( elem, name, ret );\n\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set (#7116)\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, add the unit (except for certain CSS properties)\n\t\t\t// The isCustomProp check can be removed in jQuery 4.0 when we only auto-append\n\t\t\t// \"px\" to a few hardcoded values.\n\t\t\tif ( type === \"number\" && !isCustomProp ) {\n\t\t\t\tvalue += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? \"\" : \"px\" );\n\t\t\t}\n\n\t\t\t// background-* props affect original clone's values\n\t\t\tif ( !support.clearCloneStyle && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !( \"set\" in hooks ) ||\n\t\t\t\t( value = hooks.set( elem, value, extra ) ) !== undefined ) {\n\n\t\t\t\tif ( isCustomProp ) {\n\t\t\t\t\tstyle.setProperty( name, value );\n\t\t\t\t} else {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks &&\n\t\t\t\t( ret = hooks.get( elem, false, extra ) ) !== undefined ) {\n\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name );\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to modify the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Try prefixed name followed by the unprefixed name\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t// Convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Make numeric if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || isFinite( num ) ? num || 0 : val;\n\t\t}\n\n\t\treturn val;\n\t}\n} );\n\njQuery.each( [ \"height\", \"width\" ], function( _i, dimension ) {\n\tjQuery.cssHooks[ dimension ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\n\t\t\t\t// Certain elements can have dimension info if we invisibly show them\n\t\t\t\t// but it must have a current display style that would benefit\n\t\t\t\treturn rdisplayswap.test( jQuery.css( elem, \"display\" ) ) &&\n\n\t\t\t\t\t// Support: Safari 8+\n\t\t\t\t\t// Table columns in Safari have non-zero offsetWidth & zero\n\t\t\t\t\t// getBoundingClientRect().width unless display is changed.\n\t\t\t\t\t// Support: IE <=11 only\n\t\t\t\t\t// Running getBoundingClientRect on a disconnected node\n\t\t\t\t\t// in IE throws an error.\n\t\t\t\t\t( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?\n\t\t\t\t\tswap( elem, cssShow, function() {\n\t\t\t\t\t\treturn getWidthOrHeight( elem, dimension, extra );\n\t\t\t\t\t} ) :\n\t\t\t\t\tgetWidthOrHeight( elem, dimension, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar matches,\n\t\t\t\tstyles = getStyles( elem ),\n\n\t\t\t\t// Only read styles.position if the test has a chance to fail\n\t\t\t\t// to avoid forcing a reflow.\n\t\t\t\tscrollboxSizeBuggy = !support.scrollboxSize() &&\n\t\t\t\t\tstyles.position === \"absolute\",\n\n\t\t\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)\n\t\t\t\tboxSizingNeeded = scrollboxSizeBuggy || extra,\n\t\t\t\tisBorderBox = boxSizingNeeded &&\n\t\t\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\tsubtract = extra ?\n\t\t\t\t\tboxModelAdjustment(\n\t\t\t\t\t\telem,\n\t\t\t\t\t\tdimension,\n\t\t\t\t\t\textra,\n\t\t\t\t\t\tisBorderBox,\n\t\t\t\t\t\tstyles\n\t\t\t\t\t) :\n\t\t\t\t\t0;\n\n\t\t\t// Account for unreliable border-box dimensions by comparing offset* to computed and\n\t\t\t// faking a content-box to get border and padding (gh-3699)\n\t\t\tif ( isBorderBox && scrollboxSizeBuggy ) {\n\t\t\t\tsubtract -= Math.ceil(\n\t\t\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\t\t\tparseFloat( styles[ dimension ] ) -\n\t\t\t\t\tboxModelAdjustment( elem, dimension, \"border\", false, styles ) -\n\t\t\t\t\t0.5\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Convert to pixels if value adjustment is needed\n\t\t\tif ( subtract && ( matches = rcssNum.exec( value ) ) &&\n\t\t\t\t( matches[ 3 ] || \"px\" ) !== \"px\" ) {\n\n\t\t\t\telem.style[ dimension ] = value;\n\t\t\t\tvalue = jQuery.css( elem, dimension );\n\t\t\t}\n\n\t\t\treturn setPositiveNumber( elem, value, subtract );\n\t\t}\n\t};\n} );\n\njQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\treturn ( parseFloat( curCSS( elem, \"marginLeft\" ) ) ||\n\t\t\t\telem.getBoundingClientRect().left -\n\t\t\t\t\tswap( elem, { marginLeft: 0 }, function() {\n\t\t\t\t\t\treturn elem.getBoundingClientRect().left;\n\t\t\t\t\t} )\n\t\t\t) + \"px\";\n\t\t}\n\t}\n);\n\n// These hooks are used by animate to expand properties\njQuery.each( {\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// Assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split( \" \" ) : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( prefix !== \"margin\" ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n} );\n\njQuery.fn.extend( {\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( Array.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t}\n} );\n\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || jQuery.easing._default;\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\t// Use a property on the element directly when it is not a DOM element,\n\t\t\t// or when there is no matching style property that exists.\n\t\t\tif ( tween.elem.nodeType !== 1 ||\n\t\t\t\ttween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// Passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails.\n\t\t\t// Simple values such as \"10px\" are parsed to Float;\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as-is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\n\t\t\t// Use step hook for back compat.\n\t\t\t// Use cssHook if its there.\n\t\t\t// Use .style if available and use plain properties where available.\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.nodeType === 1 && (\n\t\t\t\tjQuery.cssHooks[ tween.prop ] ||\n\t\t\t\t\ttween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Support: IE <=9 only\n// Panic based approach to setting things on disconnected nodes\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t},\n\t_default: \"swing\"\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back compat <1.8 extension point\njQuery.fx.step = {};\n\n\n\n\nvar\n\tfxNow, inProgress,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trrun = /queueHooks$/;\n\nfunction schedule() {\n\tif ( inProgress ) {\n\t\tif ( document.hidden === false && window.requestAnimationFrame ) {\n\t\t\twindow.requestAnimationFrame( schedule );\n\t\t} else {\n\t\t\twindow.setTimeout( schedule, jQuery.fx.interval );\n\t\t}\n\n\t\tjQuery.fx.tick();\n\t}\n}\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\twindow.setTimeout( function() {\n\t\tfxNow = undefined;\n\t} );\n\treturn ( fxNow = Date.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\ti = 0,\n\t\tattrs = { height: type };\n\n\t// If we include width, step value is 1 to do all cssExpand values,\n\t// otherwise step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {\n\n\t\t\t// We're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\tvar prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,\n\t\tisBox = \"width\" in props || \"height\" in props,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHiddenWithinTree( elem ),\n\t\tdataShow = dataPriv.get( elem, \"fxshow\" );\n\n\t// Queue-skipping animations hijack the fx hooks\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always( function() {\n\n\t\t\t// Ensure the complete handler is called before this completes\n\t\t\tanim.always( function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t// Detect show/hide animations\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.test( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// Pretend to be hidden if this is a \"show\" and\n\t\t\t\t// there is still data from a stopped show/hide\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\n\t\t\t\t// Ignore all other no-op show/hide data\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\t\t}\n\t}\n\n\t// Bail out if this is a no-op like .hide().hide()\n\tpropTween = !jQuery.isEmptyObject( props );\n\tif ( !propTween && jQuery.isEmptyObject( orig ) ) {\n\t\treturn;\n\t}\n\n\t// Restrict \"overflow\" and \"display\" styles during box animations\n\tif ( isBox && elem.nodeType === 1 ) {\n\n\t\t// Support: IE <=9 - 11, Edge 12 - 15\n\t\t// Record all 3 overflow attributes because IE does not infer the shorthand\n\t\t// from identically-valued overflowX and overflowY and Edge just mirrors\n\t\t// the overflowX value there.\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Identify a display type, preferring old show/hide data over the CSS cascade\n\t\trestoreDisplay = dataShow && dataShow.display;\n\t\tif ( restoreDisplay == null ) {\n\t\t\trestoreDisplay = dataPriv.get( elem, \"display\" );\n\t\t}\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\tif ( display === \"none\" ) {\n\t\t\tif ( restoreDisplay ) {\n\t\t\t\tdisplay = restoreDisplay;\n\t\t\t} else {\n\n\t\t\t\t// Get nonempty value(s) by temporarily forcing visibility\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t\trestoreDisplay = elem.style.display || restoreDisplay;\n\t\t\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\t\t\tshowHide( [ elem ] );\n\t\t\t}\n\t\t}\n\n\t\t// Animate inline elements as inline-block\n\t\tif ( display === \"inline\" || display === \"inline-block\" && restoreDisplay != null ) {\n\t\t\tif ( jQuery.css( elem, \"float\" ) === \"none\" ) {\n\n\t\t\t\t// Restore the original display value at the end of pure show/hide animations\n\t\t\t\tif ( !propTween ) {\n\t\t\t\t\tanim.done( function() {\n\t\t\t\t\t\tstyle.display = restoreDisplay;\n\t\t\t\t\t} );\n\t\t\t\t\tif ( restoreDisplay == null ) {\n\t\t\t\t\t\tdisplay = style.display;\n\t\t\t\t\t\trestoreDisplay = display === \"none\" ? \"\" : display;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tstyle.display = \"inline-block\";\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tanim.always( function() {\n\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t} );\n\t}\n\n\t// Implement show/hide animations\n\tpropTween = false;\n\tfor ( prop in orig ) {\n\n\t\t// General show/hide setup for this element animation\n\t\tif ( !propTween ) {\n\t\t\tif ( dataShow ) {\n\t\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\t\thidden = dataShow.hidden;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdataShow = dataPriv.access( elem, \"fxshow\", { display: restoreDisplay } );\n\t\t\t}\n\n\t\t\t// Store hidden/visible for toggle so `.stop().toggle()` \"reverses\"\n\t\t\tif ( toggle ) {\n\t\t\t\tdataShow.hidden = !hidden;\n\t\t\t}\n\n\t\t\t// Show elements before animating them\n\t\t\tif ( hidden ) {\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t}\n\n\t\t\t/* eslint-disable no-loop-func */\n\n\t\t\tanim.done( function() {\n\n\t\t\t\t/* eslint-enable no-loop-func */\n\n\t\t\t\t// The final step of a \"hide\" animation is actually hiding the element\n\t\t\t\tif ( !hidden ) {\n\t\t\t\t\tshowHide( [ elem ] );\n\t\t\t\t}\n\t\t\t\tdataPriv.remove( elem, \"fxshow\" );\n\t\t\t\tfor ( prop in orig ) {\n\t\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\t// Per-property setup\n\t\tpropTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\t\tif ( !( prop in dataShow ) ) {\n\t\t\tdataShow[ prop ] = propTween.start;\n\t\t\tif ( hidden ) {\n\t\t\t\tpropTween.end = propTween.start;\n\t\t\t\tpropTween.start = 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( Array.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// Not quite $.extend, this won't overwrite existing keys.\n\t\t\t// Reusing 'index' because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = Animation.prefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\n\t\t\t// Don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t} ),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\n\t\t\t\t// Support: Android 2.3 only\n\t\t\t\t// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ] );\n\n\t\t\t// If there's more to do, yield\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t}\n\n\t\t\t// If this was an empty animation, synthesize a final progress notification\n\t\t\tif ( !length ) {\n\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t}\n\n\t\t\t// Resolve the animation and report its conclusion\n\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\treturn false;\n\t\t},\n\t\tanimation = deferred.promise( {\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, {\n\t\t\t\tspecialEasing: {},\n\t\t\t\teasing: jQuery.easing._default\n\t\t\t}, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\n\t\t\t\t\t// If we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// Resolve when we played the last frame; otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t} ),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length; index++ ) {\n\t\tresult = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\tif ( isFunction( result.stop ) ) {\n\t\t\t\tjQuery._queueHooks( animation.elem, animation.opts.queue ).stop =\n\t\t\t\t\tresult.stop.bind( result );\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\t// Attach callbacks from options\n\tanimation\n\t\t.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t} )\n\t);\n\n\treturn animation;\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\n\ttweeners: {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value );\n\t\t\tadjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );\n\t\t\treturn tween;\n\t\t} ]\n\t},\n\n\ttweener: function( props, callback ) {\n\t\tif ( isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.match( rnothtmlwhite );\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\tAnimation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];\n\t\t\tAnimation.tweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilters: [ defaultPrefilter ],\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tAnimation.prefilters.unshift( callback );\n\t\t} else {\n\t\t\tAnimation.prefilters.push( callback );\n\t\t}\n\t}\n} );\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tisFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !isFunction( easing ) && easing\n\t};\n\n\t// Go to the end state if fx are off\n\tif ( jQuery.fx.off ) {\n\t\topt.duration = 0;\n\n\t} else {\n\t\tif ( typeof opt.duration !== \"number\" ) {\n\t\t\tif ( opt.duration in jQuery.fx.speeds ) {\n\t\t\t\topt.duration = jQuery.fx.speeds[ opt.duration ];\n\n\t\t\t} else {\n\t\t\t\topt.duration = jQuery.fx.speeds._default;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend( {\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// Show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHiddenWithinTree ).css( \"opacity\", 0 ).show()\n\n\t\t\t// Animate to the value specified\n\t\t\t.end().animate( { opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || dataPriv.get( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\n\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = dataPriv.get( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this &&\n\t\t\t\t\t( type == null || timers[ index ].queue === type ) ) {\n\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Start the next in the queue if the last step wasn't forced.\n\t\t\t// Timers currently will call their complete callbacks, which\n\t\t\t// will dequeue but only if they were gotoEnd.\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t} );\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tvar index,\n\t\t\t\tdata = dataPriv.get( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// Enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// Empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// Look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t} );\n\t}\n} );\n\njQuery.each( [ \"toggle\", \"show\", \"hide\" ], function( _i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n} );\n\n// Generate shortcuts for custom animations\njQuery.each( {\n\tslideDown: genFx( \"show\" ),\n\tslideUp: genFx( \"hide\" ),\n\tslideToggle: genFx( \"toggle\" ),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n} );\n\njQuery.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ti = 0,\n\t\ttimers = jQuery.timers;\n\n\tfxNow = Date.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\n\t\t// Run the timer and safely remove it when done (allowing for external removal)\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tjQuery.fx.start();\n};\n\njQuery.fx.interval = 13;\njQuery.fx.start = function() {\n\tif ( inProgress ) {\n\t\treturn;\n\t}\n\n\tinProgress = true;\n\tschedule();\n};\n\njQuery.fx.stop = function() {\n\tinProgress = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\n\t// Default speed\n\t_default: 400\n};\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = window.setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\twindow.clearTimeout( timeout );\n\t\t};\n\t} );\n};\n\n\n( function() {\n\tvar input = document.createElement( \"input\" ),\n\t\tselect = document.createElement( \"select\" ),\n\t\topt = select.appendChild( document.createElement( \"option\" ) );\n\n\tinput.type = \"checkbox\";\n\n\t// Support: Android <=4.3 only\n\t// Default value for a checkbox should be \"on\"\n\tsupport.checkOn = input.value !== \"\";\n\n\t// Support: IE <=11 only\n\t// Must access selectedIndex to make default options select\n\tsupport.optSelected = opt.selected;\n\n\t// Support: IE <=11 only\n\t// An input loses its value after becoming a radio\n\tinput = document.createElement( \"input\" );\n\tinput.value = \"t\";\n\tinput.type = \"radio\";\n\tsupport.radioValue = input.value === \"t\";\n} )();\n\n\nvar boolHook,\n\tattrHandle = jQuery.expr.attrHandle;\n\njQuery.fn.extend( {\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tattr: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set attributes on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// Attribute hooks are determined by the lowercase version\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\thooks = jQuery.attrHooks[ name.toLowerCase() ] ||\n\t\t\t\t( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\treturn value;\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tret = jQuery.find.attr( elem, name );\n\n\t\t// Non-existent attributes return null, we normalize to undefined\n\t\treturn ret == null ? undefined : ret;\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !support.radioValue && value === \"radio\" &&\n\t\t\t\t\tnodeName( elem, \"input\" ) ) {\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name,\n\t\t\ti = 0,\n\n\t\t\t// Attribute names can contain non-HTML whitespace characters\n\t\t\t// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2\n\t\t\tattrNames = value && value.match( rnothtmlwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( ( name = attrNames[ i++ ] ) ) {\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Hooks for boolean attributes\nboolHook = {\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else {\n\t\t\telem.setAttribute( name, name );\n\t\t}\n\t\treturn name;\n\t}\n};\n\njQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( _i, name ) {\n\tvar getter = attrHandle[ name ] || jQuery.find.attr;\n\n\tattrHandle[ name ] = function( elem, name, isXML ) {\n\t\tvar ret, handle,\n\t\t\tlowercaseName = name.toLowerCase();\n\n\t\tif ( !isXML ) {\n\n\t\t\t// Avoid an infinite loop by temporarily removing this function from the getter\n\t\t\thandle = attrHandle[ lowercaseName ];\n\t\t\tattrHandle[ lowercaseName ] = ret;\n\t\t\tret = getter( elem, name, isXML ) != null ?\n\t\t\t\tlowercaseName :\n\t\t\t\tnull;\n\t\t\tattrHandle[ lowercaseName ] = handle;\n\t\t}\n\t\treturn ret;\n\t};\n} );\n\n\n\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i,\n\trclickable = /^(?:a|area)$/i;\n\njQuery.fn.extend( {\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set properties on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\treturn ( elem[ name ] = value );\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\treturn elem[ name ];\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\t// Support: IE <=9 - 11 only\n\t\t\t\t// elem.tabIndex doesn't always return the\n\t\t\t\t// correct value when it hasn't been explicitly set\n\t\t\t\t// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\t// Use proper attribute retrieval(#12072)\n\t\t\t\tvar tabindex = jQuery.find.attr( elem, \"tabindex\" );\n\n\t\t\t\tif ( tabindex ) {\n\t\t\t\t\treturn parseInt( tabindex, 10 );\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\trfocusable.test( elem.nodeName ) ||\n\t\t\t\t\trclickable.test( elem.nodeName ) &&\n\t\t\t\t\telem.href\n\t\t\t\t) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t}\n} );\n\n// Support: IE <=11 only\n// Accessing the selectedIndex property\n// forces the browser to respect setting selected\n// on the option\n// The getter ensures a default option is selected\n// when in an optgroup\n// eslint rule \"no-unused-expressions\" is disabled for this code\n// since it considers such accessions noop\nif ( !support.optSelected ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tset: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent ) {\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\njQuery.each( [\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n} );\n\n\n\n\n\t// Strip and collapse whitespace according to HTML spec\n\t// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace\n\tfunction stripAndCollapse( value ) {\n\t\tvar tokens = value.match( rnothtmlwhite ) || [];\n\t\treturn tokens.join( \" \" );\n\t}\n\n\nfunction getClass( elem ) {\n\treturn elem.getAttribute && elem.getAttribute( \"class\" ) || \"\";\n}\n\nfunction classesToArray( value ) {\n\tif ( Array.isArray( value ) ) {\n\t\treturn value;\n\t}\n\tif ( typeof value === \"string\" ) {\n\t\treturn value.match( rnothtmlwhite ) || [];\n\t}\n\treturn [];\n}\n\njQuery.fn.extend( {\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( !arguments.length ) {\n\t\t\treturn this.attr( \"class\", \"\" );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) > -1 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value,\n\t\t\tisValidValue = type === \"string\" || Array.isArray( value );\n\n\t\tif ( typeof stateVal === \"boolean\" && isValidValue ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).toggleClass(\n\t\t\t\t\tvalue.call( this, i, getClass( this ), stateVal ),\n\t\t\t\t\tstateVal\n\t\t\t\t);\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar className, i, self, classNames;\n\n\t\t\tif ( isValidValue ) {\n\n\t\t\t\t// Toggle individual class names\n\t\t\t\ti = 0;\n\t\t\t\tself = jQuery( this );\n\t\t\t\tclassNames = classesToArray( value );\n\n\t\t\t\twhile ( ( className = classNames[ i++ ] ) ) {\n\n\t\t\t\t\t// Check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( value === undefined || type === \"boolean\" ) {\n\t\t\t\tclassName = getClass( this );\n\t\t\t\tif ( className ) {\n\n\t\t\t\t\t// Store className if set\n\t\t\t\t\tdataPriv.set( this, \"__className__\", className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed `false`,\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tif ( this.setAttribute ) {\n\t\t\t\t\tthis.setAttribute( \"class\",\n\t\t\t\t\t\tclassName || value === false ?\n\t\t\t\t\t\t\t\"\" :\n\t\t\t\t\t\t\tdataPriv.get( this, \"__className__\" ) || \"\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className, elem,\n\t\t\ti = 0;\n\n\t\tclassName = \" \" + selector + \" \";\n\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\tif ( elem.nodeType === 1 &&\n\t\t\t\t( \" \" + stripAndCollapse( getClass( elem ) ) + \" \" ).indexOf( className ) > -1 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n} );\n\n\n\n\nvar rreturn = /\\r/g;\n\njQuery.fn.extend( {\n\tval: function( value ) {\n\t\tvar hooks, ret, valueIsFunction,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] ||\n\t\t\t\t\tjQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks &&\n\t\t\t\t\t\"get\" in hooks &&\n\t\t\t\t\t( ret = hooks.get( elem, \"value\" ) ) !== undefined\n\t\t\t\t) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\t// Handle most common string cases\n\t\t\t\tif ( typeof ret === \"string\" ) {\n\t\t\t\t\treturn ret.replace( rreturn, \"\" );\n\t\t\t\t}\n\n\t\t\t\t// Handle cases where value is null/undef or number\n\t\t\t\treturn ret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tvalueIsFunction = isFunction( value );\n\n\t\treturn this.each( function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( Array.isArray( val ) ) {\n\t\t\t\tval = jQuery.map( val, function( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !( \"set\" in hooks ) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\tvar val = jQuery.find.attr( elem, \"value\" );\n\t\t\t\treturn val != null ?\n\t\t\t\t\tval :\n\n\t\t\t\t\t// Support: IE <=10 - 11 only\n\t\t\t\t\t// option.text throws exceptions (#14686, #14858)\n\t\t\t\t\t// Strip and collapse whitespace\n\t\t\t\t\t// https://html.spec.whatwg.org/#strip-and-collapse-whitespace\n\t\t\t\t\tstripAndCollapse( jQuery.text( elem ) );\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option, i,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\",\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length;\n\n\t\t\t\tif ( index < 0 ) {\n\t\t\t\t\ti = max;\n\n\t\t\t\t} else {\n\t\t\t\t\ti = one ? index : 0;\n\t\t\t\t}\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t// IE8-9 doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t!option.disabled &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled ||\n\t\t\t\t\t\t\t\t!nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t/* eslint-disable no-cond-assign */\n\n\t\t\t\t\tif ( option.selected =\n\t\t\t\t\t\tjQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1\n\t\t\t\t\t) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\n\t\t\t\t\t/* eslint-enable no-cond-assign */\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Radios and checkboxes getter/setter\njQuery.each( [ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( Array.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );\n\t\t\t}\n\t\t}\n\t};\n\tif ( !support.checkOn ) {\n\t\tjQuery.valHooks[ this ].get = function( elem ) {\n\t\t\treturn elem.getAttribute( \"value\" ) === null ? \"on\" : elem.value;\n\t\t};\n\t}\n} );\n\n\n\n\n// Return jQuery for attributes-only inclusion\n\n\nsupport.focusin = \"onfocusin\" in window;\n\n\nvar rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\tstopPropagationCallback = function( e ) {\n\t\te.stopPropagation();\n\t};\n\njQuery.extend( jQuery.event, {\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special, lastElement,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split( \".\" ) : [];\n\n\t\tcur = lastElement = tmp = elem = elem || document;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf( \".\" ) > -1 ) {\n\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split( \".\" );\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf( \":\" ) < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join( \".\" );\n\t\tevent.rnamespace = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === ( elem.ownerDocument || document ) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tlastElement = cur;\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( dataPriv.get( cur, \"events\" ) || Object.create( null ) )[ event.type ] &&\n\t\t\t\tdataPriv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( ( !special._default ||\n\t\t\t\tspecial._default.apply( eventPath.pop(), data ) === false ) &&\n\t\t\t\tacceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.addEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\telem[ type ]();\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.removeEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\t// Piggyback on a donor event to simulate a different one\n\t// Used only for `focus(in | out)` events\n\tsimulate: function( type, elem, event ) {\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true\n\t\t\t}\n\t\t);\n\n\t\tjQuery.event.trigger( e, null, elem );\n\t}\n\n} );\n\njQuery.fn.extend( {\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t} );\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[ 0 ];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n} );\n\n\n// Support: Firefox <=44\n// Firefox doesn't have focus(in | out) events\n// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787\n//\n// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1\n// focus(in | out) events fire after focus & blur events,\n// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order\n// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857\nif ( !support.focusin ) {\n\tjQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler on the document while someone wants focusin/focusout\n\t\tvar handler = function( event ) {\n\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );\n\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\n\t\t\t\t// Handle: regular nodes (via `this.ownerDocument`), window\n\t\t\t\t// (via `this.document`) & document (via `this`).\n\t\t\t\tvar doc = this.ownerDocument || this.document || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix );\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t\tdataPriv.access( doc, fix, ( attaches || 0 ) + 1 );\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tvar doc = this.ownerDocument || this.document || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix ) - 1;\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.removeEventListener( orig, handler, true );\n\t\t\t\t\tdataPriv.remove( doc, fix );\n\n\t\t\t\t} else {\n\t\t\t\t\tdataPriv.access( doc, fix, attaches );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t} );\n}\nvar location = window.location;\n\nvar nonce = { guid: Date.now() };\n\nvar rquery = ( /\\?/ );\n\n\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml, parserErrorElem;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE 9 - 11 only\n\t// IE throws on parseFromString with invalid input.\n\ttry {\n\t\txml = ( new window.DOMParser() ).parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {}\n\n\tparserErrorElem = xml && xml.getElementsByTagName( \"parsererror\" )[ 0 ];\n\tif ( !xml || parserErrorElem ) {\n\t\tjQuery.error( \"Invalid XML: \" + (\n\t\t\tparserErrorElem ?\n\t\t\t\tjQuery.map( parserErrorElem.childNodes, function( el ) {\n\t\t\t\t\treturn el.textContent;\n\t\t\t\t} ).join( \"\\n\" ) :\n\t\t\t\tdata\n\t\t) );\n\t}\n\treturn xml;\n};\n\n\nvar\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( Array.isArray( obj ) ) {\n\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams(\n\t\t\t\t\tprefix + \"[\" + ( typeof v === \"object\" && v != null ? i : \"\" ) + \"]\",\n\t\t\t\t\tv,\n\t\t\t\t\ttraditional,\n\t\t\t\t\tadd\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t} else if ( !traditional && toType( obj ) === \"object\" ) {\n\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, valueOrFunction ) {\n\n\t\t\t// If value is a function, invoke it and use its return value\n\t\t\tvar value = isFunction( valueOrFunction ) ?\n\t\t\t\tvalueOrFunction() :\n\t\t\t\tvalueOrFunction;\n\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" +\n\t\t\t\tencodeURIComponent( value == null ? \"\" : value );\n\t\t};\n\n\tif ( a == null ) {\n\t\treturn \"\";\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t} );\n\n\t} else {\n\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" );\n};\n\njQuery.fn.extend( {\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map( function() {\n\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t} ).filter( function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t} ).map( function( _i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\tif ( val == null ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ( Array.isArray( val ) ) {\n\t\t\t\treturn jQuery.map( val, function( val ) {\n\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t} ).get();\n\t}\n} );\n\n\nvar\n\tr20 = /%20/g,\n\trhash = /#.*$/,\n\trantiCache = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t * - BEFORE asking for a transport\n\t * - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat( \"*\" ),\n\n\t// Anchor tag for parsing the document origin\n\toriginAnchor = document.createElement( \"a\" );\n\noriginAnchor.href = location.href;\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];\n\n\t\tif ( isFunction( func ) ) {\n\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( ( dataType = dataTypes[ i++ ] ) ) {\n\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[ 0 ] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" &&\n\t\t\t\t!seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t} );\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\n\n\t// Remove auto dataType and get content-type in the process\n\twhile ( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader( \"Content-Type\" );\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[ 0 ] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n/* Chain conversions given the request and the original response\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\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\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s.throws ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tstate: \"parsererror\",\n\t\t\t\t\t\t\t\terror: conv ? e : \"No conversion from \" + prev + \" to \" + current\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\t\t\t}\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n\njQuery.extend( {\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: location.href,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( location.protocol ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /\\bxml\\b/,\n\t\t\thtml: /\\bhtml/,\n\t\t\tjson: /\\bjson\\b/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\",\n\t\t\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": JSON.parse,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar transport,\n\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\n\t\t\t// Url cleanup var\n\t\t\turlAnchor,\n\n\t\t\t// Request state (becomes false upon send and true upon completion)\n\t\t\tcompleted,\n\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\n\t\t\t// Loop variable\n\t\t\ti,\n\n\t\t\t// uncached part of the url\n\t\t\tuncached,\n\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context &&\n\t\t\t\t( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\tjQuery.event,\n\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks( \"once memory\" ),\n\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( completed ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( ( match = rheaders.exec( responseHeadersString ) ) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[ 1 ].toLowerCase() + \" \" ] =\n\t\t\t\t\t\t\t\t\t( responseHeaders[ match[ 1 ].toLowerCase() + \" \" ] || [] )\n\t\t\t\t\t\t\t\t\t\t.concat( match[ 2 ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() + \" \" ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match.join( \", \" );\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn completed ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\tname = requestHeadersNames[ name.toLowerCase() ] =\n\t\t\t\t\t\t\trequestHeadersNames[ name.toLowerCase() ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( completed ) {\n\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Lazy-add the new callbacks in a way that preserves old ones\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\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\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR );\n\n\t\t// Add protocol if not provided (prefilters might expect it)\n\t\t// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || location.href ) + \"\" )\n\t\t\t.replace( rprotocol, location.protocol + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = ( s.dataType || \"*\" ).toLowerCase().match( rnothtmlwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when the origin doesn't match the current origin.\n\t\tif ( s.crossDomain == null ) {\n\t\t\turlAnchor = document.createElement( \"a\" );\n\n\t\t\t// Support: IE <=8 - 11, Edge 12 - 15\n\t\t\t// IE throws exception on accessing the href property if url is malformed,\n\t\t\t// e.g. http://example.com:80x/\n\t\t\ttry {\n\t\t\t\turlAnchor.href = s.url;\n\n\t\t\t\t// Support: IE <=8 - 11 only\n\t\t\t\t// Anchor's host property isn't correctly set when s.url is relative\n\t\t\t\turlAnchor.href = urlAnchor.href;\n\t\t\t\ts.crossDomain = originAnchor.protocol + \"//\" + originAnchor.host !==\n\t\t\t\t\turlAnchor.protocol + \"//\" + urlAnchor.host;\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// If there is an error parsing the URL, assume it is crossDomain,\n\t\t\t\t// it can be rejected by the transport if it is invalid\n\t\t\t\ts.crossDomain = true;\n\t\t\t}\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( completed ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\t// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)\n\t\tfireGlobals = jQuery.event && s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger( \"ajaxStart\" );\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\t// Remove hash to simplify url manipulation\n\t\tcacheURL = s.url.replace( rhash, \"\" );\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// Remember the hash so we can put it back\n\t\t\tuncached = s.url.slice( cacheURL.length );\n\n\t\t\t// If data is available and should be processed, append data to url\n\t\t\tif ( s.data && ( s.processData || typeof s.data === \"string\" ) ) {\n\t\t\t\tcacheURL += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data;\n\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add or update anti-cache param if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\tcacheURL = cacheURL.replace( rantiCache, \"$1\" );\n\t\t\t\tuncached = ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + ( nonce.guid++ ) +\n\t\t\t\t\tuncached;\n\t\t\t}\n\n\t\t\t// Put hash and anti-cache on the URL that will be requested (gh-1732)\n\t\t\ts.url = cacheURL + uncached;\n\n\t\t// Change '%20' to '+' if this is encoded form body content (gh-2658)\n\t\t} else if ( s.data && s.processData &&\n\t\t\t( s.contentType || \"\" ).indexOf( \"application/x-www-form-urlencoded\" ) === 0 ) {\n\t\t\ts.data = s.data.replace( r20, \"+\" );\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[ 0 ] ] +\n\t\t\t\t\t( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend &&\n\t\t\t( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {\n\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// Aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tcompleteDeferred.add( s.complete );\n\t\tjqXHR.done( s.success );\n\t\tjqXHR.fail( s.error );\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\n\t\t\t// If request was aborted inside ajaxSend, stop there\n\t\t\tif ( completed ) {\n\t\t\t\treturn jqXHR;\n\t\t\t}\n\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = window.setTimeout( function() {\n\t\t\t\t\tjqXHR.abort( \"timeout\" );\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tcompleted = false;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// Rethrow post-completion exceptions\n\t\t\t\tif ( completed ) {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\n\t\t\t\t// Propagate others as results\n\t\t\t\tdone( -1, e );\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Ignore repeat invocations\n\t\t\tif ( completed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcompleted = true;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\twindow.clearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Use a noop converter for missing script but not if jsonp\n\t\t\tif ( !isSuccess &&\n\t\t\t\tjQuery.inArray( \"script\", s.dataTypes ) > -1 &&\n\t\t\t\tjQuery.inArray( \"json\", s.dataTypes ) < 0 ) {\n\t\t\t\ts.converters[ \"text script\" ] = function() {};\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"Last-Modified\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"etag\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\n\t\t\t\t// Extract error from statusText and normalize for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger( \"ajaxStop\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t}\n} );\n\njQuery.each( [ \"get\", \"post\" ], function( _i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\n\t\t// Shift arguments if data argument was omitted\n\t\tif ( isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\t// The url can be an options object (which then must have .url)\n\t\treturn jQuery.ajax( jQuery.extend( {\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t}, jQuery.isPlainObject( url ) && url ) );\n\t};\n} );\n\njQuery.ajaxPrefilter( function( s ) {\n\tvar i;\n\tfor ( i in s.headers ) {\n\t\tif ( i.toLowerCase() === \"content-type\" ) {\n\t\t\ts.contentType = s.headers[ i ] || \"\";\n\t\t}\n\t}\n} );\n\n\njQuery._evalUrl = function( url, options, doc ) {\n\treturn jQuery.ajax( {\n\t\turl: url,\n\n\t\t// Make this explicit, since user can override this through ajaxSetup (#11264)\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tcache: true,\n\t\tasync: false,\n\t\tglobal: false,\n\n\t\t// Only evaluate the response if it is successful (gh-4126)\n\t\t// dataFilter is not invoked for failure responses, so using it instead\n\t\t// of the default converter is kludgy but it works.\n\t\tconverters: {\n\t\t\t\"text script\": function() {}\n\t\t},\n\t\tdataFilter: function( response ) {\n\t\t\tjQuery.globalEval( response, options, doc );\n\t\t}\n\t} );\n};\n\n\njQuery.fn.extend( {\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( this[ 0 ] ) {\n\t\t\tif ( isFunction( html ) ) {\n\t\t\t\thtml = html.call( this[ 0 ] );\n\t\t\t}\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n\t\t\tif ( this[ 0 ].parentNode ) {\n\t\t\t\twrap.insertBefore( this[ 0 ] );\n\t\t\t}\n\n\t\t\twrap.map( function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t} ).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( isFunction( html ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).wrapInner( html.call( this, i ) );\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t} );\n\t},\n\n\twrap: function( html ) {\n\t\tvar htmlIsFunction = isFunction( html );\n\n\t\treturn this.each( function( i ) {\n\t\t\tjQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );\n\t\t} );\n\t},\n\n\tunwrap: function( selector ) {\n\t\tthis.parent( selector ).not( \"body\" ).each( function() {\n\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t} );\n\t\treturn this;\n\t}\n} );\n\n\njQuery.expr.pseudos.hidden = function( elem ) {\n\treturn !jQuery.expr.pseudos.visible( elem );\n};\njQuery.expr.pseudos.visible = function( elem ) {\n\treturn !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );\n};\n\n\n\n\njQuery.ajaxSettings.xhr = function() {\n\ttry {\n\t\treturn new window.XMLHttpRequest();\n\t} catch ( e ) {}\n};\n\nvar xhrSuccessStatus = {\n\n\t\t// File protocol always yields status code 0, assume 200\n\t\t0: 200,\n\n\t\t// Support: IE <=9 only\n\t\t// #1450: sometimes IE returns 1223 when it should be 204\n\t\t1223: 204\n\t},\n\txhrSupported = jQuery.ajaxSettings.xhr();\n\nsupport.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nsupport.ajax = xhrSupported = !!xhrSupported;\n\njQuery.ajaxTransport( function( options ) {\n\tvar callback, errorCallback;\n\n\t// Cross domain only allowed if supported through XMLHttpRequest\n\tif ( support.cors || xhrSupported && !options.crossDomain ) {\n\t\treturn {\n\t\t\tsend: function( headers, complete ) {\n\t\t\t\tvar i,\n\t\t\t\t\txhr = options.xhr();\n\n\t\t\t\txhr.open(\n\t\t\t\t\toptions.type,\n\t\t\t\t\toptions.url,\n\t\t\t\t\toptions.async,\n\t\t\t\t\toptions.username,\n\t\t\t\t\toptions.password\n\t\t\t\t);\n\n\t\t\t\t// Apply custom fields if provided\n\t\t\t\tif ( options.xhrFields ) {\n\t\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Override mime type if needed\n\t\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\txhr.overrideMimeType( options.mimeType );\n\t\t\t\t}\n\n\t\t\t\t// X-Requested-With header\n\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\tif ( !options.crossDomain && !headers[ \"X-Requested-With\" ] ) {\n\t\t\t\t\theaders[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n\t\t\t\t}\n\n\t\t\t\t// Set headers\n\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t}\n\n\t\t\t\t// Callback\n\t\t\t\tcallback = function( type ) {\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\tcallback = errorCallback = xhr.onload =\n\t\t\t\t\t\t\t\txhr.onerror = xhr.onabort = xhr.ontimeout =\n\t\t\t\t\t\t\t\t\txhr.onreadystatechange = null;\n\n\t\t\t\t\t\t\tif ( type === \"abort\" ) {\n\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t} else if ( type === \"error\" ) {\n\n\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t// On a manual native abort, IE9 throws\n\t\t\t\t\t\t\t\t// errors on any property access that is not readyState\n\t\t\t\t\t\t\t\tif ( typeof xhr.status !== \"number\" ) {\n\t\t\t\t\t\t\t\t\tcomplete( 0, \"error\" );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcomplete(\n\n\t\t\t\t\t\t\t\t\t\t// File: protocol always yields status 0; see #8605, #14207\n\t\t\t\t\t\t\t\t\t\txhr.status,\n\t\t\t\t\t\t\t\t\t\txhr.statusText\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} else {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\txhrSuccessStatus[ xhr.status ] || xhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText,\n\n\t\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t\t// IE9 has no XHR2 but throws on binary (trac-11426)\n\t\t\t\t\t\t\t\t\t// For XHR2 non-text, let the caller handle it (gh-2498)\n\t\t\t\t\t\t\t\t\t( xhr.responseType || \"text\" ) !== \"text\" ||\n\t\t\t\t\t\t\t\t\ttypeof xhr.responseText !== \"string\" ?\n\t\t\t\t\t\t\t\t\t\t{ binary: xhr.response } :\n\t\t\t\t\t\t\t\t\t\t{ text: xhr.responseText },\n\t\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()\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\t// Listen to events\n\t\t\t\txhr.onload = callback();\n\t\t\t\terrorCallback = xhr.onerror = xhr.ontimeout = callback( \"error\" );\n\n\t\t\t\t// Support: IE 9 only\n\t\t\t\t// Use onreadystatechange to replace onabort\n\t\t\t\t// to handle uncaught aborts\n\t\t\t\tif ( xhr.onabort !== undefined ) {\n\t\t\t\t\txhr.onabort = errorCallback;\n\t\t\t\t} else {\n\t\t\t\t\txhr.onreadystatechange = function() {\n\n\t\t\t\t\t\t// Check readyState before timeout as it changes\n\t\t\t\t\t\tif ( xhr.readyState === 4 ) {\n\n\t\t\t\t\t\t\t// Allow onerror to be called first,\n\t\t\t\t\t\t\t// but that will not handle a native abort\n\t\t\t\t\t\t\t// Also, save errorCallback to a variable\n\t\t\t\t\t\t\t// as xhr.onerror cannot be accessed\n\t\t\t\t\t\t\twindow.setTimeout( function() {\n\t\t\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\t\t\terrorCallback();\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\t// Create the abort callback\n\t\t\t\tcallback = callback( \"abort\" );\n\n\t\t\t\ttry {\n\n\t\t\t\t\t// Do send the request (this may raise an exception)\n\t\t\t\t\txhr.send( options.hasContent && options.data || null );\n\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t// #14683: Only rethrow if this hasn't been notified as an error yet\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\n// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)\njQuery.ajaxPrefilter( function( s ) {\n\tif ( s.crossDomain ) {\n\t\ts.contents.script = false;\n\t}\n} );\n\n// Install script dataType\njQuery.ajaxSetup( {\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, \" +\n\t\t\t\"application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /\\b(?:java|ecma)script\\b/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n} );\n\n// Handle cache's special case and crossDomain\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t}\n} );\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function( s ) {\n\n\t// This transport only deals with cross domain or forced-by-attrs requests\n\tif ( s.crossDomain || s.scriptAttrs ) {\n\t\tvar script, callback;\n\t\treturn {\n\t\t\tsend: function( _, complete ) {\n\t\t\t\tscript = jQuery( \"<script>\" )\n\t\t\t\t\t.attr( s.scriptAttrs || {} )\n\t\t\t\t\t.prop( { charset: s.scriptCharset, src: s.url } )\n\t\t\t\t\t.on( \"load error\", callback = function( evt ) {\n\t\t\t\t\t\tscript.remove();\n\t\t\t\t\t\tcallback = null;\n\t\t\t\t\t\tif ( evt ) {\n\t\t\t\t\t\t\tcomplete( evt.type === \"error\" ? 404 : 200, evt.type );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\n\t\t\t\t// Use native DOM manipulation to avoid our domManip AJAX trickery\n\t\t\t\tdocument.head.appendChild( script[ 0 ] );\n\t\t\t},\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\nvar oldCallbacks = [],\n\trjsonp = /(=)\\?(?=&|$)|\\?\\?/;\n\n// Default jsonp settings\njQuery.ajaxSetup( {\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\tvar callback = oldCallbacks.pop() || ( jQuery.expando + \"_\" + ( nonce.guid++ ) );\n\t\tthis[ callback ] = true;\n\t\treturn callback;\n\t}\n} );\n\n// Detect, normalize options and install callbacks for jsonp requests\njQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n\tvar callbackName, overwritten, responseContainer,\n\t\tjsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?\n\t\t\t\"url\" :\n\t\t\ttypeof s.data === \"string\" &&\n\t\t\t\t( s.contentType || \"\" )\n\t\t\t\t\t.indexOf( \"application/x-www-form-urlencoded\" ) === 0 &&\n\t\t\t\trjsonp.test( s.data ) && \"data\"\n\t\t);\n\n\t// Handle iff the expected data type is \"jsonp\" or we have a parameter to set\n\tif ( jsonProp || s.dataTypes[ 0 ] === \"jsonp\" ) {\n\n\t\t// Get callback name, remembering preexisting value associated with it\n\t\tcallbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ?\n\t\t\ts.jsonpCallback() :\n\t\t\ts.jsonpCallback;\n\n\t\t// Insert callback into url or form data\n\t\tif ( jsonProp ) {\n\t\t\ts[ jsonProp ] = s[ jsonProp ].replace( rjsonp, \"$1\" + callbackName );\n\t\t} else if ( s.jsonp !== false ) {\n\t\t\ts.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.jsonp + \"=\" + callbackName;\n\t\t}\n\n\t\t// Use data converter to retrieve json after script execution\n\t\ts.converters[ \"script json\" ] = function() {\n\t\t\tif ( !responseContainer ) {\n\t\t\t\tjQuery.error( callbackName + \" was not called\" );\n\t\t\t}\n\t\t\treturn responseContainer[ 0 ];\n\t\t};\n\n\t\t// Force json dataType\n\t\ts.dataTypes[ 0 ] = \"json\";\n\n\t\t// Install callback\n\t\toverwritten = window[ callbackName ];\n\t\twindow[ callbackName ] = function() {\n\t\t\tresponseContainer = arguments;\n\t\t};\n\n\t\t// Clean-up function (fires after converters)\n\t\tjqXHR.always( function() {\n\n\t\t\t// If previous value didn't exist - remove it\n\t\t\tif ( overwritten === undefined ) {\n\t\t\t\tjQuery( window ).removeProp( callbackName );\n\n\t\t\t// Otherwise restore preexisting value\n\t\t\t} else {\n\t\t\t\twindow[ callbackName ] = overwritten;\n\t\t\t}\n\n\t\t\t// Save back as free\n\t\t\tif ( s[ callbackName ] ) {\n\n\t\t\t\t// Make sure that re-using the options doesn't screw things around\n\t\t\t\ts.jsonpCallback = originalSettings.jsonpCallback;\n\n\t\t\t\t// Save the callback name for future use\n\t\t\t\toldCallbacks.push( callbackName );\n\t\t\t}\n\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && isFunction( overwritten ) ) {\n\t\t\t\toverwritten( responseContainer[ 0 ] );\n\t\t\t}\n\n\t\t\tresponseContainer = overwritten = undefined;\n\t\t} );\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n} );\n\n\n\n\n// Support: Safari 8 only\n// In Safari 8 documents created via document.implementation.createHTMLDocument\n// collapse sibling forms: the second one becomes a child of the first one.\n// Because of that, this security measure has to be disabled in Safari 8.\n// https://bugs.webkit.org/show_bug.cgi?id=137337\nsupport.createHTMLDocument = ( function() {\n\tvar body = document.implementation.createHTMLDocument( \"\" ).body;\n\tbody.innerHTML = \"<form></form><form></form>\";\n\treturn body.childNodes.length === 2;\n} )();\n\n\n// Argument \"data\" should be string of html\n// context (optional): If specified, the fragment will be created in this context,\n// defaults to document\n// keepScripts (optional): If true, will include scripts passed in the html string\njQuery.parseHTML = function( data, context, keepScripts ) {\n\tif ( typeof data !== \"string\" ) {\n\t\treturn [];\n\t}\n\tif ( typeof context === \"boolean\" ) {\n\t\tkeepScripts = context;\n\t\tcontext = false;\n\t}\n\n\tvar base, parsed, scripts;\n\n\tif ( !context ) {\n\n\t\t// Stop scripts or inline event handlers from being executed immediately\n\t\t// by using document.implementation\n\t\tif ( support.createHTMLDocument ) {\n\t\t\tcontext = document.implementation.createHTMLDocument( \"\" );\n\n\t\t\t// Set the base href for the created document\n\t\t\t// so any parsed elements with URLs\n\t\t\t// are based on the document's URL (gh-2965)\n\t\t\tbase = context.createElement( \"base\" );\n\t\t\tbase.href = document.location.href;\n\t\t\tcontext.head.appendChild( base );\n\t\t} else {\n\t\t\tcontext = document;\n\t\t}\n\t}\n\n\tparsed = rsingleTag.exec( data );\n\tscripts = !keepScripts && [];\n\n\t// Single tag\n\tif ( parsed ) {\n\t\treturn [ context.createElement( parsed[ 1 ] ) ];\n\t}\n\n\tparsed = buildFragment( [ data ], context, scripts );\n\n\tif ( scripts && scripts.length ) {\n\t\tjQuery( scripts ).remove();\n\t}\n\n\treturn jQuery.merge( [], parsed.childNodes );\n};\n\n\n/**\n * Load a url into a page\n */\njQuery.fn.load = function( url, params, callback ) {\n\tvar selector, type, response,\n\t\tself = this,\n\t\toff = url.indexOf( \" \" );\n\n\tif ( off > -1 ) {\n\t\tselector = stripAndCollapse( url.slice( off ) );\n\t\turl = url.slice( 0, off );\n\t}\n\n\t// If it's a function\n\tif ( isFunction( params ) ) {\n\n\t\t// We assume that it's the callback\n\t\tcallback = params;\n\t\tparams = undefined;\n\n\t// Otherwise, build a param string\n\t} else if ( params && typeof params === \"object\" ) {\n\t\ttype = \"POST\";\n\t}\n\n\t// If we have elements to modify, make the request\n\tif ( self.length > 0 ) {\n\t\tjQuery.ajax( {\n\t\t\turl: url,\n\n\t\t\t// If \"type\" variable is undefined, then \"GET\" method will be used.\n\t\t\t// Make value of this field explicit since\n\t\t\t// user can override it through ajaxSetup method\n\t\t\ttype: type || \"GET\",\n\t\t\tdataType: \"html\",\n\t\t\tdata: params\n\t\t} ).done( function( responseText ) {\n\n\t\t\t// Save response for use in complete callback\n\t\t\tresponse = arguments;\n\n\t\t\tself.html( selector ?\n\n\t\t\t\t// If a selector was specified, locate the right elements in a dummy div\n\t\t\t\t// Exclude scripts to avoid IE 'Permission Denied' errors\n\t\t\t\tjQuery( \"<div>\" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n\t\t\t\t// Otherwise use the full result\n\t\t\t\tresponseText );\n\n\t\t// If the request succeeds, this function gets \"data\", \"status\", \"jqXHR\"\n\t\t// but they are ignored because response was set above.\n\t\t// If it fails, this function gets \"jqXHR\", \"status\", \"error\"\n\t\t} ).always( callback && function( jqXHR, status ) {\n\t\t\tself.each( function() {\n\t\t\t\tcallback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );\n\t\t\t} );\n\t\t} );\n\t}\n\n\treturn this;\n};\n\n\n\n\njQuery.expr.pseudos.animated = function( elem ) {\n\treturn jQuery.grep( jQuery.timers, function( fn ) {\n\t\treturn elem === fn.elem;\n\t} ).length;\n};\n\n\n\n\njQuery.offset = {\n\tsetOffset: function( elem, options, i ) {\n\t\tvar curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,\n\t\t\tposition = jQuery.css( elem, \"position\" ),\n\t\t\tcurElem = jQuery( elem ),\n\t\t\tprops = {};\n\n\t\t// Set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tcurOffset = curElem.offset();\n\t\tcurCSSTop = jQuery.css( elem, \"top\" );\n\t\tcurCSSLeft = jQuery.css( elem, \"left\" );\n\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) &&\n\t\t\t( curCSSTop + curCSSLeft ).indexOf( \"auto\" ) > -1;\n\n\t\t// Need to be able to calculate position if either\n\t\t// top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( isFunction( options ) ) {\n\n\t\t\t// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)\n\t\t\toptions = options.call( elem, i, jQuery.extend( {}, curOffset ) );\n\t\t}\n\n\t\tif ( options.top != null ) {\n\t\t\tprops.top = ( options.top - curOffset.top ) + curTop;\n\t\t}\n\t\tif ( options.left != null ) {\n\t\t\tprops.left = ( options.left - curOffset.left ) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\njQuery.fn.extend( {\n\n\t// offset() relates an element's border box to the document origin\n\toffset: function( options ) {\n\n\t\t// Preserve chaining for setter\n\t\tif ( arguments.length ) {\n\t\t\treturn options === undefined ?\n\t\t\t\tthis :\n\t\t\t\tthis.each( function( i ) {\n\t\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t\t} );\n\t\t}\n\n\t\tvar rect, win,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !elem ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Return zeros for disconnected and hidden (display: none) elements (gh-2310)\n\t\t// Support: IE <=11 only\n\t\t// Running getBoundingClientRect on a\n\t\t// disconnected node in IE throws an error\n\t\tif ( !elem.getClientRects().length ) {\n\t\t\treturn { top: 0, left: 0 };\n\t\t}\n\n\t\t// Get document-relative position by adding viewport scroll to viewport-relative gBCR\n\t\trect = elem.getBoundingClientRect();\n\t\twin = elem.ownerDocument.defaultView;\n\t\treturn {\n\t\t\ttop: rect.top + win.pageYOffset,\n\t\t\tleft: rect.left + win.pageXOffset\n\t\t};\n\t},\n\n\t// position() relates an element's margin box to its offset parent's padding box\n\t// This corresponds to the behavior of CSS absolute positioning\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset, doc,\n\t\t\telem = this[ 0 ],\n\t\t\tparentOffset = { top: 0, left: 0 };\n\n\t\t// position:fixed elements are offset from the viewport, which itself always has zero offset\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\n\t\t\t// Assume position:fixed implies availability of getBoundingClientRect\n\t\t\toffset = elem.getBoundingClientRect();\n\n\t\t} else {\n\t\t\toffset = this.offset();\n\n\t\t\t// Account for the *real* offset parent, which can be the document or its root element\n\t\t\t// when a statically positioned element is identified\n\t\t\tdoc = elem.ownerDocument;\n\t\t\toffsetParent = elem.offsetParent || doc.documentElement;\n\t\t\twhile ( offsetParent &&\n\t\t\t\t( offsetParent === doc.body || offsetParent === doc.documentElement ) &&\n\t\t\t\tjQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n\n\t\t\t\toffsetParent = offsetParent.parentNode;\n\t\t\t}\n\t\t\tif ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {\n\n\t\t\t\t// Incorporate borders into its offset, since they are outside its content origin\n\t\t\t\tparentOffset = jQuery( offsetParent ).offset();\n\t\t\t\tparentOffset.top += jQuery.css( offsetParent, \"borderTopWidth\", true );\n\t\t\t\tparentOffset.left += jQuery.css( offsetParent, \"borderLeftWidth\", true );\n\t\t\t}\n\t\t}\n\n\t\t// Subtract parent offsets and element margins\n\t\treturn {\n\t\t\ttop: offset.top - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true )\n\t\t};\n\t},\n\n\t// This method will return documentElement in the following cases:\n\t// 1) For the element inside the iframe without offsetParent, this method will return\n\t// documentElement of the parent window\n\t// 2) For the hidden or detached element\n\t// 3) For body or html element, i.e. in case of the html node - it will return itself\n\t//\n\t// but those exceptions were never presented as a real life use-cases\n\t// and might be considered as more preferable results.\n\t//\n\t// This logic, however, is not guaranteed and can change at any point in the future\n\toffsetParent: function() {\n\t\treturn this.map( function() {\n\t\t\tvar offsetParent = this.offsetParent;\n\n\t\t\twhile ( offsetParent && jQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\n\t\t\treturn offsetParent || documentElement;\n\t\t} );\n\t}\n} );\n\n// Create scrollLeft and scrollTop methods\njQuery.each( { scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\" }, function( method, prop ) {\n\tvar top = \"pageYOffset\" === prop;\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn access( this, function( elem, method, val ) {\n\n\t\t\t// Coalesce documents and windows\n\t\t\tvar win;\n\t\t\tif ( isWindow( elem ) ) {\n\t\t\t\twin = elem;\n\t\t\t} else if ( elem.nodeType === 9 ) {\n\t\t\t\twin = elem.defaultView;\n\t\t\t}\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? win[ prop ] : elem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : win.pageXOffset,\n\t\t\t\t\ttop ? val : win.pageYOffset\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length );\n\t};\n} );\n\n// Support: Safari <=7 - 9.1, Chrome <=37 - 49\n// Add the top/left cssHooks using jQuery.fn.position\n// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347\n// getComputedStyle returns percent when specified for top/left/bottom/right;\n// rather than make the css module depend on the offset module, just check for it here\njQuery.each( [ \"top\", \"left\" ], function( _i, prop ) {\n\tjQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,\n\t\tfunction( elem, computed ) {\n\t\t\tif ( computed ) {\n\t\t\t\tcomputed = curCSS( elem, prop );\n\n\t\t\t\t// If curCSS returns percentage, fallback to offset\n\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\tcomputed;\n\t\t\t}\n\t\t}\n\t);\n} );\n\n\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( {\n\t\tpadding: \"inner\" + name,\n\t\tcontent: type,\n\t\t\"\": \"outer\" + name\n\t}, function( defaultExtra, funcName ) {\n\n\t\t// Margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( isWindow( elem ) ) {\n\n\t\t\t\t\t// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)\n\t\t\t\t\treturn funcName.indexOf( \"outer\" ) === 0 ?\n\t\t\t\t\t\telem[ \"inner\" + name ] :\n\t\t\t\t\t\telem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],\n\t\t\t\t\t// whichever is greatest\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable );\n\t\t};\n\t} );\n} );\n\n\njQuery.each( [\n\t\"ajaxStart\",\n\t\"ajaxStop\",\n\t\"ajaxComplete\",\n\t\"ajaxError\",\n\t\"ajaxSuccess\",\n\t\"ajaxSend\"\n], function( _i, type ) {\n\tjQuery.fn[ type ] = function( fn ) {\n\t\treturn this.on( type, fn );\n\t};\n} );\n\n\n\n\njQuery.fn.extend( {\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length === 1 ?\n\t\t\tthis.off( selector, \"**\" ) :\n\t\t\tthis.off( types, selector || \"**\", fn );\n\t},\n\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t}\n} );\n\njQuery.each(\n\t( \"blur focus focusin focusout resize scroll click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup contextmenu\" ).split( \" \" ),\n\tfunction( _i, name ) {\n\n\t\t// Handle event binding\n\t\tjQuery.fn[ name ] = function( data, fn ) {\n\t\t\treturn arguments.length > 0 ?\n\t\t\t\tthis.on( name, null, data, fn ) :\n\t\t\t\tthis.trigger( name );\n\t\t};\n\t}\n);\n\n\n\n\n// Support: Android <=4.0 only\n// Make sure we trim BOM and NBSP\nvar rtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;\n\n// Bind a function to a context, optionally partially applying any\n// arguments.\n// jQuery.proxy is deprecated to promote standards (specifically Function#bind)\n// However, it is not slated for removal any time soon\njQuery.proxy = function( fn, context ) {\n\tvar tmp, args, proxy;\n\n\tif ( typeof context === \"string\" ) {\n\t\ttmp = fn[ context ];\n\t\tcontext = fn;\n\t\tfn = tmp;\n\t}\n\n\t// Quick check to determine if target is callable, in the spec\n\t// this throws a TypeError, but we will just return undefined.\n\tif ( !isFunction( fn ) ) {\n\t\treturn undefined;\n\t}\n\n\t// Simulated bind\n\targs = slice.call( arguments, 2 );\n\tproxy = function() {\n\t\treturn fn.apply( context || this, args.concat( slice.call( arguments ) ) );\n\t};\n\n\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\tproxy.guid = fn.guid = fn.guid || jQuery.guid++;\n\n\treturn proxy;\n};\n\njQuery.holdReady = function( hold ) {\n\tif ( hold ) {\n\t\tjQuery.readyWait++;\n\t} else {\n\t\tjQuery.ready( true );\n\t}\n};\njQuery.isArray = Array.isArray;\njQuery.parseJSON = JSON.parse;\njQuery.nodeName = nodeName;\njQuery.isFunction = isFunction;\njQuery.isWindow = isWindow;\njQuery.camelCase = camelCase;\njQuery.type = toType;\n\njQuery.now = Date.now;\n\njQuery.isNumeric = function( obj ) {\n\n\t// As of jQuery 3.0, isNumeric is limited to\n\t// strings and numbers (primitives or objects)\n\t// that can be coerced to finite numbers (gh-2662)\n\tvar type = jQuery.type( obj );\n\treturn ( type === \"number\" || type === \"string\" ) &&\n\n\t\t// parseFloat NaNs numeric-cast false positives (\"\")\n\t\t// ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n\t\t// subtraction forces infinities to NaN\n\t\t!isNaN( obj - parseFloat( obj ) );\n};\n\njQuery.trim = function( text ) {\n\treturn text == null ?\n\t\t\"\" :\n\t\t( text + \"\" ).replace( rtrim, \"\" );\n};\n\n\n\n// Register as a named AMD module, since jQuery can be concatenated with other\n// files that may use define, but not via a proper concatenation script that\n// understands anonymous AMD modules. A named AMD is safest and most robust\n// way to register. Lowercase jquery is used because AMD module names are\n// derived from file names, and jQuery is normally delivered in a lowercase\n// file name. Do this after creating the global so that if an AMD module wants\n// to call noConflict to hide this version of jQuery, it will work.\n\n// Note that for maximum portability, libraries that are not jQuery should\n// declare themselves as anonymous modules, and avoid setting a global if an\n// AMD loader is present. jQuery is a special case. For more information, see\n// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon\n\nif ( true ) {\n\t!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = (function() {\n\t\treturn jQuery;\n\t}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),\n\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n}\n\n\n\n\nvar\n\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$;\n\njQuery.noConflict = function( deep ) {\n\tif ( window.$ === jQuery ) {\n\t\twindow.$ = _$;\n\t}\n\n\tif ( deep && window.jQuery === jQuery ) {\n\t\twindow.jQuery = _jQuery;\n\t}\n\n\treturn jQuery;\n};\n\n// Expose jQuery and $ identifiers, even in AMD\n// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)\n// and CommonJS for browser emulators (#13566)\nif ( typeof noGlobal === \"undefined\" ) {\n\twindow.jQuery = window.$ = jQuery;\n}\n\n\n\n\nreturn jQuery;\n} );\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvanF1ZXJ5L2Rpc3QvanF1ZXJ5LmpzLmpzIiwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsTUFBTSxLQUEwQjs7QUFFaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBOzs7QUFHQTs7OztBQUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSwrQkFBK0I7QUFDL0I7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLFNBQVMsWUFBWTs7QUFFckI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGLG9CQUFvQjs7QUFFcEI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUYsOENBQThDO0FBQzlDO0FBQ0E7QUFDQSxtQkFBbUIsaUNBQWlDO0FBQ3BELEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVyxZQUFZO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxVQUFVLFNBQVM7QUFDbkI7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxVQUFVLFlBQVk7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFlBQVk7QUFDdkI7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQSxlQUFlO0FBQ2Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSxTQUFTO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLGtDQUFrQyxJQUFJO0FBQ3RDOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLDJCQUEyQjtBQUMzQjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQSxnQkFBZ0IsSUFBSTs7QUFFcEI7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsMENBQTBDLElBQUk7QUFDOUM7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILElBQUk7QUFDSjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0YsVUFBVTs7QUFFVjtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBOztBQUVBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxNQUFNO0FBQ047QUFDQTs7QUFFQTtBQUNBLE1BQU07QUFDTjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsYUFBYSwwQkFBMEI7QUFDdkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxXQUFXLFVBQVU7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVyxVQUFVO0FBQ3JCO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVyxRQUFRO0FBQ25CLFdBQVcsVUFBVTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVyxTQUFTO0FBQ3BCLFdBQVcsU0FBUztBQUNwQixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFdBQVcsUUFBUTtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVyxRQUFRO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxXQUFXLFNBQVMsNkJBQTZCO0FBQ2pEO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVyxVQUFVO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0EsV0FBVyxpQkFBaUI7QUFDNUIsYUFBYSx3QkFBd0I7QUFDckM7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVyxnQkFBZ0I7QUFDM0IsYUFBYSxTQUFTO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFdBQVcsZ0JBQWdCO0FBQzNCLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxtQkFBbUI7QUFDbkI7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQkFBbUI7QUFDbkI7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUI7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EscUJBQXFCO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxxQkFBcUI7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EscUJBQXFCO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQjtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CO0FBQ25CO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVyxXQUFXO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVyxlQUFlO0FBQzFCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0EsaUNBQWlDLE1BQU07QUFDdkM7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLGVBQWU7O0FBRWYsU0FBUzs7QUFFVDtBQUNBLFNBQVMsZ0NBQWdDO0FBQ3pDLFNBQVMsbUJBQW1CO0FBQzVCLFNBQVMscUNBQXFDO0FBQzlDLFNBQVM7QUFDVCxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsR0FBRzs7QUFFSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ04sR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsTUFBTTs7QUFFTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLDhEQUE4RDs7QUFFOUQ7QUFDQTtBQUNBO0FBQ0EsMkNBQTJDOztBQUUzQztBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxRQUFROztBQUVSO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLCtEQUErRDs7QUFFL0Q7QUFDQTtBQUNBO0FBQ0EsNENBQTRDOztBQUU1QztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLG1DQUFtQzs7QUFFbkM7QUFDQTtBQUNBO0FBQ0EsK0NBQStDOztBQUUvQztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxHQUFHOztBQUVIO0FBQ0E7O0FBRUE7QUFDQSxrRUFBa0UsVUFBVTtBQUM1RSx1Q0FBdUMsMkJBQTJCO0FBQ2xFO0FBQ0EsaUNBQWlDLE1BQU07QUFDdkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQSxXQUFXLFlBQVk7QUFDdkI7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0EsV0FBVyxZQUFZO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxVQUFVO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBLFdBQVcsY0FBYztBQUN6QjtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLGFBQWEsdUVBQXVFO0FBQ3BGO0FBQ0E7QUFDQSxhQUFhLDRCQUE0QjtBQUN6QztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTLFNBQVM7QUFDbEI7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsNkRBQTZEOztBQUU3RDtBQUNBO0FBQ0E7QUFDQSwwQ0FBMEM7O0FBRTFDO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7O0FBRUE7QUFDQTtBQUNBLFFBQVE7O0FBRVI7QUFDQTs7QUFFQSxvQ0FBb0M7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTLFNBQVM7QUFDbEI7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLFNBQVMsU0FBUztBQUNsQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSixTQUFTLFNBQVM7QUFDbEI7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZLFNBQVM7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCLGlEQUFpRDtBQUNsRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxzQkFBc0I7QUFDdEI7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxrREFBa0Q7QUFDbEQsV0FBVyw0Q0FBNEM7QUFDdkQ7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsdUJBQXVCO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLGlCQUFpQjtBQUM1QjtBQUNBLFdBQVcsU0FBUztBQUNwQixXQUFXLE9BQU87QUFDbEIsV0FBVyxPQUFPO0FBQ2xCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIOztBQUVBOztBQUVBLEVBQUU7Ozs7QUFJRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQUtBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTs7QUFFQSxTQUFTLEdBQUc7QUFDWjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOzs7QUFHQTs7OztBQUlBOztBQUVBOztBQUVBO0FBQ0E7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxpQkFBaUIsU0FBUztBQUMxQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTs7QUFFQSxlQUFlLFNBQVM7QUFDeEI7QUFDQTs7QUFFQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOzs7QUFHRjs7O0FBR0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsTUFBTTtBQUNOOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7OztBQUdBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxXQUFXLE9BQU87QUFDbEI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFdBQVcsT0FBTztBQUNsQiwyQkFBMkIsd0JBQXdCOztBQUVuRDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQSwyQ0FBMkM7QUFDM0MsRUFBRTtBQUNGO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQjs7QUFFbkI7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVyxjQUFjO0FBQ3pCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUzs7QUFFVDtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1IsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEseUNBQXlDLHFDQUFxQztBQUM5RSxxQ0FBcUMsc0NBQXNDO0FBQzNFLHFDQUFxQyxxQ0FBcUM7QUFDMUU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxRQUFRO0FBQ1I7QUFDQSxPQUFPO0FBQ1AsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLFlBQVk7O0FBRVo7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsV0FBVzs7QUFFWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTOztBQUVUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7O0FBRVo7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7O0FBRVQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE1BQU07O0FBRU47QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHFDQUFxQztBQUNyQyxzQ0FBc0M7QUFDdEMscUNBQXFDO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7O0FBR0Y7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUFLQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7Ozs7O0FBS0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7Ozs7O0FBS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsV0FBVyxTQUFTO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxnQ0FBZ0M7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FBS0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSx3QkFBd0IsYUFBYTtBQUNyQyxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7QUFDRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOzs7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLG9CQUFvQixTQUFTO0FBQzdCOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0EsRUFBRTs7O0FBR0Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxJQUFJO0FBQ0o7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLEVBQUU7QUFDRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGOztBQUVBOzs7QUFHQTs7QUFFQTs7OztBQUlBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsZUFBZTs7QUFFZjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsU0FBUyxnQkFBZ0I7QUFDekI7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0Esa0JBQWtCLGdCQUFnQjtBQUNsQztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0EsRUFBRTtBQUNGOztBQUVBOztBQUVBOzs7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOzs7QUFHRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsR0FBRztBQUNIOztBQUVBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxTQUFTLE9BQU87QUFDaEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBLHNCQUFzQjs7QUFFdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLFNBQVMsT0FBTztBQUNoQjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7O0FBR0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxXQUFXOztBQUVYOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsNENBQTRDO0FBQzVDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLGVBQWUsc0JBQXNCO0FBQ3JDO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSwwQkFBMEI7QUFDMUI7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLGdFQUFnRTtBQUNoRTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLFdBQVcsY0FBYzs7QUFFekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQixtQkFBbUI7QUFDckM7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQix1Q0FBdUM7QUFDbEU7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLHVEQUF1RDtBQUMvRTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0EsSUFBSTtBQUNKLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNLCtDQUErQztBQUNyRDtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNOztBQUVOO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSx1Q0FBdUM7QUFDdkM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQsZUFBZSxvQ0FBb0M7QUFDbkQ7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQ0FBc0M7QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDO0FBQ0Q7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBLEVBQUU7OztBQUdGOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLDRDQUE0QyxPQUFPO0FBQ25EO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsOEJBQThCOztBQUU5QjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLE9BQU87QUFDbEI7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxpQkFBaUIsZ0JBQWdCO0FBQ2pDO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsU0FBUywrQkFBK0I7QUFDeEM7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLHdDQUF3QyxPQUFPO0FBQy9DO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHlDQUF5QyxPQUFPO0FBQ2hEO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsVUFBVSxxQ0FBcUM7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTixHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSixFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQSxVQUFVLDhCQUE4QjtBQUN4Qzs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7QUFDSixFQUFFOztBQUVGO0FBQ0E7QUFDQSw2QkFBNkI7QUFDN0I7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsYUFBYSxPQUFPO0FBQ3BCOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLE1BQU07QUFDTjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxHQUFHO0FBQ0g7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsVUFBVSxXQUFXO0FBQ3JCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7QUFDRjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOzs7QUFHQTs7OztBQUlBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSwrQ0FBK0MsY0FBYyxXQUFXO0FBQ3hFLG1CQUFtQixVQUFVO0FBQzdCO0FBQ0Esc0JBQXNCLGNBQWMsc0JBQXNCLGdCQUFnQjtBQUMxRSxnQkFBZ0IsV0FBVyxZQUFZO0FBQ3ZDLGNBQWM7QUFDZDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUNBQWlDO0FBQ2pDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLDZDQUE2QyxjQUFjO0FBQzNEOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7O0FBR0Y7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsbUJBQW1CO0FBQ25CO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLDhEQUE4RDtBQUMzRTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxTQUFTLE9BQU87O0FBRWhCO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsYUFBYTs7QUFFYjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQixlQUFlO0FBQ2xDO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCOztBQUVqQjtBQUNBOztBQUVBLFdBQVcsT0FBTztBQUNsQjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7O0FBRUE7QUFDQTtBQUNBOztBQUVBLFlBQVksU0FBUztBQUNyQjtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0EsRUFBRTs7O0FBR0Y7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOzs7OztBQUtBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZOztBQUVaO0FBQ0E7QUFDQTtBQUNBLFNBQVMsT0FBTztBQUNoQjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVMsZ0JBQWdCO0FBQ3pCOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxJQUFJO0FBQ0o7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxrREFBa0QsMEJBQTBCO0FBQzVFOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsV0FBVyxnQkFBZ0I7QUFDM0I7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBLDJCQUEyQjtBQUMzQjtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxnQkFBZ0I7QUFDNUI7QUFDQTs7QUFFQSw4Q0FBOEM7QUFDOUM7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBOztBQUVBLFNBQVMsZ0JBQWdCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsVUFBVSxnQkFBZ0I7QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0EsaUVBQWlFO0FBQ2pFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7O0FBRUEsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxxQkFBcUIsYUFBYTtBQUNsQyxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxpREFBaUQ7O0FBRWpEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGdDQUFnQyxTQUFTO0FBQ3pDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGdDQUFnQyxTQUFTO0FBQ3pDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxvQkFBb0IsZ0JBQWdCO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxpQkFBaUI7QUFDNUIsWUFBWSxpQkFBaUI7QUFDN0IsZUFBZTtBQUNmLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsU0FBUyxtQkFBbUI7QUFDNUI7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7OztBQUdBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7O0FBR0Y7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7Ozs7QUFLRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7Ozs7QUFLRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7Ozs7O0FBS0Y7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQSxrQ0FBa0M7QUFDbEM7QUFDQTs7QUFFQSxLQUFLO0FBQ0w7O0FBRUEsS0FBSztBQUNMO0FBQ0E7QUFDQSxNQUFNO0FBQ047O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLE1BQU07QUFDTjtBQUNBOztBQUVBO0FBQ0EsWUFBWSxTQUFTO0FBQ3JCOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOzs7OztBQUtGOzs7QUFHQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsdUNBQXVDO0FBQ3ZDO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSwwQkFBMEI7QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSwrQ0FBK0M7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSw0Q0FBNEM7QUFDNUM7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLEtBQUs7QUFDaEI7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7OztBQUdGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixvQ0FBb0M7O0FBRXBEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTs7QUFFQSxjQUFjOztBQUVkOzs7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUosR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSixHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsY0FBYztBQUNkLE1BQU07QUFDTjs7QUFFQSxZQUFZO0FBQ1osSUFBSTtBQUNKO0FBQ0EsRUFBRTs7O0FBR0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7O0FBRWhCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7O0FBRWhCLGlEQUFpRDtBQUNqRDs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxtQkFBbUI7QUFDbkI7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EseURBQXlEO0FBQ3pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjs7QUFFakI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxVQUFVO0FBQ1Y7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLGlCQUFpQjtBQUNqQixTQUFTOztBQUVUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbURBQW1EOztBQUVuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLDJCQUEyQjs7QUFFM0I7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGtDQUFrQzs7QUFFbEM7QUFDQSxzQkFBc0I7QUFDdEIsMkJBQTJCOztBQUUzQjtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxRQUFROztBQUVSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVEQUF1RDtBQUN2RDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsTUFBTTtBQUNOOztBQUVBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7O0FBR0Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDs7O0FBR0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLElBQUk7QUFDSixFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7QUFDSixFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0EsRUFBRTs7O0FBR0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQUtBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxTQUFTOztBQUVUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7O0FBRUEsb0RBQW9EO0FBQ3BEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSx1QkFBdUI7QUFDbkMsWUFBWSx3QkFBd0I7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsTUFBTTs7QUFFTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7Ozs7O0FBS0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0M7QUFDaEMsY0FBYyx1Q0FBdUM7QUFDckQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7Ozs7QUFLRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBLEVBQUU7Ozs7O0FBS0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7O0FBR0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxHQUFHO0FBQ0g7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsSUFBSTtBQUNKOztBQUVBO0FBQ0E7Ozs7O0FBS0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIOzs7OztBQUtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJO0FBQ0o7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EscURBQXFEO0FBQ3JEOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLG9CQUFvQjs7QUFFcEI7QUFDQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7QUFDSjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLElBQUk7QUFDSjtBQUNBLEVBQUU7O0FBRUY7QUFDQSxlQUFlLHFEQUFxRDtBQUNwRTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSztBQUNMO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOzs7QUFHRjtBQUNBLGVBQWUsa0NBQWtDO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0EsR0FBRztBQUNILEVBQUU7OztBQUdGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOzs7OztBQUtGOztBQUVBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7QUFDRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FBS0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSyxJQUEwQztBQUMvQyxDQUFDLGlDQUFrQixFQUFFLG1DQUFFO0FBQ3ZCO0FBQ0EsRUFBRTtBQUFBLGtHQUFFO0FBQ0o7Ozs7O0FBS0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUFLQTtBQUNBLEVBQUUiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvanF1ZXJ5L2Rpc3QvanF1ZXJ5LmpzPzgyNjIiXSwic291cmNlc0NvbnRlbnQiOlsiLyohXG4gKiBqUXVlcnkgSmF2YVNjcmlwdCBMaWJyYXJ5IHYzLjYuMFxuICogaHR0cHM6Ly9qcXVlcnkuY29tL1xuICpcbiAqIEluY2x1ZGVzIFNpenpsZS5qc1xuICogaHR0cHM6Ly9zaXp6bGVqcy5jb20vXG4gKlxuICogQ29weXJpZ2h0IE9wZW5KUyBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZVxuICogaHR0cHM6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqXG4gKiBEYXRlOiAyMDIxLTAzLTAyVDE3OjA4WlxuICovXG4oIGZ1bmN0aW9uKCBnbG9iYWwsIGZhY3RvcnkgKSB7XG5cblx0XCJ1c2Ugc3RyaWN0XCI7XG5cblx0aWYgKCB0eXBlb2YgbW9kdWxlID09PSBcIm9iamVjdFwiICYmIHR5cGVvZiBtb2R1bGUuZXhwb3J0cyA9PT0gXCJvYmplY3RcIiApIHtcblxuXHRcdC8vIEZvciBDb21tb25KUyBhbmQgQ29tbW9uSlMtbGlrZSBlbnZpcm9ubWVudHMgd2hlcmUgYSBwcm9wZXIgYHdpbmRvd2Bcblx0XHQvLyBpcyBwcmVzZW50LCBleGVjdXRlIHRoZSBmYWN0b3J5IGFuZCBnZXQgalF1ZXJ5LlxuXHRcdC8vIEZvciBlbnZpcm9ubWVudHMgdGhhdCBkbyBub3QgaGF2ZSBhIGB3aW5kb3dgIHdpdGggYSBgZG9jdW1lbnRgXG5cdFx0Ly8gKHN1Y2ggYXMgTm9kZS5qcyksIGV4cG9zZSBhIGZhY3RvcnkgYXMgbW9kdWxlLmV4cG9ydHMuXG5cdFx0Ly8gVGhpcyBhY2NlbnR1YXRlcyB0aGUgbmVlZCBmb3IgdGhlIGNyZWF0aW9uIG9mIGEgcmVhbCBgd2luZG93YC5cblx0XHQvLyBlLmcuIHZhciBqUXVlcnkgPSByZXF1aXJlKFwianF1ZXJ5XCIpKHdpbmRvdyk7XG5cdFx0Ly8gU2VlIHRpY2tldCAjMTQ1NDkgZm9yIG1vcmUgaW5mby5cblx0XHRtb2R1bGUuZXhwb3J0cyA9IGdsb2JhbC5kb2N1bWVudCA/XG5cdFx0XHRmYWN0b3J5KCBnbG9iYWwsIHRydWUgKSA6XG5cdFx0XHRmdW5jdGlvbiggdyApIHtcblx0XHRcdFx0aWYgKCAhdy5kb2N1bWVudCApIHtcblx0XHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoIFwialF1ZXJ5IHJlcXVpcmVzIGEgd2luZG93IHdpdGggYSBkb2N1bWVudFwiICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIGZhY3RvcnkoIHcgKTtcblx0XHRcdH07XG5cdH0gZWxzZSB7XG5cdFx0ZmFjdG9yeSggZ2xvYmFsICk7XG5cdH1cblxuLy8gUGFzcyB0aGlzIGlmIHdpbmRvdyBpcyBub3QgZGVmaW5lZCB5ZXRcbn0gKSggdHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIiA/IHdpbmRvdyA6IHRoaXMsIGZ1bmN0aW9uKCB3aW5kb3csIG5vR2xvYmFsICkge1xuXG4vLyBFZGdlIDw9IDEyIC0gMTMrLCBGaXJlZm94IDw9MTggLSA0NSssIElFIDEwIC0gMTEsIFNhZmFyaSA1LjEgLSA5KywgaU9TIDYgLSA5LjFcbi8vIHRocm93IGV4Y2VwdGlvbnMgd2hlbiBub24tc3RyaWN0IGNvZGUgKGUuZy4sIEFTUC5ORVQgNC41KSBhY2Nlc3NlcyBzdHJpY3QgbW9kZVxuLy8gYXJndW1lbnRzLmNhbGxlZS5jYWxsZXIgKHRyYWMtMTMzMzUpLiBCdXQgYXMgb2YgalF1ZXJ5IDMuMCAoMjAxNiksIHN0cmljdCBtb2RlIHNob3VsZCBiZSBjb21tb25cbi8vIGVub3VnaCB0aGF0IGFsbCBzdWNoIGF0dGVtcHRzIGFyZSBndWFyZGVkIGluIGEgdHJ5IGJsb2NrLlxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBhcnIgPSBbXTtcblxudmFyIGdldFByb3RvID0gT2JqZWN0LmdldFByb3RvdHlwZU9mO1xuXG52YXIgc2xpY2UgPSBhcnIuc2xpY2U7XG5cbnZhciBmbGF0ID0gYXJyLmZsYXQgPyBmdW5jdGlvbiggYXJyYXkgKSB7XG5cdHJldHVybiBhcnIuZmxhdC5jYWxsKCBhcnJheSApO1xufSA6IGZ1bmN0aW9uKCBhcnJheSApIHtcblx0cmV0dXJuIGFyci5jb25jYXQuYXBwbHkoIFtdLCBhcnJheSApO1xufTtcblxuXG52YXIgcHVzaCA9IGFyci5wdXNoO1xuXG52YXIgaW5kZXhPZiA9IGFyci5pbmRleE9mO1xuXG52YXIgY2xhc3MydHlwZSA9IHt9O1xuXG52YXIgdG9TdHJpbmcgPSBjbGFzczJ0eXBlLnRvU3RyaW5nO1xuXG52YXIgaGFzT3duID0gY2xhc3MydHlwZS5oYXNPd25Qcm9wZXJ0eTtcblxudmFyIGZuVG9TdHJpbmcgPSBoYXNPd24udG9TdHJpbmc7XG5cbnZhciBPYmplY3RGdW5jdGlvblN0cmluZyA9IGZuVG9TdHJpbmcuY2FsbCggT2JqZWN0ICk7XG5cbnZhciBzdXBwb3J0ID0ge307XG5cbnZhciBpc0Z1bmN0aW9uID0gZnVuY3Rpb24gaXNGdW5jdGlvbiggb2JqICkge1xuXG5cdFx0Ly8gU3VwcG9ydDogQ2hyb21lIDw9NTcsIEZpcmVmb3ggPD01MlxuXHRcdC8vIEluIHNvbWUgYnJvd3NlcnMsIHR5cGVvZiByZXR1cm5zIFwiZnVuY3Rpb25cIiBmb3IgSFRNTCA8b2JqZWN0PiBlbGVtZW50c1xuXHRcdC8vIChpLmUuLCBgdHlwZW9mIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwib2JqZWN0XCIgKSA9PT0gXCJmdW5jdGlvblwiYCkuXG5cdFx0Ly8gV2UgZG9uJ3Qgd2FudCB0byBjbGFzc2lmeSAqYW55KiBET00gbm9kZSBhcyBhIGZ1bmN0aW9uLlxuXHRcdC8vIFN1cHBvcnQ6IFF0V2ViIDw9My44LjUsIFdlYktpdCA8PTUzNC4zNCwgd2todG1sdG9wZGYgdG9vbCA8PTAuMTIuNVxuXHRcdC8vIFBsdXMgZm9yIG9sZCBXZWJLaXQsIHR5cGVvZiByZXR1cm5zIFwiZnVuY3Rpb25cIiBmb3IgSFRNTCBjb2xsZWN0aW9uc1xuXHRcdC8vIChlLmcuLCBgdHlwZW9mIGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKFwiZGl2XCIpID09PSBcImZ1bmN0aW9uXCJgKS4gKGdoLTQ3NTYpXG5cdFx0cmV0dXJuIHR5cGVvZiBvYmogPT09IFwiZnVuY3Rpb25cIiAmJiB0eXBlb2Ygb2JqLm5vZGVUeXBlICE9PSBcIm51bWJlclwiICYmXG5cdFx0XHR0eXBlb2Ygb2JqLml0ZW0gIT09IFwiZnVuY3Rpb25cIjtcblx0fTtcblxuXG52YXIgaXNXaW5kb3cgPSBmdW5jdGlvbiBpc1dpbmRvdyggb2JqICkge1xuXHRcdHJldHVybiBvYmogIT0gbnVsbCAmJiBvYmogPT09IG9iai53aW5kb3c7XG5cdH07XG5cblxudmFyIGRvY3VtZW50ID0gd2luZG93LmRvY3VtZW50O1xuXG5cblxuXHR2YXIgcHJlc2VydmVkU2NyaXB0QXR0cmlidXRlcyA9IHtcblx0XHR0eXBlOiB0cnVlLFxuXHRcdHNyYzogdHJ1ZSxcblx0XHRub25jZTogdHJ1ZSxcblx0XHRub01vZHVsZTogdHJ1ZVxuXHR9O1xuXG5cdGZ1bmN0aW9uIERPTUV2YWwoIGNvZGUsIG5vZGUsIGRvYyApIHtcblx0XHRkb2MgPSBkb2MgfHwgZG9jdW1lbnQ7XG5cblx0XHR2YXIgaSwgdmFsLFxuXHRcdFx0c2NyaXB0ID0gZG9jLmNyZWF0ZUVsZW1lbnQoIFwic2NyaXB0XCIgKTtcblxuXHRcdHNjcmlwdC50ZXh0ID0gY29kZTtcblx0XHRpZiAoIG5vZGUgKSB7XG5cdFx0XHRmb3IgKCBpIGluIHByZXNlcnZlZFNjcmlwdEF0dHJpYnV0ZXMgKSB7XG5cblx0XHRcdFx0Ly8gU3VwcG9ydDogRmlyZWZveCA2NCssIEVkZ2UgMTgrXG5cdFx0XHRcdC8vIFNvbWUgYnJvd3NlcnMgZG9uJ3Qgc3VwcG9ydCB0aGUgXCJub25jZVwiIHByb3BlcnR5IG9uIHNjcmlwdHMuXG5cdFx0XHRcdC8vIE9uIHRoZSBvdGhlciBoYW5kLCBqdXN0IHVzaW5nIGBnZXRBdHRyaWJ1dGVgIGlzIG5vdCBlbm91Z2ggYXNcblx0XHRcdFx0Ly8gdGhlIGBub25jZWAgYXR0cmlidXRlIGlzIHJlc2V0IHRvIGFuIGVtcHR5IHN0cmluZyB3aGVuZXZlciBpdFxuXHRcdFx0XHQvLyBiZWNvbWVzIGJyb3dzaW5nLWNvbnRleHQgY29ubmVjdGVkLlxuXHRcdFx0XHQvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL3doYXR3Zy9odG1sL2lzc3Vlcy8yMzY5XG5cdFx0XHRcdC8vIFNlZSBodHRwczovL2h0bWwuc3BlYy53aGF0d2cub3JnLyNub25jZS1hdHRyaWJ1dGVzXG5cdFx0XHRcdC8vIFRoZSBgbm9kZS5nZXRBdHRyaWJ1dGVgIGNoZWNrIHdhcyBhZGRlZCBmb3IgdGhlIHNha2Ugb2Zcblx0XHRcdFx0Ly8gYGpRdWVyeS5nbG9iYWxFdmFsYCBzbyB0aGF0IGl0IGNhbiBmYWtlIGEgbm9uY2UtY29udGFpbmluZyBub2RlXG5cdFx0XHRcdC8vIHZpYSBhbiBvYmplY3QuXG5cdFx0XHRcdHZhbCA9IG5vZGVbIGkgXSB8fCBub2RlLmdldEF0dHJpYnV0ZSAmJiBub2RlLmdldEF0dHJpYnV0ZSggaSApO1xuXHRcdFx0XHRpZiAoIHZhbCApIHtcblx0XHRcdFx0XHRzY3JpcHQuc2V0QXR0cmlidXRlKCBpLCB2YWwgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XHRkb2MuaGVhZC5hcHBlbmRDaGlsZCggc2NyaXB0ICkucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCggc2NyaXB0ICk7XG5cdH1cblxuXG5mdW5jdGlvbiB0b1R5cGUoIG9iaiApIHtcblx0aWYgKCBvYmogPT0gbnVsbCApIHtcblx0XHRyZXR1cm4gb2JqICsgXCJcIjtcblx0fVxuXG5cdC8vIFN1cHBvcnQ6IEFuZHJvaWQgPD0yLjMgb25seSAoZnVuY3Rpb25pc2ggUmVnRXhwKVxuXHRyZXR1cm4gdHlwZW9mIG9iaiA9PT0gXCJvYmplY3RcIiB8fCB0eXBlb2Ygb2JqID09PSBcImZ1bmN0aW9uXCIgP1xuXHRcdGNsYXNzMnR5cGVbIHRvU3RyaW5nLmNhbGwoIG9iaiApIF0gfHwgXCJvYmplY3RcIiA6XG5cdFx0dHlwZW9mIG9iajtcbn1cbi8qIGdsb2JhbCBTeW1ib2wgKi9cbi8vIERlZmluaW5nIHRoaXMgZ2xvYmFsIGluIC5lc2xpbnRyYy5qc29uIHdvdWxkIGNyZWF0ZSBhIGRhbmdlciBvZiB1c2luZyB0aGUgZ2xvYmFsXG4vLyB1bmd1YXJkZWQgaW4gYW5vdGhlciBwbGFjZSwgaXQgc2VlbXMgc2FmZXIgdG8gZGVmaW5lIGdsb2JhbCBvbmx5IGZvciB0aGlzIG1vZHVsZVxuXG5cblxudmFyXG5cdHZlcnNpb24gPSBcIjMuNi4wXCIsXG5cblx0Ly8gRGVmaW5lIGEgbG9jYWwgY29weSBvZiBqUXVlcnlcblx0alF1ZXJ5ID0gZnVuY3Rpb24oIHNlbGVjdG9yLCBjb250ZXh0ICkge1xuXG5cdFx0Ly8gVGhlIGpRdWVyeSBvYmplY3QgaXMgYWN0dWFsbHkganVzdCB0aGUgaW5pdCBjb25zdHJ1Y3RvciAnZW5oYW5jZWQnXG5cdFx0Ly8gTmVlZCBpbml0IGlmIGpRdWVyeSBpcyBjYWxsZWQgKGp1c3QgYWxsb3cgZXJyb3IgdG8gYmUgdGhyb3duIGlmIG5vdCBpbmNsdWRlZClcblx0XHRyZXR1cm4gbmV3IGpRdWVyeS5mbi5pbml0KCBzZWxlY3RvciwgY29udGV4dCApO1xuXHR9O1xuXG5qUXVlcnkuZm4gPSBqUXVlcnkucHJvdG90eXBlID0ge1xuXG5cdC8vIFRoZSBjdXJyZW50IHZlcnNpb24gb2YgalF1ZXJ5IGJlaW5nIHVzZWRcblx0anF1ZXJ5OiB2ZXJzaW9uLFxuXG5cdGNvbnN0cnVjdG9yOiBqUXVlcnksXG5cblx0Ly8gVGhlIGRlZmF1bHQgbGVuZ3RoIG9mIGEgalF1ZXJ5IG9iamVjdCBpcyAwXG5cdGxlbmd0aDogMCxcblxuXHR0b0FycmF5OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gc2xpY2UuY2FsbCggdGhpcyApO1xuXHR9LFxuXG5cdC8vIEdldCB0aGUgTnRoIGVsZW1lbnQgaW4gdGhlIG1hdGNoZWQgZWxlbWVudCBzZXQgT1Jcblx0Ly8gR2V0IHRoZSB3aG9sZSBtYXRjaGVkIGVsZW1lbnQgc2V0IGFzIGEgY2xlYW4gYXJyYXlcblx0Z2V0OiBmdW5jdGlvbiggbnVtICkge1xuXG5cdFx0Ly8gUmV0dXJuIGFsbCB0aGUgZWxlbWVudHMgaW4gYSBjbGVhbiBhcnJheVxuXHRcdGlmICggbnVtID09IG51bGwgKSB7XG5cdFx0XHRyZXR1cm4gc2xpY2UuY2FsbCggdGhpcyApO1xuXHRcdH1cblxuXHRcdC8vIFJldHVybiBqdXN0IHRoZSBvbmUgZWxlbWVudCBmcm9tIHRoZSBzZXRcblx0XHRyZXR1cm4gbnVtIDwgMCA/IHRoaXNbIG51bSArIHRoaXMubGVuZ3RoIF0gOiB0aGlzWyBudW0gXTtcblx0fSxcblxuXHQvLyBUYWtlIGFuIGFycmF5IG9mIGVsZW1lbnRzIGFuZCBwdXNoIGl0IG9udG8gdGhlIHN0YWNrXG5cdC8vIChyZXR1cm5pbmcgdGhlIG5ldyBtYXRjaGVkIGVsZW1lbnQgc2V0KVxuXHRwdXNoU3RhY2s6IGZ1bmN0aW9uKCBlbGVtcyApIHtcblxuXHRcdC8vIEJ1aWxkIGEgbmV3IGpRdWVyeSBtYXRjaGVkIGVsZW1lbnQgc2V0XG5cdFx0dmFyIHJldCA9IGpRdWVyeS5tZXJnZSggdGhpcy5jb25zdHJ1Y3RvcigpLCBlbGVtcyApO1xuXG5cdFx0Ly8gQWRkIHRoZSBvbGQgb2JqZWN0IG9udG8gdGhlIHN0YWNrIChhcyBhIHJlZmVyZW5jZSlcblx0XHRyZXQucHJldk9iamVjdCA9IHRoaXM7XG5cblx0XHQvLyBSZXR1cm4gdGhlIG5ld2x5LWZvcm1lZCBlbGVtZW50IHNldFxuXHRcdHJldHVybiByZXQ7XG5cdH0sXG5cblx0Ly8gRXhlY3V0ZSBhIGNhbGxiYWNrIGZvciBldmVyeSBlbGVtZW50IGluIHRoZSBtYXRjaGVkIHNldC5cblx0ZWFjaDogZnVuY3Rpb24oIGNhbGxiYWNrICkge1xuXHRcdHJldHVybiBqUXVlcnkuZWFjaCggdGhpcywgY2FsbGJhY2sgKTtcblx0fSxcblxuXHRtYXA6IGZ1bmN0aW9uKCBjYWxsYmFjayApIHtcblx0XHRyZXR1cm4gdGhpcy5wdXNoU3RhY2soIGpRdWVyeS5tYXAoIHRoaXMsIGZ1bmN0aW9uKCBlbGVtLCBpICkge1xuXHRcdFx0cmV0dXJuIGNhbGxiYWNrLmNhbGwoIGVsZW0sIGksIGVsZW0gKTtcblx0XHR9ICkgKTtcblx0fSxcblxuXHRzbGljZTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMucHVzaFN0YWNrKCBzbGljZS5hcHBseSggdGhpcywgYXJndW1lbnRzICkgKTtcblx0fSxcblxuXHRmaXJzdDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuZXEoIDAgKTtcblx0fSxcblxuXHRsYXN0OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5lcSggLTEgKTtcblx0fSxcblxuXHRldmVuOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5wdXNoU3RhY2soIGpRdWVyeS5ncmVwKCB0aGlzLCBmdW5jdGlvbiggX2VsZW0sIGkgKSB7XG5cdFx0XHRyZXR1cm4gKCBpICsgMSApICUgMjtcblx0XHR9ICkgKTtcblx0fSxcblxuXHRvZGQ6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLnB1c2hTdGFjayggalF1ZXJ5LmdyZXAoIHRoaXMsIGZ1bmN0aW9uKCBfZWxlbSwgaSApIHtcblx0XHRcdHJldHVybiBpICUgMjtcblx0XHR9ICkgKTtcblx0fSxcblxuXHRlcTogZnVuY3Rpb24oIGkgKSB7XG5cdFx0dmFyIGxlbiA9IHRoaXMubGVuZ3RoLFxuXHRcdFx0aiA9ICtpICsgKCBpIDwgMCA/IGxlbiA6IDAgKTtcblx0XHRyZXR1cm4gdGhpcy5wdXNoU3RhY2soIGogPj0gMCAmJiBqIDwgbGVuID8gWyB0aGlzWyBqIF0gXSA6IFtdICk7XG5cdH0sXG5cblx0ZW5kOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5wcmV2T2JqZWN0IHx8IHRoaXMuY29uc3RydWN0b3IoKTtcblx0fSxcblxuXHQvLyBGb3IgaW50ZXJuYWwgdXNlIG9ubHkuXG5cdC8vIEJlaGF2ZXMgbGlrZSBhbiBBcnJheSdzIG1ldGhvZCwgbm90IGxpa2UgYSBqUXVlcnkgbWV0aG9kLlxuXHRwdXNoOiBwdXNoLFxuXHRzb3J0OiBhcnIuc29ydCxcblx0c3BsaWNlOiBhcnIuc3BsaWNlXG59O1xuXG5qUXVlcnkuZXh0ZW5kID0galF1ZXJ5LmZuLmV4dGVuZCA9IGZ1bmN0aW9uKCkge1xuXHR2YXIgb3B0aW9ucywgbmFtZSwgc3JjLCBjb3B5LCBjb3B5SXNBcnJheSwgY2xvbmUsXG5cdFx0dGFyZ2V0ID0gYXJndW1lbnRzWyAwIF0gfHwge30sXG5cdFx0aSA9IDEsXG5cdFx0bGVuZ3RoID0gYXJndW1lbnRzLmxlbmd0aCxcblx0XHRkZWVwID0gZmFsc2U7XG5cblx0Ly8gSGFuZGxlIGEgZGVlcCBjb3B5IHNpdHVhdGlvblxuXHRpZiAoIHR5cGVvZiB0YXJnZXQgPT09IFwiYm9vbGVhblwiICkge1xuXHRcdGRlZXAgPSB0YXJnZXQ7XG5cblx0XHQvLyBTa2lwIHRoZSBib29sZWFuIGFuZCB0aGUgdGFyZ2V0XG5cdFx0dGFyZ2V0ID0gYXJndW1lbnRzWyBpIF0gfHwge307XG5cdFx0aSsrO1xuXHR9XG5cblx0Ly8gSGFuZGxlIGNhc2Ugd2hlbiB0YXJnZXQgaXMgYSBzdHJpbmcgb3Igc29tZXRoaW5nIChwb3NzaWJsZSBpbiBkZWVwIGNvcHkpXG5cdGlmICggdHlwZW9mIHRhcmdldCAhPT0gXCJvYmplY3RcIiAmJiAhaXNGdW5jdGlvbiggdGFyZ2V0ICkgKSB7XG5cdFx0dGFyZ2V0ID0ge307XG5cdH1cblxuXHQvLyBFeHRlbmQgalF1ZXJ5IGl0c2VsZiBpZiBvbmx5IG9uZSBhcmd1bWVudCBpcyBwYXNzZWRcblx0aWYgKCBpID09PSBsZW5ndGggKSB7XG5cdFx0dGFyZ2V0ID0gdGhpcztcblx0XHRpLS07XG5cdH1cblxuXHRmb3IgKCA7IGkgPCBsZW5ndGg7IGkrKyApIHtcblxuXHRcdC8vIE9ubHkgZGVhbCB3aXRoIG5vbi1udWxsL3VuZGVmaW5lZCB2YWx1ZXNcblx0XHRpZiAoICggb3B0aW9ucyA9IGFyZ3VtZW50c1sgaSBdICkgIT0gbnVsbCApIHtcblxuXHRcdFx0Ly8gRXh0ZW5kIHRoZSBiYXNlIG9iamVjdFxuXHRcdFx0Zm9yICggbmFtZSBpbiBvcHRpb25zICkge1xuXHRcdFx0XHRjb3B5ID0gb3B0aW9uc1sgbmFtZSBdO1xuXG5cdFx0XHRcdC8vIFByZXZlbnQgT2JqZWN0LnByb3RvdHlwZSBwb2xsdXRpb25cblx0XHRcdFx0Ly8gUHJldmVudCBuZXZlci1lbmRpbmcgbG9vcFxuXHRcdFx0XHRpZiAoIG5hbWUgPT09IFwiX19wcm90b19fXCIgfHwgdGFyZ2V0ID09PSBjb3B5ICkge1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gUmVjdXJzZSBpZiB3ZSdyZSBtZXJnaW5nIHBsYWluIG9iamVjdHMgb3IgYXJyYXlzXG5cdFx0XHRcdGlmICggZGVlcCAmJiBjb3B5ICYmICggalF1ZXJ5LmlzUGxhaW5PYmplY3QoIGNvcHkgKSB8fFxuXHRcdFx0XHRcdCggY29weUlzQXJyYXkgPSBBcnJheS5pc0FycmF5KCBjb3B5ICkgKSApICkge1xuXHRcdFx0XHRcdHNyYyA9IHRhcmdldFsgbmFtZSBdO1xuXG5cdFx0XHRcdFx0Ly8gRW5zdXJlIHByb3BlciB0eXBlIGZvciB0aGUgc291cmNlIHZhbHVlXG5cdFx0XHRcdFx0aWYgKCBjb3B5SXNBcnJheSAmJiAhQXJyYXkuaXNBcnJheSggc3JjICkgKSB7XG5cdFx0XHRcdFx0XHRjbG9uZSA9IFtdO1xuXHRcdFx0XHRcdH0gZWxzZSBpZiAoICFjb3B5SXNBcnJheSAmJiAhalF1ZXJ5LmlzUGxhaW5PYmplY3QoIHNyYyApICkge1xuXHRcdFx0XHRcdFx0Y2xvbmUgPSB7fTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0Y2xvbmUgPSBzcmM7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGNvcHlJc0FycmF5ID0gZmFsc2U7XG5cblx0XHRcdFx0XHQvLyBOZXZlciBtb3ZlIG9yaWdpbmFsIG9iamVjdHMsIGNsb25lIHRoZW1cblx0XHRcdFx0XHR0YXJnZXRbIG5hbWUgXSA9IGpRdWVyeS5leHRlbmQoIGRlZXAsIGNsb25lLCBjb3B5ICk7XG5cblx0XHRcdFx0Ly8gRG9uJ3QgYnJpbmcgaW4gdW5kZWZpbmVkIHZhbHVlc1xuXHRcdFx0XHR9IGVsc2UgaWYgKCBjb3B5ICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0dGFyZ2V0WyBuYW1lIF0gPSBjb3B5O1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0Ly8gUmV0dXJuIHRoZSBtb2RpZmllZCBvYmplY3Rcblx0cmV0dXJuIHRhcmdldDtcbn07XG5cbmpRdWVyeS5leHRlbmQoIHtcblxuXHQvLyBVbmlxdWUgZm9yIGVhY2ggY29weSBvZiBqUXVlcnkgb24gdGhlIHBhZ2Vcblx0ZXhwYW5kbzogXCJqUXVlcnlcIiArICggdmVyc2lvbiArIE1hdGgucmFuZG9tKCkgKS5yZXBsYWNlKCAvXFxEL2csIFwiXCIgKSxcblxuXHQvLyBBc3N1bWUgalF1ZXJ5IGlzIHJlYWR5IHdpdGhvdXQgdGhlIHJlYWR5IG1vZHVsZVxuXHRpc1JlYWR5OiB0cnVlLFxuXG5cdGVycm9yOiBmdW5jdGlvbiggbXNnICkge1xuXHRcdHRocm93IG5ldyBFcnJvciggbXNnICk7XG5cdH0sXG5cblx0bm9vcDogZnVuY3Rpb24oKSB7fSxcblxuXHRpc1BsYWluT2JqZWN0OiBmdW5jdGlvbiggb2JqICkge1xuXHRcdHZhciBwcm90bywgQ3RvcjtcblxuXHRcdC8vIERldGVjdCBvYnZpb3VzIG5lZ2F0aXZlc1xuXHRcdC8vIFVzZSB0b1N0cmluZyBpbnN0ZWFkIG9mIGpRdWVyeS50eXBlIHRvIGNhdGNoIGhvc3Qgb2JqZWN0c1xuXHRcdGlmICggIW9iaiB8fCB0b1N0cmluZy5jYWxsKCBvYmogKSAhPT0gXCJbb2JqZWN0IE9iamVjdF1cIiApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHRwcm90byA9IGdldFByb3RvKCBvYmogKTtcblxuXHRcdC8vIE9iamVjdHMgd2l0aCBubyBwcm90b3R5cGUgKGUuZy4sIGBPYmplY3QuY3JlYXRlKCBudWxsIClgKSBhcmUgcGxhaW5cblx0XHRpZiAoICFwcm90byApIHtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH1cblxuXHRcdC8vIE9iamVjdHMgd2l0aCBwcm90b3R5cGUgYXJlIHBsYWluIGlmZiB0aGV5IHdlcmUgY29uc3RydWN0ZWQgYnkgYSBnbG9iYWwgT2JqZWN0IGZ1bmN0aW9uXG5cdFx0Q3RvciA9IGhhc093bi5jYWxsKCBwcm90bywgXCJjb25zdHJ1Y3RvclwiICkgJiYgcHJvdG8uY29uc3RydWN0b3I7XG5cdFx0cmV0dXJuIHR5cGVvZiBDdG9yID09PSBcImZ1bmN0aW9uXCIgJiYgZm5Ub1N0cmluZy5jYWxsKCBDdG9yICkgPT09IE9iamVjdEZ1bmN0aW9uU3RyaW5nO1xuXHR9LFxuXG5cdGlzRW1wdHlPYmplY3Q6IGZ1bmN0aW9uKCBvYmogKSB7XG5cdFx0dmFyIG5hbWU7XG5cblx0XHRmb3IgKCBuYW1lIGluIG9iaiApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cdFx0cmV0dXJuIHRydWU7XG5cdH0sXG5cblx0Ly8gRXZhbHVhdGVzIGEgc2NyaXB0IGluIGEgcHJvdmlkZWQgY29udGV4dDsgZmFsbHMgYmFjayB0byB0aGUgZ2xvYmFsIG9uZVxuXHQvLyBpZiBub3Qgc3BlY2lmaWVkLlxuXHRnbG9iYWxFdmFsOiBmdW5jdGlvbiggY29kZSwgb3B0aW9ucywgZG9jICkge1xuXHRcdERPTUV2YWwoIGNvZGUsIHsgbm9uY2U6IG9wdGlvbnMgJiYgb3B0aW9ucy5ub25jZSB9LCBkb2MgKTtcblx0fSxcblxuXHRlYWNoOiBmdW5jdGlvbiggb2JqLCBjYWxsYmFjayApIHtcblx0XHR2YXIgbGVuZ3RoLCBpID0gMDtcblxuXHRcdGlmICggaXNBcnJheUxpa2UoIG9iaiApICkge1xuXHRcdFx0bGVuZ3RoID0gb2JqLmxlbmd0aDtcblx0XHRcdGZvciAoIDsgaSA8IGxlbmd0aDsgaSsrICkge1xuXHRcdFx0XHRpZiAoIGNhbGxiYWNrLmNhbGwoIG9ialsgaSBdLCBpLCBvYmpbIGkgXSApID09PSBmYWxzZSApIHtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHRmb3IgKCBpIGluIG9iaiApIHtcblx0XHRcdFx0aWYgKCBjYWxsYmFjay5jYWxsKCBvYmpbIGkgXSwgaSwgb2JqWyBpIF0gKSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gb2JqO1xuXHR9LFxuXG5cdC8vIHJlc3VsdHMgaXMgZm9yIGludGVybmFsIHVzYWdlIG9ubHlcblx0bWFrZUFycmF5OiBmdW5jdGlvbiggYXJyLCByZXN1bHRzICkge1xuXHRcdHZhciByZXQgPSByZXN1bHRzIHx8IFtdO1xuXG5cdFx0aWYgKCBhcnIgIT0gbnVsbCApIHtcblx0XHRcdGlmICggaXNBcnJheUxpa2UoIE9iamVjdCggYXJyICkgKSApIHtcblx0XHRcdFx0alF1ZXJ5Lm1lcmdlKCByZXQsXG5cdFx0XHRcdFx0dHlwZW9mIGFyciA9PT0gXCJzdHJpbmdcIiA/XG5cdFx0XHRcdFx0XHRbIGFyciBdIDogYXJyXG5cdFx0XHRcdCk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRwdXNoLmNhbGwoIHJldCwgYXJyICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHJldDtcblx0fSxcblxuXHRpbkFycmF5OiBmdW5jdGlvbiggZWxlbSwgYXJyLCBpICkge1xuXHRcdHJldHVybiBhcnIgPT0gbnVsbCA/IC0xIDogaW5kZXhPZi5jYWxsKCBhcnIsIGVsZW0sIGkgKTtcblx0fSxcblxuXHQvLyBTdXBwb3J0OiBBbmRyb2lkIDw9NC4wIG9ubHksIFBoYW50b21KUyAxIG9ubHlcblx0Ly8gcHVzaC5hcHBseShfLCBhcnJheWxpa2UpIHRocm93cyBvbiBhbmNpZW50IFdlYktpdFxuXHRtZXJnZTogZnVuY3Rpb24oIGZpcnN0LCBzZWNvbmQgKSB7XG5cdFx0dmFyIGxlbiA9ICtzZWNvbmQubGVuZ3RoLFxuXHRcdFx0aiA9IDAsXG5cdFx0XHRpID0gZmlyc3QubGVuZ3RoO1xuXG5cdFx0Zm9yICggOyBqIDwgbGVuOyBqKysgKSB7XG5cdFx0XHRmaXJzdFsgaSsrIF0gPSBzZWNvbmRbIGogXTtcblx0XHR9XG5cblx0XHRmaXJzdC5sZW5ndGggPSBpO1xuXG5cdFx0cmV0dXJuIGZpcnN0O1xuXHR9LFxuXG5cdGdyZXA6IGZ1bmN0aW9uKCBlbGVtcywgY2FsbGJhY2ssIGludmVydCApIHtcblx0XHR2YXIgY2FsbGJhY2tJbnZlcnNlLFxuXHRcdFx0bWF0Y2hlcyA9IFtdLFxuXHRcdFx0aSA9IDAsXG5cdFx0XHRsZW5ndGggPSBlbGVtcy5sZW5ndGgsXG5cdFx0XHRjYWxsYmFja0V4cGVjdCA9ICFpbnZlcnQ7XG5cblx0XHQvLyBHbyB0aHJvdWdoIHRoZSBhcnJheSwgb25seSBzYXZpbmcgdGhlIGl0ZW1zXG5cdFx0Ly8gdGhhdCBwYXNzIHRoZSB2YWxpZGF0b3IgZnVuY3Rpb25cblx0XHRmb3IgKCA7IGkgPCBsZW5ndGg7IGkrKyApIHtcblx0XHRcdGNhbGxiYWNrSW52ZXJzZSA9ICFjYWxsYmFjayggZWxlbXNbIGkgXSwgaSApO1xuXHRcdFx0aWYgKCBjYWxsYmFja0ludmVyc2UgIT09IGNhbGxiYWNrRXhwZWN0ICkge1xuXHRcdFx0XHRtYXRjaGVzLnB1c2goIGVsZW1zWyBpIF0gKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gbWF0Y2hlcztcblx0fSxcblxuXHQvLyBhcmcgaXMgZm9yIGludGVybmFsIHVzYWdlIG9ubHlcblx0bWFwOiBmdW5jdGlvbiggZWxlbXMsIGNhbGxiYWNrLCBhcmcgKSB7XG5cdFx0dmFyIGxlbmd0aCwgdmFsdWUsXG5cdFx0XHRpID0gMCxcblx0XHRcdHJldCA9IFtdO1xuXG5cdFx0Ly8gR28gdGhyb3VnaCB0aGUgYXJyYXksIHRyYW5zbGF0aW5nIGVhY2ggb2YgdGhlIGl0ZW1zIHRvIHRoZWlyIG5ldyB2YWx1ZXNcblx0XHRpZiAoIGlzQXJyYXlMaWtlKCBlbGVtcyApICkge1xuXHRcdFx0bGVuZ3RoID0gZWxlbXMubGVuZ3RoO1xuXHRcdFx0Zm9yICggOyBpIDwgbGVuZ3RoOyBpKysgKSB7XG5cdFx0XHRcdHZhbHVlID0gY2FsbGJhY2soIGVsZW1zWyBpIF0sIGksIGFyZyApO1xuXG5cdFx0XHRcdGlmICggdmFsdWUgIT0gbnVsbCApIHtcblx0XHRcdFx0XHRyZXQucHVzaCggdmFsdWUgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0Ly8gR28gdGhyb3VnaCBldmVyeSBrZXkgb24gdGhlIG9iamVjdCxcblx0XHR9IGVsc2Uge1xuXHRcdFx0Zm9yICggaSBpbiBlbGVtcyApIHtcblx0XHRcdFx0dmFsdWUgPSBjYWxsYmFjayggZWxlbXNbIGkgXSwgaSwgYXJnICk7XG5cblx0XHRcdFx0aWYgKCB2YWx1ZSAhPSBudWxsICkge1xuXHRcdFx0XHRcdHJldC5wdXNoKCB2YWx1ZSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gRmxhdHRlbiBhbnkgbmVzdGVkIGFycmF5c1xuXHRcdHJldHVybiBmbGF0KCByZXQgKTtcblx0fSxcblxuXHQvLyBBIGdsb2JhbCBHVUlEIGNvdW50ZXIgZm9yIG9iamVjdHNcblx0Z3VpZDogMSxcblxuXHQvLyBqUXVlcnkuc3VwcG9ydCBpcyBub3QgdXNlZCBpbiBDb3JlIGJ1dCBvdGhlciBwcm9qZWN0cyBhdHRhY2ggdGhlaXJcblx0Ly8gcHJvcGVydGllcyB0byBpdCBzbyBpdCBuZWVkcyB0byBleGlzdC5cblx0c3VwcG9ydDogc3VwcG9ydFxufSApO1xuXG5pZiAoIHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiApIHtcblx0alF1ZXJ5LmZuWyBTeW1ib2wuaXRlcmF0b3IgXSA9IGFyclsgU3ltYm9sLml0ZXJhdG9yIF07XG59XG5cbi8vIFBvcHVsYXRlIHRoZSBjbGFzczJ0eXBlIG1hcFxualF1ZXJ5LmVhY2goIFwiQm9vbGVhbiBOdW1iZXIgU3RyaW5nIEZ1bmN0aW9uIEFycmF5IERhdGUgUmVnRXhwIE9iamVjdCBFcnJvciBTeW1ib2xcIi5zcGxpdCggXCIgXCIgKSxcblx0ZnVuY3Rpb24oIF9pLCBuYW1lICkge1xuXHRcdGNsYXNzMnR5cGVbIFwiW29iamVjdCBcIiArIG5hbWUgKyBcIl1cIiBdID0gbmFtZS50b0xvd2VyQ2FzZSgpO1xuXHR9ICk7XG5cbmZ1bmN0aW9uIGlzQXJyYXlMaWtlKCBvYmogKSB7XG5cblx0Ly8gU3VwcG9ydDogcmVhbCBpT1MgOC4yIG9ubHkgKG5vdCByZXByb2R1Y2libGUgaW4gc2ltdWxhdG9yKVxuXHQvLyBgaW5gIGNoZWNrIHVzZWQgdG8gcHJldmVudCBKSVQgZXJyb3IgKGdoLTIxNDUpXG5cdC8vIGhhc093biBpc24ndCB1c2VkIGhlcmUgZHVlIHRvIGZhbHNlIG5lZ2F0aXZlc1xuXHQvLyByZWdhcmRpbmcgTm9kZWxpc3QgbGVuZ3RoIGluIElFXG5cdHZhciBsZW5ndGggPSAhIW9iaiAmJiBcImxlbmd0aFwiIGluIG9iaiAmJiBvYmoubGVuZ3RoLFxuXHRcdHR5cGUgPSB0b1R5cGUoIG9iaiApO1xuXG5cdGlmICggaXNGdW5jdGlvbiggb2JqICkgfHwgaXNXaW5kb3coIG9iaiApICkge1xuXHRcdHJldHVybiBmYWxzZTtcblx0fVxuXG5cdHJldHVybiB0eXBlID09PSBcImFycmF5XCIgfHwgbGVuZ3RoID09PSAwIHx8XG5cdFx0dHlwZW9mIGxlbmd0aCA9PT0gXCJudW1iZXJcIiAmJiBsZW5ndGggPiAwICYmICggbGVuZ3RoIC0gMSApIGluIG9iajtcbn1cbnZhciBTaXp6bGUgPVxuLyohXG4gKiBTaXp6bGUgQ1NTIFNlbGVjdG9yIEVuZ2luZSB2Mi4zLjZcbiAqIGh0dHBzOi8vc2l6emxlanMuY29tL1xuICpcbiAqIENvcHlyaWdodCBKUyBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZVxuICogaHR0cHM6Ly9qcy5mb3VuZGF0aW9uL1xuICpcbiAqIERhdGU6IDIwMjEtMDItMTZcbiAqL1xuKCBmdW5jdGlvbiggd2luZG93ICkge1xudmFyIGksXG5cdHN1cHBvcnQsXG5cdEV4cHIsXG5cdGdldFRleHQsXG5cdGlzWE1MLFxuXHR0b2tlbml6ZSxcblx0Y29tcGlsZSxcblx0c2VsZWN0LFxuXHRvdXRlcm1vc3RDb250ZXh0LFxuXHRzb3J0SW5wdXQsXG5cdGhhc0R1cGxpY2F0ZSxcblxuXHQvLyBMb2NhbCBkb2N1bWVudCB2YXJzXG5cdHNldERvY3VtZW50LFxuXHRkb2N1bWVudCxcblx0ZG9jRWxlbSxcblx0ZG9jdW1lbnRJc0hUTUwsXG5cdHJidWdneVFTQSxcblx0cmJ1Z2d5TWF0Y2hlcyxcblx0bWF0Y2hlcyxcblx0Y29udGFpbnMsXG5cblx0Ly8gSW5zdGFuY2Utc3BlY2lmaWMgZGF0YVxuXHRleHBhbmRvID0gXCJzaXp6bGVcIiArIDEgKiBuZXcgRGF0ZSgpLFxuXHRwcmVmZXJyZWREb2MgPSB3aW5kb3cuZG9jdW1lbnQsXG5cdGRpcnJ1bnMgPSAwLFxuXHRkb25lID0gMCxcblx0Y2xhc3NDYWNoZSA9IGNyZWF0ZUNhY2hlKCksXG5cdHRva2VuQ2FjaGUgPSBjcmVhdGVDYWNoZSgpLFxuXHRjb21waWxlckNhY2hlID0gY3JlYXRlQ2FjaGUoKSxcblx0bm9ubmF0aXZlU2VsZWN0b3JDYWNoZSA9IGNyZWF0ZUNhY2hlKCksXG5cdHNvcnRPcmRlciA9IGZ1bmN0aW9uKCBhLCBiICkge1xuXHRcdGlmICggYSA9PT0gYiApIHtcblx0XHRcdGhhc0R1cGxpY2F0ZSA9IHRydWU7XG5cdFx0fVxuXHRcdHJldHVybiAwO1xuXHR9LFxuXG5cdC8vIEluc3RhbmNlIG1ldGhvZHNcblx0aGFzT3duID0gKCB7fSApLmhhc093blByb3BlcnR5LFxuXHRhcnIgPSBbXSxcblx0cG9wID0gYXJyLnBvcCxcblx0cHVzaE5hdGl2ZSA9IGFyci5wdXNoLFxuXHRwdXNoID0gYXJyLnB1c2gsXG5cdHNsaWNlID0gYXJyLnNsaWNlLFxuXG5cdC8vIFVzZSBhIHN0cmlwcGVkLWRvd24gaW5kZXhPZiBhcyBpdCdzIGZhc3RlciB0aGFuIG5hdGl2ZVxuXHQvLyBodHRwczovL2pzcGVyZi5jb20vdGhvci1pbmRleG9mLXZzLWZvci81XG5cdGluZGV4T2YgPSBmdW5jdGlvbiggbGlzdCwgZWxlbSApIHtcblx0XHR2YXIgaSA9IDAsXG5cdFx0XHRsZW4gPSBsaXN0Lmxlbmd0aDtcblx0XHRmb3IgKCA7IGkgPCBsZW47IGkrKyApIHtcblx0XHRcdGlmICggbGlzdFsgaSBdID09PSBlbGVtICkge1xuXHRcdFx0XHRyZXR1cm4gaTtcblx0XHRcdH1cblx0XHR9XG5cdFx0cmV0dXJuIC0xO1xuXHR9LFxuXG5cdGJvb2xlYW5zID0gXCJjaGVja2VkfHNlbGVjdGVkfGFzeW5jfGF1dG9mb2N1c3xhdXRvcGxheXxjb250cm9sc3xkZWZlcnxkaXNhYmxlZHxoaWRkZW58XCIgK1xuXHRcdFwiaXNtYXB8bG9vcHxtdWx0aXBsZXxvcGVufHJlYWRvbmx5fHJlcXVpcmVkfHNjb3BlZFwiLFxuXG5cdC8vIFJlZ3VsYXIgZXhwcmVzc2lvbnNcblxuXHQvLyBodHRwOi8vd3d3LnczLm9yZy9UUi9jc3MzLXNlbGVjdG9ycy8jd2hpdGVzcGFjZVxuXHR3aGl0ZXNwYWNlID0gXCJbXFxcXHgyMFxcXFx0XFxcXHJcXFxcblxcXFxmXVwiLFxuXG5cdC8vIGh0dHBzOi8vd3d3LnczLm9yZy9UUi9jc3Mtc3ludGF4LTMvI2lkZW50LXRva2VuLWRpYWdyYW1cblx0aWRlbnRpZmllciA9IFwiKD86XFxcXFxcXFxbXFxcXGRhLWZBLUZdezEsNn1cIiArIHdoaXRlc3BhY2UgK1xuXHRcdFwiP3xcXFxcXFxcXFteXFxcXHJcXFxcblxcXFxmXXxbXFxcXHctXXxbXlxcMC1cXFxceDdmXSkrXCIsXG5cblx0Ly8gQXR0cmlidXRlIHNlbGVjdG9yczogaHR0cDovL3d3dy53My5vcmcvVFIvc2VsZWN0b3JzLyNhdHRyaWJ1dGUtc2VsZWN0b3JzXG5cdGF0dHJpYnV0ZXMgPSBcIlxcXFxbXCIgKyB3aGl0ZXNwYWNlICsgXCIqKFwiICsgaWRlbnRpZmllciArIFwiKSg/OlwiICsgd2hpdGVzcGFjZSArXG5cblx0XHQvLyBPcGVyYXRvciAoY2FwdHVyZSAyKVxuXHRcdFwiKihbKl4kfCF+XT89KVwiICsgd2hpdGVzcGFjZSArXG5cblx0XHQvLyBcIkF0dHJpYnV0ZSB2YWx1ZXMgbXVzdCBiZSBDU1MgaWRlbnRpZmllcnMgW2NhcHR1cmUgNV1cblx0XHQvLyBvciBzdHJpbmdzIFtjYXB0dXJlIDMgb3IgY2FwdHVyZSA0XVwiXG5cdFx0XCIqKD86JygoPzpcXFxcXFxcXC58W15cXFxcXFxcXCddKSopJ3xcXFwiKCg/OlxcXFxcXFxcLnxbXlxcXFxcXFxcXFxcIl0pKilcXFwifChcIiArIGlkZW50aWZpZXIgKyBcIikpfClcIiArXG5cdFx0d2hpdGVzcGFjZSArIFwiKlxcXFxdXCIsXG5cblx0cHNldWRvcyA9IFwiOihcIiArIGlkZW50aWZpZXIgKyBcIikoPzpcXFxcKChcIiArXG5cblx0XHQvLyBUbyByZWR1Y2UgdGhlIG51bWJlciBvZiBzZWxlY3RvcnMgbmVlZGluZyB0b2tlbml6ZSBpbiB0aGUgcHJlRmlsdGVyLCBwcmVmZXIgYXJndW1lbnRzOlxuXHRcdC8vIDEuIHF1b3RlZCAoY2FwdHVyZSAzOyBjYXB0dXJlIDQgb3IgY2FwdHVyZSA1KVxuXHRcdFwiKCcoKD86XFxcXFxcXFwufFteXFxcXFxcXFwnXSkqKSd8XFxcIigoPzpcXFxcXFxcXC58W15cXFxcXFxcXFxcXCJdKSopXFxcIil8XCIgK1xuXG5cdFx0Ly8gMi4gc2ltcGxlIChjYXB0dXJlIDYpXG5cdFx0XCIoKD86XFxcXFxcXFwufFteXFxcXFxcXFwoKVtcXFxcXV18XCIgKyBhdHRyaWJ1dGVzICsgXCIpKil8XCIgK1xuXG5cdFx0Ly8gMy4gYW55dGhpbmcgZWxzZSAoY2FwdHVyZSAyKVxuXHRcdFwiLipcIiArXG5cdFx0XCIpXFxcXCl8KVwiLFxuXG5cdC8vIExlYWRpbmcgYW5kIG5vbi1lc2NhcGVkIHRyYWlsaW5nIHdoaXRlc3BhY2UsIGNhcHR1cmluZyBzb21lIG5vbi13aGl0ZXNwYWNlIGNoYXJhY3RlcnMgcHJlY2VkaW5nIHRoZSBsYXR0ZXJcblx0cndoaXRlc3BhY2UgPSBuZXcgUmVnRXhwKCB3aGl0ZXNwYWNlICsgXCIrXCIsIFwiZ1wiICksXG5cdHJ0cmltID0gbmV3IFJlZ0V4cCggXCJeXCIgKyB3aGl0ZXNwYWNlICsgXCIrfCgoPzpefFteXFxcXFxcXFxdKSg/OlxcXFxcXFxcLikqKVwiICtcblx0XHR3aGl0ZXNwYWNlICsgXCIrJFwiLCBcImdcIiApLFxuXG5cdHJjb21tYSA9IG5ldyBSZWdFeHAoIFwiXlwiICsgd2hpdGVzcGFjZSArIFwiKixcIiArIHdoaXRlc3BhY2UgKyBcIipcIiApLFxuXHRyY29tYmluYXRvcnMgPSBuZXcgUmVnRXhwKCBcIl5cIiArIHdoaXRlc3BhY2UgKyBcIiooWz4rfl18XCIgKyB3aGl0ZXNwYWNlICsgXCIpXCIgKyB3aGl0ZXNwYWNlICtcblx0XHRcIipcIiApLFxuXHRyZGVzY2VuZCA9IG5ldyBSZWdFeHAoIHdoaXRlc3BhY2UgKyBcInw+XCIgKSxcblxuXHRycHNldWRvID0gbmV3IFJlZ0V4cCggcHNldWRvcyApLFxuXHRyaWRlbnRpZmllciA9IG5ldyBSZWdFeHAoIFwiXlwiICsgaWRlbnRpZmllciArIFwiJFwiICksXG5cblx0bWF0Y2hFeHByID0ge1xuXHRcdFwiSURcIjogbmV3IFJlZ0V4cCggXCJeIyhcIiArIGlkZW50aWZpZXIgKyBcIilcIiApLFxuXHRcdFwiQ0xBU1NcIjogbmV3IFJlZ0V4cCggXCJeXFxcXC4oXCIgKyBpZGVudGlmaWVyICsgXCIpXCIgKSxcblx0XHRcIlRBR1wiOiBuZXcgUmVnRXhwKCBcIl4oXCIgKyBpZGVudGlmaWVyICsgXCJ8WypdKVwiICksXG5cdFx0XCJBVFRSXCI6IG5ldyBSZWdFeHAoIFwiXlwiICsgYXR0cmlidXRlcyApLFxuXHRcdFwiUFNFVURPXCI6IG5ldyBSZWdFeHAoIFwiXlwiICsgcHNldWRvcyApLFxuXHRcdFwiQ0hJTERcIjogbmV3IFJlZ0V4cCggXCJeOihvbmx5fGZpcnN0fGxhc3R8bnRofG50aC1sYXN0KS0oY2hpbGR8b2YtdHlwZSkoPzpcXFxcKFwiICtcblx0XHRcdHdoaXRlc3BhY2UgKyBcIiooZXZlbnxvZGR8KChbKy1dfCkoXFxcXGQqKW58KVwiICsgd2hpdGVzcGFjZSArIFwiKig/OihbKy1dfClcIiArXG5cdFx0XHR3aGl0ZXNwYWNlICsgXCIqKFxcXFxkKyl8KSlcIiArIHdoaXRlc3BhY2UgKyBcIipcXFxcKXwpXCIsIFwiaVwiICksXG5cdFx0XCJib29sXCI6IG5ldyBSZWdFeHAoIFwiXig/OlwiICsgYm9vbGVhbnMgKyBcIikkXCIsIFwiaVwiICksXG5cblx0XHQvLyBGb3IgdXNlIGluIGxpYnJhcmllcyBpbXBsZW1lbnRpbmcgLmlzKClcblx0XHQvLyBXZSB1c2UgdGhpcyBmb3IgUE9TIG1hdGNoaW5nIGluIGBzZWxlY3RgXG5cdFx0XCJuZWVkc0NvbnRleHRcIjogbmV3IFJlZ0V4cCggXCJeXCIgKyB3aGl0ZXNwYWNlICtcblx0XHRcdFwiKls+K35dfDooZXZlbnxvZGR8ZXF8Z3R8bHR8bnRofGZpcnN0fGxhc3QpKD86XFxcXChcIiArIHdoaXRlc3BhY2UgK1xuXHRcdFx0XCIqKCg/Oi1cXFxcZCk/XFxcXGQqKVwiICsgd2hpdGVzcGFjZSArIFwiKlxcXFwpfCkoPz1bXi1dfCQpXCIsIFwiaVwiIClcblx0fSxcblxuXHRyaHRtbCA9IC9IVE1MJC9pLFxuXHRyaW5wdXRzID0gL14oPzppbnB1dHxzZWxlY3R8dGV4dGFyZWF8YnV0dG9uKSQvaSxcblx0cmhlYWRlciA9IC9eaFxcZCQvaSxcblxuXHRybmF0aXZlID0gL15bXntdK1xce1xccypcXFtuYXRpdmUgXFx3LyxcblxuXHQvLyBFYXNpbHktcGFyc2VhYmxlL3JldHJpZXZhYmxlIElEIG9yIFRBRyBvciBDTEFTUyBzZWxlY3RvcnNcblx0cnF1aWNrRXhwciA9IC9eKD86IyhbXFx3LV0rKXwoXFx3Kyl8XFwuKFtcXHctXSspKSQvLFxuXG5cdHJzaWJsaW5nID0gL1srfl0vLFxuXG5cdC8vIENTUyBlc2NhcGVzXG5cdC8vIGh0dHA6Ly93d3cudzMub3JnL1RSL0NTUzIxL3N5bmRhdGEuaHRtbCNlc2NhcGVkLWNoYXJhY3RlcnNcblx0cnVuZXNjYXBlID0gbmV3IFJlZ0V4cCggXCJcXFxcXFxcXFtcXFxcZGEtZkEtRl17MSw2fVwiICsgd2hpdGVzcGFjZSArIFwiP3xcXFxcXFxcXChbXlxcXFxyXFxcXG5cXFxcZl0pXCIsIFwiZ1wiICksXG5cdGZ1bmVzY2FwZSA9IGZ1bmN0aW9uKCBlc2NhcGUsIG5vbkhleCApIHtcblx0XHR2YXIgaGlnaCA9IFwiMHhcIiArIGVzY2FwZS5zbGljZSggMSApIC0gMHgxMDAwMDtcblxuXHRcdHJldHVybiBub25IZXggP1xuXG5cdFx0XHQvLyBTdHJpcCB0aGUgYmFja3NsYXNoIHByZWZpeCBmcm9tIGEgbm9uLWhleCBlc2NhcGUgc2VxdWVuY2Vcblx0XHRcdG5vbkhleCA6XG5cblx0XHRcdC8vIFJlcGxhY2UgYSBoZXhhZGVjaW1hbCBlc2NhcGUgc2VxdWVuY2Ugd2l0aCB0aGUgZW5jb2RlZCBVbmljb2RlIGNvZGUgcG9pbnRcblx0XHRcdC8vIFN1cHBvcnQ6IElFIDw9MTErXG5cdFx0XHQvLyBGb3IgdmFsdWVzIG91dHNpZGUgdGhlIEJhc2ljIE11bHRpbGluZ3VhbCBQbGFuZSAoQk1QKSwgbWFudWFsbHkgY29uc3RydWN0IGFcblx0XHRcdC8vIHN1cnJvZ2F0ZSBwYWlyXG5cdFx0XHRoaWdoIDwgMCA/XG5cdFx0XHRcdFN0cmluZy5mcm9tQ2hhckNvZGUoIGhpZ2ggKyAweDEwMDAwICkgOlxuXHRcdFx0XHRTdHJpbmcuZnJvbUNoYXJDb2RlKCBoaWdoID4+IDEwIHwgMHhEODAwLCBoaWdoICYgMHgzRkYgfCAweERDMDAgKTtcblx0fSxcblxuXHQvLyBDU1Mgc3RyaW5nL2lkZW50aWZpZXIgc2VyaWFsaXphdGlvblxuXHQvLyBodHRwczovL2RyYWZ0cy5jc3N3Zy5vcmcvY3Nzb20vI2NvbW1vbi1zZXJpYWxpemluZy1pZGlvbXNcblx0cmNzc2VzY2FwZSA9IC8oW1xcMC1cXHgxZlxceDdmXXxeLT9cXGQpfF4tJHxbXlxcMC1cXHgxZlxceDdmLVxcdUZGRkZcXHctXS9nLFxuXHRmY3NzZXNjYXBlID0gZnVuY3Rpb24oIGNoLCBhc0NvZGVQb2ludCApIHtcblx0XHRpZiAoIGFzQ29kZVBvaW50ICkge1xuXG5cdFx0XHQvLyBVKzAwMDAgTlVMTCBiZWNvbWVzIFUrRkZGRCBSRVBMQUNFTUVOVCBDSEFSQUNURVJcblx0XHRcdGlmICggY2ggPT09IFwiXFwwXCIgKSB7XG5cdFx0XHRcdHJldHVybiBcIlxcdUZGRkRcIjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ29udHJvbCBjaGFyYWN0ZXJzIGFuZCAoZGVwZW5kZW50IHVwb24gcG9zaXRpb24pIG51bWJlcnMgZ2V0IGVzY2FwZWQgYXMgY29kZSBwb2ludHNcblx0XHRcdHJldHVybiBjaC5zbGljZSggMCwgLTEgKSArIFwiXFxcXFwiICtcblx0XHRcdFx0Y2guY2hhckNvZGVBdCggY2gubGVuZ3RoIC0gMSApLnRvU3RyaW5nKCAxNiApICsgXCIgXCI7XG5cdFx0fVxuXG5cdFx0Ly8gT3RoZXIgcG90ZW50aWFsbHktc3BlY2lhbCBBU0NJSSBjaGFyYWN0ZXJzIGdldCBiYWNrc2xhc2gtZXNjYXBlZFxuXHRcdHJldHVybiBcIlxcXFxcIiArIGNoO1xuXHR9LFxuXG5cdC8vIFVzZWQgZm9yIGlmcmFtZXNcblx0Ly8gU2VlIHNldERvY3VtZW50KClcblx0Ly8gUmVtb3ZpbmcgdGhlIGZ1bmN0aW9uIHdyYXBwZXIgY2F1c2VzIGEgXCJQZXJtaXNzaW9uIERlbmllZFwiXG5cdC8vIGVycm9yIGluIElFXG5cdHVubG9hZEhhbmRsZXIgPSBmdW5jdGlvbigpIHtcblx0XHRzZXREb2N1bWVudCgpO1xuXHR9LFxuXG5cdGluRGlzYWJsZWRGaWVsZHNldCA9IGFkZENvbWJpbmF0b3IoXG5cdFx0ZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gZWxlbS5kaXNhYmxlZCA9PT0gdHJ1ZSAmJiBlbGVtLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IFwiZmllbGRzZXRcIjtcblx0XHR9LFxuXHRcdHsgZGlyOiBcInBhcmVudE5vZGVcIiwgbmV4dDogXCJsZWdlbmRcIiB9XG5cdCk7XG5cbi8vIE9wdGltaXplIGZvciBwdXNoLmFwcGx5KCBfLCBOb2RlTGlzdCApXG50cnkge1xuXHRwdXNoLmFwcGx5KFxuXHRcdCggYXJyID0gc2xpY2UuY2FsbCggcHJlZmVycmVkRG9jLmNoaWxkTm9kZXMgKSApLFxuXHRcdHByZWZlcnJlZERvYy5jaGlsZE5vZGVzXG5cdCk7XG5cblx0Ly8gU3VwcG9ydDogQW5kcm9pZDw0LjBcblx0Ly8gRGV0ZWN0IHNpbGVudGx5IGZhaWxpbmcgcHVzaC5hcHBseVxuXHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW51c2VkLWV4cHJlc3Npb25zXG5cdGFyclsgcHJlZmVycmVkRG9jLmNoaWxkTm9kZXMubGVuZ3RoIF0ubm9kZVR5cGU7XG59IGNhdGNoICggZSApIHtcblx0cHVzaCA9IHsgYXBwbHk6IGFyci5sZW5ndGggP1xuXG5cdFx0Ly8gTGV2ZXJhZ2Ugc2xpY2UgaWYgcG9zc2libGVcblx0XHRmdW5jdGlvbiggdGFyZ2V0LCBlbHMgKSB7XG5cdFx0XHRwdXNoTmF0aXZlLmFwcGx5KCB0YXJnZXQsIHNsaWNlLmNhbGwoIGVscyApICk7XG5cdFx0fSA6XG5cblx0XHQvLyBTdXBwb3J0OiBJRTw5XG5cdFx0Ly8gT3RoZXJ3aXNlIGFwcGVuZCBkaXJlY3RseVxuXHRcdGZ1bmN0aW9uKCB0YXJnZXQsIGVscyApIHtcblx0XHRcdHZhciBqID0gdGFyZ2V0Lmxlbmd0aCxcblx0XHRcdFx0aSA9IDA7XG5cblx0XHRcdC8vIENhbid0IHRydXN0IE5vZGVMaXN0Lmxlbmd0aFxuXHRcdFx0d2hpbGUgKCAoIHRhcmdldFsgaisrIF0gPSBlbHNbIGkrKyBdICkgKSB7fVxuXHRcdFx0dGFyZ2V0Lmxlbmd0aCA9IGogLSAxO1xuXHRcdH1cblx0fTtcbn1cblxuZnVuY3Rpb24gU2l6emxlKCBzZWxlY3RvciwgY29udGV4dCwgcmVzdWx0cywgc2VlZCApIHtcblx0dmFyIG0sIGksIGVsZW0sIG5pZCwgbWF0Y2gsIGdyb3VwcywgbmV3U2VsZWN0b3IsXG5cdFx0bmV3Q29udGV4dCA9IGNvbnRleHQgJiYgY29udGV4dC5vd25lckRvY3VtZW50LFxuXG5cdFx0Ly8gbm9kZVR5cGUgZGVmYXVsdHMgdG8gOSwgc2luY2UgY29udGV4dCBkZWZhdWx0cyB0byBkb2N1bWVudFxuXHRcdG5vZGVUeXBlID0gY29udGV4dCA/IGNvbnRleHQubm9kZVR5cGUgOiA5O1xuXG5cdHJlc3VsdHMgPSByZXN1bHRzIHx8IFtdO1xuXG5cdC8vIFJldHVybiBlYXJseSBmcm9tIGNhbGxzIHdpdGggaW52YWxpZCBzZWxlY3RvciBvciBjb250ZXh0XG5cdGlmICggdHlwZW9mIHNlbGVjdG9yICE9PSBcInN0cmluZ1wiIHx8ICFzZWxlY3RvciB8fFxuXHRcdG5vZGVUeXBlICE9PSAxICYmIG5vZGVUeXBlICE9PSA5ICYmIG5vZGVUeXBlICE9PSAxMSApIHtcblxuXHRcdHJldHVybiByZXN1bHRzO1xuXHR9XG5cblx0Ly8gVHJ5IHRvIHNob3J0Y3V0IGZpbmQgb3BlcmF0aW9ucyAoYXMgb3Bwb3NlZCB0byBmaWx0ZXJzKSBpbiBIVE1MIGRvY3VtZW50c1xuXHRpZiAoICFzZWVkICkge1xuXHRcdHNldERvY3VtZW50KCBjb250ZXh0ICk7XG5cdFx0Y29udGV4dCA9IGNvbnRleHQgfHwgZG9jdW1lbnQ7XG5cblx0XHRpZiAoIGRvY3VtZW50SXNIVE1MICkge1xuXG5cdFx0XHQvLyBJZiB0aGUgc2VsZWN0b3IgaXMgc3VmZmljaWVudGx5IHNpbXBsZSwgdHJ5IHVzaW5nIGEgXCJnZXQqQnkqXCIgRE9NIG1ldGhvZFxuXHRcdFx0Ly8gKGV4Y2VwdGluZyBEb2N1bWVudEZyYWdtZW50IGNvbnRleHQsIHdoZXJlIHRoZSBtZXRob2RzIGRvbid0IGV4aXN0KVxuXHRcdFx0aWYgKCBub2RlVHlwZSAhPT0gMTEgJiYgKCBtYXRjaCA9IHJxdWlja0V4cHIuZXhlYyggc2VsZWN0b3IgKSApICkge1xuXG5cdFx0XHRcdC8vIElEIHNlbGVjdG9yXG5cdFx0XHRcdGlmICggKCBtID0gbWF0Y2hbIDEgXSApICkge1xuXG5cdFx0XHRcdFx0Ly8gRG9jdW1lbnQgY29udGV4dFxuXHRcdFx0XHRcdGlmICggbm9kZVR5cGUgPT09IDkgKSB7XG5cdFx0XHRcdFx0XHRpZiAoICggZWxlbSA9IGNvbnRleHQuZ2V0RWxlbWVudEJ5SWQoIG0gKSApICkge1xuXG5cdFx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFLCBPcGVyYSwgV2Via2l0XG5cdFx0XHRcdFx0XHRcdC8vIFRPRE86IGlkZW50aWZ5IHZlcnNpb25zXG5cdFx0XHRcdFx0XHRcdC8vIGdldEVsZW1lbnRCeUlkIGNhbiBtYXRjaCBlbGVtZW50cyBieSBuYW1lIGluc3RlYWQgb2YgSURcblx0XHRcdFx0XHRcdFx0aWYgKCBlbGVtLmlkID09PSBtICkge1xuXHRcdFx0XHRcdFx0XHRcdHJlc3VsdHMucHVzaCggZWxlbSApO1xuXHRcdFx0XHRcdFx0XHRcdHJldHVybiByZXN1bHRzO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gcmVzdWx0cztcblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIEVsZW1lbnQgY29udGV4dFxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFLCBPcGVyYSwgV2Via2l0XG5cdFx0XHRcdFx0XHQvLyBUT0RPOiBpZGVudGlmeSB2ZXJzaW9uc1xuXHRcdFx0XHRcdFx0Ly8gZ2V0RWxlbWVudEJ5SWQgY2FuIG1hdGNoIGVsZW1lbnRzIGJ5IG5hbWUgaW5zdGVhZCBvZiBJRFxuXHRcdFx0XHRcdFx0aWYgKCBuZXdDb250ZXh0ICYmICggZWxlbSA9IG5ld0NvbnRleHQuZ2V0RWxlbWVudEJ5SWQoIG0gKSApICYmXG5cdFx0XHRcdFx0XHRcdGNvbnRhaW5zKCBjb250ZXh0LCBlbGVtICkgJiZcblx0XHRcdFx0XHRcdFx0ZWxlbS5pZCA9PT0gbSApIHtcblxuXHRcdFx0XHRcdFx0XHRyZXN1bHRzLnB1c2goIGVsZW0gKTtcblx0XHRcdFx0XHRcdFx0cmV0dXJuIHJlc3VsdHM7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFR5cGUgc2VsZWN0b3Jcblx0XHRcdFx0fSBlbHNlIGlmICggbWF0Y2hbIDIgXSApIHtcblx0XHRcdFx0XHRwdXNoLmFwcGx5KCByZXN1bHRzLCBjb250ZXh0LmdldEVsZW1lbnRzQnlUYWdOYW1lKCBzZWxlY3RvciApICk7XG5cdFx0XHRcdFx0cmV0dXJuIHJlc3VsdHM7XG5cblx0XHRcdFx0Ly8gQ2xhc3Mgc2VsZWN0b3Jcblx0XHRcdFx0fSBlbHNlIGlmICggKCBtID0gbWF0Y2hbIDMgXSApICYmIHN1cHBvcnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSAmJlxuXHRcdFx0XHRcdGNvbnRleHQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSApIHtcblxuXHRcdFx0XHRcdHB1c2guYXBwbHkoIHJlc3VsdHMsIGNvbnRleHQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSggbSApICk7XG5cdFx0XHRcdFx0cmV0dXJuIHJlc3VsdHM7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Ly8gVGFrZSBhZHZhbnRhZ2Ugb2YgcXVlcnlTZWxlY3RvckFsbFxuXHRcdFx0aWYgKCBzdXBwb3J0LnFzYSAmJlxuXHRcdFx0XHQhbm9ubmF0aXZlU2VsZWN0b3JDYWNoZVsgc2VsZWN0b3IgKyBcIiBcIiBdICYmXG5cdFx0XHRcdCggIXJidWdneVFTQSB8fCAhcmJ1Z2d5UVNBLnRlc3QoIHNlbGVjdG9yICkgKSAmJlxuXG5cdFx0XHRcdC8vIFN1cHBvcnQ6IElFIDggb25seVxuXHRcdFx0XHQvLyBFeGNsdWRlIG9iamVjdCBlbGVtZW50c1xuXHRcdFx0XHQoIG5vZGVUeXBlICE9PSAxIHx8IGNvbnRleHQubm9kZU5hbWUudG9Mb3dlckNhc2UoKSAhPT0gXCJvYmplY3RcIiApICkge1xuXG5cdFx0XHRcdG5ld1NlbGVjdG9yID0gc2VsZWN0b3I7XG5cdFx0XHRcdG5ld0NvbnRleHQgPSBjb250ZXh0O1xuXG5cdFx0XHRcdC8vIHFTQSBjb25zaWRlcnMgZWxlbWVudHMgb3V0c2lkZSBhIHNjb3Bpbmcgcm9vdCB3aGVuIGV2YWx1YXRpbmcgY2hpbGQgb3Jcblx0XHRcdFx0Ly8gZGVzY2VuZGFudCBjb21iaW5hdG9ycywgd2hpY2ggaXMgbm90IHdoYXQgd2Ugd2FudC5cblx0XHRcdFx0Ly8gSW4gc3VjaCBjYXNlcywgd2Ugd29yayBhcm91bmQgdGhlIGJlaGF2aW9yIGJ5IHByZWZpeGluZyBldmVyeSBzZWxlY3RvciBpbiB0aGVcblx0XHRcdFx0Ly8gbGlzdCB3aXRoIGFuIElEIHNlbGVjdG9yIHJlZmVyZW5jaW5nIHRoZSBzY29wZSBjb250ZXh0LlxuXHRcdFx0XHQvLyBUaGUgdGVjaG5pcXVlIGhhcyB0byBiZSB1c2VkIGFzIHdlbGwgd2hlbiBhIGxlYWRpbmcgY29tYmluYXRvciBpcyB1c2VkXG5cdFx0XHRcdC8vIGFzIHN1Y2ggc2VsZWN0b3JzIGFyZSBub3QgcmVjb2duaXplZCBieSBxdWVyeVNlbGVjdG9yQWxsLlxuXHRcdFx0XHQvLyBUaGFua3MgdG8gQW5kcmV3IER1cG9udCBmb3IgdGhpcyB0ZWNobmlxdWUuXG5cdFx0XHRcdGlmICggbm9kZVR5cGUgPT09IDEgJiZcblx0XHRcdFx0XHQoIHJkZXNjZW5kLnRlc3QoIHNlbGVjdG9yICkgfHwgcmNvbWJpbmF0b3JzLnRlc3QoIHNlbGVjdG9yICkgKSApIHtcblxuXHRcdFx0XHRcdC8vIEV4cGFuZCBjb250ZXh0IGZvciBzaWJsaW5nIHNlbGVjdG9yc1xuXHRcdFx0XHRcdG5ld0NvbnRleHQgPSByc2libGluZy50ZXN0KCBzZWxlY3RvciApICYmIHRlc3RDb250ZXh0KCBjb250ZXh0LnBhcmVudE5vZGUgKSB8fFxuXHRcdFx0XHRcdFx0Y29udGV4dDtcblxuXHRcdFx0XHRcdC8vIFdlIGNhbiB1c2UgOnNjb3BlIGluc3RlYWQgb2YgdGhlIElEIGhhY2sgaWYgdGhlIGJyb3dzZXJcblx0XHRcdFx0XHQvLyBzdXBwb3J0cyBpdCAmIGlmIHdlJ3JlIG5vdCBjaGFuZ2luZyB0aGUgY29udGV4dC5cblx0XHRcdFx0XHRpZiAoIG5ld0NvbnRleHQgIT09IGNvbnRleHQgfHwgIXN1cHBvcnQuc2NvcGUgKSB7XG5cblx0XHRcdFx0XHRcdC8vIENhcHR1cmUgdGhlIGNvbnRleHQgSUQsIHNldHRpbmcgaXQgZmlyc3QgaWYgbmVjZXNzYXJ5XG5cdFx0XHRcdFx0XHRpZiAoICggbmlkID0gY29udGV4dC5nZXRBdHRyaWJ1dGUoIFwiaWRcIiApICkgKSB7XG5cdFx0XHRcdFx0XHRcdG5pZCA9IG5pZC5yZXBsYWNlKCByY3NzZXNjYXBlLCBmY3NzZXNjYXBlICk7XG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRjb250ZXh0LnNldEF0dHJpYnV0ZSggXCJpZFwiLCAoIG5pZCA9IGV4cGFuZG8gKSApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIFByZWZpeCBldmVyeSBzZWxlY3RvciBpbiB0aGUgbGlzdFxuXHRcdFx0XHRcdGdyb3VwcyA9IHRva2VuaXplKCBzZWxlY3RvciApO1xuXHRcdFx0XHRcdGkgPSBncm91cHMubGVuZ3RoO1xuXHRcdFx0XHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0XHRcdFx0Z3JvdXBzWyBpIF0gPSAoIG5pZCA/IFwiI1wiICsgbmlkIDogXCI6c2NvcGVcIiApICsgXCIgXCIgK1xuXHRcdFx0XHRcdFx0XHR0b1NlbGVjdG9yKCBncm91cHNbIGkgXSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRuZXdTZWxlY3RvciA9IGdyb3Vwcy5qb2luKCBcIixcIiApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRwdXNoLmFwcGx5KCByZXN1bHRzLFxuXHRcdFx0XHRcdFx0bmV3Q29udGV4dC5xdWVyeVNlbGVjdG9yQWxsKCBuZXdTZWxlY3RvciApXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRyZXR1cm4gcmVzdWx0cztcblx0XHRcdFx0fSBjYXRjaCAoIHFzYUVycm9yICkge1xuXHRcdFx0XHRcdG5vbm5hdGl2ZVNlbGVjdG9yQ2FjaGUoIHNlbGVjdG9yLCB0cnVlICk7XG5cdFx0XHRcdH0gZmluYWxseSB7XG5cdFx0XHRcdFx0aWYgKCBuaWQgPT09IGV4cGFuZG8gKSB7XG5cdFx0XHRcdFx0XHRjb250ZXh0LnJlbW92ZUF0dHJpYnV0ZSggXCJpZFwiICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0Ly8gQWxsIG90aGVyc1xuXHRyZXR1cm4gc2VsZWN0KCBzZWxlY3Rvci5yZXBsYWNlKCBydHJpbSwgXCIkMVwiICksIGNvbnRleHQsIHJlc3VsdHMsIHNlZWQgKTtcbn1cblxuLyoqXG4gKiBDcmVhdGUga2V5LXZhbHVlIGNhY2hlcyBvZiBsaW1pdGVkIHNpemVcbiAqIEByZXR1cm5zIHtmdW5jdGlvbihzdHJpbmcsIG9iamVjdCl9IFJldHVybnMgdGhlIE9iamVjdCBkYXRhIGFmdGVyIHN0b3JpbmcgaXQgb24gaXRzZWxmIHdpdGhcbiAqXHRwcm9wZXJ0eSBuYW1lIHRoZSAoc3BhY2Utc3VmZml4ZWQpIHN0cmluZyBhbmQgKGlmIHRoZSBjYWNoZSBpcyBsYXJnZXIgdGhhbiBFeHByLmNhY2hlTGVuZ3RoKVxuICpcdGRlbGV0aW5nIHRoZSBvbGRlc3QgZW50cnlcbiAqL1xuZnVuY3Rpb24gY3JlYXRlQ2FjaGUoKSB7XG5cdHZhciBrZXlzID0gW107XG5cblx0ZnVuY3Rpb24gY2FjaGUoIGtleSwgdmFsdWUgKSB7XG5cblx0XHQvLyBVc2UgKGtleSArIFwiIFwiKSB0byBhdm9pZCBjb2xsaXNpb24gd2l0aCBuYXRpdmUgcHJvdG90eXBlIHByb3BlcnRpZXMgKHNlZSBJc3N1ZSAjMTU3KVxuXHRcdGlmICgga2V5cy5wdXNoKCBrZXkgKyBcIiBcIiApID4gRXhwci5jYWNoZUxlbmd0aCApIHtcblxuXHRcdFx0Ly8gT25seSBrZWVwIHRoZSBtb3N0IHJlY2VudCBlbnRyaWVzXG5cdFx0XHRkZWxldGUgY2FjaGVbIGtleXMuc2hpZnQoKSBdO1xuXHRcdH1cblx0XHRyZXR1cm4gKCBjYWNoZVsga2V5ICsgXCIgXCIgXSA9IHZhbHVlICk7XG5cdH1cblx0cmV0dXJuIGNhY2hlO1xufVxuXG4vKipcbiAqIE1hcmsgYSBmdW5jdGlvbiBmb3Igc3BlY2lhbCB1c2UgYnkgU2l6emxlXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiBUaGUgZnVuY3Rpb24gdG8gbWFya1xuICovXG5mdW5jdGlvbiBtYXJrRnVuY3Rpb24oIGZuICkge1xuXHRmblsgZXhwYW5kbyBdID0gdHJ1ZTtcblx0cmV0dXJuIGZuO1xufVxuXG4vKipcbiAqIFN1cHBvcnQgdGVzdGluZyB1c2luZyBhbiBlbGVtZW50XG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiBQYXNzZWQgdGhlIGNyZWF0ZWQgZWxlbWVudCBhbmQgcmV0dXJucyBhIGJvb2xlYW4gcmVzdWx0XG4gKi9cbmZ1bmN0aW9uIGFzc2VydCggZm4gKSB7XG5cdHZhciBlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwiZmllbGRzZXRcIiApO1xuXG5cdHRyeSB7XG5cdFx0cmV0dXJuICEhZm4oIGVsICk7XG5cdH0gY2F0Y2ggKCBlICkge1xuXHRcdHJldHVybiBmYWxzZTtcblx0fSBmaW5hbGx5IHtcblxuXHRcdC8vIFJlbW92ZSBmcm9tIGl0cyBwYXJlbnQgYnkgZGVmYXVsdFxuXHRcdGlmICggZWwucGFyZW50Tm9kZSApIHtcblx0XHRcdGVsLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoIGVsICk7XG5cdFx0fVxuXG5cdFx0Ly8gcmVsZWFzZSBtZW1vcnkgaW4gSUVcblx0XHRlbCA9IG51bGw7XG5cdH1cbn1cblxuLyoqXG4gKiBBZGRzIHRoZSBzYW1lIGhhbmRsZXIgZm9yIGFsbCBvZiB0aGUgc3BlY2lmaWVkIGF0dHJzXG4gKiBAcGFyYW0ge1N0cmluZ30gYXR0cnMgUGlwZS1zZXBhcmF0ZWQgbGlzdCBvZiBhdHRyaWJ1dGVzXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBoYW5kbGVyIFRoZSBtZXRob2QgdGhhdCB3aWxsIGJlIGFwcGxpZWRcbiAqL1xuZnVuY3Rpb24gYWRkSGFuZGxlKCBhdHRycywgaGFuZGxlciApIHtcblx0dmFyIGFyciA9IGF0dHJzLnNwbGl0KCBcInxcIiApLFxuXHRcdGkgPSBhcnIubGVuZ3RoO1xuXG5cdHdoaWxlICggaS0tICkge1xuXHRcdEV4cHIuYXR0ckhhbmRsZVsgYXJyWyBpIF0gXSA9IGhhbmRsZXI7XG5cdH1cbn1cblxuLyoqXG4gKiBDaGVja3MgZG9jdW1lbnQgb3JkZXIgb2YgdHdvIHNpYmxpbmdzXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGFcbiAqIEBwYXJhbSB7RWxlbWVudH0gYlxuICogQHJldHVybnMge051bWJlcn0gUmV0dXJucyBsZXNzIHRoYW4gMCBpZiBhIHByZWNlZGVzIGIsIGdyZWF0ZXIgdGhhbiAwIGlmIGEgZm9sbG93cyBiXG4gKi9cbmZ1bmN0aW9uIHNpYmxpbmdDaGVjayggYSwgYiApIHtcblx0dmFyIGN1ciA9IGIgJiYgYSxcblx0XHRkaWZmID0gY3VyICYmIGEubm9kZVR5cGUgPT09IDEgJiYgYi5ub2RlVHlwZSA9PT0gMSAmJlxuXHRcdFx0YS5zb3VyY2VJbmRleCAtIGIuc291cmNlSW5kZXg7XG5cblx0Ly8gVXNlIElFIHNvdXJjZUluZGV4IGlmIGF2YWlsYWJsZSBvbiBib3RoIG5vZGVzXG5cdGlmICggZGlmZiApIHtcblx0XHRyZXR1cm4gZGlmZjtcblx0fVxuXG5cdC8vIENoZWNrIGlmIGIgZm9sbG93cyBhXG5cdGlmICggY3VyICkge1xuXHRcdHdoaWxlICggKCBjdXIgPSBjdXIubmV4dFNpYmxpbmcgKSApIHtcblx0XHRcdGlmICggY3VyID09PSBiICkge1xuXHRcdFx0XHRyZXR1cm4gLTE7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIGEgPyAxIDogLTE7XG59XG5cbi8qKlxuICogUmV0dXJucyBhIGZ1bmN0aW9uIHRvIHVzZSBpbiBwc2V1ZG9zIGZvciBpbnB1dCB0eXBlc1xuICogQHBhcmFtIHtTdHJpbmd9IHR5cGVcbiAqL1xuZnVuY3Rpb24gY3JlYXRlSW5wdXRQc2V1ZG8oIHR5cGUgKSB7XG5cdHJldHVybiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHR2YXIgbmFtZSA9IGVsZW0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtcblx0XHRyZXR1cm4gbmFtZSA9PT0gXCJpbnB1dFwiICYmIGVsZW0udHlwZSA9PT0gdHlwZTtcblx0fTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIGEgZnVuY3Rpb24gdG8gdXNlIGluIHBzZXVkb3MgZm9yIGJ1dHRvbnNcbiAqIEBwYXJhbSB7U3RyaW5nfSB0eXBlXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUJ1dHRvblBzZXVkbyggdHlwZSApIHtcblx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdHZhciBuYW1lID0gZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xuXHRcdHJldHVybiAoIG5hbWUgPT09IFwiaW5wdXRcIiB8fCBuYW1lID09PSBcImJ1dHRvblwiICkgJiYgZWxlbS50eXBlID09PSB0eXBlO1xuXHR9O1xufVxuXG4vKipcbiAqIFJldHVybnMgYSBmdW5jdGlvbiB0byB1c2UgaW4gcHNldWRvcyBmb3IgOmVuYWJsZWQvOmRpc2FibGVkXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGRpc2FibGVkIHRydWUgZm9yIDpkaXNhYmxlZDsgZmFsc2UgZm9yIDplbmFibGVkXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZURpc2FibGVkUHNldWRvKCBkaXNhYmxlZCApIHtcblxuXHQvLyBLbm93biA6ZGlzYWJsZWQgZmFsc2UgcG9zaXRpdmVzOiBmaWVsZHNldFtkaXNhYmxlZF0gPiBsZWdlbmQ6bnRoLW9mLXR5cGUobisyKSA6Y2FuLWRpc2FibGVcblx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkge1xuXG5cdFx0Ly8gT25seSBjZXJ0YWluIGVsZW1lbnRzIGNhbiBtYXRjaCA6ZW5hYmxlZCBvciA6ZGlzYWJsZWRcblx0XHQvLyBodHRwczovL2h0bWwuc3BlYy53aGF0d2cub3JnL211bHRpcGFnZS9zY3JpcHRpbmcuaHRtbCNzZWxlY3Rvci1lbmFibGVkXG5cdFx0Ly8gaHR0cHM6Ly9odG1sLnNwZWMud2hhdHdnLm9yZy9tdWx0aXBhZ2Uvc2NyaXB0aW5nLmh0bWwjc2VsZWN0b3ItZGlzYWJsZWRcblx0XHRpZiAoIFwiZm9ybVwiIGluIGVsZW0gKSB7XG5cblx0XHRcdC8vIENoZWNrIGZvciBpbmhlcml0ZWQgZGlzYWJsZWRuZXNzIG9uIHJlbGV2YW50IG5vbi1kaXNhYmxlZCBlbGVtZW50czpcblx0XHRcdC8vICogbGlzdGVkIGZvcm0tYXNzb2NpYXRlZCBlbGVtZW50cyBpbiBhIGRpc2FibGVkIGZpZWxkc2V0XG5cdFx0XHQvLyAgIGh0dHBzOi8vaHRtbC5zcGVjLndoYXR3Zy5vcmcvbXVsdGlwYWdlL2Zvcm1zLmh0bWwjY2F0ZWdvcnktbGlzdGVkXG5cdFx0XHQvLyAgIGh0dHBzOi8vaHRtbC5zcGVjLndoYXR3Zy5vcmcvbXVsdGlwYWdlL2Zvcm1zLmh0bWwjY29uY2VwdC1mZS1kaXNhYmxlZFxuXHRcdFx0Ly8gKiBvcHRpb24gZWxlbWVudHMgaW4gYSBkaXNhYmxlZCBvcHRncm91cFxuXHRcdFx0Ly8gICBodHRwczovL2h0bWwuc3BlYy53aGF0d2cub3JnL211bHRpcGFnZS9mb3Jtcy5odG1sI2NvbmNlcHQtb3B0aW9uLWRpc2FibGVkXG5cdFx0XHQvLyBBbGwgc3VjaCBlbGVtZW50cyBoYXZlIGEgXCJmb3JtXCIgcHJvcGVydHkuXG5cdFx0XHRpZiAoIGVsZW0ucGFyZW50Tm9kZSAmJiBlbGVtLmRpc2FibGVkID09PSBmYWxzZSApIHtcblxuXHRcdFx0XHQvLyBPcHRpb24gZWxlbWVudHMgZGVmZXIgdG8gYSBwYXJlbnQgb3B0Z3JvdXAgaWYgcHJlc2VudFxuXHRcdFx0XHRpZiAoIFwibGFiZWxcIiBpbiBlbGVtICkge1xuXHRcdFx0XHRcdGlmICggXCJsYWJlbFwiIGluIGVsZW0ucGFyZW50Tm9kZSApIHtcblx0XHRcdFx0XHRcdHJldHVybiBlbGVtLnBhcmVudE5vZGUuZGlzYWJsZWQgPT09IGRpc2FibGVkO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZWxlbS5kaXNhYmxlZCA9PT0gZGlzYWJsZWQ7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gU3VwcG9ydDogSUUgNiAtIDExXG5cdFx0XHRcdC8vIFVzZSB0aGUgaXNEaXNhYmxlZCBzaG9ydGN1dCBwcm9wZXJ0eSB0byBjaGVjayBmb3IgZGlzYWJsZWQgZmllbGRzZXQgYW5jZXN0b3JzXG5cdFx0XHRcdHJldHVybiBlbGVtLmlzRGlzYWJsZWQgPT09IGRpc2FibGVkIHx8XG5cblx0XHRcdFx0XHQvLyBXaGVyZSB0aGVyZSBpcyBubyBpc0Rpc2FibGVkLCBjaGVjayBtYW51YWxseVxuXHRcdFx0XHRcdC8qIGpzaGludCAtVzAxOCAqL1xuXHRcdFx0XHRcdGVsZW0uaXNEaXNhYmxlZCAhPT0gIWRpc2FibGVkICYmXG5cdFx0XHRcdFx0aW5EaXNhYmxlZEZpZWxkc2V0KCBlbGVtICkgPT09IGRpc2FibGVkO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gZWxlbS5kaXNhYmxlZCA9PT0gZGlzYWJsZWQ7XG5cblx0XHQvLyBUcnkgdG8gd2lubm93IG91dCBlbGVtZW50cyB0aGF0IGNhbid0IGJlIGRpc2FibGVkIGJlZm9yZSB0cnVzdGluZyB0aGUgZGlzYWJsZWQgcHJvcGVydHkuXG5cdFx0Ly8gU29tZSB2aWN0aW1zIGdldCBjYXVnaHQgaW4gb3VyIG5ldCAobGFiZWwsIGxlZ2VuZCwgbWVudSwgdHJhY2spLCBidXQgaXQgc2hvdWxkbid0XG5cdFx0Ly8gZXZlbiBleGlzdCBvbiB0aGVtLCBsZXQgYWxvbmUgaGF2ZSBhIGJvb2xlYW4gdmFsdWUuXG5cdFx0fSBlbHNlIGlmICggXCJsYWJlbFwiIGluIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gZWxlbS5kaXNhYmxlZCA9PT0gZGlzYWJsZWQ7XG5cdFx0fVxuXG5cdFx0Ly8gUmVtYWluaW5nIGVsZW1lbnRzIGFyZSBuZWl0aGVyIDplbmFibGVkIG5vciA6ZGlzYWJsZWRcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH07XG59XG5cbi8qKlxuICogUmV0dXJucyBhIGZ1bmN0aW9uIHRvIHVzZSBpbiBwc2V1ZG9zIGZvciBwb3NpdGlvbmFsc1xuICogQHBhcmFtIHtGdW5jdGlvbn0gZm5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlUG9zaXRpb25hbFBzZXVkbyggZm4gKSB7XG5cdHJldHVybiBtYXJrRnVuY3Rpb24oIGZ1bmN0aW9uKCBhcmd1bWVudCApIHtcblx0XHRhcmd1bWVudCA9ICthcmd1bWVudDtcblx0XHRyZXR1cm4gbWFya0Z1bmN0aW9uKCBmdW5jdGlvbiggc2VlZCwgbWF0Y2hlcyApIHtcblx0XHRcdHZhciBqLFxuXHRcdFx0XHRtYXRjaEluZGV4ZXMgPSBmbiggW10sIHNlZWQubGVuZ3RoLCBhcmd1bWVudCApLFxuXHRcdFx0XHRpID0gbWF0Y2hJbmRleGVzLmxlbmd0aDtcblxuXHRcdFx0Ly8gTWF0Y2ggZWxlbWVudHMgZm91bmQgYXQgdGhlIHNwZWNpZmllZCBpbmRleGVzXG5cdFx0XHR3aGlsZSAoIGktLSApIHtcblx0XHRcdFx0aWYgKCBzZWVkWyAoIGogPSBtYXRjaEluZGV4ZXNbIGkgXSApIF0gKSB7XG5cdFx0XHRcdFx0c2VlZFsgaiBdID0gISggbWF0Y2hlc1sgaiBdID0gc2VlZFsgaiBdICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9ICk7XG5cdH0gKTtcbn1cblxuLyoqXG4gKiBDaGVja3MgYSBub2RlIGZvciB2YWxpZGl0eSBhcyBhIFNpenpsZSBjb250ZXh0XG4gKiBAcGFyYW0ge0VsZW1lbnR8T2JqZWN0PX0gY29udGV4dFxuICogQHJldHVybnMge0VsZW1lbnR8T2JqZWN0fEJvb2xlYW59IFRoZSBpbnB1dCBub2RlIGlmIGFjY2VwdGFibGUsIG90aGVyd2lzZSBhIGZhbHN5IHZhbHVlXG4gKi9cbmZ1bmN0aW9uIHRlc3RDb250ZXh0KCBjb250ZXh0ICkge1xuXHRyZXR1cm4gY29udGV4dCAmJiB0eXBlb2YgY29udGV4dC5nZXRFbGVtZW50c0J5VGFnTmFtZSAhPT0gXCJ1bmRlZmluZWRcIiAmJiBjb250ZXh0O1xufVxuXG4vLyBFeHBvc2Ugc3VwcG9ydCB2YXJzIGZvciBjb252ZW5pZW5jZVxuc3VwcG9ydCA9IFNpenpsZS5zdXBwb3J0ID0ge307XG5cbi8qKlxuICogRGV0ZWN0cyBYTUwgbm9kZXNcbiAqIEBwYXJhbSB7RWxlbWVudHxPYmplY3R9IGVsZW0gQW4gZWxlbWVudCBvciBhIGRvY3VtZW50XG4gKiBAcmV0dXJucyB7Qm9vbGVhbn0gVHJ1ZSBpZmYgZWxlbSBpcyBhIG5vbi1IVE1MIFhNTCBub2RlXG4gKi9cbmlzWE1MID0gU2l6emxlLmlzWE1MID0gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdHZhciBuYW1lc3BhY2UgPSBlbGVtICYmIGVsZW0ubmFtZXNwYWNlVVJJLFxuXHRcdGRvY0VsZW0gPSBlbGVtICYmICggZWxlbS5vd25lckRvY3VtZW50IHx8IGVsZW0gKS5kb2N1bWVudEVsZW1lbnQ7XG5cblx0Ly8gU3VwcG9ydDogSUUgPD04XG5cdC8vIEFzc3VtZSBIVE1MIHdoZW4gZG9jdW1lbnRFbGVtZW50IGRvZXNuJ3QgeWV0IGV4aXN0LCBzdWNoIGFzIGluc2lkZSBsb2FkaW5nIGlmcmFtZXNcblx0Ly8gaHR0cHM6Ly9idWdzLmpxdWVyeS5jb20vdGlja2V0LzQ4MzNcblx0cmV0dXJuICFyaHRtbC50ZXN0KCBuYW1lc3BhY2UgfHwgZG9jRWxlbSAmJiBkb2NFbGVtLm5vZGVOYW1lIHx8IFwiSFRNTFwiICk7XG59O1xuXG4vKipcbiAqIFNldHMgZG9jdW1lbnQtcmVsYXRlZCB2YXJpYWJsZXMgb25jZSBiYXNlZCBvbiB0aGUgY3VycmVudCBkb2N1bWVudFxuICogQHBhcmFtIHtFbGVtZW50fE9iamVjdH0gW2RvY10gQW4gZWxlbWVudCBvciBkb2N1bWVudCBvYmplY3QgdG8gdXNlIHRvIHNldCB0aGUgZG9jdW1lbnRcbiAqIEByZXR1cm5zIHtPYmplY3R9IFJldHVybnMgdGhlIGN1cnJlbnQgZG9jdW1lbnRcbiAqL1xuc2V0RG9jdW1lbnQgPSBTaXp6bGUuc2V0RG9jdW1lbnQgPSBmdW5jdGlvbiggbm9kZSApIHtcblx0dmFyIGhhc0NvbXBhcmUsIHN1YldpbmRvdyxcblx0XHRkb2MgPSBub2RlID8gbm9kZS5vd25lckRvY3VtZW50IHx8IG5vZGUgOiBwcmVmZXJyZWREb2M7XG5cblx0Ly8gUmV0dXJuIGVhcmx5IGlmIGRvYyBpcyBpbnZhbGlkIG9yIGFscmVhZHkgc2VsZWN0ZWRcblx0Ly8gU3VwcG9ydDogSUUgMTErLCBFZGdlIDE3IC0gMTgrXG5cdC8vIElFL0VkZ2Ugc29tZXRpbWVzIHRocm93IGEgXCJQZXJtaXNzaW9uIGRlbmllZFwiIGVycm9yIHdoZW4gc3RyaWN0LWNvbXBhcmluZ1xuXHQvLyB0d28gZG9jdW1lbnRzOyBzaGFsbG93IGNvbXBhcmlzb25zIHdvcmsuXG5cdC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBlcWVxZXFcblx0aWYgKCBkb2MgPT0gZG9jdW1lbnQgfHwgZG9jLm5vZGVUeXBlICE9PSA5IHx8ICFkb2MuZG9jdW1lbnRFbGVtZW50ICkge1xuXHRcdHJldHVybiBkb2N1bWVudDtcblx0fVxuXG5cdC8vIFVwZGF0ZSBnbG9iYWwgdmFyaWFibGVzXG5cdGRvY3VtZW50ID0gZG9jO1xuXHRkb2NFbGVtID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50O1xuXHRkb2N1bWVudElzSFRNTCA9ICFpc1hNTCggZG9jdW1lbnQgKTtcblxuXHQvLyBTdXBwb3J0OiBJRSA5IC0gMTErLCBFZGdlIDEyIC0gMTgrXG5cdC8vIEFjY2Vzc2luZyBpZnJhbWUgZG9jdW1lbnRzIGFmdGVyIHVubG9hZCB0aHJvd3MgXCJwZXJtaXNzaW9uIGRlbmllZFwiIGVycm9ycyAoalF1ZXJ5ICMxMzkzNilcblx0Ly8gU3VwcG9ydDogSUUgMTErLCBFZGdlIDE3IC0gMTgrXG5cdC8vIElFL0VkZ2Ugc29tZXRpbWVzIHRocm93IGEgXCJQZXJtaXNzaW9uIGRlbmllZFwiIGVycm9yIHdoZW4gc3RyaWN0LWNvbXBhcmluZ1xuXHQvLyB0d28gZG9jdW1lbnRzOyBzaGFsbG93IGNvbXBhcmlzb25zIHdvcmsuXG5cdC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBlcWVxZXFcblx0aWYgKCBwcmVmZXJyZWREb2MgIT0gZG9jdW1lbnQgJiZcblx0XHQoIHN1YldpbmRvdyA9IGRvY3VtZW50LmRlZmF1bHRWaWV3ICkgJiYgc3ViV2luZG93LnRvcCAhPT0gc3ViV2luZG93ICkge1xuXG5cdFx0Ly8gU3VwcG9ydDogSUUgMTEsIEVkZ2Vcblx0XHRpZiAoIHN1YldpbmRvdy5hZGRFdmVudExpc3RlbmVyICkge1xuXHRcdFx0c3ViV2luZG93LmFkZEV2ZW50TGlzdGVuZXIoIFwidW5sb2FkXCIsIHVubG9hZEhhbmRsZXIsIGZhbHNlICk7XG5cblx0XHQvLyBTdXBwb3J0OiBJRSA5IC0gMTAgb25seVxuXHRcdH0gZWxzZSBpZiAoIHN1YldpbmRvdy5hdHRhY2hFdmVudCApIHtcblx0XHRcdHN1YldpbmRvdy5hdHRhY2hFdmVudCggXCJvbnVubG9hZFwiLCB1bmxvYWRIYW5kbGVyICk7XG5cdFx0fVxuXHR9XG5cblx0Ly8gU3VwcG9ydDogSUUgOCAtIDExKywgRWRnZSAxMiAtIDE4KywgQ2hyb21lIDw9MTYgLSAyNSBvbmx5LCBGaXJlZm94IDw9My42IC0gMzEgb25seSxcblx0Ly8gU2FmYXJpIDQgLSA1IG9ubHksIE9wZXJhIDw9MTEuNiAtIDEyLnggb25seVxuXHQvLyBJRS9FZGdlICYgb2xkZXIgYnJvd3NlcnMgZG9uJ3Qgc3VwcG9ydCB0aGUgOnNjb3BlIHBzZXVkby1jbGFzcy5cblx0Ly8gU3VwcG9ydDogU2FmYXJpIDYuMCBvbmx5XG5cdC8vIFNhZmFyaSA2LjAgc3VwcG9ydHMgOnNjb3BlIGJ1dCBpdCdzIGFuIGFsaWFzIG9mIDpyb290IHRoZXJlLlxuXHRzdXBwb3J0LnNjb3BlID0gYXNzZXJ0KCBmdW5jdGlvbiggZWwgKSB7XG5cdFx0ZG9jRWxlbS5hcHBlbmRDaGlsZCggZWwgKS5hcHBlbmRDaGlsZCggZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggXCJkaXZcIiApICk7XG5cdFx0cmV0dXJuIHR5cGVvZiBlbC5xdWVyeVNlbGVjdG9yQWxsICE9PSBcInVuZGVmaW5lZFwiICYmXG5cdFx0XHQhZWwucXVlcnlTZWxlY3RvckFsbCggXCI6c2NvcGUgZmllbGRzZXQgZGl2XCIgKS5sZW5ndGg7XG5cdH0gKTtcblxuXHQvKiBBdHRyaWJ1dGVzXG5cdC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuXHQvLyBTdXBwb3J0OiBJRTw4XG5cdC8vIFZlcmlmeSB0aGF0IGdldEF0dHJpYnV0ZSByZWFsbHkgcmV0dXJucyBhdHRyaWJ1dGVzIGFuZCBub3QgcHJvcGVydGllc1xuXHQvLyAoZXhjZXB0aW5nIElFOCBib29sZWFucylcblx0c3VwcG9ydC5hdHRyaWJ1dGVzID0gYXNzZXJ0KCBmdW5jdGlvbiggZWwgKSB7XG5cdFx0ZWwuY2xhc3NOYW1lID0gXCJpXCI7XG5cdFx0cmV0dXJuICFlbC5nZXRBdHRyaWJ1dGUoIFwiY2xhc3NOYW1lXCIgKTtcblx0fSApO1xuXG5cdC8qIGdldEVsZW1lbnQocylCeSpcblx0LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG5cdC8vIENoZWNrIGlmIGdldEVsZW1lbnRzQnlUYWdOYW1lKFwiKlwiKSByZXR1cm5zIG9ubHkgZWxlbWVudHNcblx0c3VwcG9ydC5nZXRFbGVtZW50c0J5VGFnTmFtZSA9IGFzc2VydCggZnVuY3Rpb24oIGVsICkge1xuXHRcdGVsLmFwcGVuZENoaWxkKCBkb2N1bWVudC5jcmVhdGVDb21tZW50KCBcIlwiICkgKTtcblx0XHRyZXR1cm4gIWVsLmdldEVsZW1lbnRzQnlUYWdOYW1lKCBcIipcIiApLmxlbmd0aDtcblx0fSApO1xuXG5cdC8vIFN1cHBvcnQ6IElFPDlcblx0c3VwcG9ydC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lID0gcm5hdGl2ZS50ZXN0KCBkb2N1bWVudC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lICk7XG5cblx0Ly8gU3VwcG9ydDogSUU8MTBcblx0Ly8gQ2hlY2sgaWYgZ2V0RWxlbWVudEJ5SWQgcmV0dXJucyBlbGVtZW50cyBieSBuYW1lXG5cdC8vIFRoZSBicm9rZW4gZ2V0RWxlbWVudEJ5SWQgbWV0aG9kcyBkb24ndCBwaWNrIHVwIHByb2dyYW1tYXRpY2FsbHktc2V0IG5hbWVzLFxuXHQvLyBzbyB1c2UgYSByb3VuZGFib3V0IGdldEVsZW1lbnRzQnlOYW1lIHRlc3Rcblx0c3VwcG9ydC5nZXRCeUlkID0gYXNzZXJ0KCBmdW5jdGlvbiggZWwgKSB7XG5cdFx0ZG9jRWxlbS5hcHBlbmRDaGlsZCggZWwgKS5pZCA9IGV4cGFuZG87XG5cdFx0cmV0dXJuICFkb2N1bWVudC5nZXRFbGVtZW50c0J5TmFtZSB8fCAhZG9jdW1lbnQuZ2V0RWxlbWVudHNCeU5hbWUoIGV4cGFuZG8gKS5sZW5ndGg7XG5cdH0gKTtcblxuXHQvLyBJRCBmaWx0ZXIgYW5kIGZpbmRcblx0aWYgKCBzdXBwb3J0LmdldEJ5SWQgKSB7XG5cdFx0RXhwci5maWx0ZXJbIFwiSURcIiBdID0gZnVuY3Rpb24oIGlkICkge1xuXHRcdFx0dmFyIGF0dHJJZCA9IGlkLnJlcGxhY2UoIHJ1bmVzY2FwZSwgZnVuZXNjYXBlICk7XG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRcdHJldHVybiBlbGVtLmdldEF0dHJpYnV0ZSggXCJpZFwiICkgPT09IGF0dHJJZDtcblx0XHRcdH07XG5cdFx0fTtcblx0XHRFeHByLmZpbmRbIFwiSURcIiBdID0gZnVuY3Rpb24oIGlkLCBjb250ZXh0ICkge1xuXHRcdFx0aWYgKCB0eXBlb2YgY29udGV4dC5nZXRFbGVtZW50QnlJZCAhPT0gXCJ1bmRlZmluZWRcIiAmJiBkb2N1bWVudElzSFRNTCApIHtcblx0XHRcdFx0dmFyIGVsZW0gPSBjb250ZXh0LmdldEVsZW1lbnRCeUlkKCBpZCApO1xuXHRcdFx0XHRyZXR1cm4gZWxlbSA/IFsgZWxlbSBdIDogW107XG5cdFx0XHR9XG5cdFx0fTtcblx0fSBlbHNlIHtcblx0XHRFeHByLmZpbHRlclsgXCJJRFwiIF0gPSAgZnVuY3Rpb24oIGlkICkge1xuXHRcdFx0dmFyIGF0dHJJZCA9IGlkLnJlcGxhY2UoIHJ1bmVzY2FwZSwgZnVuZXNjYXBlICk7XG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRcdHZhciBub2RlID0gdHlwZW9mIGVsZW0uZ2V0QXR0cmlidXRlTm9kZSAhPT0gXCJ1bmRlZmluZWRcIiAmJlxuXHRcdFx0XHRcdGVsZW0uZ2V0QXR0cmlidXRlTm9kZSggXCJpZFwiICk7XG5cdFx0XHRcdHJldHVybiBub2RlICYmIG5vZGUudmFsdWUgPT09IGF0dHJJZDtcblx0XHRcdH07XG5cdFx0fTtcblxuXHRcdC8vIFN1cHBvcnQ6IElFIDYgLSA3IG9ubHlcblx0XHQvLyBnZXRFbGVtZW50QnlJZCBpcyBub3QgcmVsaWFibGUgYXMgYSBmaW5kIHNob3J0Y3V0XG5cdFx0RXhwci5maW5kWyBcIklEXCIgXSA9IGZ1bmN0aW9uKCBpZCwgY29udGV4dCApIHtcblx0XHRcdGlmICggdHlwZW9mIGNvbnRleHQuZ2V0RWxlbWVudEJ5SWQgIT09IFwidW5kZWZpbmVkXCIgJiYgZG9jdW1lbnRJc0hUTUwgKSB7XG5cdFx0XHRcdHZhciBub2RlLCBpLCBlbGVtcyxcblx0XHRcdFx0XHRlbGVtID0gY29udGV4dC5nZXRFbGVtZW50QnlJZCggaWQgKTtcblxuXHRcdFx0XHRpZiAoIGVsZW0gKSB7XG5cblx0XHRcdFx0XHQvLyBWZXJpZnkgdGhlIGlkIGF0dHJpYnV0ZVxuXHRcdFx0XHRcdG5vZGUgPSBlbGVtLmdldEF0dHJpYnV0ZU5vZGUoIFwiaWRcIiApO1xuXHRcdFx0XHRcdGlmICggbm9kZSAmJiBub2RlLnZhbHVlID09PSBpZCApIHtcblx0XHRcdFx0XHRcdHJldHVybiBbIGVsZW0gXTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBGYWxsIGJhY2sgb24gZ2V0RWxlbWVudHNCeU5hbWVcblx0XHRcdFx0XHRlbGVtcyA9IGNvbnRleHQuZ2V0RWxlbWVudHNCeU5hbWUoIGlkICk7XG5cdFx0XHRcdFx0aSA9IDA7XG5cdFx0XHRcdFx0d2hpbGUgKCAoIGVsZW0gPSBlbGVtc1sgaSsrIF0gKSApIHtcblx0XHRcdFx0XHRcdG5vZGUgPSBlbGVtLmdldEF0dHJpYnV0ZU5vZGUoIFwiaWRcIiApO1xuXHRcdFx0XHRcdFx0aWYgKCBub2RlICYmIG5vZGUudmFsdWUgPT09IGlkICkge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gWyBlbGVtIF07XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0cmV0dXJuIFtdO1xuXHRcdFx0fVxuXHRcdH07XG5cdH1cblxuXHQvLyBUYWdcblx0RXhwci5maW5kWyBcIlRBR1wiIF0gPSBzdXBwb3J0LmdldEVsZW1lbnRzQnlUYWdOYW1lID9cblx0XHRmdW5jdGlvbiggdGFnLCBjb250ZXh0ICkge1xuXHRcdFx0aWYgKCB0eXBlb2YgY29udGV4dC5nZXRFbGVtZW50c0J5VGFnTmFtZSAhPT0gXCJ1bmRlZmluZWRcIiApIHtcblx0XHRcdFx0cmV0dXJuIGNvbnRleHQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoIHRhZyApO1xuXG5cdFx0XHQvLyBEb2N1bWVudEZyYWdtZW50IG5vZGVzIGRvbid0IGhhdmUgZ0VCVE5cblx0XHRcdH0gZWxzZSBpZiAoIHN1cHBvcnQucXNhICkge1xuXHRcdFx0XHRyZXR1cm4gY29udGV4dC5xdWVyeVNlbGVjdG9yQWxsKCB0YWcgKTtcblx0XHRcdH1cblx0XHR9IDpcblxuXHRcdGZ1bmN0aW9uKCB0YWcsIGNvbnRleHQgKSB7XG5cdFx0XHR2YXIgZWxlbSxcblx0XHRcdFx0dG1wID0gW10sXG5cdFx0XHRcdGkgPSAwLFxuXG5cdFx0XHRcdC8vIEJ5IGhhcHB5IGNvaW5jaWRlbmNlLCBhIChicm9rZW4pIGdFQlROIGFwcGVhcnMgb24gRG9jdW1lbnRGcmFnbWVudCBub2RlcyB0b29cblx0XHRcdFx0cmVzdWx0cyA9IGNvbnRleHQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoIHRhZyApO1xuXG5cdFx0XHQvLyBGaWx0ZXIgb3V0IHBvc3NpYmxlIGNvbW1lbnRzXG5cdFx0XHRpZiAoIHRhZyA9PT0gXCIqXCIgKSB7XG5cdFx0XHRcdHdoaWxlICggKCBlbGVtID0gcmVzdWx0c1sgaSsrIF0gKSApIHtcblx0XHRcdFx0XHRpZiAoIGVsZW0ubm9kZVR5cGUgPT09IDEgKSB7XG5cdFx0XHRcdFx0XHR0bXAucHVzaCggZWxlbSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiB0bXA7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gcmVzdWx0cztcblx0XHR9O1xuXG5cdC8vIENsYXNzXG5cdEV4cHIuZmluZFsgXCJDTEFTU1wiIF0gPSBzdXBwb3J0LmdldEVsZW1lbnRzQnlDbGFzc05hbWUgJiYgZnVuY3Rpb24oIGNsYXNzTmFtZSwgY29udGV4dCApIHtcblx0XHRpZiAoIHR5cGVvZiBjb250ZXh0LmdldEVsZW1lbnRzQnlDbGFzc05hbWUgIT09IFwidW5kZWZpbmVkXCIgJiYgZG9jdW1lbnRJc0hUTUwgKSB7XG5cdFx0XHRyZXR1cm4gY29udGV4dC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKCBjbGFzc05hbWUgKTtcblx0XHR9XG5cdH07XG5cblx0LyogUVNBL21hdGNoZXNTZWxlY3RvclxuXHQtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cblx0Ly8gUVNBIGFuZCBtYXRjaGVzU2VsZWN0b3Igc3VwcG9ydFxuXG5cdC8vIG1hdGNoZXNTZWxlY3Rvcig6YWN0aXZlKSByZXBvcnRzIGZhbHNlIHdoZW4gdHJ1ZSAoSUU5L09wZXJhIDExLjUpXG5cdHJidWdneU1hdGNoZXMgPSBbXTtcblxuXHQvLyBxU2EoOmZvY3VzKSByZXBvcnRzIGZhbHNlIHdoZW4gdHJ1ZSAoQ2hyb21lIDIxKVxuXHQvLyBXZSBhbGxvdyB0aGlzIGJlY2F1c2Ugb2YgYSBidWcgaW4gSUU4LzkgdGhhdCB0aHJvd3MgYW4gZXJyb3Jcblx0Ly8gd2hlbmV2ZXIgYGRvY3VtZW50LmFjdGl2ZUVsZW1lbnRgIGlzIGFjY2Vzc2VkIG9uIGFuIGlmcmFtZVxuXHQvLyBTbywgd2UgYWxsb3cgOmZvY3VzIHRvIHBhc3MgdGhyb3VnaCBRU0EgYWxsIHRoZSB0aW1lIHRvIGF2b2lkIHRoZSBJRSBlcnJvclxuXHQvLyBTZWUgaHR0cHM6Ly9idWdzLmpxdWVyeS5jb20vdGlja2V0LzEzMzc4XG5cdHJidWdneVFTQSA9IFtdO1xuXG5cdGlmICggKCBzdXBwb3J0LnFzYSA9IHJuYXRpdmUudGVzdCggZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCApICkgKSB7XG5cblx0XHQvLyBCdWlsZCBRU0EgcmVnZXhcblx0XHQvLyBSZWdleCBzdHJhdGVneSBhZG9wdGVkIGZyb20gRGllZ28gUGVyaW5pXG5cdFx0YXNzZXJ0KCBmdW5jdGlvbiggZWwgKSB7XG5cblx0XHRcdHZhciBpbnB1dDtcblxuXHRcdFx0Ly8gU2VsZWN0IGlzIHNldCB0byBlbXB0eSBzdHJpbmcgb24gcHVycG9zZVxuXHRcdFx0Ly8gVGhpcyBpcyB0byB0ZXN0IElFJ3MgdHJlYXRtZW50IG9mIG5vdCBleHBsaWNpdGx5XG5cdFx0XHQvLyBzZXR0aW5nIGEgYm9vbGVhbiBjb250ZW50IGF0dHJpYnV0ZSxcblx0XHRcdC8vIHNpbmNlIGl0cyBwcmVzZW5jZSBzaG91bGQgYmUgZW5vdWdoXG5cdFx0XHQvLyBodHRwczovL2J1Z3MuanF1ZXJ5LmNvbS90aWNrZXQvMTIzNTlcblx0XHRcdGRvY0VsZW0uYXBwZW5kQ2hpbGQoIGVsICkuaW5uZXJIVE1MID0gXCI8YSBpZD0nXCIgKyBleHBhbmRvICsgXCInPjwvYT5cIiArXG5cdFx0XHRcdFwiPHNlbGVjdCBpZD0nXCIgKyBleHBhbmRvICsgXCItXFxyXFxcXCcgbXNhbGxvd2NhcHR1cmU9Jyc+XCIgK1xuXHRcdFx0XHRcIjxvcHRpb24gc2VsZWN0ZWQ9Jyc+PC9vcHRpb24+PC9zZWxlY3Q+XCI7XG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFOCwgT3BlcmEgMTEtMTIuMTZcblx0XHRcdC8vIE5vdGhpbmcgc2hvdWxkIGJlIHNlbGVjdGVkIHdoZW4gZW1wdHkgc3RyaW5ncyBmb2xsb3cgXj0gb3IgJD0gb3IgKj1cblx0XHRcdC8vIFRoZSB0ZXN0IGF0dHJpYnV0ZSBtdXN0IGJlIHVua25vd24gaW4gT3BlcmEgYnV0IFwic2FmZVwiIGZvciBXaW5SVFxuXHRcdFx0Ly8gaHR0cHM6Ly9tc2RuLm1pY3Jvc29mdC5jb20vZW4tdXMvbGlicmFyeS9pZS9oaDQ2NTM4OC5hc3B4I2F0dHJpYnV0ZV9zZWN0aW9uXG5cdFx0XHRpZiAoIGVsLnF1ZXJ5U2VsZWN0b3JBbGwoIFwiW21zYWxsb3djYXB0dXJlXj0nJ11cIiApLmxlbmd0aCApIHtcblx0XHRcdFx0cmJ1Z2d5UVNBLnB1c2goIFwiWypeJF09XCIgKyB3aGl0ZXNwYWNlICsgXCIqKD86Jyd8XFxcIlxcXCIpXCIgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gU3VwcG9ydDogSUU4XG5cdFx0XHQvLyBCb29sZWFuIGF0dHJpYnV0ZXMgYW5kIFwidmFsdWVcIiBhcmUgbm90IHRyZWF0ZWQgY29ycmVjdGx5XG5cdFx0XHRpZiAoICFlbC5xdWVyeVNlbGVjdG9yQWxsKCBcIltzZWxlY3RlZF1cIiApLmxlbmd0aCApIHtcblx0XHRcdFx0cmJ1Z2d5UVNBLnB1c2goIFwiXFxcXFtcIiArIHdoaXRlc3BhY2UgKyBcIiooPzp2YWx1ZXxcIiArIGJvb2xlYW5zICsgXCIpXCIgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gU3VwcG9ydDogQ2hyb21lPDI5LCBBbmRyb2lkPDQuNCwgU2FmYXJpPDcuMCssIGlPUzw3LjArLCBQaGFudG9tSlM8MS45LjgrXG5cdFx0XHRpZiAoICFlbC5xdWVyeVNlbGVjdG9yQWxsKCBcIltpZH49XCIgKyBleHBhbmRvICsgXCItXVwiICkubGVuZ3RoICkge1xuXHRcdFx0XHRyYnVnZ3lRU0EucHVzaCggXCJ+PVwiICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFIDExKywgRWRnZSAxNSAtIDE4K1xuXHRcdFx0Ly8gSUUgMTEvRWRnZSBkb24ndCBmaW5kIGVsZW1lbnRzIG9uIGEgYFtuYW1lPScnXWAgcXVlcnkgaW4gc29tZSBjYXNlcy5cblx0XHRcdC8vIEFkZGluZyBhIHRlbXBvcmFyeSBhdHRyaWJ1dGUgdG8gdGhlIGRvY3VtZW50IGJlZm9yZSB0aGUgc2VsZWN0aW9uIHdvcmtzXG5cdFx0XHQvLyBhcm91bmQgdGhlIGlzc3VlLlxuXHRcdFx0Ly8gSW50ZXJlc3RpbmdseSwgSUUgMTAgJiBvbGRlciBkb24ndCBzZWVtIHRvIGhhdmUgdGhlIGlzc3VlLlxuXHRcdFx0aW5wdXQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcImlucHV0XCIgKTtcblx0XHRcdGlucHV0LnNldEF0dHJpYnV0ZSggXCJuYW1lXCIsIFwiXCIgKTtcblx0XHRcdGVsLmFwcGVuZENoaWxkKCBpbnB1dCApO1xuXHRcdFx0aWYgKCAhZWwucXVlcnlTZWxlY3RvckFsbCggXCJbbmFtZT0nJ11cIiApLmxlbmd0aCApIHtcblx0XHRcdFx0cmJ1Z2d5UVNBLnB1c2goIFwiXFxcXFtcIiArIHdoaXRlc3BhY2UgKyBcIipuYW1lXCIgKyB3aGl0ZXNwYWNlICsgXCIqPVwiICtcblx0XHRcdFx0XHR3aGl0ZXNwYWNlICsgXCIqKD86Jyd8XFxcIlxcXCIpXCIgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gV2Via2l0L09wZXJhIC0gOmNoZWNrZWQgc2hvdWxkIHJldHVybiBzZWxlY3RlZCBvcHRpb24gZWxlbWVudHNcblx0XHRcdC8vIGh0dHA6Ly93d3cudzMub3JnL1RSLzIwMTEvUkVDLWNzczMtc2VsZWN0b3JzLTIwMTEwOTI5LyNjaGVja2VkXG5cdFx0XHQvLyBJRTggdGhyb3dzIGVycm9yIGhlcmUgYW5kIHdpbGwgbm90IHNlZSBsYXRlciB0ZXN0c1xuXHRcdFx0aWYgKCAhZWwucXVlcnlTZWxlY3RvckFsbCggXCI6Y2hlY2tlZFwiICkubGVuZ3RoICkge1xuXHRcdFx0XHRyYnVnZ3lRU0EucHVzaCggXCI6Y2hlY2tlZFwiICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFN1cHBvcnQ6IFNhZmFyaSA4KywgaU9TIDgrXG5cdFx0XHQvLyBodHRwczovL2J1Z3Mud2Via2l0Lm9yZy9zaG93X2J1Zy5jZ2k/aWQ9MTM2ODUxXG5cdFx0XHQvLyBJbi1wYWdlIGBzZWxlY3RvciNpZCBzaWJsaW5nLWNvbWJpbmF0b3Igc2VsZWN0b3JgIGZhaWxzXG5cdFx0XHRpZiAoICFlbC5xdWVyeVNlbGVjdG9yQWxsKCBcImEjXCIgKyBleHBhbmRvICsgXCIrKlwiICkubGVuZ3RoICkge1xuXHRcdFx0XHRyYnVnZ3lRU0EucHVzaCggXCIuIy4rWyt+XVwiICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFN1cHBvcnQ6IEZpcmVmb3ggPD0zLjYgLSA1IG9ubHlcblx0XHRcdC8vIE9sZCBGaXJlZm94IGRvZXNuJ3QgdGhyb3cgb24gYSBiYWRseS1lc2NhcGVkIGlkZW50aWZpZXIuXG5cdFx0XHRlbC5xdWVyeVNlbGVjdG9yQWxsKCBcIlxcXFxcXGZcIiApO1xuXHRcdFx0cmJ1Z2d5UVNBLnB1c2goIFwiW1xcXFxyXFxcXG5cXFxcZl1cIiApO1xuXHRcdH0gKTtcblxuXHRcdGFzc2VydCggZnVuY3Rpb24oIGVsICkge1xuXHRcdFx0ZWwuaW5uZXJIVE1MID0gXCI8YSBocmVmPScnIGRpc2FibGVkPSdkaXNhYmxlZCc+PC9hPlwiICtcblx0XHRcdFx0XCI8c2VsZWN0IGRpc2FibGVkPSdkaXNhYmxlZCc+PG9wdGlvbi8+PC9zZWxlY3Q+XCI7XG5cblx0XHRcdC8vIFN1cHBvcnQ6IFdpbmRvd3MgOCBOYXRpdmUgQXBwc1xuXHRcdFx0Ly8gVGhlIHR5cGUgYW5kIG5hbWUgYXR0cmlidXRlcyBhcmUgcmVzdHJpY3RlZCBkdXJpbmcgLmlubmVySFRNTCBhc3NpZ25tZW50XG5cdFx0XHR2YXIgaW5wdXQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcImlucHV0XCIgKTtcblx0XHRcdGlucHV0LnNldEF0dHJpYnV0ZSggXCJ0eXBlXCIsIFwiaGlkZGVuXCIgKTtcblx0XHRcdGVsLmFwcGVuZENoaWxkKCBpbnB1dCApLnNldEF0dHJpYnV0ZSggXCJuYW1lXCIsIFwiRFwiICk7XG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFOFxuXHRcdFx0Ly8gRW5mb3JjZSBjYXNlLXNlbnNpdGl2aXR5IG9mIG5hbWUgYXR0cmlidXRlXG5cdFx0XHRpZiAoIGVsLnF1ZXJ5U2VsZWN0b3JBbGwoIFwiW25hbWU9ZF1cIiApLmxlbmd0aCApIHtcblx0XHRcdFx0cmJ1Z2d5UVNBLnB1c2goIFwibmFtZVwiICsgd2hpdGVzcGFjZSArIFwiKlsqXiR8IX5dPz1cIiApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBGRiAzLjUgLSA6ZW5hYmxlZC86ZGlzYWJsZWQgYW5kIGhpZGRlbiBlbGVtZW50cyAoaGlkZGVuIGVsZW1lbnRzIGFyZSBzdGlsbCBlbmFibGVkKVxuXHRcdFx0Ly8gSUU4IHRocm93cyBlcnJvciBoZXJlIGFuZCB3aWxsIG5vdCBzZWUgbGF0ZXIgdGVzdHNcblx0XHRcdGlmICggZWwucXVlcnlTZWxlY3RvckFsbCggXCI6ZW5hYmxlZFwiICkubGVuZ3RoICE9PSAyICkge1xuXHRcdFx0XHRyYnVnZ3lRU0EucHVzaCggXCI6ZW5hYmxlZFwiLCBcIjpkaXNhYmxlZFwiICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFOS0xMStcblx0XHRcdC8vIElFJ3MgOmRpc2FibGVkIHNlbGVjdG9yIGRvZXMgbm90IHBpY2sgdXAgdGhlIGNoaWxkcmVuIG9mIGRpc2FibGVkIGZpZWxkc2V0c1xuXHRcdFx0ZG9jRWxlbS5hcHBlbmRDaGlsZCggZWwgKS5kaXNhYmxlZCA9IHRydWU7XG5cdFx0XHRpZiAoIGVsLnF1ZXJ5U2VsZWN0b3JBbGwoIFwiOmRpc2FibGVkXCIgKS5sZW5ndGggIT09IDIgKSB7XG5cdFx0XHRcdHJidWdneVFTQS5wdXNoKCBcIjplbmFibGVkXCIsIFwiOmRpc2FibGVkXCIgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gU3VwcG9ydDogT3BlcmEgMTAgLSAxMSBvbmx5XG5cdFx0XHQvLyBPcGVyYSAxMC0xMSBkb2VzIG5vdCB0aHJvdyBvbiBwb3N0LWNvbW1hIGludmFsaWQgcHNldWRvc1xuXHRcdFx0ZWwucXVlcnlTZWxlY3RvckFsbCggXCIqLDp4XCIgKTtcblx0XHRcdHJidWdneVFTQS5wdXNoKCBcIiwuKjpcIiApO1xuXHRcdH0gKTtcblx0fVxuXG5cdGlmICggKCBzdXBwb3J0Lm1hdGNoZXNTZWxlY3RvciA9IHJuYXRpdmUudGVzdCggKCBtYXRjaGVzID0gZG9jRWxlbS5tYXRjaGVzIHx8XG5cdFx0ZG9jRWxlbS53ZWJraXRNYXRjaGVzU2VsZWN0b3IgfHxcblx0XHRkb2NFbGVtLm1vek1hdGNoZXNTZWxlY3RvciB8fFxuXHRcdGRvY0VsZW0ub01hdGNoZXNTZWxlY3RvciB8fFxuXHRcdGRvY0VsZW0ubXNNYXRjaGVzU2VsZWN0b3IgKSApICkgKSB7XG5cblx0XHRhc3NlcnQoIGZ1bmN0aW9uKCBlbCApIHtcblxuXHRcdFx0Ly8gQ2hlY2sgdG8gc2VlIGlmIGl0J3MgcG9zc2libGUgdG8gZG8gbWF0Y2hlc1NlbGVjdG9yXG5cdFx0XHQvLyBvbiBhIGRpc2Nvbm5lY3RlZCBub2RlIChJRSA5KVxuXHRcdFx0c3VwcG9ydC5kaXNjb25uZWN0ZWRNYXRjaCA9IG1hdGNoZXMuY2FsbCggZWwsIFwiKlwiICk7XG5cblx0XHRcdC8vIFRoaXMgc2hvdWxkIGZhaWwgd2l0aCBhbiBleGNlcHRpb25cblx0XHRcdC8vIEdlY2tvIGRvZXMgbm90IGVycm9yLCByZXR1cm5zIGZhbHNlIGluc3RlYWRcblx0XHRcdG1hdGNoZXMuY2FsbCggZWwsIFwiW3MhPScnXTp4XCIgKTtcblx0XHRcdHJidWdneU1hdGNoZXMucHVzaCggXCIhPVwiLCBwc2V1ZG9zICk7XG5cdFx0fSApO1xuXHR9XG5cblx0cmJ1Z2d5UVNBID0gcmJ1Z2d5UVNBLmxlbmd0aCAmJiBuZXcgUmVnRXhwKCByYnVnZ3lRU0Euam9pbiggXCJ8XCIgKSApO1xuXHRyYnVnZ3lNYXRjaGVzID0gcmJ1Z2d5TWF0Y2hlcy5sZW5ndGggJiYgbmV3IFJlZ0V4cCggcmJ1Z2d5TWF0Y2hlcy5qb2luKCBcInxcIiApICk7XG5cblx0LyogQ29udGFpbnNcblx0LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXHRoYXNDb21wYXJlID0gcm5hdGl2ZS50ZXN0KCBkb2NFbGVtLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uICk7XG5cblx0Ly8gRWxlbWVudCBjb250YWlucyBhbm90aGVyXG5cdC8vIFB1cnBvc2VmdWxseSBzZWxmLWV4Y2x1c2l2ZVxuXHQvLyBBcyBpbiwgYW4gZWxlbWVudCBkb2VzIG5vdCBjb250YWluIGl0c2VsZlxuXHRjb250YWlucyA9IGhhc0NvbXBhcmUgfHwgcm5hdGl2ZS50ZXN0KCBkb2NFbGVtLmNvbnRhaW5zICkgP1xuXHRcdGZ1bmN0aW9uKCBhLCBiICkge1xuXHRcdFx0dmFyIGFkb3duID0gYS5ub2RlVHlwZSA9PT0gOSA/IGEuZG9jdW1lbnRFbGVtZW50IDogYSxcblx0XHRcdFx0YnVwID0gYiAmJiBiLnBhcmVudE5vZGU7XG5cdFx0XHRyZXR1cm4gYSA9PT0gYnVwIHx8ICEhKCBidXAgJiYgYnVwLm5vZGVUeXBlID09PSAxICYmIChcblx0XHRcdFx0YWRvd24uY29udGFpbnMgP1xuXHRcdFx0XHRcdGFkb3duLmNvbnRhaW5zKCBidXAgKSA6XG5cdFx0XHRcdFx0YS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiAmJiBhLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKCBidXAgKSAmIDE2XG5cdFx0XHQpICk7XG5cdFx0fSA6XG5cdFx0ZnVuY3Rpb24oIGEsIGIgKSB7XG5cdFx0XHRpZiAoIGIgKSB7XG5cdFx0XHRcdHdoaWxlICggKCBiID0gYi5wYXJlbnROb2RlICkgKSB7XG5cdFx0XHRcdFx0aWYgKCBiID09PSBhICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fTtcblxuXHQvKiBTb3J0aW5nXG5cdC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuXHQvLyBEb2N1bWVudCBvcmRlciBzb3J0aW5nXG5cdHNvcnRPcmRlciA9IGhhc0NvbXBhcmUgP1xuXHRmdW5jdGlvbiggYSwgYiApIHtcblxuXHRcdC8vIEZsYWcgZm9yIGR1cGxpY2F0ZSByZW1vdmFsXG5cdFx0aWYgKCBhID09PSBiICkge1xuXHRcdFx0aGFzRHVwbGljYXRlID0gdHJ1ZTtcblx0XHRcdHJldHVybiAwO1xuXHRcdH1cblxuXHRcdC8vIFNvcnQgb24gbWV0aG9kIGV4aXN0ZW5jZSBpZiBvbmx5IG9uZSBpbnB1dCBoYXMgY29tcGFyZURvY3VtZW50UG9zaXRpb25cblx0XHR2YXIgY29tcGFyZSA9ICFhLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uIC0gIWIuY29tcGFyZURvY3VtZW50UG9zaXRpb247XG5cdFx0aWYgKCBjb21wYXJlICkge1xuXHRcdFx0cmV0dXJuIGNvbXBhcmU7XG5cdFx0fVxuXG5cdFx0Ly8gQ2FsY3VsYXRlIHBvc2l0aW9uIGlmIGJvdGggaW5wdXRzIGJlbG9uZyB0byB0aGUgc2FtZSBkb2N1bWVudFxuXHRcdC8vIFN1cHBvcnQ6IElFIDExKywgRWRnZSAxNyAtIDE4K1xuXHRcdC8vIElFL0VkZ2Ugc29tZXRpbWVzIHRocm93IGEgXCJQZXJtaXNzaW9uIGRlbmllZFwiIGVycm9yIHdoZW4gc3RyaWN0LWNvbXBhcmluZ1xuXHRcdC8vIHR3byBkb2N1bWVudHM7IHNoYWxsb3cgY29tcGFyaXNvbnMgd29yay5cblx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZXFlcWVxXG5cdFx0Y29tcGFyZSA9ICggYS5vd25lckRvY3VtZW50IHx8IGEgKSA9PSAoIGIub3duZXJEb2N1bWVudCB8fCBiICkgP1xuXHRcdFx0YS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiggYiApIDpcblxuXHRcdFx0Ly8gT3RoZXJ3aXNlIHdlIGtub3cgdGhleSBhcmUgZGlzY29ubmVjdGVkXG5cdFx0XHQxO1xuXG5cdFx0Ly8gRGlzY29ubmVjdGVkIG5vZGVzXG5cdFx0aWYgKCBjb21wYXJlICYgMSB8fFxuXHRcdFx0KCAhc3VwcG9ydC5zb3J0RGV0YWNoZWQgJiYgYi5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiggYSApID09PSBjb21wYXJlICkgKSB7XG5cblx0XHRcdC8vIENob29zZSB0aGUgZmlyc3QgZWxlbWVudCB0aGF0IGlzIHJlbGF0ZWQgdG8gb3VyIHByZWZlcnJlZCBkb2N1bWVudFxuXHRcdFx0Ly8gU3VwcG9ydDogSUUgMTErLCBFZGdlIDE3IC0gMTgrXG5cdFx0XHQvLyBJRS9FZGdlIHNvbWV0aW1lcyB0aHJvdyBhIFwiUGVybWlzc2lvbiBkZW5pZWRcIiBlcnJvciB3aGVuIHN0cmljdC1jb21wYXJpbmdcblx0XHRcdC8vIHR3byBkb2N1bWVudHM7IHNoYWxsb3cgY29tcGFyaXNvbnMgd29yay5cblx0XHRcdC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBlcWVxZXFcblx0XHRcdGlmICggYSA9PSBkb2N1bWVudCB8fCBhLm93bmVyRG9jdW1lbnQgPT0gcHJlZmVycmVkRG9jICYmXG5cdFx0XHRcdGNvbnRhaW5zKCBwcmVmZXJyZWREb2MsIGEgKSApIHtcblx0XHRcdFx0cmV0dXJuIC0xO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTdXBwb3J0OiBJRSAxMSssIEVkZ2UgMTcgLSAxOCtcblx0XHRcdC8vIElFL0VkZ2Ugc29tZXRpbWVzIHRocm93IGEgXCJQZXJtaXNzaW9uIGRlbmllZFwiIGVycm9yIHdoZW4gc3RyaWN0LWNvbXBhcmluZ1xuXHRcdFx0Ly8gdHdvIGRvY3VtZW50czsgc2hhbGxvdyBjb21wYXJpc29ucyB3b3JrLlxuXHRcdFx0Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGVxZXFlcVxuXHRcdFx0aWYgKCBiID09IGRvY3VtZW50IHx8IGIub3duZXJEb2N1bWVudCA9PSBwcmVmZXJyZWREb2MgJiZcblx0XHRcdFx0Y29udGFpbnMoIHByZWZlcnJlZERvYywgYiApICkge1xuXHRcdFx0XHRyZXR1cm4gMTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gTWFpbnRhaW4gb3JpZ2luYWwgb3JkZXJcblx0XHRcdHJldHVybiBzb3J0SW5wdXQgP1xuXHRcdFx0XHQoIGluZGV4T2YoIHNvcnRJbnB1dCwgYSApIC0gaW5kZXhPZiggc29ydElucHV0LCBiICkgKSA6XG5cdFx0XHRcdDA7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGNvbXBhcmUgJiA0ID8gLTEgOiAxO1xuXHR9IDpcblx0ZnVuY3Rpb24oIGEsIGIgKSB7XG5cblx0XHQvLyBFeGl0IGVhcmx5IGlmIHRoZSBub2RlcyBhcmUgaWRlbnRpY2FsXG5cdFx0aWYgKCBhID09PSBiICkge1xuXHRcdFx0aGFzRHVwbGljYXRlID0gdHJ1ZTtcblx0XHRcdHJldHVybiAwO1xuXHRcdH1cblxuXHRcdHZhciBjdXIsXG5cdFx0XHRpID0gMCxcblx0XHRcdGF1cCA9IGEucGFyZW50Tm9kZSxcblx0XHRcdGJ1cCA9IGIucGFyZW50Tm9kZSxcblx0XHRcdGFwID0gWyBhIF0sXG5cdFx0XHRicCA9IFsgYiBdO1xuXG5cdFx0Ly8gUGFyZW50bGVzcyBub2RlcyBhcmUgZWl0aGVyIGRvY3VtZW50cyBvciBkaXNjb25uZWN0ZWRcblx0XHRpZiAoICFhdXAgfHwgIWJ1cCApIHtcblxuXHRcdFx0Ly8gU3VwcG9ydDogSUUgMTErLCBFZGdlIDE3IC0gMTgrXG5cdFx0XHQvLyBJRS9FZGdlIHNvbWV0aW1lcyB0aHJvdyBhIFwiUGVybWlzc2lvbiBkZW5pZWRcIiBlcnJvciB3aGVuIHN0cmljdC1jb21wYXJpbmdcblx0XHRcdC8vIHR3byBkb2N1bWVudHM7IHNoYWxsb3cgY29tcGFyaXNvbnMgd29yay5cblx0XHRcdC8qIGVzbGludC1kaXNhYmxlIGVxZXFlcSAqL1xuXHRcdFx0cmV0dXJuIGEgPT0gZG9jdW1lbnQgPyAtMSA6XG5cdFx0XHRcdGIgPT0gZG9jdW1lbnQgPyAxIDpcblx0XHRcdFx0LyogZXNsaW50LWVuYWJsZSBlcWVxZXEgKi9cblx0XHRcdFx0YXVwID8gLTEgOlxuXHRcdFx0XHRidXAgPyAxIDpcblx0XHRcdFx0c29ydElucHV0ID9cblx0XHRcdFx0KCBpbmRleE9mKCBzb3J0SW5wdXQsIGEgKSAtIGluZGV4T2YoIHNvcnRJbnB1dCwgYiApICkgOlxuXHRcdFx0XHQwO1xuXG5cdFx0Ly8gSWYgdGhlIG5vZGVzIGFyZSBzaWJsaW5ncywgd2UgY2FuIGRvIGEgcXVpY2sgY2hlY2tcblx0XHR9IGVsc2UgaWYgKCBhdXAgPT09IGJ1cCApIHtcblx0XHRcdHJldHVybiBzaWJsaW5nQ2hlY2soIGEsIGIgKTtcblx0XHR9XG5cblx0XHQvLyBPdGhlcndpc2Ugd2UgbmVlZCBmdWxsIGxpc3RzIG9mIHRoZWlyIGFuY2VzdG9ycyBmb3IgY29tcGFyaXNvblxuXHRcdGN1ciA9IGE7XG5cdFx0d2hpbGUgKCAoIGN1ciA9IGN1ci5wYXJlbnROb2RlICkgKSB7XG5cdFx0XHRhcC51bnNoaWZ0KCBjdXIgKTtcblx0XHR9XG5cdFx0Y3VyID0gYjtcblx0XHR3aGlsZSAoICggY3VyID0gY3VyLnBhcmVudE5vZGUgKSApIHtcblx0XHRcdGJwLnVuc2hpZnQoIGN1ciApO1xuXHRcdH1cblxuXHRcdC8vIFdhbGsgZG93biB0aGUgdHJlZSBsb29raW5nIGZvciBhIGRpc2NyZXBhbmN5XG5cdFx0d2hpbGUgKCBhcFsgaSBdID09PSBicFsgaSBdICkge1xuXHRcdFx0aSsrO1xuXHRcdH1cblxuXHRcdHJldHVybiBpID9cblxuXHRcdFx0Ly8gRG8gYSBzaWJsaW5nIGNoZWNrIGlmIHRoZSBub2RlcyBoYXZlIGEgY29tbW9uIGFuY2VzdG9yXG5cdFx0XHRzaWJsaW5nQ2hlY2soIGFwWyBpIF0sIGJwWyBpIF0gKSA6XG5cblx0XHRcdC8vIE90aGVyd2lzZSBub2RlcyBpbiBvdXIgZG9jdW1lbnQgc29ydCBmaXJzdFxuXHRcdFx0Ly8gU3VwcG9ydDogSUUgMTErLCBFZGdlIDE3IC0gMTgrXG5cdFx0XHQvLyBJRS9FZGdlIHNvbWV0aW1lcyB0aHJvdyBhIFwiUGVybWlzc2lvbiBkZW5pZWRcIiBlcnJvciB3aGVuIHN0cmljdC1jb21wYXJpbmdcblx0XHRcdC8vIHR3byBkb2N1bWVudHM7IHNoYWxsb3cgY29tcGFyaXNvbnMgd29yay5cblx0XHRcdC8qIGVzbGludC1kaXNhYmxlIGVxZXFlcSAqL1xuXHRcdFx0YXBbIGkgXSA9PSBwcmVmZXJyZWREb2MgPyAtMSA6XG5cdFx0XHRicFsgaSBdID09IHByZWZlcnJlZERvYyA/IDEgOlxuXHRcdFx0LyogZXNsaW50LWVuYWJsZSBlcWVxZXEgKi9cblx0XHRcdDA7XG5cdH07XG5cblx0cmV0dXJuIGRvY3VtZW50O1xufTtcblxuU2l6emxlLm1hdGNoZXMgPSBmdW5jdGlvbiggZXhwciwgZWxlbWVudHMgKSB7XG5cdHJldHVybiBTaXp6bGUoIGV4cHIsIG51bGwsIG51bGwsIGVsZW1lbnRzICk7XG59O1xuXG5TaXp6bGUubWF0Y2hlc1NlbGVjdG9yID0gZnVuY3Rpb24oIGVsZW0sIGV4cHIgKSB7XG5cdHNldERvY3VtZW50KCBlbGVtICk7XG5cblx0aWYgKCBzdXBwb3J0Lm1hdGNoZXNTZWxlY3RvciAmJiBkb2N1bWVudElzSFRNTCAmJlxuXHRcdCFub25uYXRpdmVTZWxlY3RvckNhY2hlWyBleHByICsgXCIgXCIgXSAmJlxuXHRcdCggIXJidWdneU1hdGNoZXMgfHwgIXJidWdneU1hdGNoZXMudGVzdCggZXhwciApICkgJiZcblx0XHQoICFyYnVnZ3lRU0EgICAgIHx8ICFyYnVnZ3lRU0EudGVzdCggZXhwciApICkgKSB7XG5cblx0XHR0cnkge1xuXHRcdFx0dmFyIHJldCA9IG1hdGNoZXMuY2FsbCggZWxlbSwgZXhwciApO1xuXG5cdFx0XHQvLyBJRSA5J3MgbWF0Y2hlc1NlbGVjdG9yIHJldHVybnMgZmFsc2Ugb24gZGlzY29ubmVjdGVkIG5vZGVzXG5cdFx0XHRpZiAoIHJldCB8fCBzdXBwb3J0LmRpc2Nvbm5lY3RlZE1hdGNoIHx8XG5cblx0XHRcdFx0Ly8gQXMgd2VsbCwgZGlzY29ubmVjdGVkIG5vZGVzIGFyZSBzYWlkIHRvIGJlIGluIGEgZG9jdW1lbnRcblx0XHRcdFx0Ly8gZnJhZ21lbnQgaW4gSUUgOVxuXHRcdFx0XHRlbGVtLmRvY3VtZW50ICYmIGVsZW0uZG9jdW1lbnQubm9kZVR5cGUgIT09IDExICkge1xuXHRcdFx0XHRyZXR1cm4gcmV0O1xuXHRcdFx0fVxuXHRcdH0gY2F0Y2ggKCBlICkge1xuXHRcdFx0bm9ubmF0aXZlU2VsZWN0b3JDYWNoZSggZXhwciwgdHJ1ZSApO1xuXHRcdH1cblx0fVxuXG5cdHJldHVybiBTaXp6bGUoIGV4cHIsIGRvY3VtZW50LCBudWxsLCBbIGVsZW0gXSApLmxlbmd0aCA+IDA7XG59O1xuXG5TaXp6bGUuY29udGFpbnMgPSBmdW5jdGlvbiggY29udGV4dCwgZWxlbSApIHtcblxuXHQvLyBTZXQgZG9jdW1lbnQgdmFycyBpZiBuZWVkZWRcblx0Ly8gU3VwcG9ydDogSUUgMTErLCBFZGdlIDE3IC0gMTgrXG5cdC8vIElFL0VkZ2Ugc29tZXRpbWVzIHRocm93IGEgXCJQZXJtaXNzaW9uIGRlbmllZFwiIGVycm9yIHdoZW4gc3RyaWN0LWNvbXBhcmluZ1xuXHQvLyB0d28gZG9jdW1lbnRzOyBzaGFsbG93IGNvbXBhcmlzb25zIHdvcmsuXG5cdC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBlcWVxZXFcblx0aWYgKCAoIGNvbnRleHQub3duZXJEb2N1bWVudCB8fCBjb250ZXh0ICkgIT0gZG9jdW1lbnQgKSB7XG5cdFx0c2V0RG9jdW1lbnQoIGNvbnRleHQgKTtcblx0fVxuXHRyZXR1cm4gY29udGFpbnMoIGNvbnRleHQsIGVsZW0gKTtcbn07XG5cblNpenpsZS5hdHRyID0gZnVuY3Rpb24oIGVsZW0sIG5hbWUgKSB7XG5cblx0Ly8gU2V0IGRvY3VtZW50IHZhcnMgaWYgbmVlZGVkXG5cdC8vIFN1cHBvcnQ6IElFIDExKywgRWRnZSAxNyAtIDE4K1xuXHQvLyBJRS9FZGdlIHNvbWV0aW1lcyB0aHJvdyBhIFwiUGVybWlzc2lvbiBkZW5pZWRcIiBlcnJvciB3aGVuIHN0cmljdC1jb21wYXJpbmdcblx0Ly8gdHdvIGRvY3VtZW50czsgc2hhbGxvdyBjb21wYXJpc29ucyB3b3JrLlxuXHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZXFlcWVxXG5cdGlmICggKCBlbGVtLm93bmVyRG9jdW1lbnQgfHwgZWxlbSApICE9IGRvY3VtZW50ICkge1xuXHRcdHNldERvY3VtZW50KCBlbGVtICk7XG5cdH1cblxuXHR2YXIgZm4gPSBFeHByLmF0dHJIYW5kbGVbIG5hbWUudG9Mb3dlckNhc2UoKSBdLFxuXG5cdFx0Ly8gRG9uJ3QgZ2V0IGZvb2xlZCBieSBPYmplY3QucHJvdG90eXBlIHByb3BlcnRpZXMgKGpRdWVyeSAjMTM4MDcpXG5cdFx0dmFsID0gZm4gJiYgaGFzT3duLmNhbGwoIEV4cHIuYXR0ckhhbmRsZSwgbmFtZS50b0xvd2VyQ2FzZSgpICkgP1xuXHRcdFx0Zm4oIGVsZW0sIG5hbWUsICFkb2N1bWVudElzSFRNTCApIDpcblx0XHRcdHVuZGVmaW5lZDtcblxuXHRyZXR1cm4gdmFsICE9PSB1bmRlZmluZWQgP1xuXHRcdHZhbCA6XG5cdFx0c3VwcG9ydC5hdHRyaWJ1dGVzIHx8ICFkb2N1bWVudElzSFRNTCA/XG5cdFx0XHRlbGVtLmdldEF0dHJpYnV0ZSggbmFtZSApIDpcblx0XHRcdCggdmFsID0gZWxlbS5nZXRBdHRyaWJ1dGVOb2RlKCBuYW1lICkgKSAmJiB2YWwuc3BlY2lmaWVkID9cblx0XHRcdFx0dmFsLnZhbHVlIDpcblx0XHRcdFx0bnVsbDtcbn07XG5cblNpenpsZS5lc2NhcGUgPSBmdW5jdGlvbiggc2VsICkge1xuXHRyZXR1cm4gKCBzZWwgKyBcIlwiICkucmVwbGFjZSggcmNzc2VzY2FwZSwgZmNzc2VzY2FwZSApO1xufTtcblxuU2l6emxlLmVycm9yID0gZnVuY3Rpb24oIG1zZyApIHtcblx0dGhyb3cgbmV3IEVycm9yKCBcIlN5bnRheCBlcnJvciwgdW5yZWNvZ25pemVkIGV4cHJlc3Npb246IFwiICsgbXNnICk7XG59O1xuXG4vKipcbiAqIERvY3VtZW50IHNvcnRpbmcgYW5kIHJlbW92aW5nIGR1cGxpY2F0ZXNcbiAqIEBwYXJhbSB7QXJyYXlMaWtlfSByZXN1bHRzXG4gKi9cblNpenpsZS51bmlxdWVTb3J0ID0gZnVuY3Rpb24oIHJlc3VsdHMgKSB7XG5cdHZhciBlbGVtLFxuXHRcdGR1cGxpY2F0ZXMgPSBbXSxcblx0XHRqID0gMCxcblx0XHRpID0gMDtcblxuXHQvLyBVbmxlc3Mgd2UgKmtub3cqIHdlIGNhbiBkZXRlY3QgZHVwbGljYXRlcywgYXNzdW1lIHRoZWlyIHByZXNlbmNlXG5cdGhhc0R1cGxpY2F0ZSA9ICFzdXBwb3J0LmRldGVjdER1cGxpY2F0ZXM7XG5cdHNvcnRJbnB1dCA9ICFzdXBwb3J0LnNvcnRTdGFibGUgJiYgcmVzdWx0cy5zbGljZSggMCApO1xuXHRyZXN1bHRzLnNvcnQoIHNvcnRPcmRlciApO1xuXG5cdGlmICggaGFzRHVwbGljYXRlICkge1xuXHRcdHdoaWxlICggKCBlbGVtID0gcmVzdWx0c1sgaSsrIF0gKSApIHtcblx0XHRcdGlmICggZWxlbSA9PT0gcmVzdWx0c1sgaSBdICkge1xuXHRcdFx0XHRqID0gZHVwbGljYXRlcy5wdXNoKCBpICk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHdoaWxlICggai0tICkge1xuXHRcdFx0cmVzdWx0cy5zcGxpY2UoIGR1cGxpY2F0ZXNbIGogXSwgMSApO1xuXHRcdH1cblx0fVxuXG5cdC8vIENsZWFyIGlucHV0IGFmdGVyIHNvcnRpbmcgdG8gcmVsZWFzZSBvYmplY3RzXG5cdC8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vanF1ZXJ5L3NpenpsZS9wdWxsLzIyNVxuXHRzb3J0SW5wdXQgPSBudWxsO1xuXG5cdHJldHVybiByZXN1bHRzO1xufTtcblxuLyoqXG4gKiBVdGlsaXR5IGZ1bmN0aW9uIGZvciByZXRyaWV2aW5nIHRoZSB0ZXh0IHZhbHVlIG9mIGFuIGFycmF5IG9mIERPTSBub2Rlc1xuICogQHBhcmFtIHtBcnJheXxFbGVtZW50fSBlbGVtXG4gKi9cbmdldFRleHQgPSBTaXp6bGUuZ2V0VGV4dCA9IGZ1bmN0aW9uKCBlbGVtICkge1xuXHR2YXIgbm9kZSxcblx0XHRyZXQgPSBcIlwiLFxuXHRcdGkgPSAwLFxuXHRcdG5vZGVUeXBlID0gZWxlbS5ub2RlVHlwZTtcblxuXHRpZiAoICFub2RlVHlwZSApIHtcblxuXHRcdC8vIElmIG5vIG5vZGVUeXBlLCB0aGlzIGlzIGV4cGVjdGVkIHRvIGJlIGFuIGFycmF5XG5cdFx0d2hpbGUgKCAoIG5vZGUgPSBlbGVtWyBpKysgXSApICkge1xuXG5cdFx0XHQvLyBEbyBub3QgdHJhdmVyc2UgY29tbWVudCBub2Rlc1xuXHRcdFx0cmV0ICs9IGdldFRleHQoIG5vZGUgKTtcblx0XHR9XG5cdH0gZWxzZSBpZiAoIG5vZGVUeXBlID09PSAxIHx8IG5vZGVUeXBlID09PSA5IHx8IG5vZGVUeXBlID09PSAxMSApIHtcblxuXHRcdC8vIFVzZSB0ZXh0Q29udGVudCBmb3IgZWxlbWVudHNcblx0XHQvLyBpbm5lclRleHQgdXNhZ2UgcmVtb3ZlZCBmb3IgY29uc2lzdGVuY3kgb2YgbmV3IGxpbmVzIChqUXVlcnkgIzExMTUzKVxuXHRcdGlmICggdHlwZW9mIGVsZW0udGV4dENvbnRlbnQgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRyZXR1cm4gZWxlbS50ZXh0Q29udGVudDtcblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBUcmF2ZXJzZSBpdHMgY2hpbGRyZW5cblx0XHRcdGZvciAoIGVsZW0gPSBlbGVtLmZpcnN0Q2hpbGQ7IGVsZW07IGVsZW0gPSBlbGVtLm5leHRTaWJsaW5nICkge1xuXHRcdFx0XHRyZXQgKz0gZ2V0VGV4dCggZWxlbSApO1xuXHRcdFx0fVxuXHRcdH1cblx0fSBlbHNlIGlmICggbm9kZVR5cGUgPT09IDMgfHwgbm9kZVR5cGUgPT09IDQgKSB7XG5cdFx0cmV0dXJuIGVsZW0ubm9kZVZhbHVlO1xuXHR9XG5cblx0Ly8gRG8gbm90IGluY2x1ZGUgY29tbWVudCBvciBwcm9jZXNzaW5nIGluc3RydWN0aW9uIG5vZGVzXG5cblx0cmV0dXJuIHJldDtcbn07XG5cbkV4cHIgPSBTaXp6bGUuc2VsZWN0b3JzID0ge1xuXG5cdC8vIENhbiBiZSBhZGp1c3RlZCBieSB0aGUgdXNlclxuXHRjYWNoZUxlbmd0aDogNTAsXG5cblx0Y3JlYXRlUHNldWRvOiBtYXJrRnVuY3Rpb24sXG5cblx0bWF0Y2g6IG1hdGNoRXhwcixcblxuXHRhdHRySGFuZGxlOiB7fSxcblxuXHRmaW5kOiB7fSxcblxuXHRyZWxhdGl2ZToge1xuXHRcdFwiPlwiOiB7IGRpcjogXCJwYXJlbnROb2RlXCIsIGZpcnN0OiB0cnVlIH0sXG5cdFx0XCIgXCI6IHsgZGlyOiBcInBhcmVudE5vZGVcIiB9LFxuXHRcdFwiK1wiOiB7IGRpcjogXCJwcmV2aW91c1NpYmxpbmdcIiwgZmlyc3Q6IHRydWUgfSxcblx0XHRcIn5cIjogeyBkaXI6IFwicHJldmlvdXNTaWJsaW5nXCIgfVxuXHR9LFxuXG5cdHByZUZpbHRlcjoge1xuXHRcdFwiQVRUUlwiOiBmdW5jdGlvbiggbWF0Y2ggKSB7XG5cdFx0XHRtYXRjaFsgMSBdID0gbWF0Y2hbIDEgXS5yZXBsYWNlKCBydW5lc2NhcGUsIGZ1bmVzY2FwZSApO1xuXG5cdFx0XHQvLyBNb3ZlIHRoZSBnaXZlbiB2YWx1ZSB0byBtYXRjaFszXSB3aGV0aGVyIHF1b3RlZCBvciB1bnF1b3RlZFxuXHRcdFx0bWF0Y2hbIDMgXSA9ICggbWF0Y2hbIDMgXSB8fCBtYXRjaFsgNCBdIHx8XG5cdFx0XHRcdG1hdGNoWyA1IF0gfHwgXCJcIiApLnJlcGxhY2UoIHJ1bmVzY2FwZSwgZnVuZXNjYXBlICk7XG5cblx0XHRcdGlmICggbWF0Y2hbIDIgXSA9PT0gXCJ+PVwiICkge1xuXHRcdFx0XHRtYXRjaFsgMyBdID0gXCIgXCIgKyBtYXRjaFsgMyBdICsgXCIgXCI7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBtYXRjaC5zbGljZSggMCwgNCApO1xuXHRcdH0sXG5cblx0XHRcIkNISUxEXCI6IGZ1bmN0aW9uKCBtYXRjaCApIHtcblxuXHRcdFx0LyogbWF0Y2hlcyBmcm9tIG1hdGNoRXhwcltcIkNISUxEXCJdXG5cdFx0XHRcdDEgdHlwZSAob25seXxudGh8Li4uKVxuXHRcdFx0XHQyIHdoYXQgKGNoaWxkfG9mLXR5cGUpXG5cdFx0XHRcdDMgYXJndW1lbnQgKGV2ZW58b2RkfFxcZCp8XFxkKm4oWystXVxcZCspP3wuLi4pXG5cdFx0XHRcdDQgeG4tY29tcG9uZW50IG9mIHhuK3kgYXJndW1lbnQgKFsrLV0/XFxkKm58KVxuXHRcdFx0XHQ1IHNpZ24gb2YgeG4tY29tcG9uZW50XG5cdFx0XHRcdDYgeCBvZiB4bi1jb21wb25lbnRcblx0XHRcdFx0NyBzaWduIG9mIHktY29tcG9uZW50XG5cdFx0XHRcdDggeSBvZiB5LWNvbXBvbmVudFxuXHRcdFx0Ki9cblx0XHRcdG1hdGNoWyAxIF0gPSBtYXRjaFsgMSBdLnRvTG93ZXJDYXNlKCk7XG5cblx0XHRcdGlmICggbWF0Y2hbIDEgXS5zbGljZSggMCwgMyApID09PSBcIm50aFwiICkge1xuXG5cdFx0XHRcdC8vIG50aC0qIHJlcXVpcmVzIGFyZ3VtZW50XG5cdFx0XHRcdGlmICggIW1hdGNoWyAzIF0gKSB7XG5cdFx0XHRcdFx0U2l6emxlLmVycm9yKCBtYXRjaFsgMCBdICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBudW1lcmljIHggYW5kIHkgcGFyYW1ldGVycyBmb3IgRXhwci5maWx0ZXIuQ0hJTERcblx0XHRcdFx0Ly8gcmVtZW1iZXIgdGhhdCBmYWxzZS90cnVlIGNhc3QgcmVzcGVjdGl2ZWx5IHRvIDAvMVxuXHRcdFx0XHRtYXRjaFsgNCBdID0gKyggbWF0Y2hbIDQgXSA/XG5cdFx0XHRcdFx0bWF0Y2hbIDUgXSArICggbWF0Y2hbIDYgXSB8fCAxICkgOlxuXHRcdFx0XHRcdDIgKiAoIG1hdGNoWyAzIF0gPT09IFwiZXZlblwiIHx8IG1hdGNoWyAzIF0gPT09IFwib2RkXCIgKSApO1xuXHRcdFx0XHRtYXRjaFsgNSBdID0gKyggKCBtYXRjaFsgNyBdICsgbWF0Y2hbIDggXSApIHx8IG1hdGNoWyAzIF0gPT09IFwib2RkXCIgKTtcblxuXHRcdFx0XHQvLyBvdGhlciB0eXBlcyBwcm9oaWJpdCBhcmd1bWVudHNcblx0XHRcdH0gZWxzZSBpZiAoIG1hdGNoWyAzIF0gKSB7XG5cdFx0XHRcdFNpenpsZS5lcnJvciggbWF0Y2hbIDAgXSApO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gbWF0Y2g7XG5cdFx0fSxcblxuXHRcdFwiUFNFVURPXCI6IGZ1bmN0aW9uKCBtYXRjaCApIHtcblx0XHRcdHZhciBleGNlc3MsXG5cdFx0XHRcdHVucXVvdGVkID0gIW1hdGNoWyA2IF0gJiYgbWF0Y2hbIDIgXTtcblxuXHRcdFx0aWYgKCBtYXRjaEV4cHJbIFwiQ0hJTERcIiBdLnRlc3QoIG1hdGNoWyAwIF0gKSApIHtcblx0XHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEFjY2VwdCBxdW90ZWQgYXJndW1lbnRzIGFzLWlzXG5cdFx0XHRpZiAoIG1hdGNoWyAzIF0gKSB7XG5cdFx0XHRcdG1hdGNoWyAyIF0gPSBtYXRjaFsgNCBdIHx8IG1hdGNoWyA1IF0gfHwgXCJcIjtcblxuXHRcdFx0Ly8gU3RyaXAgZXhjZXNzIGNoYXJhY3RlcnMgZnJvbSB1bnF1b3RlZCBhcmd1bWVudHNcblx0XHRcdH0gZWxzZSBpZiAoIHVucXVvdGVkICYmIHJwc2V1ZG8udGVzdCggdW5xdW90ZWQgKSAmJlxuXG5cdFx0XHRcdC8vIEdldCBleGNlc3MgZnJvbSB0b2tlbml6ZSAocmVjdXJzaXZlbHkpXG5cdFx0XHRcdCggZXhjZXNzID0gdG9rZW5pemUoIHVucXVvdGVkLCB0cnVlICkgKSAmJlxuXG5cdFx0XHRcdC8vIGFkdmFuY2UgdG8gdGhlIG5leHQgY2xvc2luZyBwYXJlbnRoZXNpc1xuXHRcdFx0XHQoIGV4Y2VzcyA9IHVucXVvdGVkLmluZGV4T2YoIFwiKVwiLCB1bnF1b3RlZC5sZW5ndGggLSBleGNlc3MgKSAtIHVucXVvdGVkLmxlbmd0aCApICkge1xuXG5cdFx0XHRcdC8vIGV4Y2VzcyBpcyBhIG5lZ2F0aXZlIGluZGV4XG5cdFx0XHRcdG1hdGNoWyAwIF0gPSBtYXRjaFsgMCBdLnNsaWNlKCAwLCBleGNlc3MgKTtcblx0XHRcdFx0bWF0Y2hbIDIgXSA9IHVucXVvdGVkLnNsaWNlKCAwLCBleGNlc3MgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gUmV0dXJuIG9ubHkgY2FwdHVyZXMgbmVlZGVkIGJ5IHRoZSBwc2V1ZG8gZmlsdGVyIG1ldGhvZCAodHlwZSBhbmQgYXJndW1lbnQpXG5cdFx0XHRyZXR1cm4gbWF0Y2guc2xpY2UoIDAsIDMgKTtcblx0XHR9XG5cdH0sXG5cblx0ZmlsdGVyOiB7XG5cblx0XHRcIlRBR1wiOiBmdW5jdGlvbiggbm9kZU5hbWVTZWxlY3RvciApIHtcblx0XHRcdHZhciBub2RlTmFtZSA9IG5vZGVOYW1lU2VsZWN0b3IucmVwbGFjZSggcnVuZXNjYXBlLCBmdW5lc2NhcGUgKS50b0xvd2VyQ2FzZSgpO1xuXHRcdFx0cmV0dXJuIG5vZGVOYW1lU2VsZWN0b3IgPT09IFwiKlwiID9cblx0XHRcdFx0ZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHRcdH0gOlxuXHRcdFx0XHRmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdFx0XHRyZXR1cm4gZWxlbS5ub2RlTmFtZSAmJiBlbGVtLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IG5vZGVOYW1lO1xuXHRcdFx0XHR9O1xuXHRcdH0sXG5cblx0XHRcIkNMQVNTXCI6IGZ1bmN0aW9uKCBjbGFzc05hbWUgKSB7XG5cdFx0XHR2YXIgcGF0dGVybiA9IGNsYXNzQ2FjaGVbIGNsYXNzTmFtZSArIFwiIFwiIF07XG5cblx0XHRcdHJldHVybiBwYXR0ZXJuIHx8XG5cdFx0XHRcdCggcGF0dGVybiA9IG5ldyBSZWdFeHAoIFwiKF58XCIgKyB3aGl0ZXNwYWNlICtcblx0XHRcdFx0XHRcIilcIiArIGNsYXNzTmFtZSArIFwiKFwiICsgd2hpdGVzcGFjZSArIFwifCQpXCIgKSApICYmIGNsYXNzQ2FjaGUoXG5cdFx0XHRcdFx0XHRjbGFzc05hbWUsIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gcGF0dGVybi50ZXN0KFxuXHRcdFx0XHRcdFx0XHRcdHR5cGVvZiBlbGVtLmNsYXNzTmFtZSA9PT0gXCJzdHJpbmdcIiAmJiBlbGVtLmNsYXNzTmFtZSB8fFxuXHRcdFx0XHRcdFx0XHRcdHR5cGVvZiBlbGVtLmdldEF0dHJpYnV0ZSAhPT0gXCJ1bmRlZmluZWRcIiAmJlxuXHRcdFx0XHRcdFx0XHRcdFx0ZWxlbS5nZXRBdHRyaWJ1dGUoIFwiY2xhc3NcIiApIHx8XG5cdFx0XHRcdFx0XHRcdFx0XCJcIlxuXHRcdFx0XHRcdFx0XHQpO1xuXHRcdFx0XHR9ICk7XG5cdFx0fSxcblxuXHRcdFwiQVRUUlwiOiBmdW5jdGlvbiggbmFtZSwgb3BlcmF0b3IsIGNoZWNrICkge1xuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHR2YXIgcmVzdWx0ID0gU2l6emxlLmF0dHIoIGVsZW0sIG5hbWUgKTtcblxuXHRcdFx0XHRpZiAoIHJlc3VsdCA9PSBudWxsICkge1xuXHRcdFx0XHRcdHJldHVybiBvcGVyYXRvciA9PT0gXCIhPVwiO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggIW9wZXJhdG9yICkge1xuXHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0cmVzdWx0ICs9IFwiXCI7XG5cblx0XHRcdFx0LyogZXNsaW50LWRpc2FibGUgbWF4LWxlbiAqL1xuXG5cdFx0XHRcdHJldHVybiBvcGVyYXRvciA9PT0gXCI9XCIgPyByZXN1bHQgPT09IGNoZWNrIDpcblx0XHRcdFx0XHRvcGVyYXRvciA9PT0gXCIhPVwiID8gcmVzdWx0ICE9PSBjaGVjayA6XG5cdFx0XHRcdFx0b3BlcmF0b3IgPT09IFwiXj1cIiA/IGNoZWNrICYmIHJlc3VsdC5pbmRleE9mKCBjaGVjayApID09PSAwIDpcblx0XHRcdFx0XHRvcGVyYXRvciA9PT0gXCIqPVwiID8gY2hlY2sgJiYgcmVzdWx0LmluZGV4T2YoIGNoZWNrICkgPiAtMSA6XG5cdFx0XHRcdFx0b3BlcmF0b3IgPT09IFwiJD1cIiA/IGNoZWNrICYmIHJlc3VsdC5zbGljZSggLWNoZWNrLmxlbmd0aCApID09PSBjaGVjayA6XG5cdFx0XHRcdFx0b3BlcmF0b3IgPT09IFwifj1cIiA/ICggXCIgXCIgKyByZXN1bHQucmVwbGFjZSggcndoaXRlc3BhY2UsIFwiIFwiICkgKyBcIiBcIiApLmluZGV4T2YoIGNoZWNrICkgPiAtMSA6XG5cdFx0XHRcdFx0b3BlcmF0b3IgPT09IFwifD1cIiA/IHJlc3VsdCA9PT0gY2hlY2sgfHwgcmVzdWx0LnNsaWNlKCAwLCBjaGVjay5sZW5ndGggKyAxICkgPT09IGNoZWNrICsgXCItXCIgOlxuXHRcdFx0XHRcdGZhbHNlO1xuXHRcdFx0XHQvKiBlc2xpbnQtZW5hYmxlIG1heC1sZW4gKi9cblxuXHRcdFx0fTtcblx0XHR9LFxuXG5cdFx0XCJDSElMRFwiOiBmdW5jdGlvbiggdHlwZSwgd2hhdCwgX2FyZ3VtZW50LCBmaXJzdCwgbGFzdCApIHtcblx0XHRcdHZhciBzaW1wbGUgPSB0eXBlLnNsaWNlKCAwLCAzICkgIT09IFwibnRoXCIsXG5cdFx0XHRcdGZvcndhcmQgPSB0eXBlLnNsaWNlKCAtNCApICE9PSBcImxhc3RcIixcblx0XHRcdFx0b2ZUeXBlID0gd2hhdCA9PT0gXCJvZi10eXBlXCI7XG5cblx0XHRcdHJldHVybiBmaXJzdCA9PT0gMSAmJiBsYXN0ID09PSAwID9cblxuXHRcdFx0XHQvLyBTaG9ydGN1dCBmb3IgOm50aC0qKG4pXG5cdFx0XHRcdGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHRcdHJldHVybiAhIWVsZW0ucGFyZW50Tm9kZTtcblx0XHRcdFx0fSA6XG5cblx0XHRcdFx0ZnVuY3Rpb24oIGVsZW0sIF9jb250ZXh0LCB4bWwgKSB7XG5cdFx0XHRcdFx0dmFyIGNhY2hlLCB1bmlxdWVDYWNoZSwgb3V0ZXJDYWNoZSwgbm9kZSwgbm9kZUluZGV4LCBzdGFydCxcblx0XHRcdFx0XHRcdGRpciA9IHNpbXBsZSAhPT0gZm9yd2FyZCA/IFwibmV4dFNpYmxpbmdcIiA6IFwicHJldmlvdXNTaWJsaW5nXCIsXG5cdFx0XHRcdFx0XHRwYXJlbnQgPSBlbGVtLnBhcmVudE5vZGUsXG5cdFx0XHRcdFx0XHRuYW1lID0gb2ZUeXBlICYmIGVsZW0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKSxcblx0XHRcdFx0XHRcdHVzZUNhY2hlID0gIXhtbCAmJiAhb2ZUeXBlLFxuXHRcdFx0XHRcdFx0ZGlmZiA9IGZhbHNlO1xuXG5cdFx0XHRcdFx0aWYgKCBwYXJlbnQgKSB7XG5cblx0XHRcdFx0XHRcdC8vIDooZmlyc3R8bGFzdHxvbmx5KS0oY2hpbGR8b2YtdHlwZSlcblx0XHRcdFx0XHRcdGlmICggc2ltcGxlICkge1xuXHRcdFx0XHRcdFx0XHR3aGlsZSAoIGRpciApIHtcblx0XHRcdFx0XHRcdFx0XHRub2RlID0gZWxlbTtcblx0XHRcdFx0XHRcdFx0XHR3aGlsZSAoICggbm9kZSA9IG5vZGVbIGRpciBdICkgKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAoIG9mVHlwZSA/XG5cdFx0XHRcdFx0XHRcdFx0XHRcdG5vZGUubm9kZU5hbWUudG9Mb3dlckNhc2UoKSA9PT0gbmFtZSA6XG5cdFx0XHRcdFx0XHRcdFx0XHRcdG5vZGUubm9kZVR5cGUgPT09IDEgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHRcdC8vIFJldmVyc2UgZGlyZWN0aW9uIGZvciA6b25seS0qIChpZiB3ZSBoYXZlbid0IHlldCBkb25lIHNvKVxuXHRcdFx0XHRcdFx0XHRcdHN0YXJ0ID0gZGlyID0gdHlwZSA9PT0gXCJvbmx5XCIgJiYgIXN0YXJ0ICYmIFwibmV4dFNpYmxpbmdcIjtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0c3RhcnQgPSBbIGZvcndhcmQgPyBwYXJlbnQuZmlyc3RDaGlsZCA6IHBhcmVudC5sYXN0Q2hpbGQgXTtcblxuXHRcdFx0XHRcdFx0Ly8gbm9uLXhtbCA6bnRoLWNoaWxkKC4uLikgc3RvcmVzIGNhY2hlIGRhdGEgb24gYHBhcmVudGBcblx0XHRcdFx0XHRcdGlmICggZm9yd2FyZCAmJiB1c2VDYWNoZSApIHtcblxuXHRcdFx0XHRcdFx0XHQvLyBTZWVrIGBlbGVtYCBmcm9tIGEgcHJldmlvdXNseS1jYWNoZWQgaW5kZXhcblxuXHRcdFx0XHRcdFx0XHQvLyAuLi5pbiBhIGd6aXAtZnJpZW5kbHkgd2F5XG5cdFx0XHRcdFx0XHRcdG5vZGUgPSBwYXJlbnQ7XG5cdFx0XHRcdFx0XHRcdG91dGVyQ2FjaGUgPSBub2RlWyBleHBhbmRvIF0gfHwgKCBub2RlWyBleHBhbmRvIF0gPSB7fSApO1xuXG5cdFx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFIDw5IG9ubHlcblx0XHRcdFx0XHRcdFx0Ly8gRGVmZW5kIGFnYWluc3QgY2xvbmVkIGF0dHJvcGVydGllcyAoalF1ZXJ5IGdoLTE3MDkpXG5cdFx0XHRcdFx0XHRcdHVuaXF1ZUNhY2hlID0gb3V0ZXJDYWNoZVsgbm9kZS51bmlxdWVJRCBdIHx8XG5cdFx0XHRcdFx0XHRcdFx0KCBvdXRlckNhY2hlWyBub2RlLnVuaXF1ZUlEIF0gPSB7fSApO1xuXG5cdFx0XHRcdFx0XHRcdGNhY2hlID0gdW5pcXVlQ2FjaGVbIHR5cGUgXSB8fCBbXTtcblx0XHRcdFx0XHRcdFx0bm9kZUluZGV4ID0gY2FjaGVbIDAgXSA9PT0gZGlycnVucyAmJiBjYWNoZVsgMSBdO1xuXHRcdFx0XHRcdFx0XHRkaWZmID0gbm9kZUluZGV4ICYmIGNhY2hlWyAyIF07XG5cdFx0XHRcdFx0XHRcdG5vZGUgPSBub2RlSW5kZXggJiYgcGFyZW50LmNoaWxkTm9kZXNbIG5vZGVJbmRleCBdO1xuXG5cdFx0XHRcdFx0XHRcdHdoaWxlICggKCBub2RlID0gKytub2RlSW5kZXggJiYgbm9kZSAmJiBub2RlWyBkaXIgXSB8fFxuXG5cdFx0XHRcdFx0XHRcdFx0Ly8gRmFsbGJhY2sgdG8gc2Vla2luZyBgZWxlbWAgZnJvbSB0aGUgc3RhcnRcblx0XHRcdFx0XHRcdFx0XHQoIGRpZmYgPSBub2RlSW5kZXggPSAwICkgfHwgc3RhcnQucG9wKCkgKSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIFdoZW4gZm91bmQsIGNhY2hlIGluZGV4ZXMgb24gYHBhcmVudGAgYW5kIGJyZWFrXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCBub2RlLm5vZGVUeXBlID09PSAxICYmICsrZGlmZiAmJiBub2RlID09PSBlbGVtICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0dW5pcXVlQ2FjaGVbIHR5cGUgXSA9IFsgZGlycnVucywgbm9kZUluZGV4LCBkaWZmIF07XG5cdFx0XHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHQvLyBVc2UgcHJldmlvdXNseS1jYWNoZWQgZWxlbWVudCBpbmRleCBpZiBhdmFpbGFibGVcblx0XHRcdFx0XHRcdFx0aWYgKCB1c2VDYWNoZSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIC4uLmluIGEgZ3ppcC1mcmllbmRseSB3YXlcblx0XHRcdFx0XHRcdFx0XHRub2RlID0gZWxlbTtcblx0XHRcdFx0XHRcdFx0XHRvdXRlckNhY2hlID0gbm9kZVsgZXhwYW5kbyBdIHx8ICggbm9kZVsgZXhwYW5kbyBdID0ge30gKTtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFIDw5IG9ubHlcblx0XHRcdFx0XHRcdFx0XHQvLyBEZWZlbmQgYWdhaW5zdCBjbG9uZWQgYXR0cm9wZXJ0aWVzIChqUXVlcnkgZ2gtMTcwOSlcblx0XHRcdFx0XHRcdFx0XHR1bmlxdWVDYWNoZSA9IG91dGVyQ2FjaGVbIG5vZGUudW5pcXVlSUQgXSB8fFxuXHRcdFx0XHRcdFx0XHRcdFx0KCBvdXRlckNhY2hlWyBub2RlLnVuaXF1ZUlEIF0gPSB7fSApO1xuXG5cdFx0XHRcdFx0XHRcdFx0Y2FjaGUgPSB1bmlxdWVDYWNoZVsgdHlwZSBdIHx8IFtdO1xuXHRcdFx0XHRcdFx0XHRcdG5vZGVJbmRleCA9IGNhY2hlWyAwIF0gPT09IGRpcnJ1bnMgJiYgY2FjaGVbIDEgXTtcblx0XHRcdFx0XHRcdFx0XHRkaWZmID0gbm9kZUluZGV4O1xuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0Ly8geG1sIDpudGgtY2hpbGQoLi4uKVxuXHRcdFx0XHRcdFx0XHQvLyBvciA6bnRoLWxhc3QtY2hpbGQoLi4uKSBvciA6bnRoKC1sYXN0KT8tb2YtdHlwZSguLi4pXG5cdFx0XHRcdFx0XHRcdGlmICggZGlmZiA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHQvLyBVc2UgdGhlIHNhbWUgbG9vcCBhcyBhYm92ZSB0byBzZWVrIGBlbGVtYCBmcm9tIHRoZSBzdGFydFxuXHRcdFx0XHRcdFx0XHRcdHdoaWxlICggKCBub2RlID0gKytub2RlSW5kZXggJiYgbm9kZSAmJiBub2RlWyBkaXIgXSB8fFxuXHRcdFx0XHRcdFx0XHRcdFx0KCBkaWZmID0gbm9kZUluZGV4ID0gMCApIHx8IHN0YXJ0LnBvcCgpICkgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdGlmICggKCBvZlR5cGUgP1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRub2RlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IG5hbWUgOlxuXHRcdFx0XHRcdFx0XHRcdFx0XHRub2RlLm5vZGVUeXBlID09PSAxICkgJiZcblx0XHRcdFx0XHRcdFx0XHRcdFx0KytkaWZmICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIENhY2hlIHRoZSBpbmRleCBvZiBlYWNoIGVuY291bnRlcmVkIGVsZW1lbnRcblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKCB1c2VDYWNoZSApIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRvdXRlckNhY2hlID0gbm9kZVsgZXhwYW5kbyBdIHx8XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQoIG5vZGVbIGV4cGFuZG8gXSA9IHt9ICk7XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBTdXBwb3J0OiBJRSA8OSBvbmx5XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gRGVmZW5kIGFnYWluc3QgY2xvbmVkIGF0dHJvcGVydGllcyAoalF1ZXJ5IGdoLTE3MDkpXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0dW5pcXVlQ2FjaGUgPSBvdXRlckNhY2hlWyBub2RlLnVuaXF1ZUlEIF0gfHxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCggb3V0ZXJDYWNoZVsgbm9kZS51bmlxdWVJRCBdID0ge30gKTtcblxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHVuaXF1ZUNhY2hlWyB0eXBlIF0gPSBbIGRpcnJ1bnMsIGRpZmYgXTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdGlmICggbm9kZSA9PT0gZWxlbSApIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHQvLyBJbmNvcnBvcmF0ZSB0aGUgb2Zmc2V0LCB0aGVuIGNoZWNrIGFnYWluc3QgY3ljbGUgc2l6ZVxuXHRcdFx0XHRcdFx0ZGlmZiAtPSBsYXN0O1xuXHRcdFx0XHRcdFx0cmV0dXJuIGRpZmYgPT09IGZpcnN0IHx8ICggZGlmZiAlIGZpcnN0ID09PSAwICYmIGRpZmYgLyBmaXJzdCA+PSAwICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9O1xuXHRcdH0sXG5cblx0XHRcIlBTRVVET1wiOiBmdW5jdGlvbiggcHNldWRvLCBhcmd1bWVudCApIHtcblxuXHRcdFx0Ly8gcHNldWRvLWNsYXNzIG5hbWVzIGFyZSBjYXNlLWluc2Vuc2l0aXZlXG5cdFx0XHQvLyBodHRwOi8vd3d3LnczLm9yZy9UUi9zZWxlY3RvcnMvI3BzZXVkby1jbGFzc2VzXG5cdFx0XHQvLyBQcmlvcml0aXplIGJ5IGNhc2Ugc2Vuc2l0aXZpdHkgaW4gY2FzZSBjdXN0b20gcHNldWRvcyBhcmUgYWRkZWQgd2l0aCB1cHBlcmNhc2UgbGV0dGVyc1xuXHRcdFx0Ly8gUmVtZW1iZXIgdGhhdCBzZXRGaWx0ZXJzIGluaGVyaXRzIGZyb20gcHNldWRvc1xuXHRcdFx0dmFyIGFyZ3MsXG5cdFx0XHRcdGZuID0gRXhwci5wc2V1ZG9zWyBwc2V1ZG8gXSB8fCBFeHByLnNldEZpbHRlcnNbIHBzZXVkby50b0xvd2VyQ2FzZSgpIF0gfHxcblx0XHRcdFx0XHRTaXp6bGUuZXJyb3IoIFwidW5zdXBwb3J0ZWQgcHNldWRvOiBcIiArIHBzZXVkbyApO1xuXG5cdFx0XHQvLyBUaGUgdXNlciBtYXkgdXNlIGNyZWF0ZVBzZXVkbyB0byBpbmRpY2F0ZSB0aGF0XG5cdFx0XHQvLyBhcmd1bWVudHMgYXJlIG5lZWRlZCB0byBjcmVhdGUgdGhlIGZpbHRlciBmdW5jdGlvblxuXHRcdFx0Ly8ganVzdCBhcyBTaXp6bGUgZG9lc1xuXHRcdFx0aWYgKCBmblsgZXhwYW5kbyBdICkge1xuXHRcdFx0XHRyZXR1cm4gZm4oIGFyZ3VtZW50ICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEJ1dCBtYWludGFpbiBzdXBwb3J0IGZvciBvbGQgc2lnbmF0dXJlc1xuXHRcdFx0aWYgKCBmbi5sZW5ndGggPiAxICkge1xuXHRcdFx0XHRhcmdzID0gWyBwc2V1ZG8sIHBzZXVkbywgXCJcIiwgYXJndW1lbnQgXTtcblx0XHRcdFx0cmV0dXJuIEV4cHIuc2V0RmlsdGVycy5oYXNPd25Qcm9wZXJ0eSggcHNldWRvLnRvTG93ZXJDYXNlKCkgKSA/XG5cdFx0XHRcdFx0bWFya0Z1bmN0aW9uKCBmdW5jdGlvbiggc2VlZCwgbWF0Y2hlcyApIHtcblx0XHRcdFx0XHRcdHZhciBpZHgsXG5cdFx0XHRcdFx0XHRcdG1hdGNoZWQgPSBmbiggc2VlZCwgYXJndW1lbnQgKSxcblx0XHRcdFx0XHRcdFx0aSA9IG1hdGNoZWQubGVuZ3RoO1xuXHRcdFx0XHRcdFx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0XHRcdFx0XHRcdGlkeCA9IGluZGV4T2YoIHNlZWQsIG1hdGNoZWRbIGkgXSApO1xuXHRcdFx0XHRcdFx0XHRzZWVkWyBpZHggXSA9ICEoIG1hdGNoZXNbIGlkeCBdID0gbWF0Y2hlZFsgaSBdICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSApIDpcblx0XHRcdFx0XHRmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdFx0XHRcdHJldHVybiBmbiggZWxlbSwgMCwgYXJncyApO1xuXHRcdFx0XHRcdH07XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBmbjtcblx0XHR9XG5cdH0sXG5cblx0cHNldWRvczoge1xuXG5cdFx0Ly8gUG90ZW50aWFsbHkgY29tcGxleCBwc2V1ZG9zXG5cdFx0XCJub3RcIjogbWFya0Z1bmN0aW9uKCBmdW5jdGlvbiggc2VsZWN0b3IgKSB7XG5cblx0XHRcdC8vIFRyaW0gdGhlIHNlbGVjdG9yIHBhc3NlZCB0byBjb21waWxlXG5cdFx0XHQvLyB0byBhdm9pZCB0cmVhdGluZyBsZWFkaW5nIGFuZCB0cmFpbGluZ1xuXHRcdFx0Ly8gc3BhY2VzIGFzIGNvbWJpbmF0b3JzXG5cdFx0XHR2YXIgaW5wdXQgPSBbXSxcblx0XHRcdFx0cmVzdWx0cyA9IFtdLFxuXHRcdFx0XHRtYXRjaGVyID0gY29tcGlsZSggc2VsZWN0b3IucmVwbGFjZSggcnRyaW0sIFwiJDFcIiApICk7XG5cblx0XHRcdHJldHVybiBtYXRjaGVyWyBleHBhbmRvIF0gP1xuXHRcdFx0XHRtYXJrRnVuY3Rpb24oIGZ1bmN0aW9uKCBzZWVkLCBtYXRjaGVzLCBfY29udGV4dCwgeG1sICkge1xuXHRcdFx0XHRcdHZhciBlbGVtLFxuXHRcdFx0XHRcdFx0dW5tYXRjaGVkID0gbWF0Y2hlciggc2VlZCwgbnVsbCwgeG1sLCBbXSApLFxuXHRcdFx0XHRcdFx0aSA9IHNlZWQubGVuZ3RoO1xuXG5cdFx0XHRcdFx0Ly8gTWF0Y2ggZWxlbWVudHMgdW5tYXRjaGVkIGJ5IGBtYXRjaGVyYFxuXHRcdFx0XHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0XHRcdFx0aWYgKCAoIGVsZW0gPSB1bm1hdGNoZWRbIGkgXSApICkge1xuXHRcdFx0XHRcdFx0XHRzZWVkWyBpIF0gPSAhKCBtYXRjaGVzWyBpIF0gPSBlbGVtICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICkgOlxuXHRcdFx0XHRmdW5jdGlvbiggZWxlbSwgX2NvbnRleHQsIHhtbCApIHtcblx0XHRcdFx0XHRpbnB1dFsgMCBdID0gZWxlbTtcblx0XHRcdFx0XHRtYXRjaGVyKCBpbnB1dCwgbnVsbCwgeG1sLCByZXN1bHRzICk7XG5cblx0XHRcdFx0XHQvLyBEb24ndCBrZWVwIHRoZSBlbGVtZW50IChpc3N1ZSAjMjk5KVxuXHRcdFx0XHRcdGlucHV0WyAwIF0gPSBudWxsO1xuXHRcdFx0XHRcdHJldHVybiAhcmVzdWx0cy5wb3AoKTtcblx0XHRcdFx0fTtcblx0XHR9ICksXG5cblx0XHRcImhhc1wiOiBtYXJrRnVuY3Rpb24oIGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHRcdHJldHVybiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdFx0cmV0dXJuIFNpenpsZSggc2VsZWN0b3IsIGVsZW0gKS5sZW5ndGggPiAwO1xuXHRcdFx0fTtcblx0XHR9ICksXG5cblx0XHRcImNvbnRhaW5zXCI6IG1hcmtGdW5jdGlvbiggZnVuY3Rpb24oIHRleHQgKSB7XG5cdFx0XHR0ZXh0ID0gdGV4dC5yZXBsYWNlKCBydW5lc2NhcGUsIGZ1bmVzY2FwZSApO1xuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHRyZXR1cm4gKCBlbGVtLnRleHRDb250ZW50IHx8IGdldFRleHQoIGVsZW0gKSApLmluZGV4T2YoIHRleHQgKSA+IC0xO1xuXHRcdFx0fTtcblx0XHR9ICksXG5cblx0XHQvLyBcIldoZXRoZXIgYW4gZWxlbWVudCBpcyByZXByZXNlbnRlZCBieSBhIDpsYW5nKCkgc2VsZWN0b3Jcblx0XHQvLyBpcyBiYXNlZCBzb2xlbHkgb24gdGhlIGVsZW1lbnQncyBsYW5ndWFnZSB2YWx1ZVxuXHRcdC8vIGJlaW5nIGVxdWFsIHRvIHRoZSBpZGVudGlmaWVyIEMsXG5cdFx0Ly8gb3IgYmVnaW5uaW5nIHdpdGggdGhlIGlkZW50aWZpZXIgQyBpbW1lZGlhdGVseSBmb2xsb3dlZCBieSBcIi1cIi5cblx0XHQvLyBUaGUgbWF0Y2hpbmcgb2YgQyBhZ2FpbnN0IHRoZSBlbGVtZW50J3MgbGFuZ3VhZ2UgdmFsdWUgaXMgcGVyZm9ybWVkIGNhc2UtaW5zZW5zaXRpdmVseS5cblx0XHQvLyBUaGUgaWRlbnRpZmllciBDIGRvZXMgbm90IGhhdmUgdG8gYmUgYSB2YWxpZCBsYW5ndWFnZSBuYW1lLlwiXG5cdFx0Ly8gaHR0cDovL3d3dy53My5vcmcvVFIvc2VsZWN0b3JzLyNsYW5nLXBzZXVkb1xuXHRcdFwibGFuZ1wiOiBtYXJrRnVuY3Rpb24oIGZ1bmN0aW9uKCBsYW5nICkge1xuXG5cdFx0XHQvLyBsYW5nIHZhbHVlIG11c3QgYmUgYSB2YWxpZCBpZGVudGlmaWVyXG5cdFx0XHRpZiAoICFyaWRlbnRpZmllci50ZXN0KCBsYW5nIHx8IFwiXCIgKSApIHtcblx0XHRcdFx0U2l6emxlLmVycm9yKCBcInVuc3VwcG9ydGVkIGxhbmc6IFwiICsgbGFuZyApO1xuXHRcdFx0fVxuXHRcdFx0bGFuZyA9IGxhbmcucmVwbGFjZSggcnVuZXNjYXBlLCBmdW5lc2NhcGUgKS50b0xvd2VyQ2FzZSgpO1xuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHR2YXIgZWxlbUxhbmc7XG5cdFx0XHRcdGRvIHtcblx0XHRcdFx0XHRpZiAoICggZWxlbUxhbmcgPSBkb2N1bWVudElzSFRNTCA/XG5cdFx0XHRcdFx0XHRlbGVtLmxhbmcgOlxuXHRcdFx0XHRcdFx0ZWxlbS5nZXRBdHRyaWJ1dGUoIFwieG1sOmxhbmdcIiApIHx8IGVsZW0uZ2V0QXR0cmlidXRlKCBcImxhbmdcIiApICkgKSB7XG5cblx0XHRcdFx0XHRcdGVsZW1MYW5nID0gZWxlbUxhbmcudG9Mb3dlckNhc2UoKTtcblx0XHRcdFx0XHRcdHJldHVybiBlbGVtTGFuZyA9PT0gbGFuZyB8fCBlbGVtTGFuZy5pbmRleE9mKCBsYW5nICsgXCItXCIgKSA9PT0gMDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gd2hpbGUgKCAoIGVsZW0gPSBlbGVtLnBhcmVudE5vZGUgKSAmJiBlbGVtLm5vZGVUeXBlID09PSAxICk7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH07XG5cdFx0fSApLFxuXG5cdFx0Ly8gTWlzY2VsbGFuZW91c1xuXHRcdFwidGFyZ2V0XCI6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0dmFyIGhhc2ggPSB3aW5kb3cubG9jYXRpb24gJiYgd2luZG93LmxvY2F0aW9uLmhhc2g7XG5cdFx0XHRyZXR1cm4gaGFzaCAmJiBoYXNoLnNsaWNlKCAxICkgPT09IGVsZW0uaWQ7XG5cdFx0fSxcblxuXHRcdFwicm9vdFwiOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdHJldHVybiBlbGVtID09PSBkb2NFbGVtO1xuXHRcdH0sXG5cblx0XHRcImZvY3VzXCI6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0cmV0dXJuIGVsZW0gPT09IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQgJiZcblx0XHRcdFx0KCAhZG9jdW1lbnQuaGFzRm9jdXMgfHwgZG9jdW1lbnQuaGFzRm9jdXMoKSApICYmXG5cdFx0XHRcdCEhKCBlbGVtLnR5cGUgfHwgZWxlbS5ocmVmIHx8IH5lbGVtLnRhYkluZGV4ICk7XG5cdFx0fSxcblxuXHRcdC8vIEJvb2xlYW4gcHJvcGVydGllc1xuXHRcdFwiZW5hYmxlZFwiOiBjcmVhdGVEaXNhYmxlZFBzZXVkbyggZmFsc2UgKSxcblx0XHRcImRpc2FibGVkXCI6IGNyZWF0ZURpc2FibGVkUHNldWRvKCB0cnVlICksXG5cblx0XHRcImNoZWNrZWRcIjogZnVuY3Rpb24oIGVsZW0gKSB7XG5cblx0XHRcdC8vIEluIENTUzMsIDpjaGVja2VkIHNob3VsZCByZXR1cm4gYm90aCBjaGVja2VkIGFuZCBzZWxlY3RlZCBlbGVtZW50c1xuXHRcdFx0Ly8gaHR0cDovL3d3dy53My5vcmcvVFIvMjAxMS9SRUMtY3NzMy1zZWxlY3RvcnMtMjAxMTA5MjkvI2NoZWNrZWRcblx0XHRcdHZhciBub2RlTmFtZSA9IGVsZW0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtcblx0XHRcdHJldHVybiAoIG5vZGVOYW1lID09PSBcImlucHV0XCIgJiYgISFlbGVtLmNoZWNrZWQgKSB8fFxuXHRcdFx0XHQoIG5vZGVOYW1lID09PSBcIm9wdGlvblwiICYmICEhZWxlbS5zZWxlY3RlZCApO1xuXHRcdH0sXG5cblx0XHRcInNlbGVjdGVkXCI6IGZ1bmN0aW9uKCBlbGVtICkge1xuXG5cdFx0XHQvLyBBY2Nlc3NpbmcgdGhpcyBwcm9wZXJ0eSBtYWtlcyBzZWxlY3RlZC1ieS1kZWZhdWx0XG5cdFx0XHQvLyBvcHRpb25zIGluIFNhZmFyaSB3b3JrIHByb3Blcmx5XG5cdFx0XHRpZiAoIGVsZW0ucGFyZW50Tm9kZSApIHtcblx0XHRcdFx0Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVudXNlZC1leHByZXNzaW9uc1xuXHRcdFx0XHRlbGVtLnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleDtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGVsZW0uc2VsZWN0ZWQgPT09IHRydWU7XG5cdFx0fSxcblxuXHRcdC8vIENvbnRlbnRzXG5cdFx0XCJlbXB0eVwiOiBmdW5jdGlvbiggZWxlbSApIHtcblxuXHRcdFx0Ly8gaHR0cDovL3d3dy53My5vcmcvVFIvc2VsZWN0b3JzLyNlbXB0eS1wc2V1ZG9cblx0XHRcdC8vIDplbXB0eSBpcyBuZWdhdGVkIGJ5IGVsZW1lbnQgKDEpIG9yIGNvbnRlbnQgbm9kZXMgKHRleHQ6IDM7IGNkYXRhOiA0OyBlbnRpdHkgcmVmOiA1KSxcblx0XHRcdC8vICAgYnV0IG5vdCBieSBvdGhlcnMgKGNvbW1lbnQ6IDg7IHByb2Nlc3NpbmcgaW5zdHJ1Y3Rpb246IDc7IGV0Yy4pXG5cdFx0XHQvLyBub2RlVHlwZSA8IDYgd29ya3MgYmVjYXVzZSBhdHRyaWJ1dGVzICgyKSBkbyBub3QgYXBwZWFyIGFzIGNoaWxkcmVuXG5cdFx0XHRmb3IgKCBlbGVtID0gZWxlbS5maXJzdENoaWxkOyBlbGVtOyBlbGVtID0gZWxlbS5uZXh0U2libGluZyApIHtcblx0XHRcdFx0aWYgKCBlbGVtLm5vZGVUeXBlIDwgNiApIHtcblx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH0sXG5cblx0XHRcInBhcmVudFwiOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdHJldHVybiAhRXhwci5wc2V1ZG9zWyBcImVtcHR5XCIgXSggZWxlbSApO1xuXHRcdH0sXG5cblx0XHQvLyBFbGVtZW50L2lucHV0IHR5cGVzXG5cdFx0XCJoZWFkZXJcIjogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gcmhlYWRlci50ZXN0KCBlbGVtLm5vZGVOYW1lICk7XG5cdFx0fSxcblxuXHRcdFwiaW5wdXRcIjogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gcmlucHV0cy50ZXN0KCBlbGVtLm5vZGVOYW1lICk7XG5cdFx0fSxcblxuXHRcdFwiYnV0dG9uXCI6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0dmFyIG5hbWUgPSBlbGVtLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7XG5cdFx0XHRyZXR1cm4gbmFtZSA9PT0gXCJpbnB1dFwiICYmIGVsZW0udHlwZSA9PT0gXCJidXR0b25cIiB8fCBuYW1lID09PSBcImJ1dHRvblwiO1xuXHRcdH0sXG5cblx0XHRcInRleHRcIjogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHR2YXIgYXR0cjtcblx0XHRcdHJldHVybiBlbGVtLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IFwiaW5wdXRcIiAmJlxuXHRcdFx0XHRlbGVtLnR5cGUgPT09IFwidGV4dFwiICYmXG5cblx0XHRcdFx0Ly8gU3VwcG9ydDogSUU8OFxuXHRcdFx0XHQvLyBOZXcgSFRNTDUgYXR0cmlidXRlIHZhbHVlcyAoZS5nLiwgXCJzZWFyY2hcIikgYXBwZWFyIHdpdGggZWxlbS50eXBlID09PSBcInRleHRcIlxuXHRcdFx0XHQoICggYXR0ciA9IGVsZW0uZ2V0QXR0cmlidXRlKCBcInR5cGVcIiApICkgPT0gbnVsbCB8fFxuXHRcdFx0XHRcdGF0dHIudG9Mb3dlckNhc2UoKSA9PT0gXCJ0ZXh0XCIgKTtcblx0XHR9LFxuXG5cdFx0Ly8gUG9zaXRpb24taW4tY29sbGVjdGlvblxuXHRcdFwiZmlyc3RcIjogY3JlYXRlUG9zaXRpb25hbFBzZXVkbyggZnVuY3Rpb24oKSB7XG5cdFx0XHRyZXR1cm4gWyAwIF07XG5cdFx0fSApLFxuXG5cdFx0XCJsYXN0XCI6IGNyZWF0ZVBvc2l0aW9uYWxQc2V1ZG8oIGZ1bmN0aW9uKCBfbWF0Y2hJbmRleGVzLCBsZW5ndGggKSB7XG5cdFx0XHRyZXR1cm4gWyBsZW5ndGggLSAxIF07XG5cdFx0fSApLFxuXG5cdFx0XCJlcVwiOiBjcmVhdGVQb3NpdGlvbmFsUHNldWRvKCBmdW5jdGlvbiggX21hdGNoSW5kZXhlcywgbGVuZ3RoLCBhcmd1bWVudCApIHtcblx0XHRcdHJldHVybiBbIGFyZ3VtZW50IDwgMCA/IGFyZ3VtZW50ICsgbGVuZ3RoIDogYXJndW1lbnQgXTtcblx0XHR9ICksXG5cblx0XHRcImV2ZW5cIjogY3JlYXRlUG9zaXRpb25hbFBzZXVkbyggZnVuY3Rpb24oIG1hdGNoSW5kZXhlcywgbGVuZ3RoICkge1xuXHRcdFx0dmFyIGkgPSAwO1xuXHRcdFx0Zm9yICggOyBpIDwgbGVuZ3RoOyBpICs9IDIgKSB7XG5cdFx0XHRcdG1hdGNoSW5kZXhlcy5wdXNoKCBpICk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gbWF0Y2hJbmRleGVzO1xuXHRcdH0gKSxcblxuXHRcdFwib2RkXCI6IGNyZWF0ZVBvc2l0aW9uYWxQc2V1ZG8oIGZ1bmN0aW9uKCBtYXRjaEluZGV4ZXMsIGxlbmd0aCApIHtcblx0XHRcdHZhciBpID0gMTtcblx0XHRcdGZvciAoIDsgaSA8IGxlbmd0aDsgaSArPSAyICkge1xuXHRcdFx0XHRtYXRjaEluZGV4ZXMucHVzaCggaSApO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIG1hdGNoSW5kZXhlcztcblx0XHR9ICksXG5cblx0XHRcImx0XCI6IGNyZWF0ZVBvc2l0aW9uYWxQc2V1ZG8oIGZ1bmN0aW9uKCBtYXRjaEluZGV4ZXMsIGxlbmd0aCwgYXJndW1lbnQgKSB7XG5cdFx0XHR2YXIgaSA9IGFyZ3VtZW50IDwgMCA/XG5cdFx0XHRcdGFyZ3VtZW50ICsgbGVuZ3RoIDpcblx0XHRcdFx0YXJndW1lbnQgPiBsZW5ndGggP1xuXHRcdFx0XHRcdGxlbmd0aCA6XG5cdFx0XHRcdFx0YXJndW1lbnQ7XG5cdFx0XHRmb3IgKCA7IC0taSA+PSAwOyApIHtcblx0XHRcdFx0bWF0Y2hJbmRleGVzLnB1c2goIGkgKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBtYXRjaEluZGV4ZXM7XG5cdFx0fSApLFxuXG5cdFx0XCJndFwiOiBjcmVhdGVQb3NpdGlvbmFsUHNldWRvKCBmdW5jdGlvbiggbWF0Y2hJbmRleGVzLCBsZW5ndGgsIGFyZ3VtZW50ICkge1xuXHRcdFx0dmFyIGkgPSBhcmd1bWVudCA8IDAgPyBhcmd1bWVudCArIGxlbmd0aCA6IGFyZ3VtZW50O1xuXHRcdFx0Zm9yICggOyArK2kgPCBsZW5ndGg7ICkge1xuXHRcdFx0XHRtYXRjaEluZGV4ZXMucHVzaCggaSApO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIG1hdGNoSW5kZXhlcztcblx0XHR9IClcblx0fVxufTtcblxuRXhwci5wc2V1ZG9zWyBcIm50aFwiIF0gPSBFeHByLnBzZXVkb3NbIFwiZXFcIiBdO1xuXG4vLyBBZGQgYnV0dG9uL2lucHV0IHR5cGUgcHNldWRvc1xuZm9yICggaSBpbiB7IHJhZGlvOiB0cnVlLCBjaGVja2JveDogdHJ1ZSwgZmlsZTogdHJ1ZSwgcGFzc3dvcmQ6IHRydWUsIGltYWdlOiB0cnVlIH0gKSB7XG5cdEV4cHIucHNldWRvc1sgaSBdID0gY3JlYXRlSW5wdXRQc2V1ZG8oIGkgKTtcbn1cbmZvciAoIGkgaW4geyBzdWJtaXQ6IHRydWUsIHJlc2V0OiB0cnVlIH0gKSB7XG5cdEV4cHIucHNldWRvc1sgaSBdID0gY3JlYXRlQnV0dG9uUHNldWRvKCBpICk7XG59XG5cbi8vIEVhc3kgQVBJIGZvciBjcmVhdGluZyBuZXcgc2V0RmlsdGVyc1xuZnVuY3Rpb24gc2V0RmlsdGVycygpIHt9XG5zZXRGaWx0ZXJzLnByb3RvdHlwZSA9IEV4cHIuZmlsdGVycyA9IEV4cHIucHNldWRvcztcbkV4cHIuc2V0RmlsdGVycyA9IG5ldyBzZXRGaWx0ZXJzKCk7XG5cbnRva2VuaXplID0gU2l6emxlLnRva2VuaXplID0gZnVuY3Rpb24oIHNlbGVjdG9yLCBwYXJzZU9ubHkgKSB7XG5cdHZhciBtYXRjaGVkLCBtYXRjaCwgdG9rZW5zLCB0eXBlLFxuXHRcdHNvRmFyLCBncm91cHMsIHByZUZpbHRlcnMsXG5cdFx0Y2FjaGVkID0gdG9rZW5DYWNoZVsgc2VsZWN0b3IgKyBcIiBcIiBdO1xuXG5cdGlmICggY2FjaGVkICkge1xuXHRcdHJldHVybiBwYXJzZU9ubHkgPyAwIDogY2FjaGVkLnNsaWNlKCAwICk7XG5cdH1cblxuXHRzb0ZhciA9IHNlbGVjdG9yO1xuXHRncm91cHMgPSBbXTtcblx0cHJlRmlsdGVycyA9IEV4cHIucHJlRmlsdGVyO1xuXG5cdHdoaWxlICggc29GYXIgKSB7XG5cblx0XHQvLyBDb21tYSBhbmQgZmlyc3QgcnVuXG5cdFx0aWYgKCAhbWF0Y2hlZCB8fCAoIG1hdGNoID0gcmNvbW1hLmV4ZWMoIHNvRmFyICkgKSApIHtcblx0XHRcdGlmICggbWF0Y2ggKSB7XG5cblx0XHRcdFx0Ly8gRG9uJ3QgY29uc3VtZSB0cmFpbGluZyBjb21tYXMgYXMgdmFsaWRcblx0XHRcdFx0c29GYXIgPSBzb0Zhci5zbGljZSggbWF0Y2hbIDAgXS5sZW5ndGggKSB8fCBzb0Zhcjtcblx0XHRcdH1cblx0XHRcdGdyb3Vwcy5wdXNoKCAoIHRva2VucyA9IFtdICkgKTtcblx0XHR9XG5cblx0XHRtYXRjaGVkID0gZmFsc2U7XG5cblx0XHQvLyBDb21iaW5hdG9yc1xuXHRcdGlmICggKCBtYXRjaCA9IHJjb21iaW5hdG9ycy5leGVjKCBzb0ZhciApICkgKSB7XG5cdFx0XHRtYXRjaGVkID0gbWF0Y2guc2hpZnQoKTtcblx0XHRcdHRva2Vucy5wdXNoKCB7XG5cdFx0XHRcdHZhbHVlOiBtYXRjaGVkLFxuXG5cdFx0XHRcdC8vIENhc3QgZGVzY2VuZGFudCBjb21iaW5hdG9ycyB0byBzcGFjZVxuXHRcdFx0XHR0eXBlOiBtYXRjaFsgMCBdLnJlcGxhY2UoIHJ0cmltLCBcIiBcIiApXG5cdFx0XHR9ICk7XG5cdFx0XHRzb0ZhciA9IHNvRmFyLnNsaWNlKCBtYXRjaGVkLmxlbmd0aCApO1xuXHRcdH1cblxuXHRcdC8vIEZpbHRlcnNcblx0XHRmb3IgKCB0eXBlIGluIEV4cHIuZmlsdGVyICkge1xuXHRcdFx0aWYgKCAoIG1hdGNoID0gbWF0Y2hFeHByWyB0eXBlIF0uZXhlYyggc29GYXIgKSApICYmICggIXByZUZpbHRlcnNbIHR5cGUgXSB8fFxuXHRcdFx0XHQoIG1hdGNoID0gcHJlRmlsdGVyc1sgdHlwZSBdKCBtYXRjaCApICkgKSApIHtcblx0XHRcdFx0bWF0Y2hlZCA9IG1hdGNoLnNoaWZ0KCk7XG5cdFx0XHRcdHRva2Vucy5wdXNoKCB7XG5cdFx0XHRcdFx0dmFsdWU6IG1hdGNoZWQsXG5cdFx0XHRcdFx0dHlwZTogdHlwZSxcblx0XHRcdFx0XHRtYXRjaGVzOiBtYXRjaFxuXHRcdFx0XHR9ICk7XG5cdFx0XHRcdHNvRmFyID0gc29GYXIuc2xpY2UoIG1hdGNoZWQubGVuZ3RoICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCAhbWF0Y2hlZCApIHtcblx0XHRcdGJyZWFrO1xuXHRcdH1cblx0fVxuXG5cdC8vIFJldHVybiB0aGUgbGVuZ3RoIG9mIHRoZSBpbnZhbGlkIGV4Y2Vzc1xuXHQvLyBpZiB3ZSdyZSBqdXN0IHBhcnNpbmdcblx0Ly8gT3RoZXJ3aXNlLCB0aHJvdyBhbiBlcnJvciBvciByZXR1cm4gdG9rZW5zXG5cdHJldHVybiBwYXJzZU9ubHkgP1xuXHRcdHNvRmFyLmxlbmd0aCA6XG5cdFx0c29GYXIgP1xuXHRcdFx0U2l6emxlLmVycm9yKCBzZWxlY3RvciApIDpcblxuXHRcdFx0Ly8gQ2FjaGUgdGhlIHRva2Vuc1xuXHRcdFx0dG9rZW5DYWNoZSggc2VsZWN0b3IsIGdyb3VwcyApLnNsaWNlKCAwICk7XG59O1xuXG5mdW5jdGlvbiB0b1NlbGVjdG9yKCB0b2tlbnMgKSB7XG5cdHZhciBpID0gMCxcblx0XHRsZW4gPSB0b2tlbnMubGVuZ3RoLFxuXHRcdHNlbGVjdG9yID0gXCJcIjtcblx0Zm9yICggOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0c2VsZWN0b3IgKz0gdG9rZW5zWyBpIF0udmFsdWU7XG5cdH1cblx0cmV0dXJuIHNlbGVjdG9yO1xufVxuXG5mdW5jdGlvbiBhZGRDb21iaW5hdG9yKCBtYXRjaGVyLCBjb21iaW5hdG9yLCBiYXNlICkge1xuXHR2YXIgZGlyID0gY29tYmluYXRvci5kaXIsXG5cdFx0c2tpcCA9IGNvbWJpbmF0b3IubmV4dCxcblx0XHRrZXkgPSBza2lwIHx8IGRpcixcblx0XHRjaGVja05vbkVsZW1lbnRzID0gYmFzZSAmJiBrZXkgPT09IFwicGFyZW50Tm9kZVwiLFxuXHRcdGRvbmVOYW1lID0gZG9uZSsrO1xuXG5cdHJldHVybiBjb21iaW5hdG9yLmZpcnN0ID9cblxuXHRcdC8vIENoZWNrIGFnYWluc3QgY2xvc2VzdCBhbmNlc3Rvci9wcmVjZWRpbmcgZWxlbWVudFxuXHRcdGZ1bmN0aW9uKCBlbGVtLCBjb250ZXh0LCB4bWwgKSB7XG5cdFx0XHR3aGlsZSAoICggZWxlbSA9IGVsZW1bIGRpciBdICkgKSB7XG5cdFx0XHRcdGlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSB8fCBjaGVja05vbkVsZW1lbnRzICkge1xuXHRcdFx0XHRcdHJldHVybiBtYXRjaGVyKCBlbGVtLCBjb250ZXh0LCB4bWwgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH0gOlxuXG5cdFx0Ly8gQ2hlY2sgYWdhaW5zdCBhbGwgYW5jZXN0b3IvcHJlY2VkaW5nIGVsZW1lbnRzXG5cdFx0ZnVuY3Rpb24oIGVsZW0sIGNvbnRleHQsIHhtbCApIHtcblx0XHRcdHZhciBvbGRDYWNoZSwgdW5pcXVlQ2FjaGUsIG91dGVyQ2FjaGUsXG5cdFx0XHRcdG5ld0NhY2hlID0gWyBkaXJydW5zLCBkb25lTmFtZSBdO1xuXG5cdFx0XHQvLyBXZSBjYW4ndCBzZXQgYXJiaXRyYXJ5IGRhdGEgb24gWE1MIG5vZGVzLCBzbyB0aGV5IGRvbid0IGJlbmVmaXQgZnJvbSBjb21iaW5hdG9yIGNhY2hpbmdcblx0XHRcdGlmICggeG1sICkge1xuXHRcdFx0XHR3aGlsZSAoICggZWxlbSA9IGVsZW1bIGRpciBdICkgKSB7XG5cdFx0XHRcdFx0aWYgKCBlbGVtLm5vZGVUeXBlID09PSAxIHx8IGNoZWNrTm9uRWxlbWVudHMgKSB7XG5cdFx0XHRcdFx0XHRpZiAoIG1hdGNoZXIoIGVsZW0sIGNvbnRleHQsIHhtbCApICkge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHdoaWxlICggKCBlbGVtID0gZWxlbVsgZGlyIF0gKSApIHtcblx0XHRcdFx0XHRpZiAoIGVsZW0ubm9kZVR5cGUgPT09IDEgfHwgY2hlY2tOb25FbGVtZW50cyApIHtcblx0XHRcdFx0XHRcdG91dGVyQ2FjaGUgPSBlbGVtWyBleHBhbmRvIF0gfHwgKCBlbGVtWyBleHBhbmRvIF0gPSB7fSApO1xuXG5cdFx0XHRcdFx0XHQvLyBTdXBwb3J0OiBJRSA8OSBvbmx5XG5cdFx0XHRcdFx0XHQvLyBEZWZlbmQgYWdhaW5zdCBjbG9uZWQgYXR0cm9wZXJ0aWVzIChqUXVlcnkgZ2gtMTcwOSlcblx0XHRcdFx0XHRcdHVuaXF1ZUNhY2hlID0gb3V0ZXJDYWNoZVsgZWxlbS51bmlxdWVJRCBdIHx8XG5cdFx0XHRcdFx0XHRcdCggb3V0ZXJDYWNoZVsgZWxlbS51bmlxdWVJRCBdID0ge30gKTtcblxuXHRcdFx0XHRcdFx0aWYgKCBza2lwICYmIHNraXAgPT09IGVsZW0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKSApIHtcblx0XHRcdFx0XHRcdFx0ZWxlbSA9IGVsZW1bIGRpciBdIHx8IGVsZW07XG5cdFx0XHRcdFx0XHR9IGVsc2UgaWYgKCAoIG9sZENhY2hlID0gdW5pcXVlQ2FjaGVbIGtleSBdICkgJiZcblx0XHRcdFx0XHRcdFx0b2xkQ2FjaGVbIDAgXSA9PT0gZGlycnVucyAmJiBvbGRDYWNoZVsgMSBdID09PSBkb25lTmFtZSApIHtcblxuXHRcdFx0XHRcdFx0XHQvLyBBc3NpZ24gdG8gbmV3Q2FjaGUgc28gcmVzdWx0cyBiYWNrLXByb3BhZ2F0ZSB0byBwcmV2aW91cyBlbGVtZW50c1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gKCBuZXdDYWNoZVsgMiBdID0gb2xkQ2FjaGVbIDIgXSApO1xuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHQvLyBSZXVzZSBuZXdjYWNoZSBzbyByZXN1bHRzIGJhY2stcHJvcGFnYXRlIHRvIHByZXZpb3VzIGVsZW1lbnRzXG5cdFx0XHRcdFx0XHRcdHVuaXF1ZUNhY2hlWyBrZXkgXSA9IG5ld0NhY2hlO1xuXG5cdFx0XHRcdFx0XHRcdC8vIEEgbWF0Y2ggbWVhbnMgd2UncmUgZG9uZTsgYSBmYWlsIG1lYW5zIHdlIGhhdmUgdG8ga2VlcCBjaGVja2luZ1xuXHRcdFx0XHRcdFx0XHRpZiAoICggbmV3Q2FjaGVbIDIgXSA9IG1hdGNoZXIoIGVsZW0sIGNvbnRleHQsIHhtbCApICkgKSB7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9O1xufVxuXG5mdW5jdGlvbiBlbGVtZW50TWF0Y2hlciggbWF0Y2hlcnMgKSB7XG5cdHJldHVybiBtYXRjaGVycy5sZW5ndGggPiAxID9cblx0XHRmdW5jdGlvbiggZWxlbSwgY29udGV4dCwgeG1sICkge1xuXHRcdFx0dmFyIGkgPSBtYXRjaGVycy5sZW5ndGg7XG5cdFx0XHR3aGlsZSAoIGktLSApIHtcblx0XHRcdFx0aWYgKCAhbWF0Y2hlcnNbIGkgXSggZWxlbSwgY29udGV4dCwgeG1sICkgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9IDpcblx0XHRtYXRjaGVyc1sgMCBdO1xufVxuXG5mdW5jdGlvbiBtdWx0aXBsZUNvbnRleHRzKCBzZWxlY3RvciwgY29udGV4dHMsIHJlc3VsdHMgKSB7XG5cdHZhciBpID0gMCxcblx0XHRsZW4gPSBjb250ZXh0cy5sZW5ndGg7XG5cdGZvciAoIDsgaSA8IGxlbjsgaSsrICkge1xuXHRcdFNpenpsZSggc2VsZWN0b3IsIGNvbnRleHRzWyBpIF0sIHJlc3VsdHMgKTtcblx0fVxuXHRyZXR1cm4gcmVzdWx0cztcbn1cblxuZnVuY3Rpb24gY29uZGVuc2UoIHVubWF0Y2hlZCwgbWFwLCBmaWx0ZXIsIGNvbnRleHQsIHhtbCApIHtcblx0dmFyIGVsZW0sXG5cdFx0bmV3VW5tYXRjaGVkID0gW10sXG5cdFx0aSA9IDAsXG5cdFx0bGVuID0gdW5tYXRjaGVkLmxlbmd0aCxcblx0XHRtYXBwZWQgPSBtYXAgIT0gbnVsbDtcblxuXHRmb3IgKCA7IGkgPCBsZW47IGkrKyApIHtcblx0XHRpZiAoICggZWxlbSA9IHVubWF0Y2hlZFsgaSBdICkgKSB7XG5cdFx0XHRpZiAoICFmaWx0ZXIgfHwgZmlsdGVyKCBlbGVtLCBjb250ZXh0LCB4bWwgKSApIHtcblx0XHRcdFx0bmV3VW5tYXRjaGVkLnB1c2goIGVsZW0gKTtcblx0XHRcdFx0aWYgKCBtYXBwZWQgKSB7XG5cdFx0XHRcdFx0bWFwLnB1c2goIGkgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdHJldHVybiBuZXdVbm1hdGNoZWQ7XG59XG5cbmZ1bmN0aW9uIHNldE1hdGNoZXIoIHByZUZpbHRlciwgc2VsZWN0b3IsIG1hdGNoZXIsIHBvc3RGaWx0ZXIsIHBvc3RGaW5kZXIsIHBvc3RTZWxlY3RvciApIHtcblx0aWYgKCBwb3N0RmlsdGVyICYmICFwb3N0RmlsdGVyWyBleHBhbmRvIF0gKSB7XG5cdFx0cG9zdEZpbHRlciA9IHNldE1hdGNoZXIoIHBvc3RGaWx0ZXIgKTtcblx0fVxuXHRpZiAoIHBvc3RGaW5kZXIgJiYgIXBvc3RGaW5kZXJbIGV4cGFuZG8gXSApIHtcblx0XHRwb3N0RmluZGVyID0gc2V0TWF0Y2hlciggcG9zdEZpbmRlciwgcG9zdFNlbGVjdG9yICk7XG5cdH1cblx0cmV0dXJuIG1hcmtGdW5jdGlvbiggZnVuY3Rpb24oIHNlZWQsIHJlc3VsdHMsIGNvbnRleHQsIHhtbCApIHtcblx0XHR2YXIgdGVtcCwgaSwgZWxlbSxcblx0XHRcdHByZU1hcCA9IFtdLFxuXHRcdFx0cG9zdE1hcCA9IFtdLFxuXHRcdFx0cHJlZXhpc3RpbmcgPSByZXN1bHRzLmxlbmd0aCxcblxuXHRcdFx0Ly8gR2V0IGluaXRpYWwgZWxlbWVudHMgZnJvbSBzZWVkIG9yIGNvbnRleHRcblx0XHRcdGVsZW1zID0gc2VlZCB8fCBtdWx0aXBsZUNvbnRleHRzKFxuXHRcdFx0XHRzZWxlY3RvciB8fCBcIipcIixcblx0XHRcdFx0Y29udGV4dC5ub2RlVHlwZSA/IFsgY29udGV4dCBdIDogY29udGV4dCxcblx0XHRcdFx0W11cblx0XHRcdCksXG5cblx0XHRcdC8vIFByZWZpbHRlciB0byBnZXQgbWF0Y2hlciBpbnB1dCwgcHJlc2VydmluZyBhIG1hcCBmb3Igc2VlZC1yZXN1bHRzIHN5bmNocm9uaXphdGlvblxuXHRcdFx0bWF0Y2hlckluID0gcHJlRmlsdGVyICYmICggc2VlZCB8fCAhc2VsZWN0b3IgKSA/XG5cdFx0XHRcdGNvbmRlbnNlKCBlbGVtcywgcHJlTWFwLCBwcmVGaWx0ZXIsIGNvbnRleHQsIHhtbCApIDpcblx0XHRcdFx0ZWxlbXMsXG5cblx0XHRcdG1hdGNoZXJPdXQgPSBtYXRjaGVyID9cblxuXHRcdFx0XHQvLyBJZiB3ZSBoYXZlIGEgcG9zdEZpbmRlciwgb3IgZmlsdGVyZWQgc2VlZCwgb3Igbm9uLXNlZWQgcG9zdEZpbHRlciBvciBwcmVleGlzdGluZyByZXN1bHRzLFxuXHRcdFx0XHRwb3N0RmluZGVyIHx8ICggc2VlZCA/IHByZUZpbHRlciA6IHByZWV4aXN0aW5nIHx8IHBvc3RGaWx0ZXIgKSA/XG5cblx0XHRcdFx0XHQvLyAuLi5pbnRlcm1lZGlhdGUgcHJvY2Vzc2luZyBpcyBuZWNlc3Nhcnlcblx0XHRcdFx0XHRbXSA6XG5cblx0XHRcdFx0XHQvLyAuLi5vdGhlcndpc2UgdXNlIHJlc3VsdHMgZGlyZWN0bHlcblx0XHRcdFx0XHRyZXN1bHRzIDpcblx0XHRcdFx0bWF0Y2hlckluO1xuXG5cdFx0Ly8gRmluZCBwcmltYXJ5IG1hdGNoZXNcblx0XHRpZiAoIG1hdGNoZXIgKSB7XG5cdFx0XHRtYXRjaGVyKCBtYXRjaGVySW4sIG1hdGNoZXJPdXQsIGNvbnRleHQsIHhtbCApO1xuXHRcdH1cblxuXHRcdC8vIEFwcGx5IHBvc3RGaWx0ZXJcblx0XHRpZiAoIHBvc3RGaWx0ZXIgKSB7XG5cdFx0XHR0ZW1wID0gY29uZGVuc2UoIG1hdGNoZXJPdXQsIHBvc3RNYXAgKTtcblx0XHRcdHBvc3RGaWx0ZXIoIHRlbXAsIFtdLCBjb250ZXh0LCB4bWwgKTtcblxuXHRcdFx0Ly8gVW4tbWF0Y2ggZmFpbGluZyBlbGVtZW50cyBieSBtb3ZpbmcgdGhlbSBiYWNrIHRvIG1hdGNoZXJJblxuXHRcdFx0aSA9IHRlbXAubGVuZ3RoO1xuXHRcdFx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0XHRcdGlmICggKCBlbGVtID0gdGVtcFsgaSBdICkgKSB7XG5cdFx0XHRcdFx0bWF0Y2hlck91dFsgcG9zdE1hcFsgaSBdIF0gPSAhKCBtYXRjaGVySW5bIHBvc3RNYXBbIGkgXSBdID0gZWxlbSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCBzZWVkICkge1xuXHRcdFx0aWYgKCBwb3N0RmluZGVyIHx8IHByZUZpbHRlciApIHtcblx0XHRcdFx0aWYgKCBwb3N0RmluZGVyICkge1xuXG5cdFx0XHRcdFx0Ly8gR2V0IHRoZSBmaW5hbCBtYXRjaGVyT3V0IGJ5IGNvbmRlbnNpbmcgdGhpcyBpbnRlcm1lZGlhdGUgaW50byBwb3N0RmluZGVyIGNvbnRleHRzXG5cdFx0XHRcdFx0dGVtcCA9IFtdO1xuXHRcdFx0XHRcdGkgPSBtYXRjaGVyT3V0Lmxlbmd0aDtcblx0XHRcdFx0XHR3aGlsZSAoIGktLSApIHtcblx0XHRcdFx0XHRcdGlmICggKCBlbGVtID0gbWF0Y2hlck91dFsgaSBdICkgKSB7XG5cblx0XHRcdFx0XHRcdFx0Ly8gUmVzdG9yZSBtYXRjaGVySW4gc2luY2UgZWxlbSBpcyBub3QgeWV0IGEgZmluYWwgbWF0Y2hcblx0XHRcdFx0XHRcdFx0dGVtcC5wdXNoKCAoIG1hdGNoZXJJblsgaSBdID0gZWxlbSApICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHBvc3RGaW5kZXIoIG51bGwsICggbWF0Y2hlck91dCA9IFtdICksIHRlbXAsIHhtbCApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gTW92ZSBtYXRjaGVkIGVsZW1lbnRzIGZyb20gc2VlZCB0byByZXN1bHRzIHRvIGtlZXAgdGhlbSBzeW5jaHJvbml6ZWRcblx0XHRcdFx0aSA9IG1hdGNoZXJPdXQubGVuZ3RoO1xuXHRcdFx0XHR3aGlsZSAoIGktLSApIHtcblx0XHRcdFx0XHRpZiAoICggZWxlbSA9IG1hdGNoZXJPdXRbIGkgXSApICYmXG5cdFx0XHRcdFx0XHQoIHRlbXAgPSBwb3N0RmluZGVyID8gaW5kZXhPZiggc2VlZCwgZWxlbSApIDogcHJlTWFwWyBpIF0gKSA+IC0xICkge1xuXG5cdFx0XHRcdFx0XHRzZWVkWyB0ZW1wIF0gPSAhKCByZXN1bHRzWyB0ZW1wIF0gPSBlbGVtICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHQvLyBBZGQgZWxlbWVudHMgdG8gcmVzdWx0cywgdGhyb3VnaCBwb3N0RmluZGVyIGlmIGRlZmluZWRcblx0XHR9IGVsc2Uge1xuXHRcdFx0bWF0Y2hlck91dCA9IGNvbmRlbnNlKFxuXHRcdFx0XHRtYXRjaGVyT3V0ID09PSByZXN1bHRzID9cblx0XHRcdFx0XHRtYXRjaGVyT3V0LnNwbGljZSggcHJlZXhpc3RpbmcsIG1hdGNoZXJPdXQubGVuZ3RoICkgOlxuXHRcdFx0XHRcdG1hdGNoZXJPdXRcblx0XHRcdCk7XG5cdFx0XHRpZiAoIHBvc3RGaW5kZXIgKSB7XG5cdFx0XHRcdHBvc3RGaW5kZXIoIG51bGwsIHJlc3VsdHMsIG1hdGNoZXJPdXQsIHhtbCApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cHVzaC5hcHBseSggcmVzdWx0cywgbWF0Y2hlck91dCApO1xuXHRcdFx0fVxuXHRcdH1cblx0fSApO1xufVxuXG5mdW5jdGlvbiBtYXRjaGVyRnJvbVRva2VucyggdG9rZW5zICkge1xuXHR2YXIgY2hlY2tDb250ZXh0LCBtYXRjaGVyLCBqLFxuXHRcdGxlbiA9IHRva2Vucy5sZW5ndGgsXG5cdFx0bGVhZGluZ1JlbGF0aXZlID0gRXhwci5yZWxhdGl2ZVsgdG9rZW5zWyAwIF0udHlwZSBdLFxuXHRcdGltcGxpY2l0UmVsYXRpdmUgPSBsZWFkaW5nUmVsYXRpdmUgfHwgRXhwci5yZWxhdGl2ZVsgXCIgXCIgXSxcblx0XHRpID0gbGVhZGluZ1JlbGF0aXZlID8gMSA6IDAsXG5cblx0XHQvLyBUaGUgZm91bmRhdGlvbmFsIG1hdGNoZXIgZW5zdXJlcyB0aGF0IGVsZW1lbnRzIGFyZSByZWFjaGFibGUgZnJvbSB0b3AtbGV2ZWwgY29udGV4dChzKVxuXHRcdG1hdGNoQ29udGV4dCA9IGFkZENvbWJpbmF0b3IoIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0cmV0dXJuIGVsZW0gPT09IGNoZWNrQ29udGV4dDtcblx0XHR9LCBpbXBsaWNpdFJlbGF0aXZlLCB0cnVlICksXG5cdFx0bWF0Y2hBbnlDb250ZXh0ID0gYWRkQ29tYmluYXRvciggZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gaW5kZXhPZiggY2hlY2tDb250ZXh0LCBlbGVtICkgPiAtMTtcblx0XHR9LCBpbXBsaWNpdFJlbGF0aXZlLCB0cnVlICksXG5cdFx0bWF0Y2hlcnMgPSBbIGZ1bmN0aW9uKCBlbGVtLCBjb250ZXh0LCB4bWwgKSB7XG5cdFx0XHR2YXIgcmV0ID0gKCAhbGVhZGluZ1JlbGF0aXZlICYmICggeG1sIHx8IGNvbnRleHQgIT09IG91dGVybW9zdENvbnRleHQgKSApIHx8IChcblx0XHRcdFx0KCBjaGVja0NvbnRleHQgPSBjb250ZXh0ICkubm9kZVR5cGUgP1xuXHRcdFx0XHRcdG1hdGNoQ29udGV4dCggZWxlbSwgY29udGV4dCwgeG1sICkgOlxuXHRcdFx0XHRcdG1hdGNoQW55Q29udGV4dCggZWxlbSwgY29udGV4dCwgeG1sICkgKTtcblxuXHRcdFx0Ly8gQXZvaWQgaGFuZ2luZyBvbnRvIGVsZW1lbnQgKGlzc3VlICMyOTkpXG5cdFx0XHRjaGVja0NvbnRleHQgPSBudWxsO1xuXHRcdFx0cmV0dXJuIHJldDtcblx0XHR9IF07XG5cblx0Zm9yICggOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0aWYgKCAoIG1hdGNoZXIgPSBFeHByLnJlbGF0aXZlWyB0b2tlbnNbIGkgXS50eXBlIF0gKSApIHtcblx0XHRcdG1hdGNoZXJzID0gWyBhZGRDb21iaW5hdG9yKCBlbGVtZW50TWF0Y2hlciggbWF0Y2hlcnMgKSwgbWF0Y2hlciApIF07XG5cdFx0fSBlbHNlIHtcblx0XHRcdG1hdGNoZXIgPSBFeHByLmZpbHRlclsgdG9rZW5zWyBpIF0udHlwZSBdLmFwcGx5KCBudWxsLCB0b2tlbnNbIGkgXS5tYXRjaGVzICk7XG5cblx0XHRcdC8vIFJldHVybiBzcGVjaWFsIHVwb24gc2VlaW5nIGEgcG9zaXRpb25hbCBtYXRjaGVyXG5cdFx0XHRpZiAoIG1hdGNoZXJbIGV4cGFuZG8gXSApIHtcblxuXHRcdFx0XHQvLyBGaW5kIHRoZSBuZXh0IHJlbGF0aXZlIG9wZXJhdG9yIChpZiBhbnkpIGZvciBwcm9wZXIgaGFuZGxpbmdcblx0XHRcdFx0aiA9ICsraTtcblx0XHRcdFx0Zm9yICggOyBqIDwgbGVuOyBqKysgKSB7XG5cdFx0XHRcdFx0aWYgKCBFeHByLnJlbGF0aXZlWyB0b2tlbnNbIGogXS50eXBlIF0gKSB7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHNldE1hdGNoZXIoXG5cdFx0XHRcdFx0aSA+IDEgJiYgZWxlbWVudE1hdGNoZXIoIG1hdGNoZXJzICksXG5cdFx0XHRcdFx0aSA+IDEgJiYgdG9TZWxlY3RvcihcblxuXHRcdFx0XHRcdC8vIElmIHRoZSBwcmVjZWRpbmcgdG9rZW4gd2FzIGEgZGVzY2VuZGFudCBjb21iaW5hdG9yLCBpbnNlcnQgYW4gaW1wbGljaXQgYW55LWVsZW1lbnQgYCpgXG5cdFx0XHRcdFx0dG9rZW5zXG5cdFx0XHRcdFx0XHQuc2xpY2UoIDAsIGkgLSAxIClcblx0XHRcdFx0XHRcdC5jb25jYXQoIHsgdmFsdWU6IHRva2Vuc1sgaSAtIDIgXS50eXBlID09PSBcIiBcIiA/IFwiKlwiIDogXCJcIiB9IClcblx0XHRcdFx0XHQpLnJlcGxhY2UoIHJ0cmltLCBcIiQxXCIgKSxcblx0XHRcdFx0XHRtYXRjaGVyLFxuXHRcdFx0XHRcdGkgPCBqICYmIG1hdGNoZXJGcm9tVG9rZW5zKCB0b2tlbnMuc2xpY2UoIGksIGogKSApLFxuXHRcdFx0XHRcdGogPCBsZW4gJiYgbWF0Y2hlckZyb21Ub2tlbnMoICggdG9rZW5zID0gdG9rZW5zLnNsaWNlKCBqICkgKSApLFxuXHRcdFx0XHRcdGogPCBsZW4gJiYgdG9TZWxlY3RvciggdG9rZW5zIClcblx0XHRcdFx0KTtcblx0XHRcdH1cblx0XHRcdG1hdGNoZXJzLnB1c2goIG1hdGNoZXIgKTtcblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gZWxlbWVudE1hdGNoZXIoIG1hdGNoZXJzICk7XG59XG5cbmZ1bmN0aW9uIG1hdGNoZXJGcm9tR3JvdXBNYXRjaGVycyggZWxlbWVudE1hdGNoZXJzLCBzZXRNYXRjaGVycyApIHtcblx0dmFyIGJ5U2V0ID0gc2V0TWF0Y2hlcnMubGVuZ3RoID4gMCxcblx0XHRieUVsZW1lbnQgPSBlbGVtZW50TWF0Y2hlcnMubGVuZ3RoID4gMCxcblx0XHRzdXBlck1hdGNoZXIgPSBmdW5jdGlvbiggc2VlZCwgY29udGV4dCwgeG1sLCByZXN1bHRzLCBvdXRlcm1vc3QgKSB7XG5cdFx0XHR2YXIgZWxlbSwgaiwgbWF0Y2hlcixcblx0XHRcdFx0bWF0Y2hlZENvdW50ID0gMCxcblx0XHRcdFx0aSA9IFwiMFwiLFxuXHRcdFx0XHR1bm1hdGNoZWQgPSBzZWVkICYmIFtdLFxuXHRcdFx0XHRzZXRNYXRjaGVkID0gW10sXG5cdFx0XHRcdGNvbnRleHRCYWNrdXAgPSBvdXRlcm1vc3RDb250ZXh0LFxuXG5cdFx0XHRcdC8vIFdlIG11c3QgYWx3YXlzIGhhdmUgZWl0aGVyIHNlZWQgZWxlbWVudHMgb3Igb3V0ZXJtb3N0IGNvbnRleHRcblx0XHRcdFx0ZWxlbXMgPSBzZWVkIHx8IGJ5RWxlbWVudCAmJiBFeHByLmZpbmRbIFwiVEFHXCIgXSggXCIqXCIsIG91dGVybW9zdCApLFxuXG5cdFx0XHRcdC8vIFVzZSBpbnRlZ2VyIGRpcnJ1bnMgaWZmIHRoaXMgaXMgdGhlIG91dGVybW9zdCBtYXRjaGVyXG5cdFx0XHRcdGRpcnJ1bnNVbmlxdWUgPSAoIGRpcnJ1bnMgKz0gY29udGV4dEJhY2t1cCA9PSBudWxsID8gMSA6IE1hdGgucmFuZG9tKCkgfHwgMC4xICksXG5cdFx0XHRcdGxlbiA9IGVsZW1zLmxlbmd0aDtcblxuXHRcdFx0aWYgKCBvdXRlcm1vc3QgKSB7XG5cblx0XHRcdFx0Ly8gU3VwcG9ydDogSUUgMTErLCBFZGdlIDE3IC0gMTgrXG5cdFx0XHRcdC8vIElFL0VkZ2Ugc29tZXRpbWVzIHRocm93IGEgXCJQZXJtaXNzaW9uIGRlbmllZFwiIGVycm9yIHdoZW4gc3RyaWN0LWNvbXBhcmluZ1xuXHRcdFx0XHQvLyB0d28gZG9jdW1lbnRzOyBzaGFsbG93IGNvbXBhcmlzb25zIHdvcmsuXG5cdFx0XHRcdC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBlcWVxZXFcblx0XHRcdFx0b3V0ZXJtb3N0Q29udGV4dCA9IGNvbnRleHQgPT0gZG9jdW1lbnQgfHwgY29udGV4dCB8fCBvdXRlcm1vc3Q7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEFkZCBlbGVtZW50cyBwYXNzaW5nIGVsZW1lbnRNYXRjaGVycyBkaXJlY3RseSB0byByZXN1bHRzXG5cdFx0XHQvLyBTdXBwb3J0OiBJRTw5LCBTYWZhcmlcblx0XHRcdC8vIFRvbGVyYXRlIE5vZGVMaXN0IHByb3BlcnRpZXMgKElFOiBcImxlbmd0aFwiOyBTYWZhcmk6IDxudW1iZXI+KSBtYXRjaGluZyBlbGVtZW50cyBieSBpZFxuXHRcdFx0Zm9yICggOyBpICE9PSBsZW4gJiYgKCBlbGVtID0gZWxlbXNbIGkgXSApICE9IG51bGw7IGkrKyApIHtcblx0XHRcdFx0aWYgKCBieUVsZW1lbnQgJiYgZWxlbSApIHtcblx0XHRcdFx0XHRqID0gMDtcblxuXHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFIDExKywgRWRnZSAxNyAtIDE4K1xuXHRcdFx0XHRcdC8vIElFL0VkZ2Ugc29tZXRpbWVzIHRocm93IGEgXCJQZXJtaXNzaW9uIGRlbmllZFwiIGVycm9yIHdoZW4gc3RyaWN0LWNvbXBhcmluZ1xuXHRcdFx0XHRcdC8vIHR3byBkb2N1bWVudHM7IHNoYWxsb3cgY29tcGFyaXNvbnMgd29yay5cblx0XHRcdFx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZXFlcWVxXG5cdFx0XHRcdFx0aWYgKCAhY29udGV4dCAmJiBlbGVtLm93bmVyRG9jdW1lbnQgIT0gZG9jdW1lbnQgKSB7XG5cdFx0XHRcdFx0XHRzZXREb2N1bWVudCggZWxlbSApO1xuXHRcdFx0XHRcdFx0eG1sID0gIWRvY3VtZW50SXNIVE1MO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHR3aGlsZSAoICggbWF0Y2hlciA9IGVsZW1lbnRNYXRjaGVyc1sgaisrIF0gKSApIHtcblx0XHRcdFx0XHRcdGlmICggbWF0Y2hlciggZWxlbSwgY29udGV4dCB8fCBkb2N1bWVudCwgeG1sICkgKSB7XG5cdFx0XHRcdFx0XHRcdHJlc3VsdHMucHVzaCggZWxlbSApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKCBvdXRlcm1vc3QgKSB7XG5cdFx0XHRcdFx0XHRkaXJydW5zID0gZGlycnVuc1VuaXF1ZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBUcmFjayB1bm1hdGNoZWQgZWxlbWVudHMgZm9yIHNldCBmaWx0ZXJzXG5cdFx0XHRcdGlmICggYnlTZXQgKSB7XG5cblx0XHRcdFx0XHQvLyBUaGV5IHdpbGwgaGF2ZSBnb25lIHRocm91Z2ggYWxsIHBvc3NpYmxlIG1hdGNoZXJzXG5cdFx0XHRcdFx0aWYgKCAoIGVsZW0gPSAhbWF0Y2hlciAmJiBlbGVtICkgKSB7XG5cdFx0XHRcdFx0XHRtYXRjaGVkQ291bnQtLTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBMZW5ndGhlbiB0aGUgYXJyYXkgZm9yIGV2ZXJ5IGVsZW1lbnQsIG1hdGNoZWQgb3Igbm90XG5cdFx0XHRcdFx0aWYgKCBzZWVkICkge1xuXHRcdFx0XHRcdFx0dW5tYXRjaGVkLnB1c2goIGVsZW0gKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Ly8gYGlgIGlzIG5vdyB0aGUgY291bnQgb2YgZWxlbWVudHMgdmlzaXRlZCBhYm92ZSwgYW5kIGFkZGluZyBpdCB0byBgbWF0Y2hlZENvdW50YFxuXHRcdFx0Ly8gbWFrZXMgdGhlIGxhdHRlciBub25uZWdhdGl2ZS5cblx0XHRcdG1hdGNoZWRDb3VudCArPSBpO1xuXG5cdFx0XHQvLyBBcHBseSBzZXQgZmlsdGVycyB0byB1bm1hdGNoZWQgZWxlbWVudHNcblx0XHRcdC8vIE5PVEU6IFRoaXMgY2FuIGJlIHNraXBwZWQgaWYgdGhlcmUgYXJlIG5vIHVubWF0Y2hlZCBlbGVtZW50cyAoaS5lLiwgYG1hdGNoZWRDb3VudGBcblx0XHRcdC8vIGVxdWFscyBgaWApLCB1bmxlc3Mgd2UgZGlkbid0IHZpc2l0IF9hbnlfIGVsZW1lbnRzIGluIHRoZSBhYm92ZSBsb29wIGJlY2F1c2Ugd2UgaGF2ZVxuXHRcdFx0Ly8gbm8gZWxlbWVudCBtYXRjaGVycyBhbmQgbm8gc2VlZC5cblx0XHRcdC8vIEluY3JlbWVudGluZyBhbiBpbml0aWFsbHktc3RyaW5nIFwiMFwiIGBpYCBhbGxvd3MgYGlgIHRvIHJlbWFpbiBhIHN0cmluZyBvbmx5IGluIHRoYXRcblx0XHRcdC8vIGNhc2UsIHdoaWNoIHdpbGwgcmVzdWx0IGluIGEgXCIwMFwiIGBtYXRjaGVkQ291bnRgIHRoYXQgZGlmZmVycyBmcm9tIGBpYCBidXQgaXMgYWxzb1xuXHRcdFx0Ly8gbnVtZXJpY2FsbHkgemVyby5cblx0XHRcdGlmICggYnlTZXQgJiYgaSAhPT0gbWF0Y2hlZENvdW50ICkge1xuXHRcdFx0XHRqID0gMDtcblx0XHRcdFx0d2hpbGUgKCAoIG1hdGNoZXIgPSBzZXRNYXRjaGVyc1sgaisrIF0gKSApIHtcblx0XHRcdFx0XHRtYXRjaGVyKCB1bm1hdGNoZWQsIHNldE1hdGNoZWQsIGNvbnRleHQsIHhtbCApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBzZWVkICkge1xuXG5cdFx0XHRcdFx0Ly8gUmVpbnRlZ3JhdGUgZWxlbWVudCBtYXRjaGVzIHRvIGVsaW1pbmF0ZSB0aGUgbmVlZCBmb3Igc29ydGluZ1xuXHRcdFx0XHRcdGlmICggbWF0Y2hlZENvdW50ID4gMCApIHtcblx0XHRcdFx0XHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0XHRcdFx0XHRpZiAoICEoIHVubWF0Y2hlZFsgaSBdIHx8IHNldE1hdGNoZWRbIGkgXSApICkge1xuXHRcdFx0XHRcdFx0XHRcdHNldE1hdGNoZWRbIGkgXSA9IHBvcC5jYWxsKCByZXN1bHRzICk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBEaXNjYXJkIGluZGV4IHBsYWNlaG9sZGVyIHZhbHVlcyB0byBnZXQgb25seSBhY3R1YWwgbWF0Y2hlc1xuXHRcdFx0XHRcdHNldE1hdGNoZWQgPSBjb25kZW5zZSggc2V0TWF0Y2hlZCApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gQWRkIG1hdGNoZXMgdG8gcmVzdWx0c1xuXHRcdFx0XHRwdXNoLmFwcGx5KCByZXN1bHRzLCBzZXRNYXRjaGVkICk7XG5cblx0XHRcdFx0Ly8gU2VlZGxlc3Mgc2V0IG1hdGNoZXMgc3VjY2VlZGluZyBtdWx0aXBsZSBzdWNjZXNzZnVsIG1hdGNoZXJzIHN0aXB1bGF0ZSBzb3J0aW5nXG5cdFx0XHRcdGlmICggb3V0ZXJtb3N0ICYmICFzZWVkICYmIHNldE1hdGNoZWQubGVuZ3RoID4gMCAmJlxuXHRcdFx0XHRcdCggbWF0Y2hlZENvdW50ICsgc2V0TWF0Y2hlcnMubGVuZ3RoICkgPiAxICkge1xuXG5cdFx0XHRcdFx0U2l6emxlLnVuaXF1ZVNvcnQoIHJlc3VsdHMgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBPdmVycmlkZSBtYW5pcHVsYXRpb24gb2YgZ2xvYmFscyBieSBuZXN0ZWQgbWF0Y2hlcnNcblx0XHRcdGlmICggb3V0ZXJtb3N0ICkge1xuXHRcdFx0XHRkaXJydW5zID0gZGlycnVuc1VuaXF1ZTtcblx0XHRcdFx0b3V0ZXJtb3N0Q29udGV4dCA9IGNvbnRleHRCYWNrdXA7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB1bm1hdGNoZWQ7XG5cdFx0fTtcblxuXHRyZXR1cm4gYnlTZXQgP1xuXHRcdG1hcmtGdW5jdGlvbiggc3VwZXJNYXRjaGVyICkgOlxuXHRcdHN1cGVyTWF0Y2hlcjtcbn1cblxuY29tcGlsZSA9IFNpenpsZS5jb21waWxlID0gZnVuY3Rpb24oIHNlbGVjdG9yLCBtYXRjaCAvKiBJbnRlcm5hbCBVc2UgT25seSAqLyApIHtcblx0dmFyIGksXG5cdFx0c2V0TWF0Y2hlcnMgPSBbXSxcblx0XHRlbGVtZW50TWF0Y2hlcnMgPSBbXSxcblx0XHRjYWNoZWQgPSBjb21waWxlckNhY2hlWyBzZWxlY3RvciArIFwiIFwiIF07XG5cblx0aWYgKCAhY2FjaGVkICkge1xuXG5cdFx0Ly8gR2VuZXJhdGUgYSBmdW5jdGlvbiBvZiByZWN1cnNpdmUgZnVuY3Rpb25zIHRoYXQgY2FuIGJlIHVzZWQgdG8gY2hlY2sgZWFjaCBlbGVtZW50XG5cdFx0aWYgKCAhbWF0Y2ggKSB7XG5cdFx0XHRtYXRjaCA9IHRva2VuaXplKCBzZWxlY3RvciApO1xuXHRcdH1cblx0XHRpID0gbWF0Y2gubGVuZ3RoO1xuXHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0Y2FjaGVkID0gbWF0Y2hlckZyb21Ub2tlbnMoIG1hdGNoWyBpIF0gKTtcblx0XHRcdGlmICggY2FjaGVkWyBleHBhbmRvIF0gKSB7XG5cdFx0XHRcdHNldE1hdGNoZXJzLnB1c2goIGNhY2hlZCApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0ZWxlbWVudE1hdGNoZXJzLnB1c2goIGNhY2hlZCApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIENhY2hlIHRoZSBjb21waWxlZCBmdW5jdGlvblxuXHRcdGNhY2hlZCA9IGNvbXBpbGVyQ2FjaGUoXG5cdFx0XHRzZWxlY3Rvcixcblx0XHRcdG1hdGNoZXJGcm9tR3JvdXBNYXRjaGVycyggZWxlbWVudE1hdGNoZXJzLCBzZXRNYXRjaGVycyApXG5cdFx0KTtcblxuXHRcdC8vIFNhdmUgc2VsZWN0b3IgYW5kIHRva2VuaXphdGlvblxuXHRcdGNhY2hlZC5zZWxlY3RvciA9IHNlbGVjdG9yO1xuXHR9XG5cdHJldHVybiBjYWNoZWQ7XG59O1xuXG4vKipcbiAqIEEgbG93LWxldmVsIHNlbGVjdGlvbiBmdW5jdGlvbiB0aGF0IHdvcmtzIHdpdGggU2l6emxlJ3MgY29tcGlsZWRcbiAqICBzZWxlY3RvciBmdW5jdGlvbnNcbiAqIEBwYXJhbSB7U3RyaW5nfEZ1bmN0aW9ufSBzZWxlY3RvciBBIHNlbGVjdG9yIG9yIGEgcHJlLWNvbXBpbGVkXG4gKiAgc2VsZWN0b3IgZnVuY3Rpb24gYnVpbHQgd2l0aCBTaXp6bGUuY29tcGlsZVxuICogQHBhcmFtIHtFbGVtZW50fSBjb250ZXh0XG4gKiBAcGFyYW0ge0FycmF5fSBbcmVzdWx0c11cbiAqIEBwYXJhbSB7QXJyYXl9IFtzZWVkXSBBIHNldCBvZiBlbGVtZW50cyB0byBtYXRjaCBhZ2FpbnN0XG4gKi9cbnNlbGVjdCA9IFNpenpsZS5zZWxlY3QgPSBmdW5jdGlvbiggc2VsZWN0b3IsIGNvbnRleHQsIHJlc3VsdHMsIHNlZWQgKSB7XG5cdHZhciBpLCB0b2tlbnMsIHRva2VuLCB0eXBlLCBmaW5kLFxuXHRcdGNvbXBpbGVkID0gdHlwZW9mIHNlbGVjdG9yID09PSBcImZ1bmN0aW9uXCIgJiYgc2VsZWN0b3IsXG5cdFx0bWF0Y2ggPSAhc2VlZCAmJiB0b2tlbml6ZSggKCBzZWxlY3RvciA9IGNvbXBpbGVkLnNlbGVjdG9yIHx8IHNlbGVjdG9yICkgKTtcblxuXHRyZXN1bHRzID0gcmVzdWx0cyB8fCBbXTtcblxuXHQvLyBUcnkgdG8gbWluaW1pemUgb3BlcmF0aW9ucyBpZiB0aGVyZSBpcyBvbmx5IG9uZSBzZWxlY3RvciBpbiB0aGUgbGlzdCBhbmQgbm8gc2VlZFxuXHQvLyAodGhlIGxhdHRlciBvZiB3aGljaCBndWFyYW50ZWVzIHVzIGNvbnRleHQpXG5cdGlmICggbWF0Y2gubGVuZ3RoID09PSAxICkge1xuXG5cdFx0Ly8gUmVkdWNlIGNvbnRleHQgaWYgdGhlIGxlYWRpbmcgY29tcG91bmQgc2VsZWN0b3IgaXMgYW4gSURcblx0XHR0b2tlbnMgPSBtYXRjaFsgMCBdID0gbWF0Y2hbIDAgXS5zbGljZSggMCApO1xuXHRcdGlmICggdG9rZW5zLmxlbmd0aCA+IDIgJiYgKCB0b2tlbiA9IHRva2Vuc1sgMCBdICkudHlwZSA9PT0gXCJJRFwiICYmXG5cdFx0XHRjb250ZXh0Lm5vZGVUeXBlID09PSA5ICYmIGRvY3VtZW50SXNIVE1MICYmIEV4cHIucmVsYXRpdmVbIHRva2Vuc1sgMSBdLnR5cGUgXSApIHtcblxuXHRcdFx0Y29udGV4dCA9ICggRXhwci5maW5kWyBcIklEXCIgXSggdG9rZW4ubWF0Y2hlc1sgMCBdXG5cdFx0XHRcdC5yZXBsYWNlKCBydW5lc2NhcGUsIGZ1bmVzY2FwZSApLCBjb250ZXh0ICkgfHwgW10gKVsgMCBdO1xuXHRcdFx0aWYgKCAhY29udGV4dCApIHtcblx0XHRcdFx0cmV0dXJuIHJlc3VsdHM7XG5cblx0XHRcdC8vIFByZWNvbXBpbGVkIG1hdGNoZXJzIHdpbGwgc3RpbGwgdmVyaWZ5IGFuY2VzdHJ5LCBzbyBzdGVwIHVwIGEgbGV2ZWxcblx0XHRcdH0gZWxzZSBpZiAoIGNvbXBpbGVkICkge1xuXHRcdFx0XHRjb250ZXh0ID0gY29udGV4dC5wYXJlbnROb2RlO1xuXHRcdFx0fVxuXG5cdFx0XHRzZWxlY3RvciA9IHNlbGVjdG9yLnNsaWNlKCB0b2tlbnMuc2hpZnQoKS52YWx1ZS5sZW5ndGggKTtcblx0XHR9XG5cblx0XHQvLyBGZXRjaCBhIHNlZWQgc2V0IGZvciByaWdodC10by1sZWZ0IG1hdGNoaW5nXG5cdFx0aSA9IG1hdGNoRXhwclsgXCJuZWVkc0NvbnRleHRcIiBdLnRlc3QoIHNlbGVjdG9yICkgPyAwIDogdG9rZW5zLmxlbmd0aDtcblx0XHR3aGlsZSAoIGktLSApIHtcblx0XHRcdHRva2VuID0gdG9rZW5zWyBpIF07XG5cblx0XHRcdC8vIEFib3J0IGlmIHdlIGhpdCBhIGNvbWJpbmF0b3Jcblx0XHRcdGlmICggRXhwci5yZWxhdGl2ZVsgKCB0eXBlID0gdG9rZW4udHlwZSApIF0gKSB7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCAoIGZpbmQgPSBFeHByLmZpbmRbIHR5cGUgXSApICkge1xuXG5cdFx0XHRcdC8vIFNlYXJjaCwgZXhwYW5kaW5nIGNvbnRleHQgZm9yIGxlYWRpbmcgc2libGluZyBjb21iaW5hdG9yc1xuXHRcdFx0XHRpZiAoICggc2VlZCA9IGZpbmQoXG5cdFx0XHRcdFx0dG9rZW4ubWF0Y2hlc1sgMCBdLnJlcGxhY2UoIHJ1bmVzY2FwZSwgZnVuZXNjYXBlICksXG5cdFx0XHRcdFx0cnNpYmxpbmcudGVzdCggdG9rZW5zWyAwIF0udHlwZSApICYmIHRlc3RDb250ZXh0KCBjb250ZXh0LnBhcmVudE5vZGUgKSB8fFxuXHRcdFx0XHRcdFx0Y29udGV4dFxuXHRcdFx0XHQpICkgKSB7XG5cblx0XHRcdFx0XHQvLyBJZiBzZWVkIGlzIGVtcHR5IG9yIG5vIHRva2VucyByZW1haW4sIHdlIGNhbiByZXR1cm4gZWFybHlcblx0XHRcdFx0XHR0b2tlbnMuc3BsaWNlKCBpLCAxICk7XG5cdFx0XHRcdFx0c2VsZWN0b3IgPSBzZWVkLmxlbmd0aCAmJiB0b1NlbGVjdG9yKCB0b2tlbnMgKTtcblx0XHRcdFx0XHRpZiAoICFzZWxlY3RvciApIHtcblx0XHRcdFx0XHRcdHB1c2guYXBwbHkoIHJlc3VsdHMsIHNlZWQgKTtcblx0XHRcdFx0XHRcdHJldHVybiByZXN1bHRzO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0Ly8gQ29tcGlsZSBhbmQgZXhlY3V0ZSBhIGZpbHRlcmluZyBmdW5jdGlvbiBpZiBvbmUgaXMgbm90IHByb3ZpZGVkXG5cdC8vIFByb3ZpZGUgYG1hdGNoYCB0byBhdm9pZCByZXRva2VuaXphdGlvbiBpZiB3ZSBtb2RpZmllZCB0aGUgc2VsZWN0b3IgYWJvdmVcblx0KCBjb21waWxlZCB8fCBjb21waWxlKCBzZWxlY3RvciwgbWF0Y2ggKSApKFxuXHRcdHNlZWQsXG5cdFx0Y29udGV4dCxcblx0XHQhZG9jdW1lbnRJc0hUTUwsXG5cdFx0cmVzdWx0cyxcblx0XHQhY29udGV4dCB8fCByc2libGluZy50ZXN0KCBzZWxlY3RvciApICYmIHRlc3RDb250ZXh0KCBjb250ZXh0LnBhcmVudE5vZGUgKSB8fCBjb250ZXh0XG5cdCk7XG5cdHJldHVybiByZXN1bHRzO1xufTtcblxuLy8gT25lLXRpbWUgYXNzaWdubWVudHNcblxuLy8gU29ydCBzdGFiaWxpdHlcbnN1cHBvcnQuc29ydFN0YWJsZSA9IGV4cGFuZG8uc3BsaXQoIFwiXCIgKS5zb3J0KCBzb3J0T3JkZXIgKS5qb2luKCBcIlwiICkgPT09IGV4cGFuZG87XG5cbi8vIFN1cHBvcnQ6IENocm9tZSAxNC0zNStcbi8vIEFsd2F5cyBhc3N1bWUgZHVwbGljYXRlcyBpZiB0aGV5IGFyZW4ndCBwYXNzZWQgdG8gdGhlIGNvbXBhcmlzb24gZnVuY3Rpb25cbnN1cHBvcnQuZGV0ZWN0RHVwbGljYXRlcyA9ICEhaGFzRHVwbGljYXRlO1xuXG4vLyBJbml0aWFsaXplIGFnYWluc3QgdGhlIGRlZmF1bHQgZG9jdW1lbnRcbnNldERvY3VtZW50KCk7XG5cbi8vIFN1cHBvcnQ6IFdlYmtpdDw1MzcuMzIgLSBTYWZhcmkgNi4wLjMvQ2hyb21lIDI1IChmaXhlZCBpbiBDaHJvbWUgMjcpXG4vLyBEZXRhY2hlZCBub2RlcyBjb25mb3VuZGluZ2x5IGZvbGxvdyAqZWFjaCBvdGhlcipcbnN1cHBvcnQuc29ydERldGFjaGVkID0gYXNzZXJ0KCBmdW5jdGlvbiggZWwgKSB7XG5cblx0Ly8gU2hvdWxkIHJldHVybiAxLCBidXQgcmV0dXJucyA0IChmb2xsb3dpbmcpXG5cdHJldHVybiBlbC5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiggZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggXCJmaWVsZHNldFwiICkgKSAmIDE7XG59ICk7XG5cbi8vIFN1cHBvcnQ6IElFPDhcbi8vIFByZXZlbnQgYXR0cmlidXRlL3Byb3BlcnR5IFwiaW50ZXJwb2xhdGlvblwiXG4vLyBodHRwczovL21zZG4ubWljcm9zb2Z0LmNvbS9lbi11cy9saWJyYXJ5L21zNTM2NDI5JTI4VlMuODUlMjkuYXNweFxuaWYgKCAhYXNzZXJ0KCBmdW5jdGlvbiggZWwgKSB7XG5cdGVsLmlubmVySFRNTCA9IFwiPGEgaHJlZj0nIyc+PC9hPlwiO1xuXHRyZXR1cm4gZWwuZmlyc3RDaGlsZC5nZXRBdHRyaWJ1dGUoIFwiaHJlZlwiICkgPT09IFwiI1wiO1xufSApICkge1xuXHRhZGRIYW5kbGUoIFwidHlwZXxocmVmfGhlaWdodHx3aWR0aFwiLCBmdW5jdGlvbiggZWxlbSwgbmFtZSwgaXNYTUwgKSB7XG5cdFx0aWYgKCAhaXNYTUwgKSB7XG5cdFx0XHRyZXR1cm4gZWxlbS5nZXRBdHRyaWJ1dGUoIG5hbWUsIG5hbWUudG9Mb3dlckNhc2UoKSA9PT0gXCJ0eXBlXCIgPyAxIDogMiApO1xuXHRcdH1cblx0fSApO1xufVxuXG4vLyBTdXBwb3J0OiBJRTw5XG4vLyBVc2UgZGVmYXVsdFZhbHVlIGluIHBsYWNlIG9mIGdldEF0dHJpYnV0ZShcInZhbHVlXCIpXG5pZiAoICFzdXBwb3J0LmF0dHJpYnV0ZXMgfHwgIWFzc2VydCggZnVuY3Rpb24oIGVsICkge1xuXHRlbC5pbm5lckhUTUwgPSBcIjxpbnB1dC8+XCI7XG5cdGVsLmZpcnN0Q2hpbGQuc2V0QXR0cmlidXRlKCBcInZhbHVlXCIsIFwiXCIgKTtcblx0cmV0dXJuIGVsLmZpcnN0Q2hpbGQuZ2V0QXR0cmlidXRlKCBcInZhbHVlXCIgKSA9PT0gXCJcIjtcbn0gKSApIHtcblx0YWRkSGFuZGxlKCBcInZhbHVlXCIsIGZ1bmN0aW9uKCBlbGVtLCBfbmFtZSwgaXNYTUwgKSB7XG5cdFx0aWYgKCAhaXNYTUwgJiYgZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpID09PSBcImlucHV0XCIgKSB7XG5cdFx0XHRyZXR1cm4gZWxlbS5kZWZhdWx0VmFsdWU7XG5cdFx0fVxuXHR9ICk7XG59XG5cbi8vIFN1cHBvcnQ6IElFPDlcbi8vIFVzZSBnZXRBdHRyaWJ1dGVOb2RlIHRvIGZldGNoIGJvb2xlYW5zIHdoZW4gZ2V0QXR0cmlidXRlIGxpZXNcbmlmICggIWFzc2VydCggZnVuY3Rpb24oIGVsICkge1xuXHRyZXR1cm4gZWwuZ2V0QXR0cmlidXRlKCBcImRpc2FibGVkXCIgKSA9PSBudWxsO1xufSApICkge1xuXHRhZGRIYW5kbGUoIGJvb2xlYW5zLCBmdW5jdGlvbiggZWxlbSwgbmFtZSwgaXNYTUwgKSB7XG5cdFx0dmFyIHZhbDtcblx0XHRpZiAoICFpc1hNTCApIHtcblx0XHRcdHJldHVybiBlbGVtWyBuYW1lIF0gPT09IHRydWUgPyBuYW1lLnRvTG93ZXJDYXNlKCkgOlxuXHRcdFx0XHQoIHZhbCA9IGVsZW0uZ2V0QXR0cmlidXRlTm9kZSggbmFtZSApICkgJiYgdmFsLnNwZWNpZmllZCA/XG5cdFx0XHRcdFx0dmFsLnZhbHVlIDpcblx0XHRcdFx0XHRudWxsO1xuXHRcdH1cblx0fSApO1xufVxuXG5yZXR1cm4gU2l6emxlO1xuXG59ICkoIHdpbmRvdyApO1xuXG5cblxualF1ZXJ5LmZpbmQgPSBTaXp6bGU7XG5qUXVlcnkuZXhwciA9IFNpenpsZS5zZWxlY3RvcnM7XG5cbi8vIERlcHJlY2F0ZWRcbmpRdWVyeS5leHByWyBcIjpcIiBdID0galF1ZXJ5LmV4cHIucHNldWRvcztcbmpRdWVyeS51bmlxdWVTb3J0ID0galF1ZXJ5LnVuaXF1ZSA9IFNpenpsZS51bmlxdWVTb3J0O1xualF1ZXJ5LnRleHQgPSBTaXp6bGUuZ2V0VGV4dDtcbmpRdWVyeS5pc1hNTERvYyA9IFNpenpsZS5pc1hNTDtcbmpRdWVyeS5jb250YWlucyA9IFNpenpsZS5jb250YWlucztcbmpRdWVyeS5lc2NhcGVTZWxlY3RvciA9IFNpenpsZS5lc2NhcGU7XG5cblxuXG5cbnZhciBkaXIgPSBmdW5jdGlvbiggZWxlbSwgZGlyLCB1bnRpbCApIHtcblx0dmFyIG1hdGNoZWQgPSBbXSxcblx0XHR0cnVuY2F0ZSA9IHVudGlsICE9PSB1bmRlZmluZWQ7XG5cblx0d2hpbGUgKCAoIGVsZW0gPSBlbGVtWyBkaXIgXSApICYmIGVsZW0ubm9kZVR5cGUgIT09IDkgKSB7XG5cdFx0aWYgKCBlbGVtLm5vZGVUeXBlID09PSAxICkge1xuXHRcdFx0aWYgKCB0cnVuY2F0ZSAmJiBqUXVlcnkoIGVsZW0gKS5pcyggdW50aWwgKSApIHtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0XHRtYXRjaGVkLnB1c2goIGVsZW0gKTtcblx0XHR9XG5cdH1cblx0cmV0dXJuIG1hdGNoZWQ7XG59O1xuXG5cbnZhciBzaWJsaW5ncyA9IGZ1bmN0aW9uKCBuLCBlbGVtICkge1xuXHR2YXIgbWF0Y2hlZCA9IFtdO1xuXG5cdGZvciAoIDsgbjsgbiA9IG4ubmV4dFNpYmxpbmcgKSB7XG5cdFx0aWYgKCBuLm5vZGVUeXBlID09PSAxICYmIG4gIT09IGVsZW0gKSB7XG5cdFx0XHRtYXRjaGVkLnB1c2goIG4gKTtcblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gbWF0Y2hlZDtcbn07XG5cblxudmFyIHJuZWVkc0NvbnRleHQgPSBqUXVlcnkuZXhwci5tYXRjaC5uZWVkc0NvbnRleHQ7XG5cblxuXG5mdW5jdGlvbiBub2RlTmFtZSggZWxlbSwgbmFtZSApIHtcblxuXHRyZXR1cm4gZWxlbS5ub2RlTmFtZSAmJiBlbGVtLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IG5hbWUudG9Mb3dlckNhc2UoKTtcblxufVxudmFyIHJzaW5nbGVUYWcgPSAoIC9ePChbYS16XVteXFwvXFwwPjpcXHgyMFxcdFxcclxcblxcZl0qKVtcXHgyMFxcdFxcclxcblxcZl0qXFwvPz4oPzo8XFwvXFwxPnwpJC9pICk7XG5cblxuXG4vLyBJbXBsZW1lbnQgdGhlIGlkZW50aWNhbCBmdW5jdGlvbmFsaXR5IGZvciBmaWx0ZXIgYW5kIG5vdFxuZnVuY3Rpb24gd2lubm93KCBlbGVtZW50cywgcXVhbGlmaWVyLCBub3QgKSB7XG5cdGlmICggaXNGdW5jdGlvbiggcXVhbGlmaWVyICkgKSB7XG5cdFx0cmV0dXJuIGpRdWVyeS5ncmVwKCBlbGVtZW50cywgZnVuY3Rpb24oIGVsZW0sIGkgKSB7XG5cdFx0XHRyZXR1cm4gISFxdWFsaWZpZXIuY2FsbCggZWxlbSwgaSwgZWxlbSApICE9PSBub3Q7XG5cdFx0fSApO1xuXHR9XG5cblx0Ly8gU2luZ2xlIGVsZW1lbnRcblx0aWYgKCBxdWFsaWZpZXIubm9kZVR5cGUgKSB7XG5cdFx0cmV0dXJuIGpRdWVyeS5ncmVwKCBlbGVtZW50cywgZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gKCBlbGVtID09PSBxdWFsaWZpZXIgKSAhPT0gbm90O1xuXHRcdH0gKTtcblx0fVxuXG5cdC8vIEFycmF5bGlrZSBvZiBlbGVtZW50cyAoalF1ZXJ5LCBhcmd1bWVudHMsIEFycmF5KVxuXHRpZiAoIHR5cGVvZiBxdWFsaWZpZXIgIT09IFwic3RyaW5nXCIgKSB7XG5cdFx0cmV0dXJuIGpRdWVyeS5ncmVwKCBlbGVtZW50cywgZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gKCBpbmRleE9mLmNhbGwoIHF1YWxpZmllciwgZWxlbSApID4gLTEgKSAhPT0gbm90O1xuXHRcdH0gKTtcblx0fVxuXG5cdC8vIEZpbHRlcmVkIGRpcmVjdGx5IGZvciBib3RoIHNpbXBsZSBhbmQgY29tcGxleCBzZWxlY3RvcnNcblx0cmV0dXJuIGpRdWVyeS5maWx0ZXIoIHF1YWxpZmllciwgZWxlbWVudHMsIG5vdCApO1xufVxuXG5qUXVlcnkuZmlsdGVyID0gZnVuY3Rpb24oIGV4cHIsIGVsZW1zLCBub3QgKSB7XG5cdHZhciBlbGVtID0gZWxlbXNbIDAgXTtcblxuXHRpZiAoIG5vdCApIHtcblx0XHRleHByID0gXCI6bm90KFwiICsgZXhwciArIFwiKVwiO1xuXHR9XG5cblx0aWYgKCBlbGVtcy5sZW5ndGggPT09IDEgJiYgZWxlbS5ub2RlVHlwZSA9PT0gMSApIHtcblx0XHRyZXR1cm4galF1ZXJ5LmZpbmQubWF0Y2hlc1NlbGVjdG9yKCBlbGVtLCBleHByICkgPyBbIGVsZW0gXSA6IFtdO1xuXHR9XG5cblx0cmV0dXJuIGpRdWVyeS5maW5kLm1hdGNoZXMoIGV4cHIsIGpRdWVyeS5ncmVwKCBlbGVtcywgZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0cmV0dXJuIGVsZW0ubm9kZVR5cGUgPT09IDE7XG5cdH0gKSApO1xufTtcblxualF1ZXJ5LmZuLmV4dGVuZCgge1xuXHRmaW5kOiBmdW5jdGlvbiggc2VsZWN0b3IgKSB7XG5cdFx0dmFyIGksIHJldCxcblx0XHRcdGxlbiA9IHRoaXMubGVuZ3RoLFxuXHRcdFx0c2VsZiA9IHRoaXM7XG5cblx0XHRpZiAoIHR5cGVvZiBzZWxlY3RvciAhPT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdHJldHVybiB0aGlzLnB1c2hTdGFjayggalF1ZXJ5KCBzZWxlY3RvciApLmZpbHRlciggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGZvciAoIGkgPSAwOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0XHRcdFx0aWYgKCBqUXVlcnkuY29udGFpbnMoIHNlbGZbIGkgXSwgdGhpcyApICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9ICkgKTtcblx0XHR9XG5cblx0XHRyZXQgPSB0aGlzLnB1c2hTdGFjayggW10gKTtcblxuXHRcdGZvciAoIGkgPSAwOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0XHRqUXVlcnkuZmluZCggc2VsZWN0b3IsIHNlbGZbIGkgXSwgcmV0ICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGxlbiA+IDEgPyBqUXVlcnkudW5pcXVlU29ydCggcmV0ICkgOiByZXQ7XG5cdH0sXG5cdGZpbHRlcjogZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdHJldHVybiB0aGlzLnB1c2hTdGFjayggd2lubm93KCB0aGlzLCBzZWxlY3RvciB8fCBbXSwgZmFsc2UgKSApO1xuXHR9LFxuXHRub3Q6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHRyZXR1cm4gdGhpcy5wdXNoU3RhY2soIHdpbm5vdyggdGhpcywgc2VsZWN0b3IgfHwgW10sIHRydWUgKSApO1xuXHR9LFxuXHRpczogZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdHJldHVybiAhIXdpbm5vdyhcblx0XHRcdHRoaXMsXG5cblx0XHRcdC8vIElmIHRoaXMgaXMgYSBwb3NpdGlvbmFsL3JlbGF0aXZlIHNlbGVjdG9yLCBjaGVjayBtZW1iZXJzaGlwIGluIHRoZSByZXR1cm5lZCBzZXRcblx0XHRcdC8vIHNvICQoXCJwOmZpcnN0XCIpLmlzKFwicDpsYXN0XCIpIHdvbid0IHJldHVybiB0cnVlIGZvciBhIGRvYyB3aXRoIHR3byBcInBcIi5cblx0XHRcdHR5cGVvZiBzZWxlY3RvciA9PT0gXCJzdHJpbmdcIiAmJiBybmVlZHNDb250ZXh0LnRlc3QoIHNlbGVjdG9yICkgP1xuXHRcdFx0XHRqUXVlcnkoIHNlbGVjdG9yICkgOlxuXHRcdFx0XHRzZWxlY3RvciB8fCBbXSxcblx0XHRcdGZhbHNlXG5cdFx0KS5sZW5ndGg7XG5cdH1cbn0gKTtcblxuXG4vLyBJbml0aWFsaXplIGEgalF1ZXJ5IG9iamVjdFxuXG5cbi8vIEEgY2VudHJhbCByZWZlcmVuY2UgdG8gdGhlIHJvb3QgalF1ZXJ5KGRvY3VtZW50KVxudmFyIHJvb3RqUXVlcnksXG5cblx0Ly8gQSBzaW1wbGUgd2F5IHRvIGNoZWNrIGZvciBIVE1MIHN0cmluZ3Ncblx0Ly8gUHJpb3JpdGl6ZSAjaWQgb3ZlciA8dGFnPiB0byBhdm9pZCBYU1MgdmlhIGxvY2F0aW9uLmhhc2ggKCM5NTIxKVxuXHQvLyBTdHJpY3QgSFRNTCByZWNvZ25pdGlvbiAoIzExMjkwOiBtdXN0IHN0YXJ0IHdpdGggPClcblx0Ly8gU2hvcnRjdXQgc2ltcGxlICNpZCBjYXNlIGZvciBzcGVlZFxuXHRycXVpY2tFeHByID0gL14oPzpcXHMqKDxbXFx3XFxXXSs+KVtePl0qfCMoW1xcdy1dKykpJC8sXG5cblx0aW5pdCA9IGpRdWVyeS5mbi5pbml0ID0gZnVuY3Rpb24oIHNlbGVjdG9yLCBjb250ZXh0LCByb290ICkge1xuXHRcdHZhciBtYXRjaCwgZWxlbTtcblxuXHRcdC8vIEhBTkRMRTogJChcIlwiKSwgJChudWxsKSwgJCh1bmRlZmluZWQpLCAkKGZhbHNlKVxuXHRcdGlmICggIXNlbGVjdG9yICkge1xuXHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0fVxuXG5cdFx0Ly8gTWV0aG9kIGluaXQoKSBhY2NlcHRzIGFuIGFsdGVybmF0ZSByb290alF1ZXJ5XG5cdFx0Ly8gc28gbWlncmF0ZSBjYW4gc3VwcG9ydCBqUXVlcnkuc3ViIChnaC0yMTAxKVxuXHRcdHJvb3QgPSByb290IHx8IHJvb3RqUXVlcnk7XG5cblx0XHQvLyBIYW5kbGUgSFRNTCBzdHJpbmdzXG5cdFx0aWYgKCB0eXBlb2Ygc2VsZWN0b3IgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRpZiAoIHNlbGVjdG9yWyAwIF0gPT09IFwiPFwiICYmXG5cdFx0XHRcdHNlbGVjdG9yWyBzZWxlY3Rvci5sZW5ndGggLSAxIF0gPT09IFwiPlwiICYmXG5cdFx0XHRcdHNlbGVjdG9yLmxlbmd0aCA+PSAzICkge1xuXG5cdFx0XHRcdC8vIEFzc3VtZSB0aGF0IHN0cmluZ3MgdGhhdCBzdGFydCBhbmQgZW5kIHdpdGggPD4gYXJlIEhUTUwgYW5kIHNraXAgdGhlIHJlZ2V4IGNoZWNrXG5cdFx0XHRcdG1hdGNoID0gWyBudWxsLCBzZWxlY3RvciwgbnVsbCBdO1xuXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRtYXRjaCA9IHJxdWlja0V4cHIuZXhlYyggc2VsZWN0b3IgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gTWF0Y2ggaHRtbCBvciBtYWtlIHN1cmUgbm8gY29udGV4dCBpcyBzcGVjaWZpZWQgZm9yICNpZFxuXHRcdFx0aWYgKCBtYXRjaCAmJiAoIG1hdGNoWyAxIF0gfHwgIWNvbnRleHQgKSApIHtcblxuXHRcdFx0XHQvLyBIQU5ETEU6ICQoaHRtbCkgLT4gJChhcnJheSlcblx0XHRcdFx0aWYgKCBtYXRjaFsgMSBdICkge1xuXHRcdFx0XHRcdGNvbnRleHQgPSBjb250ZXh0IGluc3RhbmNlb2YgalF1ZXJ5ID8gY29udGV4dFsgMCBdIDogY29udGV4dDtcblxuXHRcdFx0XHRcdC8vIE9wdGlvbiB0byBydW4gc2NyaXB0cyBpcyB0cnVlIGZvciBiYWNrLWNvbXBhdFxuXHRcdFx0XHRcdC8vIEludGVudGlvbmFsbHkgbGV0IHRoZSBlcnJvciBiZSB0aHJvd24gaWYgcGFyc2VIVE1MIGlzIG5vdCBwcmVzZW50XG5cdFx0XHRcdFx0alF1ZXJ5Lm1lcmdlKCB0aGlzLCBqUXVlcnkucGFyc2VIVE1MKFxuXHRcdFx0XHRcdFx0bWF0Y2hbIDEgXSxcblx0XHRcdFx0XHRcdGNvbnRleHQgJiYgY29udGV4dC5ub2RlVHlwZSA/IGNvbnRleHQub3duZXJEb2N1bWVudCB8fCBjb250ZXh0IDogZG9jdW1lbnQsXG5cdFx0XHRcdFx0XHR0cnVlXG5cdFx0XHRcdFx0KSApO1xuXG5cdFx0XHRcdFx0Ly8gSEFORExFOiAkKGh0bWwsIHByb3BzKVxuXHRcdFx0XHRcdGlmICggcnNpbmdsZVRhZy50ZXN0KCBtYXRjaFsgMSBdICkgJiYgalF1ZXJ5LmlzUGxhaW5PYmplY3QoIGNvbnRleHQgKSApIHtcblx0XHRcdFx0XHRcdGZvciAoIG1hdGNoIGluIGNvbnRleHQgKSB7XG5cblx0XHRcdFx0XHRcdFx0Ly8gUHJvcGVydGllcyBvZiBjb250ZXh0IGFyZSBjYWxsZWQgYXMgbWV0aG9kcyBpZiBwb3NzaWJsZVxuXHRcdFx0XHRcdFx0XHRpZiAoIGlzRnVuY3Rpb24oIHRoaXNbIG1hdGNoIF0gKSApIHtcblx0XHRcdFx0XHRcdFx0XHR0aGlzWyBtYXRjaCBdKCBjb250ZXh0WyBtYXRjaCBdICk7XG5cblx0XHRcdFx0XHRcdFx0Ly8gLi4uYW5kIG90aGVyd2lzZSBzZXQgYXMgYXR0cmlidXRlc1xuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMuYXR0ciggbWF0Y2gsIGNvbnRleHRbIG1hdGNoIF0gKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdHJldHVybiB0aGlzO1xuXG5cdFx0XHRcdC8vIEhBTkRMRTogJCgjaWQpXG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0ZWxlbSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCBtYXRjaFsgMiBdICk7XG5cblx0XHRcdFx0XHRpZiAoIGVsZW0gKSB7XG5cblx0XHRcdFx0XHRcdC8vIEluamVjdCB0aGUgZWxlbWVudCBkaXJlY3RseSBpbnRvIHRoZSBqUXVlcnkgb2JqZWN0XG5cdFx0XHRcdFx0XHR0aGlzWyAwIF0gPSBlbGVtO1xuXHRcdFx0XHRcdFx0dGhpcy5sZW5ndGggPSAxO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRyZXR1cm4gdGhpcztcblx0XHRcdFx0fVxuXG5cdFx0XHQvLyBIQU5ETEU6ICQoZXhwciwgJCguLi4pKVxuXHRcdFx0fSBlbHNlIGlmICggIWNvbnRleHQgfHwgY29udGV4dC5qcXVlcnkgKSB7XG5cdFx0XHRcdHJldHVybiAoIGNvbnRleHQgfHwgcm9vdCApLmZpbmQoIHNlbGVjdG9yICk7XG5cblx0XHRcdC8vIEhBTkRMRTogJChleHByLCBjb250ZXh0KVxuXHRcdFx0Ly8gKHdoaWNoIGlzIGp1c3QgZXF1aXZhbGVudCB0bzogJChjb250ZXh0KS5maW5kKGV4cHIpXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRyZXR1cm4gdGhpcy5jb25zdHJ1Y3RvciggY29udGV4dCApLmZpbmQoIHNlbGVjdG9yICk7XG5cdFx0XHR9XG5cblx0XHQvLyBIQU5ETEU6ICQoRE9NRWxlbWVudClcblx0XHR9IGVsc2UgaWYgKCBzZWxlY3Rvci5ub2RlVHlwZSApIHtcblx0XHRcdHRoaXNbIDAgXSA9IHNlbGVjdG9yO1xuXHRcdFx0dGhpcy5sZW5ndGggPSAxO1xuXHRcdFx0cmV0dXJuIHRoaXM7XG5cblx0XHQvLyBIQU5ETEU6ICQoZnVuY3Rpb24pXG5cdFx0Ly8gU2hvcnRjdXQgZm9yIGRvY3VtZW50IHJlYWR5XG5cdFx0fSBlbHNlIGlmICggaXNGdW5jdGlvbiggc2VsZWN0b3IgKSApIHtcblx0XHRcdHJldHVybiByb290LnJlYWR5ICE9PSB1bmRlZmluZWQgP1xuXHRcdFx0XHRyb290LnJlYWR5KCBzZWxlY3RvciApIDpcblxuXHRcdFx0XHQvLyBFeGVjdXRlIGltbWVkaWF0ZWx5IGlmIHJlYWR5IGlzIG5vdCBwcmVzZW50XG5cdFx0XHRcdHNlbGVjdG9yKCBqUXVlcnkgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4galF1ZXJ5Lm1ha2VBcnJheSggc2VsZWN0b3IsIHRoaXMgKTtcblx0fTtcblxuLy8gR2l2ZSB0aGUgaW5pdCBmdW5jdGlvbiB0aGUgalF1ZXJ5IHByb3RvdHlwZSBmb3IgbGF0ZXIgaW5zdGFudGlhdGlvblxuaW5pdC5wcm90b3R5cGUgPSBqUXVlcnkuZm47XG5cbi8vIEluaXRpYWxpemUgY2VudHJhbCByZWZlcmVuY2VcbnJvb3RqUXVlcnkgPSBqUXVlcnkoIGRvY3VtZW50ICk7XG5cblxudmFyIHJwYXJlbnRzcHJldiA9IC9eKD86cGFyZW50c3xwcmV2KD86VW50aWx8QWxsKSkvLFxuXG5cdC8vIE1ldGhvZHMgZ3VhcmFudGVlZCB0byBwcm9kdWNlIGEgdW5pcXVlIHNldCB3aGVuIHN0YXJ0aW5nIGZyb20gYSB1bmlxdWUgc2V0XG5cdGd1YXJhbnRlZWRVbmlxdWUgPSB7XG5cdFx0Y2hpbGRyZW46IHRydWUsXG5cdFx0Y29udGVudHM6IHRydWUsXG5cdFx0bmV4dDogdHJ1ZSxcblx0XHRwcmV2OiB0cnVlXG5cdH07XG5cbmpRdWVyeS5mbi5leHRlbmQoIHtcblx0aGFzOiBmdW5jdGlvbiggdGFyZ2V0ICkge1xuXHRcdHZhciB0YXJnZXRzID0galF1ZXJ5KCB0YXJnZXQsIHRoaXMgKSxcblx0XHRcdGwgPSB0YXJnZXRzLmxlbmd0aDtcblxuXHRcdHJldHVybiB0aGlzLmZpbHRlciggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgaSA9IDA7XG5cdFx0XHRmb3IgKCA7IGkgPCBsOyBpKysgKSB7XG5cdFx0XHRcdGlmICggalF1ZXJ5LmNvbnRhaW5zKCB0aGlzLCB0YXJnZXRzWyBpIF0gKSApIHtcblx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRjbG9zZXN0OiBmdW5jdGlvbiggc2VsZWN0b3JzLCBjb250ZXh0ICkge1xuXHRcdHZhciBjdXIsXG5cdFx0XHRpID0gMCxcblx0XHRcdGwgPSB0aGlzLmxlbmd0aCxcblx0XHRcdG1hdGNoZWQgPSBbXSxcblx0XHRcdHRhcmdldHMgPSB0eXBlb2Ygc2VsZWN0b3JzICE9PSBcInN0cmluZ1wiICYmIGpRdWVyeSggc2VsZWN0b3JzICk7XG5cblx0XHQvLyBQb3NpdGlvbmFsIHNlbGVjdG9ycyBuZXZlciBtYXRjaCwgc2luY2UgdGhlcmUncyBubyBfc2VsZWN0aW9uXyBjb250ZXh0XG5cdFx0aWYgKCAhcm5lZWRzQ29udGV4dC50ZXN0KCBzZWxlY3RvcnMgKSApIHtcblx0XHRcdGZvciAoIDsgaSA8IGw7IGkrKyApIHtcblx0XHRcdFx0Zm9yICggY3VyID0gdGhpc1sgaSBdOyBjdXIgJiYgY3VyICE9PSBjb250ZXh0OyBjdXIgPSBjdXIucGFyZW50Tm9kZSApIHtcblxuXHRcdFx0XHRcdC8vIEFsd2F5cyBza2lwIGRvY3VtZW50IGZyYWdtZW50c1xuXHRcdFx0XHRcdGlmICggY3VyLm5vZGVUeXBlIDwgMTEgJiYgKCB0YXJnZXRzID9cblx0XHRcdFx0XHRcdHRhcmdldHMuaW5kZXgoIGN1ciApID4gLTEgOlxuXG5cdFx0XHRcdFx0XHQvLyBEb24ndCBwYXNzIG5vbi1lbGVtZW50cyB0byBTaXp6bGVcblx0XHRcdFx0XHRcdGN1ci5ub2RlVHlwZSA9PT0gMSAmJlxuXHRcdFx0XHRcdFx0XHRqUXVlcnkuZmluZC5tYXRjaGVzU2VsZWN0b3IoIGN1ciwgc2VsZWN0b3JzICkgKSApIHtcblxuXHRcdFx0XHRcdFx0bWF0Y2hlZC5wdXNoKCBjdXIgKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLnB1c2hTdGFjayggbWF0Y2hlZC5sZW5ndGggPiAxID8galF1ZXJ5LnVuaXF1ZVNvcnQoIG1hdGNoZWQgKSA6IG1hdGNoZWQgKTtcblx0fSxcblxuXHQvLyBEZXRlcm1pbmUgdGhlIHBvc2l0aW9uIG9mIGFuIGVsZW1lbnQgd2l0aGluIHRoZSBzZXRcblx0aW5kZXg6IGZ1bmN0aW9uKCBlbGVtICkge1xuXG5cdFx0Ly8gTm8gYXJndW1lbnQsIHJldHVybiBpbmRleCBpbiBwYXJlbnRcblx0XHRpZiAoICFlbGVtICkge1xuXHRcdFx0cmV0dXJuICggdGhpc1sgMCBdICYmIHRoaXNbIDAgXS5wYXJlbnROb2RlICkgPyB0aGlzLmZpcnN0KCkucHJldkFsbCgpLmxlbmd0aCA6IC0xO1xuXHRcdH1cblxuXHRcdC8vIEluZGV4IGluIHNlbGVjdG9yXG5cdFx0aWYgKCB0eXBlb2YgZWxlbSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdHJldHVybiBpbmRleE9mLmNhbGwoIGpRdWVyeSggZWxlbSApLCB0aGlzWyAwIF0gKTtcblx0XHR9XG5cblx0XHQvLyBMb2NhdGUgdGhlIHBvc2l0aW9uIG9mIHRoZSBkZXNpcmVkIGVsZW1lbnRcblx0XHRyZXR1cm4gaW5kZXhPZi5jYWxsKCB0aGlzLFxuXG5cdFx0XHQvLyBJZiBpdCByZWNlaXZlcyBhIGpRdWVyeSBvYmplY3QsIHRoZSBmaXJzdCBlbGVtZW50IGlzIHVzZWRcblx0XHRcdGVsZW0uanF1ZXJ5ID8gZWxlbVsgMCBdIDogZWxlbVxuXHRcdCk7XG5cdH0sXG5cblx0YWRkOiBmdW5jdGlvbiggc2VsZWN0b3IsIGNvbnRleHQgKSB7XG5cdFx0cmV0dXJuIHRoaXMucHVzaFN0YWNrKFxuXHRcdFx0alF1ZXJ5LnVuaXF1ZVNvcnQoXG5cdFx0XHRcdGpRdWVyeS5tZXJnZSggdGhpcy5nZXQoKSwgalF1ZXJ5KCBzZWxlY3RvciwgY29udGV4dCApIClcblx0XHRcdClcblx0XHQpO1xuXHR9LFxuXG5cdGFkZEJhY2s6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHRyZXR1cm4gdGhpcy5hZGQoIHNlbGVjdG9yID09IG51bGwgP1xuXHRcdFx0dGhpcy5wcmV2T2JqZWN0IDogdGhpcy5wcmV2T2JqZWN0LmZpbHRlciggc2VsZWN0b3IgKVxuXHRcdCk7XG5cdH1cbn0gKTtcblxuZnVuY3Rpb24gc2libGluZyggY3VyLCBkaXIgKSB7XG5cdHdoaWxlICggKCBjdXIgPSBjdXJbIGRpciBdICkgJiYgY3VyLm5vZGVUeXBlICE9PSAxICkge31cblx0cmV0dXJuIGN1cjtcbn1cblxualF1ZXJ5LmVhY2goIHtcblx0cGFyZW50OiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHR2YXIgcGFyZW50ID0gZWxlbS5wYXJlbnROb2RlO1xuXHRcdHJldHVybiBwYXJlbnQgJiYgcGFyZW50Lm5vZGVUeXBlICE9PSAxMSA/IHBhcmVudCA6IG51bGw7XG5cdH0sXG5cdHBhcmVudHM6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdHJldHVybiBkaXIoIGVsZW0sIFwicGFyZW50Tm9kZVwiICk7XG5cdH0sXG5cdHBhcmVudHNVbnRpbDogZnVuY3Rpb24oIGVsZW0sIF9pLCB1bnRpbCApIHtcblx0XHRyZXR1cm4gZGlyKCBlbGVtLCBcInBhcmVudE5vZGVcIiwgdW50aWwgKTtcblx0fSxcblx0bmV4dDogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0cmV0dXJuIHNpYmxpbmcoIGVsZW0sIFwibmV4dFNpYmxpbmdcIiApO1xuXHR9LFxuXHRwcmV2OiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRyZXR1cm4gc2libGluZyggZWxlbSwgXCJwcmV2aW91c1NpYmxpbmdcIiApO1xuXHR9LFxuXHRuZXh0QWxsOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRyZXR1cm4gZGlyKCBlbGVtLCBcIm5leHRTaWJsaW5nXCIgKTtcblx0fSxcblx0cHJldkFsbDogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0cmV0dXJuIGRpciggZWxlbSwgXCJwcmV2aW91c1NpYmxpbmdcIiApO1xuXHR9LFxuXHRuZXh0VW50aWw6IGZ1bmN0aW9uKCBlbGVtLCBfaSwgdW50aWwgKSB7XG5cdFx0cmV0dXJuIGRpciggZWxlbSwgXCJuZXh0U2libGluZ1wiLCB1bnRpbCApO1xuXHR9LFxuXHRwcmV2VW50aWw6IGZ1bmN0aW9uKCBlbGVtLCBfaSwgdW50aWwgKSB7XG5cdFx0cmV0dXJuIGRpciggZWxlbSwgXCJwcmV2aW91c1NpYmxpbmdcIiwgdW50aWwgKTtcblx0fSxcblx0c2libGluZ3M6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdHJldHVybiBzaWJsaW5ncyggKCBlbGVtLnBhcmVudE5vZGUgfHwge30gKS5maXJzdENoaWxkLCBlbGVtICk7XG5cdH0sXG5cdGNoaWxkcmVuOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRyZXR1cm4gc2libGluZ3MoIGVsZW0uZmlyc3RDaGlsZCApO1xuXHR9LFxuXHRjb250ZW50czogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0aWYgKCBlbGVtLmNvbnRlbnREb2N1bWVudCAhPSBudWxsICYmXG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFIDExK1xuXHRcdFx0Ly8gPG9iamVjdD4gZWxlbWVudHMgd2l0aCBubyBgZGF0YWAgYXR0cmlidXRlIGhhcyBhbiBvYmplY3Rcblx0XHRcdC8vIGBjb250ZW50RG9jdW1lbnRgIHdpdGggYSBgbnVsbGAgcHJvdG90eXBlLlxuXHRcdFx0Z2V0UHJvdG8oIGVsZW0uY29udGVudERvY3VtZW50ICkgKSB7XG5cblx0XHRcdHJldHVybiBlbGVtLmNvbnRlbnREb2N1bWVudDtcblx0XHR9XG5cblx0XHQvLyBTdXBwb3J0OiBJRSA5IC0gMTEgb25seSwgaU9TIDcgb25seSwgQW5kcm9pZCBCcm93c2VyIDw9NC4zIG9ubHlcblx0XHQvLyBUcmVhdCB0aGUgdGVtcGxhdGUgZWxlbWVudCBhcyBhIHJlZ3VsYXIgb25lIGluIGJyb3dzZXJzIHRoYXRcblx0XHQvLyBkb24ndCBzdXBwb3J0IGl0LlxuXHRcdGlmICggbm9kZU5hbWUoIGVsZW0sIFwidGVtcGxhdGVcIiApICkge1xuXHRcdFx0ZWxlbSA9IGVsZW0uY29udGVudCB8fCBlbGVtO1xuXHRcdH1cblxuXHRcdHJldHVybiBqUXVlcnkubWVyZ2UoIFtdLCBlbGVtLmNoaWxkTm9kZXMgKTtcblx0fVxufSwgZnVuY3Rpb24oIG5hbWUsIGZuICkge1xuXHRqUXVlcnkuZm5bIG5hbWUgXSA9IGZ1bmN0aW9uKCB1bnRpbCwgc2VsZWN0b3IgKSB7XG5cdFx0dmFyIG1hdGNoZWQgPSBqUXVlcnkubWFwKCB0aGlzLCBmbiwgdW50aWwgKTtcblxuXHRcdGlmICggbmFtZS5zbGljZSggLTUgKSAhPT0gXCJVbnRpbFwiICkge1xuXHRcdFx0c2VsZWN0b3IgPSB1bnRpbDtcblx0XHR9XG5cblx0XHRpZiAoIHNlbGVjdG9yICYmIHR5cGVvZiBzZWxlY3RvciA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdG1hdGNoZWQgPSBqUXVlcnkuZmlsdGVyKCBzZWxlY3RvciwgbWF0Y2hlZCApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5sZW5ndGggPiAxICkge1xuXG5cdFx0XHQvLyBSZW1vdmUgZHVwbGljYXRlc1xuXHRcdFx0aWYgKCAhZ3VhcmFudGVlZFVuaXF1ZVsgbmFtZSBdICkge1xuXHRcdFx0XHRqUXVlcnkudW5pcXVlU29ydCggbWF0Y2hlZCApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBSZXZlcnNlIG9yZGVyIGZvciBwYXJlbnRzKiBhbmQgcHJldi1kZXJpdmF0aXZlc1xuXHRcdFx0aWYgKCBycGFyZW50c3ByZXYudGVzdCggbmFtZSApICkge1xuXHRcdFx0XHRtYXRjaGVkLnJldmVyc2UoKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5wdXNoU3RhY2soIG1hdGNoZWQgKTtcblx0fTtcbn0gKTtcbnZhciBybm90aHRtbHdoaXRlID0gKCAvW15cXHgyMFxcdFxcclxcblxcZl0rL2cgKTtcblxuXG5cbi8vIENvbnZlcnQgU3RyaW5nLWZvcm1hdHRlZCBvcHRpb25zIGludG8gT2JqZWN0LWZvcm1hdHRlZCBvbmVzXG5mdW5jdGlvbiBjcmVhdGVPcHRpb25zKCBvcHRpb25zICkge1xuXHR2YXIgb2JqZWN0ID0ge307XG5cdGpRdWVyeS5lYWNoKCBvcHRpb25zLm1hdGNoKCBybm90aHRtbHdoaXRlICkgfHwgW10sIGZ1bmN0aW9uKCBfLCBmbGFnICkge1xuXHRcdG9iamVjdFsgZmxhZyBdID0gdHJ1ZTtcblx0fSApO1xuXHRyZXR1cm4gb2JqZWN0O1xufVxuXG4vKlxuICogQ3JlYXRlIGEgY2FsbGJhY2sgbGlzdCB1c2luZyB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnM6XG4gKlxuICpcdG9wdGlvbnM6IGFuIG9wdGlvbmFsIGxpc3Qgb2Ygc3BhY2Utc2VwYXJhdGVkIG9wdGlvbnMgdGhhdCB3aWxsIGNoYW5nZSBob3dcbiAqXHRcdFx0dGhlIGNhbGxiYWNrIGxpc3QgYmVoYXZlcyBvciBhIG1vcmUgdHJhZGl0aW9uYWwgb3B0aW9uIG9iamVjdFxuICpcbiAqIEJ5IGRlZmF1bHQgYSBjYWxsYmFjayBsaXN0IHdpbGwgYWN0IGxpa2UgYW4gZXZlbnQgY2FsbGJhY2sgbGlzdCBhbmQgY2FuIGJlXG4gKiBcImZpcmVkXCIgbXVsdGlwbGUgdGltZXMuXG4gKlxuICogUG9zc2libGUgb3B0aW9uczpcbiAqXG4gKlx0b25jZTpcdFx0XHR3aWxsIGVuc3VyZSB0aGUgY2FsbGJhY2sgbGlzdCBjYW4gb25seSBiZSBmaXJlZCBvbmNlIChsaWtlIGEgRGVmZXJyZWQpXG4gKlxuICpcdG1lbW9yeTpcdFx0XHR3aWxsIGtlZXAgdHJhY2sgb2YgcHJldmlvdXMgdmFsdWVzIGFuZCB3aWxsIGNhbGwgYW55IGNhbGxiYWNrIGFkZGVkXG4gKlx0XHRcdFx0XHRhZnRlciB0aGUgbGlzdCBoYXMgYmVlbiBmaXJlZCByaWdodCBhd2F5IHdpdGggdGhlIGxhdGVzdCBcIm1lbW9yaXplZFwiXG4gKlx0XHRcdFx0XHR2YWx1ZXMgKGxpa2UgYSBEZWZlcnJlZClcbiAqXG4gKlx0dW5pcXVlOlx0XHRcdHdpbGwgZW5zdXJlIGEgY2FsbGJhY2sgY2FuIG9ubHkgYmUgYWRkZWQgb25jZSAobm8gZHVwbGljYXRlIGluIHRoZSBsaXN0KVxuICpcbiAqXHRzdG9wT25GYWxzZTpcdGludGVycnVwdCBjYWxsaW5ncyB3aGVuIGEgY2FsbGJhY2sgcmV0dXJucyBmYWxzZVxuICpcbiAqL1xualF1ZXJ5LkNhbGxiYWNrcyA9IGZ1bmN0aW9uKCBvcHRpb25zICkge1xuXG5cdC8vIENvbnZlcnQgb3B0aW9ucyBmcm9tIFN0cmluZy1mb3JtYXR0ZWQgdG8gT2JqZWN0LWZvcm1hdHRlZCBpZiBuZWVkZWRcblx0Ly8gKHdlIGNoZWNrIGluIGNhY2hlIGZpcnN0KVxuXHRvcHRpb25zID0gdHlwZW9mIG9wdGlvbnMgPT09IFwic3RyaW5nXCIgP1xuXHRcdGNyZWF0ZU9wdGlvbnMoIG9wdGlvbnMgKSA6XG5cdFx0alF1ZXJ5LmV4dGVuZCgge30sIG9wdGlvbnMgKTtcblxuXHR2YXIgLy8gRmxhZyB0byBrbm93IGlmIGxpc3QgaXMgY3VycmVudGx5IGZpcmluZ1xuXHRcdGZpcmluZyxcblxuXHRcdC8vIExhc3QgZmlyZSB2YWx1ZSBmb3Igbm9uLWZvcmdldHRhYmxlIGxpc3RzXG5cdFx0bWVtb3J5LFxuXG5cdFx0Ly8gRmxhZyB0byBrbm93IGlmIGxpc3Qgd2FzIGFscmVhZHkgZmlyZWRcblx0XHRmaXJlZCxcblxuXHRcdC8vIEZsYWcgdG8gcHJldmVudCBmaXJpbmdcblx0XHRsb2NrZWQsXG5cblx0XHQvLyBBY3R1YWwgY2FsbGJhY2sgbGlzdFxuXHRcdGxpc3QgPSBbXSxcblxuXHRcdC8vIFF1ZXVlIG9mIGV4ZWN1dGlvbiBkYXRhIGZvciByZXBlYXRhYmxlIGxpc3RzXG5cdFx0cXVldWUgPSBbXSxcblxuXHRcdC8vIEluZGV4IG9mIGN1cnJlbnRseSBmaXJpbmcgY2FsbGJhY2sgKG1vZGlmaWVkIGJ5IGFkZC9yZW1vdmUgYXMgbmVlZGVkKVxuXHRcdGZpcmluZ0luZGV4ID0gLTEsXG5cblx0XHQvLyBGaXJlIGNhbGxiYWNrc1xuXHRcdGZpcmUgPSBmdW5jdGlvbigpIHtcblxuXHRcdFx0Ly8gRW5mb3JjZSBzaW5nbGUtZmlyaW5nXG5cdFx0XHRsb2NrZWQgPSBsb2NrZWQgfHwgb3B0aW9ucy5vbmNlO1xuXG5cdFx0XHQvLyBFeGVjdXRlIGNhbGxiYWNrcyBmb3IgYWxsIHBlbmRpbmcgZXhlY3V0aW9ucyxcblx0XHRcdC8vIHJlc3BlY3RpbmcgZmlyaW5nSW5kZXggb3ZlcnJpZGVzIGFuZCBydW50aW1lIGNoYW5nZXNcblx0XHRcdGZpcmVkID0gZmlyaW5nID0gdHJ1ZTtcblx0XHRcdGZvciAoIDsgcXVldWUubGVuZ3RoOyBmaXJpbmdJbmRleCA9IC0xICkge1xuXHRcdFx0XHRtZW1vcnkgPSBxdWV1ZS5zaGlmdCgpO1xuXHRcdFx0XHR3aGlsZSAoICsrZmlyaW5nSW5kZXggPCBsaXN0Lmxlbmd0aCApIHtcblxuXHRcdFx0XHRcdC8vIFJ1biBjYWxsYmFjayBhbmQgY2hlY2sgZm9yIGVhcmx5IHRlcm1pbmF0aW9uXG5cdFx0XHRcdFx0aWYgKCBsaXN0WyBmaXJpbmdJbmRleCBdLmFwcGx5KCBtZW1vcnlbIDAgXSwgbWVtb3J5WyAxIF0gKSA9PT0gZmFsc2UgJiZcblx0XHRcdFx0XHRcdG9wdGlvbnMuc3RvcE9uRmFsc2UgKSB7XG5cblx0XHRcdFx0XHRcdC8vIEp1bXAgdG8gZW5kIGFuZCBmb3JnZXQgdGhlIGRhdGEgc28gLmFkZCBkb2Vzbid0IHJlLWZpcmVcblx0XHRcdFx0XHRcdGZpcmluZ0luZGV4ID0gbGlzdC5sZW5ndGg7XG5cdFx0XHRcdFx0XHRtZW1vcnkgPSBmYWxzZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Ly8gRm9yZ2V0IHRoZSBkYXRhIGlmIHdlJ3JlIGRvbmUgd2l0aCBpdFxuXHRcdFx0aWYgKCAhb3B0aW9ucy5tZW1vcnkgKSB7XG5cdFx0XHRcdG1lbW9yeSA9IGZhbHNlO1xuXHRcdFx0fVxuXG5cdFx0XHRmaXJpbmcgPSBmYWxzZTtcblxuXHRcdFx0Ly8gQ2xlYW4gdXAgaWYgd2UncmUgZG9uZSBmaXJpbmcgZm9yIGdvb2Rcblx0XHRcdGlmICggbG9ja2VkICkge1xuXG5cdFx0XHRcdC8vIEtlZXAgYW4gZW1wdHkgbGlzdCBpZiB3ZSBoYXZlIGRhdGEgZm9yIGZ1dHVyZSBhZGQgY2FsbHNcblx0XHRcdFx0aWYgKCBtZW1vcnkgKSB7XG5cdFx0XHRcdFx0bGlzdCA9IFtdO1xuXG5cdFx0XHRcdC8vIE90aGVyd2lzZSwgdGhpcyBvYmplY3QgaXMgc3BlbnRcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRsaXN0ID0gXCJcIjtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0sXG5cblx0XHQvLyBBY3R1YWwgQ2FsbGJhY2tzIG9iamVjdFxuXHRcdHNlbGYgPSB7XG5cblx0XHRcdC8vIEFkZCBhIGNhbGxiYWNrIG9yIGEgY29sbGVjdGlvbiBvZiBjYWxsYmFja3MgdG8gdGhlIGxpc3Rcblx0XHRcdGFkZDogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggbGlzdCApIHtcblxuXHRcdFx0XHRcdC8vIElmIHdlIGhhdmUgbWVtb3J5IGZyb20gYSBwYXN0IHJ1biwgd2Ugc2hvdWxkIGZpcmUgYWZ0ZXIgYWRkaW5nXG5cdFx0XHRcdFx0aWYgKCBtZW1vcnkgJiYgIWZpcmluZyApIHtcblx0XHRcdFx0XHRcdGZpcmluZ0luZGV4ID0gbGlzdC5sZW5ndGggLSAxO1xuXHRcdFx0XHRcdFx0cXVldWUucHVzaCggbWVtb3J5ICk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0KCBmdW5jdGlvbiBhZGQoIGFyZ3MgKSB7XG5cdFx0XHRcdFx0XHRqUXVlcnkuZWFjaCggYXJncywgZnVuY3Rpb24oIF8sIGFyZyApIHtcblx0XHRcdFx0XHRcdFx0aWYgKCBpc0Z1bmN0aW9uKCBhcmcgKSApIHtcblx0XHRcdFx0XHRcdFx0XHRpZiAoICFvcHRpb25zLnVuaXF1ZSB8fCAhc2VsZi5oYXMoIGFyZyApICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0bGlzdC5wdXNoKCBhcmcgKTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoIGFyZyAmJiBhcmcubGVuZ3RoICYmIHRvVHlwZSggYXJnICkgIT09IFwic3RyaW5nXCIgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHQvLyBJbnNwZWN0IHJlY3Vyc2l2ZWx5XG5cdFx0XHRcdFx0XHRcdFx0YWRkKCBhcmcgKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fSApO1xuXHRcdFx0XHRcdH0gKSggYXJndW1lbnRzICk7XG5cblx0XHRcdFx0XHRpZiAoIG1lbW9yeSAmJiAhZmlyaW5nICkge1xuXHRcdFx0XHRcdFx0ZmlyZSgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gdGhpcztcblx0XHRcdH0sXG5cblx0XHRcdC8vIFJlbW92ZSBhIGNhbGxiYWNrIGZyb20gdGhlIGxpc3Rcblx0XHRcdHJlbW92ZTogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGpRdWVyeS5lYWNoKCBhcmd1bWVudHMsIGZ1bmN0aW9uKCBfLCBhcmcgKSB7XG5cdFx0XHRcdFx0dmFyIGluZGV4O1xuXHRcdFx0XHRcdHdoaWxlICggKCBpbmRleCA9IGpRdWVyeS5pbkFycmF5KCBhcmcsIGxpc3QsIGluZGV4ICkgKSA+IC0xICkge1xuXHRcdFx0XHRcdFx0bGlzdC5zcGxpY2UoIGluZGV4LCAxICk7XG5cblx0XHRcdFx0XHRcdC8vIEhhbmRsZSBmaXJpbmcgaW5kZXhlc1xuXHRcdFx0XHRcdFx0aWYgKCBpbmRleCA8PSBmaXJpbmdJbmRleCApIHtcblx0XHRcdFx0XHRcdFx0ZmlyaW5nSW5kZXgtLTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9LFxuXG5cdFx0XHQvLyBDaGVjayBpZiBhIGdpdmVuIGNhbGxiYWNrIGlzIGluIHRoZSBsaXN0LlxuXHRcdFx0Ly8gSWYgbm8gYXJndW1lbnQgaXMgZ2l2ZW4sIHJldHVybiB3aGV0aGVyIG9yIG5vdCBsaXN0IGhhcyBjYWxsYmFja3MgYXR0YWNoZWQuXG5cdFx0XHRoYXM6IGZ1bmN0aW9uKCBmbiApIHtcblx0XHRcdFx0cmV0dXJuIGZuID9cblx0XHRcdFx0XHRqUXVlcnkuaW5BcnJheSggZm4sIGxpc3QgKSA+IC0xIDpcblx0XHRcdFx0XHRsaXN0Lmxlbmd0aCA+IDA7XG5cdFx0XHR9LFxuXG5cdFx0XHQvLyBSZW1vdmUgYWxsIGNhbGxiYWNrcyBmcm9tIHRoZSBsaXN0XG5cdFx0XHRlbXB0eTogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggbGlzdCApIHtcblx0XHRcdFx0XHRsaXN0ID0gW107XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9LFxuXG5cdFx0XHQvLyBEaXNhYmxlIC5maXJlIGFuZCAuYWRkXG5cdFx0XHQvLyBBYm9ydCBhbnkgY3VycmVudC9wZW5kaW5nIGV4ZWN1dGlvbnNcblx0XHRcdC8vIENsZWFyIGFsbCBjYWxsYmFja3MgYW5kIHZhbHVlc1xuXHRcdFx0ZGlzYWJsZTogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGxvY2tlZCA9IHF1ZXVlID0gW107XG5cdFx0XHRcdGxpc3QgPSBtZW1vcnkgPSBcIlwiO1xuXHRcdFx0XHRyZXR1cm4gdGhpcztcblx0XHRcdH0sXG5cdFx0XHRkaXNhYmxlZDogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHJldHVybiAhbGlzdDtcblx0XHRcdH0sXG5cblx0XHRcdC8vIERpc2FibGUgLmZpcmVcblx0XHRcdC8vIEFsc28gZGlzYWJsZSAuYWRkIHVubGVzcyB3ZSBoYXZlIG1lbW9yeSAoc2luY2UgaXQgd291bGQgaGF2ZSBubyBlZmZlY3QpXG5cdFx0XHQvLyBBYm9ydCBhbnkgcGVuZGluZyBleGVjdXRpb25zXG5cdFx0XHRsb2NrOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0bG9ja2VkID0gcXVldWUgPSBbXTtcblx0XHRcdFx0aWYgKCAhbWVtb3J5ICYmICFmaXJpbmcgKSB7XG5cdFx0XHRcdFx0bGlzdCA9IG1lbW9yeSA9IFwiXCI7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9LFxuXHRcdFx0bG9ja2VkOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0cmV0dXJuICEhbG9ja2VkO1xuXHRcdFx0fSxcblxuXHRcdFx0Ly8gQ2FsbCBhbGwgY2FsbGJhY2tzIHdpdGggdGhlIGdpdmVuIGNvbnRleHQgYW5kIGFyZ3VtZW50c1xuXHRcdFx0ZmlyZVdpdGg6IGZ1bmN0aW9uKCBjb250ZXh0LCBhcmdzICkge1xuXHRcdFx0XHRpZiAoICFsb2NrZWQgKSB7XG5cdFx0XHRcdFx0YXJncyA9IGFyZ3MgfHwgW107XG5cdFx0XHRcdFx0YXJncyA9IFsgY29udGV4dCwgYXJncy5zbGljZSA/IGFyZ3Muc2xpY2UoKSA6IGFyZ3MgXTtcblx0XHRcdFx0XHRxdWV1ZS5wdXNoKCBhcmdzICk7XG5cdFx0XHRcdFx0aWYgKCAhZmlyaW5nICkge1xuXHRcdFx0XHRcdFx0ZmlyZSgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gdGhpcztcblx0XHRcdH0sXG5cblx0XHRcdC8vIENhbGwgYWxsIHRoZSBjYWxsYmFja3Mgd2l0aCB0aGUgZ2l2ZW4gYXJndW1lbnRzXG5cdFx0XHRmaXJlOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0c2VsZi5maXJlV2l0aCggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHRcdHJldHVybiB0aGlzO1xuXHRcdFx0fSxcblxuXHRcdFx0Ly8gVG8ga25vdyBpZiB0aGUgY2FsbGJhY2tzIGhhdmUgYWxyZWFkeSBiZWVuIGNhbGxlZCBhdCBsZWFzdCBvbmNlXG5cdFx0XHRmaXJlZDogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHJldHVybiAhIWZpcmVkO1xuXHRcdFx0fVxuXHRcdH07XG5cblx0cmV0dXJuIHNlbGY7XG59O1xuXG5cbmZ1bmN0aW9uIElkZW50aXR5KCB2ICkge1xuXHRyZXR1cm4gdjtcbn1cbmZ1bmN0aW9uIFRocm93ZXIoIGV4ICkge1xuXHR0aHJvdyBleDtcbn1cblxuZnVuY3Rpb24gYWRvcHRWYWx1ZSggdmFsdWUsIHJlc29sdmUsIHJlamVjdCwgbm9WYWx1ZSApIHtcblx0dmFyIG1ldGhvZDtcblxuXHR0cnkge1xuXG5cdFx0Ly8gQ2hlY2sgZm9yIHByb21pc2UgYXNwZWN0IGZpcnN0IHRvIHByaXZpbGVnZSBzeW5jaHJvbm91cyBiZWhhdmlvclxuXHRcdGlmICggdmFsdWUgJiYgaXNGdW5jdGlvbiggKCBtZXRob2QgPSB2YWx1ZS5wcm9taXNlICkgKSApIHtcblx0XHRcdG1ldGhvZC5jYWxsKCB2YWx1ZSApLmRvbmUoIHJlc29sdmUgKS5mYWlsKCByZWplY3QgKTtcblxuXHRcdC8vIE90aGVyIHRoZW5hYmxlc1xuXHRcdH0gZWxzZSBpZiAoIHZhbHVlICYmIGlzRnVuY3Rpb24oICggbWV0aG9kID0gdmFsdWUudGhlbiApICkgKSB7XG5cdFx0XHRtZXRob2QuY2FsbCggdmFsdWUsIHJlc29sdmUsIHJlamVjdCApO1xuXG5cdFx0Ly8gT3RoZXIgbm9uLXRoZW5hYmxlc1xuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIENvbnRyb2wgYHJlc29sdmVgIGFyZ3VtZW50cyBieSBsZXR0aW5nIEFycmF5I3NsaWNlIGNhc3QgYm9vbGVhbiBgbm9WYWx1ZWAgdG8gaW50ZWdlcjpcblx0XHRcdC8vICogZmFsc2U6IFsgdmFsdWUgXS5zbGljZSggMCApID0+IHJlc29sdmUoIHZhbHVlIClcblx0XHRcdC8vICogdHJ1ZTogWyB2YWx1ZSBdLnNsaWNlKCAxICkgPT4gcmVzb2x2ZSgpXG5cdFx0XHRyZXNvbHZlLmFwcGx5KCB1bmRlZmluZWQsIFsgdmFsdWUgXS5zbGljZSggbm9WYWx1ZSApICk7XG5cdFx0fVxuXG5cdC8vIEZvciBQcm9taXNlcy9BKywgY29udmVydCBleGNlcHRpb25zIGludG8gcmVqZWN0aW9uc1xuXHQvLyBTaW5jZSBqUXVlcnkud2hlbiBkb2Vzbid0IHVud3JhcCB0aGVuYWJsZXMsIHdlIGNhbiBza2lwIHRoZSBleHRyYSBjaGVja3MgYXBwZWFyaW5nIGluXG5cdC8vIERlZmVycmVkI3RoZW4gdG8gY29uZGl0aW9uYWxseSBzdXBwcmVzcyByZWplY3Rpb24uXG5cdH0gY2F0Y2ggKCB2YWx1ZSApIHtcblxuXHRcdC8vIFN1cHBvcnQ6IEFuZHJvaWQgNC4wIG9ubHlcblx0XHQvLyBTdHJpY3QgbW9kZSBmdW5jdGlvbnMgaW52b2tlZCB3aXRob3V0IC5jYWxsLy5hcHBseSBnZXQgZ2xvYmFsLW9iamVjdCBjb250ZXh0XG5cdFx0cmVqZWN0LmFwcGx5KCB1bmRlZmluZWQsIFsgdmFsdWUgXSApO1xuXHR9XG59XG5cbmpRdWVyeS5leHRlbmQoIHtcblxuXHREZWZlcnJlZDogZnVuY3Rpb24oIGZ1bmMgKSB7XG5cdFx0dmFyIHR1cGxlcyA9IFtcblxuXHRcdFx0XHQvLyBhY3Rpb24sIGFkZCBsaXN0ZW5lciwgY2FsbGJhY2tzLFxuXHRcdFx0XHQvLyAuLi4gLnRoZW4gaGFuZGxlcnMsIGFyZ3VtZW50IGluZGV4LCBbZmluYWwgc3RhdGVdXG5cdFx0XHRcdFsgXCJub3RpZnlcIiwgXCJwcm9ncmVzc1wiLCBqUXVlcnkuQ2FsbGJhY2tzKCBcIm1lbW9yeVwiICksXG5cdFx0XHRcdFx0alF1ZXJ5LkNhbGxiYWNrcyggXCJtZW1vcnlcIiApLCAyIF0sXG5cdFx0XHRcdFsgXCJyZXNvbHZlXCIsIFwiZG9uZVwiLCBqUXVlcnkuQ2FsbGJhY2tzKCBcIm9uY2UgbWVtb3J5XCIgKSxcblx0XHRcdFx0XHRqUXVlcnkuQ2FsbGJhY2tzKCBcIm9uY2UgbWVtb3J5XCIgKSwgMCwgXCJyZXNvbHZlZFwiIF0sXG5cdFx0XHRcdFsgXCJyZWplY3RcIiwgXCJmYWlsXCIsIGpRdWVyeS5DYWxsYmFja3MoIFwib25jZSBtZW1vcnlcIiApLFxuXHRcdFx0XHRcdGpRdWVyeS5DYWxsYmFja3MoIFwib25jZSBtZW1vcnlcIiApLCAxLCBcInJlamVjdGVkXCIgXVxuXHRcdFx0XSxcblx0XHRcdHN0YXRlID0gXCJwZW5kaW5nXCIsXG5cdFx0XHRwcm9taXNlID0ge1xuXHRcdFx0XHRzdGF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHN0YXRlO1xuXHRcdFx0XHR9LFxuXHRcdFx0XHRhbHdheXM6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdGRlZmVycmVkLmRvbmUoIGFyZ3VtZW50cyApLmZhaWwoIGFyZ3VtZW50cyApO1xuXHRcdFx0XHRcdHJldHVybiB0aGlzO1xuXHRcdFx0XHR9LFxuXHRcdFx0XHRcImNhdGNoXCI6IGZ1bmN0aW9uKCBmbiApIHtcblx0XHRcdFx0XHRyZXR1cm4gcHJvbWlzZS50aGVuKCBudWxsLCBmbiApO1xuXHRcdFx0XHR9LFxuXG5cdFx0XHRcdC8vIEtlZXAgcGlwZSBmb3IgYmFjay1jb21wYXRcblx0XHRcdFx0cGlwZTogZnVuY3Rpb24oIC8qIGZuRG9uZSwgZm5GYWlsLCBmblByb2dyZXNzICovICkge1xuXHRcdFx0XHRcdHZhciBmbnMgPSBhcmd1bWVudHM7XG5cblx0XHRcdFx0XHRyZXR1cm4galF1ZXJ5LkRlZmVycmVkKCBmdW5jdGlvbiggbmV3RGVmZXIgKSB7XG5cdFx0XHRcdFx0XHRqUXVlcnkuZWFjaCggdHVwbGVzLCBmdW5jdGlvbiggX2ksIHR1cGxlICkge1xuXG5cdFx0XHRcdFx0XHRcdC8vIE1hcCB0dXBsZXMgKHByb2dyZXNzLCBkb25lLCBmYWlsKSB0byBhcmd1bWVudHMgKGRvbmUsIGZhaWwsIHByb2dyZXNzKVxuXHRcdFx0XHRcdFx0XHR2YXIgZm4gPSBpc0Z1bmN0aW9uKCBmbnNbIHR1cGxlWyA0IF0gXSApICYmIGZuc1sgdHVwbGVbIDQgXSBdO1xuXG5cdFx0XHRcdFx0XHRcdC8vIGRlZmVycmVkLnByb2dyZXNzKGZ1bmN0aW9uKCkgeyBiaW5kIHRvIG5ld0RlZmVyIG9yIG5ld0RlZmVyLm5vdGlmeSB9KVxuXHRcdFx0XHRcdFx0XHQvLyBkZWZlcnJlZC5kb25lKGZ1bmN0aW9uKCkgeyBiaW5kIHRvIG5ld0RlZmVyIG9yIG5ld0RlZmVyLnJlc29sdmUgfSlcblx0XHRcdFx0XHRcdFx0Ly8gZGVmZXJyZWQuZmFpbChmdW5jdGlvbigpIHsgYmluZCB0byBuZXdEZWZlciBvciBuZXdEZWZlci5yZWplY3QgfSlcblx0XHRcdFx0XHRcdFx0ZGVmZXJyZWRbIHR1cGxlWyAxIF0gXSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRcdFx0dmFyIHJldHVybmVkID0gZm4gJiYgZm4uYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0XHRcdFx0XHRcdGlmICggcmV0dXJuZWQgJiYgaXNGdW5jdGlvbiggcmV0dXJuZWQucHJvbWlzZSApICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0cmV0dXJuZWQucHJvbWlzZSgpXG5cdFx0XHRcdFx0XHRcdFx0XHRcdC5wcm9ncmVzcyggbmV3RGVmZXIubm90aWZ5IClcblx0XHRcdFx0XHRcdFx0XHRcdFx0LmRvbmUoIG5ld0RlZmVyLnJlc29sdmUgKVxuXHRcdFx0XHRcdFx0XHRcdFx0XHQuZmFpbCggbmV3RGVmZXIucmVqZWN0ICk7XG5cdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHRcdG5ld0RlZmVyWyB0dXBsZVsgMCBdICsgXCJXaXRoXCIgXShcblx0XHRcdFx0XHRcdFx0XHRcdFx0dGhpcyxcblx0XHRcdFx0XHRcdFx0XHRcdFx0Zm4gPyBbIHJldHVybmVkIF0gOiBhcmd1bWVudHNcblx0XHRcdFx0XHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdFx0XHRmbnMgPSBudWxsO1xuXHRcdFx0XHRcdH0gKS5wcm9taXNlKCk7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdHRoZW46IGZ1bmN0aW9uKCBvbkZ1bGZpbGxlZCwgb25SZWplY3RlZCwgb25Qcm9ncmVzcyApIHtcblx0XHRcdFx0XHR2YXIgbWF4RGVwdGggPSAwO1xuXHRcdFx0XHRcdGZ1bmN0aW9uIHJlc29sdmUoIGRlcHRoLCBkZWZlcnJlZCwgaGFuZGxlciwgc3BlY2lhbCApIHtcblx0XHRcdFx0XHRcdHJldHVybiBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0XHRcdFx0XHRcdGFyZ3MgPSBhcmd1bWVudHMsXG5cdFx0XHRcdFx0XHRcdFx0bWlnaHRUaHJvdyA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0dmFyIHJldHVybmVkLCB0aGVuO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBTdXBwb3J0OiBQcm9taXNlcy9BKyBzZWN0aW9uIDIuMy4zLjMuM1xuXHRcdFx0XHRcdFx0XHRcdFx0Ly8gaHR0cHM6Ly9wcm9taXNlc2FwbHVzLmNvbS8jcG9pbnQtNTlcblx0XHRcdFx0XHRcdFx0XHRcdC8vIElnbm9yZSBkb3VibGUtcmVzb2x1dGlvbiBhdHRlbXB0c1xuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBkZXB0aCA8IG1heERlcHRoICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0XHRcdHJldHVybmVkID0gaGFuZGxlci5hcHBseSggdGhhdCwgYXJncyApO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBTdXBwb3J0OiBQcm9taXNlcy9BKyBzZWN0aW9uIDIuMy4xXG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBodHRwczovL3Byb21pc2VzYXBsdXMuY29tLyNwb2ludC00OFxuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKCByZXR1cm5lZCA9PT0gZGVmZXJyZWQucHJvbWlzZSgpICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR0aHJvdyBuZXcgVHlwZUVycm9yKCBcIlRoZW5hYmxlIHNlbGYtcmVzb2x1dGlvblwiICk7XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IFByb21pc2VzL0ErIHNlY3Rpb25zIDIuMy4zLjEsIDMuNVxuXHRcdFx0XHRcdFx0XHRcdFx0Ly8gaHR0cHM6Ly9wcm9taXNlc2FwbHVzLmNvbS8jcG9pbnQtNTRcblx0XHRcdFx0XHRcdFx0XHRcdC8vIGh0dHBzOi8vcHJvbWlzZXNhcGx1cy5jb20vI3BvaW50LTc1XG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBSZXRyaWV2ZSBgdGhlbmAgb25seSBvbmNlXG5cdFx0XHRcdFx0XHRcdFx0XHR0aGVuID0gcmV0dXJuZWQgJiZcblxuXHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBTdXBwb3J0OiBQcm9taXNlcy9BKyBzZWN0aW9uIDIuMy40XG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIGh0dHBzOi8vcHJvbWlzZXNhcGx1cy5jb20vI3BvaW50LTY0XG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIE9ubHkgY2hlY2sgb2JqZWN0cyBhbmQgZnVuY3Rpb25zIGZvciB0aGVuYWJpbGl0eVxuXHRcdFx0XHRcdFx0XHRcdFx0XHQoIHR5cGVvZiByZXR1cm5lZCA9PT0gXCJvYmplY3RcIiB8fFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHR5cGVvZiByZXR1cm5lZCA9PT0gXCJmdW5jdGlvblwiICkgJiZcblx0XHRcdFx0XHRcdFx0XHRcdFx0cmV0dXJuZWQudGhlbjtcblxuXHRcdFx0XHRcdFx0XHRcdFx0Ly8gSGFuZGxlIGEgcmV0dXJuZWQgdGhlbmFibGVcblx0XHRcdFx0XHRcdFx0XHRcdGlmICggaXNGdW5jdGlvbiggdGhlbiApICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIFNwZWNpYWwgcHJvY2Vzc29ycyAobm90aWZ5KSBqdXN0IHdhaXQgZm9yIHJlc29sdXRpb25cblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBzcGVjaWFsICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHRoZW4uY2FsbChcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdHJldHVybmVkLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0cmVzb2x2ZSggbWF4RGVwdGgsIGRlZmVycmVkLCBJZGVudGl0eSwgc3BlY2lhbCApLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0cmVzb2x2ZSggbWF4RGVwdGgsIGRlZmVycmVkLCBUaHJvd2VyLCBzcGVjaWFsIClcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIE5vcm1hbCBwcm9jZXNzb3JzIChyZXNvbHZlKSBhbHNvIGhvb2sgaW50byBwcm9ncmVzc1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gLi4uYW5kIGRpc3JlZ2FyZCBvbGRlciByZXNvbHV0aW9uIHZhbHVlc1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdG1heERlcHRoKys7XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHR0aGVuLmNhbGwoXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRyZXR1cm5lZCxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdHJlc29sdmUoIG1heERlcHRoLCBkZWZlcnJlZCwgSWRlbnRpdHksIHNwZWNpYWwgKSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdHJlc29sdmUoIG1heERlcHRoLCBkZWZlcnJlZCwgVGhyb3dlciwgc3BlY2lhbCApLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0cmVzb2x2ZSggbWF4RGVwdGgsIGRlZmVycmVkLCBJZGVudGl0eSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ZGVmZXJyZWQubm90aWZ5V2l0aCApXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBIYW5kbGUgYWxsIG90aGVyIHJldHVybmVkIHZhbHVlc1xuXHRcdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBPbmx5IHN1YnN0aXR1dGUgaGFuZGxlcnMgcGFzcyBvbiBjb250ZXh0XG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIGFuZCBtdWx0aXBsZSB2YWx1ZXMgKG5vbi1zcGVjIGJlaGF2aW9yKVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRpZiAoIGhhbmRsZXIgIT09IElkZW50aXR5ICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHRoYXQgPSB1bmRlZmluZWQ7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0YXJncyA9IFsgcmV0dXJuZWQgXTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIFByb2Nlc3MgdGhlIHZhbHVlKHMpXG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIERlZmF1bHQgcHJvY2VzcyBpcyByZXNvbHZlXG5cdFx0XHRcdFx0XHRcdFx0XHRcdCggc3BlY2lhbCB8fCBkZWZlcnJlZC5yZXNvbHZlV2l0aCApKCB0aGF0LCBhcmdzICk7XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0fSxcblxuXHRcdFx0XHRcdFx0XHRcdC8vIE9ubHkgbm9ybWFsIHByb2Nlc3NvcnMgKHJlc29sdmUpIGNhdGNoIGFuZCByZWplY3QgZXhjZXB0aW9uc1xuXHRcdFx0XHRcdFx0XHRcdHByb2Nlc3MgPSBzcGVjaWFsID9cblx0XHRcdFx0XHRcdFx0XHRcdG1pZ2h0VGhyb3cgOlxuXHRcdFx0XHRcdFx0XHRcdFx0ZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0bWlnaHRUaHJvdygpO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR9IGNhdGNoICggZSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdGlmICggalF1ZXJ5LkRlZmVycmVkLmV4Y2VwdGlvbkhvb2sgKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRqUXVlcnkuRGVmZXJyZWQuZXhjZXB0aW9uSG9vayggZSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0cHJvY2Vzcy5zdGFja1RyYWNlICk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gU3VwcG9ydDogUHJvbWlzZXMvQSsgc2VjdGlvbiAyLjMuMy4zLjQuMVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIGh0dHBzOi8vcHJvbWlzZXNhcGx1cy5jb20vI3BvaW50LTYxXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gSWdub3JlIHBvc3QtcmVzb2x1dGlvbiBleGNlcHRpb25zXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBkZXB0aCArIDEgPj0gbWF4RGVwdGggKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIE9ubHkgc3Vic3RpdHV0ZSBoYW5kbGVycyBwYXNzIG9uIGNvbnRleHRcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIGFuZCBtdWx0aXBsZSB2YWx1ZXMgKG5vbi1zcGVjIGJlaGF2aW9yKVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBoYW5kbGVyICE9PSBUaHJvd2VyICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR0aGF0ID0gdW5kZWZpbmVkO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRhcmdzID0gWyBlIF07XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdGRlZmVycmVkLnJlamVjdFdpdGgoIHRoYXQsIGFyZ3MgKTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdH07XG5cblx0XHRcdFx0XHRcdFx0Ly8gU3VwcG9ydDogUHJvbWlzZXMvQSsgc2VjdGlvbiAyLjMuMy4zLjFcblx0XHRcdFx0XHRcdFx0Ly8gaHR0cHM6Ly9wcm9taXNlc2FwbHVzLmNvbS8jcG9pbnQtNTdcblx0XHRcdFx0XHRcdFx0Ly8gUmUtcmVzb2x2ZSBwcm9taXNlcyBpbW1lZGlhdGVseSB0byBkb2RnZSBmYWxzZSByZWplY3Rpb24gZnJvbVxuXHRcdFx0XHRcdFx0XHQvLyBzdWJzZXF1ZW50IGVycm9yc1xuXHRcdFx0XHRcdFx0XHRpZiAoIGRlcHRoICkge1xuXHRcdFx0XHRcdFx0XHRcdHByb2Nlc3MoKTtcblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIENhbGwgYW4gb3B0aW9uYWwgaG9vayB0byByZWNvcmQgdGhlIHN0YWNrLCBpbiBjYXNlIG9mIGV4Y2VwdGlvblxuXHRcdFx0XHRcdFx0XHRcdC8vIHNpbmNlIGl0J3Mgb3RoZXJ3aXNlIGxvc3Qgd2hlbiBleGVjdXRpb24gZ29lcyBhc3luY1xuXHRcdFx0XHRcdFx0XHRcdGlmICggalF1ZXJ5LkRlZmVycmVkLmdldFN0YWNrSG9vayApIHtcblx0XHRcdFx0XHRcdFx0XHRcdHByb2Nlc3Muc3RhY2tUcmFjZSA9IGpRdWVyeS5EZWZlcnJlZC5nZXRTdGFja0hvb2soKTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0d2luZG93LnNldFRpbWVvdXQoIHByb2Nlc3MgKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRyZXR1cm4galF1ZXJ5LkRlZmVycmVkKCBmdW5jdGlvbiggbmV3RGVmZXIgKSB7XG5cblx0XHRcdFx0XHRcdC8vIHByb2dyZXNzX2hhbmRsZXJzLmFkZCggLi4uIClcblx0XHRcdFx0XHRcdHR1cGxlc1sgMCBdWyAzIF0uYWRkKFxuXHRcdFx0XHRcdFx0XHRyZXNvbHZlKFxuXHRcdFx0XHRcdFx0XHRcdDAsXG5cdFx0XHRcdFx0XHRcdFx0bmV3RGVmZXIsXG5cdFx0XHRcdFx0XHRcdFx0aXNGdW5jdGlvbiggb25Qcm9ncmVzcyApID9cblx0XHRcdFx0XHRcdFx0XHRcdG9uUHJvZ3Jlc3MgOlxuXHRcdFx0XHRcdFx0XHRcdFx0SWRlbnRpdHksXG5cdFx0XHRcdFx0XHRcdFx0bmV3RGVmZXIubm90aWZ5V2l0aFxuXHRcdFx0XHRcdFx0XHQpXG5cdFx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0XHQvLyBmdWxmaWxsZWRfaGFuZGxlcnMuYWRkKCAuLi4gKVxuXHRcdFx0XHRcdFx0dHVwbGVzWyAxIF1bIDMgXS5hZGQoXG5cdFx0XHRcdFx0XHRcdHJlc29sdmUoXG5cdFx0XHRcdFx0XHRcdFx0MCxcblx0XHRcdFx0XHRcdFx0XHRuZXdEZWZlcixcblx0XHRcdFx0XHRcdFx0XHRpc0Z1bmN0aW9uKCBvbkZ1bGZpbGxlZCApID9cblx0XHRcdFx0XHRcdFx0XHRcdG9uRnVsZmlsbGVkIDpcblx0XHRcdFx0XHRcdFx0XHRcdElkZW50aXR5XG5cdFx0XHRcdFx0XHRcdClcblx0XHRcdFx0XHRcdCk7XG5cblx0XHRcdFx0XHRcdC8vIHJlamVjdGVkX2hhbmRsZXJzLmFkZCggLi4uIClcblx0XHRcdFx0XHRcdHR1cGxlc1sgMiBdWyAzIF0uYWRkKFxuXHRcdFx0XHRcdFx0XHRyZXNvbHZlKFxuXHRcdFx0XHRcdFx0XHRcdDAsXG5cdFx0XHRcdFx0XHRcdFx0bmV3RGVmZXIsXG5cdFx0XHRcdFx0XHRcdFx0aXNGdW5jdGlvbiggb25SZWplY3RlZCApID9cblx0XHRcdFx0XHRcdFx0XHRcdG9uUmVqZWN0ZWQgOlxuXHRcdFx0XHRcdFx0XHRcdFx0VGhyb3dlclxuXHRcdFx0XHRcdFx0XHQpXG5cdFx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdH0gKS5wcm9taXNlKCk7XG5cdFx0XHRcdH0sXG5cblx0XHRcdFx0Ly8gR2V0IGEgcHJvbWlzZSBmb3IgdGhpcyBkZWZlcnJlZFxuXHRcdFx0XHQvLyBJZiBvYmogaXMgcHJvdmlkZWQsIHRoZSBwcm9taXNlIGFzcGVjdCBpcyBhZGRlZCB0byB0aGUgb2JqZWN0XG5cdFx0XHRcdHByb21pc2U6IGZ1bmN0aW9uKCBvYmogKSB7XG5cdFx0XHRcdFx0cmV0dXJuIG9iaiAhPSBudWxsID8galF1ZXJ5LmV4dGVuZCggb2JqLCBwcm9taXNlICkgOiBwcm9taXNlO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0ZGVmZXJyZWQgPSB7fTtcblxuXHRcdC8vIEFkZCBsaXN0LXNwZWNpZmljIG1ldGhvZHNcblx0XHRqUXVlcnkuZWFjaCggdHVwbGVzLCBmdW5jdGlvbiggaSwgdHVwbGUgKSB7XG5cdFx0XHR2YXIgbGlzdCA9IHR1cGxlWyAyIF0sXG5cdFx0XHRcdHN0YXRlU3RyaW5nID0gdHVwbGVbIDUgXTtcblxuXHRcdFx0Ly8gcHJvbWlzZS5wcm9ncmVzcyA9IGxpc3QuYWRkXG5cdFx0XHQvLyBwcm9taXNlLmRvbmUgPSBsaXN0LmFkZFxuXHRcdFx0Ly8gcHJvbWlzZS5mYWlsID0gbGlzdC5hZGRcblx0XHRcdHByb21pc2VbIHR1cGxlWyAxIF0gXSA9IGxpc3QuYWRkO1xuXG5cdFx0XHQvLyBIYW5kbGUgc3RhdGVcblx0XHRcdGlmICggc3RhdGVTdHJpbmcgKSB7XG5cdFx0XHRcdGxpc3QuYWRkKFxuXHRcdFx0XHRcdGZ1bmN0aW9uKCkge1xuXG5cdFx0XHRcdFx0XHQvLyBzdGF0ZSA9IFwicmVzb2x2ZWRcIiAoaS5lLiwgZnVsZmlsbGVkKVxuXHRcdFx0XHRcdFx0Ly8gc3RhdGUgPSBcInJlamVjdGVkXCJcblx0XHRcdFx0XHRcdHN0YXRlID0gc3RhdGVTdHJpbmc7XG5cdFx0XHRcdFx0fSxcblxuXHRcdFx0XHRcdC8vIHJlamVjdGVkX2NhbGxiYWNrcy5kaXNhYmxlXG5cdFx0XHRcdFx0Ly8gZnVsZmlsbGVkX2NhbGxiYWNrcy5kaXNhYmxlXG5cdFx0XHRcdFx0dHVwbGVzWyAzIC0gaSBdWyAyIF0uZGlzYWJsZSxcblxuXHRcdFx0XHRcdC8vIHJlamVjdGVkX2hhbmRsZXJzLmRpc2FibGVcblx0XHRcdFx0XHQvLyBmdWxmaWxsZWRfaGFuZGxlcnMuZGlzYWJsZVxuXHRcdFx0XHRcdHR1cGxlc1sgMyAtIGkgXVsgMyBdLmRpc2FibGUsXG5cblx0XHRcdFx0XHQvLyBwcm9ncmVzc19jYWxsYmFja3MubG9ja1xuXHRcdFx0XHRcdHR1cGxlc1sgMCBdWyAyIF0ubG9jayxcblxuXHRcdFx0XHRcdC8vIHByb2dyZXNzX2hhbmRsZXJzLmxvY2tcblx0XHRcdFx0XHR0dXBsZXNbIDAgXVsgMyBdLmxvY2tcblx0XHRcdFx0KTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gcHJvZ3Jlc3NfaGFuZGxlcnMuZmlyZVxuXHRcdFx0Ly8gZnVsZmlsbGVkX2hhbmRsZXJzLmZpcmVcblx0XHRcdC8vIHJlamVjdGVkX2hhbmRsZXJzLmZpcmVcblx0XHRcdGxpc3QuYWRkKCB0dXBsZVsgMyBdLmZpcmUgKTtcblxuXHRcdFx0Ly8gZGVmZXJyZWQubm90aWZ5ID0gZnVuY3Rpb24oKSB7IGRlZmVycmVkLm5vdGlmeVdpdGgoLi4uKSB9XG5cdFx0XHQvLyBkZWZlcnJlZC5yZXNvbHZlID0gZnVuY3Rpb24oKSB7IGRlZmVycmVkLnJlc29sdmVXaXRoKC4uLikgfVxuXHRcdFx0Ly8gZGVmZXJyZWQucmVqZWN0ID0gZnVuY3Rpb24oKSB7IGRlZmVycmVkLnJlamVjdFdpdGgoLi4uKSB9XG5cdFx0XHRkZWZlcnJlZFsgdHVwbGVbIDAgXSBdID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGRlZmVycmVkWyB0dXBsZVsgMCBdICsgXCJXaXRoXCIgXSggdGhpcyA9PT0gZGVmZXJyZWQgPyB1bmRlZmluZWQgOiB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9O1xuXG5cdFx0XHQvLyBkZWZlcnJlZC5ub3RpZnlXaXRoID0gbGlzdC5maXJlV2l0aFxuXHRcdFx0Ly8gZGVmZXJyZWQucmVzb2x2ZVdpdGggPSBsaXN0LmZpcmVXaXRoXG5cdFx0XHQvLyBkZWZlcnJlZC5yZWplY3RXaXRoID0gbGlzdC5maXJlV2l0aFxuXHRcdFx0ZGVmZXJyZWRbIHR1cGxlWyAwIF0gKyBcIldpdGhcIiBdID0gbGlzdC5maXJlV2l0aDtcblx0XHR9ICk7XG5cblx0XHQvLyBNYWtlIHRoZSBkZWZlcnJlZCBhIHByb21pc2Vcblx0XHRwcm9taXNlLnByb21pc2UoIGRlZmVycmVkICk7XG5cblx0XHQvLyBDYWxsIGdpdmVuIGZ1bmMgaWYgYW55XG5cdFx0aWYgKCBmdW5jICkge1xuXHRcdFx0ZnVuYy5jYWxsKCBkZWZlcnJlZCwgZGVmZXJyZWQgKTtcblx0XHR9XG5cblx0XHQvLyBBbGwgZG9uZSFcblx0XHRyZXR1cm4gZGVmZXJyZWQ7XG5cdH0sXG5cblx0Ly8gRGVmZXJyZWQgaGVscGVyXG5cdHdoZW46IGZ1bmN0aW9uKCBzaW5nbGVWYWx1ZSApIHtcblx0XHR2YXJcblxuXHRcdFx0Ly8gY291bnQgb2YgdW5jb21wbGV0ZWQgc3Vib3JkaW5hdGVzXG5cdFx0XHRyZW1haW5pbmcgPSBhcmd1bWVudHMubGVuZ3RoLFxuXG5cdFx0XHQvLyBjb3VudCBvZiB1bnByb2Nlc3NlZCBhcmd1bWVudHNcblx0XHRcdGkgPSByZW1haW5pbmcsXG5cblx0XHRcdC8vIHN1Ym9yZGluYXRlIGZ1bGZpbGxtZW50IGRhdGFcblx0XHRcdHJlc29sdmVDb250ZXh0cyA9IEFycmF5KCBpICksXG5cdFx0XHRyZXNvbHZlVmFsdWVzID0gc2xpY2UuY2FsbCggYXJndW1lbnRzICksXG5cblx0XHRcdC8vIHRoZSBwcmltYXJ5IERlZmVycmVkXG5cdFx0XHRwcmltYXJ5ID0galF1ZXJ5LkRlZmVycmVkKCksXG5cblx0XHRcdC8vIHN1Ym9yZGluYXRlIGNhbGxiYWNrIGZhY3Rvcnlcblx0XHRcdHVwZGF0ZUZ1bmMgPSBmdW5jdGlvbiggaSApIHtcblx0XHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRcdFx0XHRyZXNvbHZlQ29udGV4dHNbIGkgXSA9IHRoaXM7XG5cdFx0XHRcdFx0cmVzb2x2ZVZhbHVlc1sgaSBdID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgPyBzbGljZS5jYWxsKCBhcmd1bWVudHMgKSA6IHZhbHVlO1xuXHRcdFx0XHRcdGlmICggISggLS1yZW1haW5pbmcgKSApIHtcblx0XHRcdFx0XHRcdHByaW1hcnkucmVzb2x2ZVdpdGgoIHJlc29sdmVDb250ZXh0cywgcmVzb2x2ZVZhbHVlcyApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fTtcblx0XHRcdH07XG5cblx0XHQvLyBTaW5nbGUtIGFuZCBlbXB0eSBhcmd1bWVudHMgYXJlIGFkb3B0ZWQgbGlrZSBQcm9taXNlLnJlc29sdmVcblx0XHRpZiAoIHJlbWFpbmluZyA8PSAxICkge1xuXHRcdFx0YWRvcHRWYWx1ZSggc2luZ2xlVmFsdWUsIHByaW1hcnkuZG9uZSggdXBkYXRlRnVuYyggaSApICkucmVzb2x2ZSwgcHJpbWFyeS5yZWplY3QsXG5cdFx0XHRcdCFyZW1haW5pbmcgKTtcblxuXHRcdFx0Ly8gVXNlIC50aGVuKCkgdG8gdW53cmFwIHNlY29uZGFyeSB0aGVuYWJsZXMgKGNmLiBnaC0zMDAwKVxuXHRcdFx0aWYgKCBwcmltYXJ5LnN0YXRlKCkgPT09IFwicGVuZGluZ1wiIHx8XG5cdFx0XHRcdGlzRnVuY3Rpb24oIHJlc29sdmVWYWx1ZXNbIGkgXSAmJiByZXNvbHZlVmFsdWVzWyBpIF0udGhlbiApICkge1xuXG5cdFx0XHRcdHJldHVybiBwcmltYXJ5LnRoZW4oKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBNdWx0aXBsZSBhcmd1bWVudHMgYXJlIGFnZ3JlZ2F0ZWQgbGlrZSBQcm9taXNlLmFsbCBhcnJheSBlbGVtZW50c1xuXHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0YWRvcHRWYWx1ZSggcmVzb2x2ZVZhbHVlc1sgaSBdLCB1cGRhdGVGdW5jKCBpICksIHByaW1hcnkucmVqZWN0ICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHByaW1hcnkucHJvbWlzZSgpO1xuXHR9XG59ICk7XG5cblxuLy8gVGhlc2UgdXN1YWxseSBpbmRpY2F0ZSBhIHByb2dyYW1tZXIgbWlzdGFrZSBkdXJpbmcgZGV2ZWxvcG1lbnQsXG4vLyB3YXJuIGFib3V0IHRoZW0gQVNBUCByYXRoZXIgdGhhbiBzd2FsbG93aW5nIHRoZW0gYnkgZGVmYXVsdC5cbnZhciByZXJyb3JOYW1lcyA9IC9eKEV2YWx8SW50ZXJuYWx8UmFuZ2V8UmVmZXJlbmNlfFN5bnRheHxUeXBlfFVSSSlFcnJvciQvO1xuXG5qUXVlcnkuRGVmZXJyZWQuZXhjZXB0aW9uSG9vayA9IGZ1bmN0aW9uKCBlcnJvciwgc3RhY2sgKSB7XG5cblx0Ly8gU3VwcG9ydDogSUUgOCAtIDkgb25seVxuXHQvLyBDb25zb2xlIGV4aXN0cyB3aGVuIGRldiB0b29scyBhcmUgb3Blbiwgd2hpY2ggY2FuIGhhcHBlbiBhdCBhbnkgdGltZVxuXHRpZiAoIHdpbmRvdy5jb25zb2xlICYmIHdpbmRvdy5jb25zb2xlLndhcm4gJiYgZXJyb3IgJiYgcmVycm9yTmFtZXMudGVzdCggZXJyb3IubmFtZSApICkge1xuXHRcdHdpbmRvdy5jb25zb2xlLndhcm4oIFwialF1ZXJ5LkRlZmVycmVkIGV4Y2VwdGlvbjogXCIgKyBlcnJvci5tZXNzYWdlLCBlcnJvci5zdGFjaywgc3RhY2sgKTtcblx0fVxufTtcblxuXG5cblxualF1ZXJ5LnJlYWR5RXhjZXB0aW9uID0gZnVuY3Rpb24oIGVycm9yICkge1xuXHR3aW5kb3cuc2V0VGltZW91dCggZnVuY3Rpb24oKSB7XG5cdFx0dGhyb3cgZXJyb3I7XG5cdH0gKTtcbn07XG5cblxuXG5cbi8vIFRoZSBkZWZlcnJlZCB1c2VkIG9uIERPTSByZWFkeVxudmFyIHJlYWR5TGlzdCA9IGpRdWVyeS5EZWZlcnJlZCgpO1xuXG5qUXVlcnkuZm4ucmVhZHkgPSBmdW5jdGlvbiggZm4gKSB7XG5cblx0cmVhZHlMaXN0XG5cdFx0LnRoZW4oIGZuIClcblxuXHRcdC8vIFdyYXAgalF1ZXJ5LnJlYWR5RXhjZXB0aW9uIGluIGEgZnVuY3Rpb24gc28gdGhhdCB0aGUgbG9va3VwXG5cdFx0Ly8gaGFwcGVucyBhdCB0aGUgdGltZSBvZiBlcnJvciBoYW5kbGluZyBpbnN0ZWFkIG9mIGNhbGxiYWNrXG5cdFx0Ly8gcmVnaXN0cmF0aW9uLlxuXHRcdC5jYXRjaCggZnVuY3Rpb24oIGVycm9yICkge1xuXHRcdFx0alF1ZXJ5LnJlYWR5RXhjZXB0aW9uKCBlcnJvciApO1xuXHRcdH0gKTtcblxuXHRyZXR1cm4gdGhpcztcbn07XG5cbmpRdWVyeS5leHRlbmQoIHtcblxuXHQvLyBJcyB0aGUgRE9NIHJlYWR5IHRvIGJlIHVzZWQ/IFNldCB0byB0cnVlIG9uY2UgaXQgb2NjdXJzLlxuXHRpc1JlYWR5OiBmYWxzZSxcblxuXHQvLyBBIGNvdW50ZXIgdG8gdHJhY2sgaG93IG1hbnkgaXRlbXMgdG8gd2FpdCBmb3IgYmVmb3JlXG5cdC8vIHRoZSByZWFkeSBldmVudCBmaXJlcy4gU2VlICM2NzgxXG5cdHJlYWR5V2FpdDogMSxcblxuXHQvLyBIYW5kbGUgd2hlbiB0aGUgRE9NIGlzIHJlYWR5XG5cdHJlYWR5OiBmdW5jdGlvbiggd2FpdCApIHtcblxuXHRcdC8vIEFib3J0IGlmIHRoZXJlIGFyZSBwZW5kaW5nIGhvbGRzIG9yIHdlJ3JlIGFscmVhZHkgcmVhZHlcblx0XHRpZiAoIHdhaXQgPT09IHRydWUgPyAtLWpRdWVyeS5yZWFkeVdhaXQgOiBqUXVlcnkuaXNSZWFkeSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBSZW1lbWJlciB0aGF0IHRoZSBET00gaXMgcmVhZHlcblx0XHRqUXVlcnkuaXNSZWFkeSA9IHRydWU7XG5cblx0XHQvLyBJZiBhIG5vcm1hbCBET00gUmVhZHkgZXZlbnQgZmlyZWQsIGRlY3JlbWVudCwgYW5kIHdhaXQgaWYgbmVlZCBiZVxuXHRcdGlmICggd2FpdCAhPT0gdHJ1ZSAmJiAtLWpRdWVyeS5yZWFkeVdhaXQgPiAwICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIElmIHRoZXJlIGFyZSBmdW5jdGlvbnMgYm91bmQsIHRvIGV4ZWN1dGVcblx0XHRyZWFkeUxpc3QucmVzb2x2ZVdpdGgoIGRvY3VtZW50LCBbIGpRdWVyeSBdICk7XG5cdH1cbn0gKTtcblxualF1ZXJ5LnJlYWR5LnRoZW4gPSByZWFkeUxpc3QudGhlbjtcblxuLy8gVGhlIHJlYWR5IGV2ZW50IGhhbmRsZXIgYW5kIHNlbGYgY2xlYW51cCBtZXRob2RcbmZ1bmN0aW9uIGNvbXBsZXRlZCgpIHtcblx0ZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lciggXCJET01Db250ZW50TG9hZGVkXCIsIGNvbXBsZXRlZCApO1xuXHR3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lciggXCJsb2FkXCIsIGNvbXBsZXRlZCApO1xuXHRqUXVlcnkucmVhZHkoKTtcbn1cblxuLy8gQ2F0Y2ggY2FzZXMgd2hlcmUgJChkb2N1bWVudCkucmVhZHkoKSBpcyBjYWxsZWRcbi8vIGFmdGVyIHRoZSBicm93c2VyIGV2ZW50IGhhcyBhbHJlYWR5IG9jY3VycmVkLlxuLy8gU3VwcG9ydDogSUUgPD05IC0gMTAgb25seVxuLy8gT2xkZXIgSUUgc29tZXRpbWVzIHNpZ25hbHMgXCJpbnRlcmFjdGl2ZVwiIHRvbyBzb29uXG5pZiAoIGRvY3VtZW50LnJlYWR5U3RhdGUgPT09IFwiY29tcGxldGVcIiB8fFxuXHQoIGRvY3VtZW50LnJlYWR5U3RhdGUgIT09IFwibG9hZGluZ1wiICYmICFkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuZG9TY3JvbGwgKSApIHtcblxuXHQvLyBIYW5kbGUgaXQgYXN5bmNocm9ub3VzbHkgdG8gYWxsb3cgc2NyaXB0cyB0aGUgb3Bwb3J0dW5pdHkgdG8gZGVsYXkgcmVhZHlcblx0d2luZG93LnNldFRpbWVvdXQoIGpRdWVyeS5yZWFkeSApO1xuXG59IGVsc2Uge1xuXG5cdC8vIFVzZSB0aGUgaGFuZHkgZXZlbnQgY2FsbGJhY2tcblx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggXCJET01Db250ZW50TG9hZGVkXCIsIGNvbXBsZXRlZCApO1xuXG5cdC8vIEEgZmFsbGJhY2sgdG8gd2luZG93Lm9ubG9hZCwgdGhhdCB3aWxsIGFsd2F5cyB3b3JrXG5cdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCBcImxvYWRcIiwgY29tcGxldGVkICk7XG59XG5cblxuXG5cbi8vIE11bHRpZnVuY3Rpb25hbCBtZXRob2QgdG8gZ2V0IGFuZCBzZXQgdmFsdWVzIG9mIGEgY29sbGVjdGlvblxuLy8gVGhlIHZhbHVlL3MgY2FuIG9wdGlvbmFsbHkgYmUgZXhlY3V0ZWQgaWYgaXQncyBhIGZ1bmN0aW9uXG52YXIgYWNjZXNzID0gZnVuY3Rpb24oIGVsZW1zLCBmbiwga2V5LCB2YWx1ZSwgY2hhaW5hYmxlLCBlbXB0eUdldCwgcmF3ICkge1xuXHR2YXIgaSA9IDAsXG5cdFx0bGVuID0gZWxlbXMubGVuZ3RoLFxuXHRcdGJ1bGsgPSBrZXkgPT0gbnVsbDtcblxuXHQvLyBTZXRzIG1hbnkgdmFsdWVzXG5cdGlmICggdG9UeXBlKCBrZXkgKSA9PT0gXCJvYmplY3RcIiApIHtcblx0XHRjaGFpbmFibGUgPSB0cnVlO1xuXHRcdGZvciAoIGkgaW4ga2V5ICkge1xuXHRcdFx0YWNjZXNzKCBlbGVtcywgZm4sIGksIGtleVsgaSBdLCB0cnVlLCBlbXB0eUdldCwgcmF3ICk7XG5cdFx0fVxuXG5cdC8vIFNldHMgb25lIHZhbHVlXG5cdH0gZWxzZSBpZiAoIHZhbHVlICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0Y2hhaW5hYmxlID0gdHJ1ZTtcblxuXHRcdGlmICggIWlzRnVuY3Rpb24oIHZhbHVlICkgKSB7XG5cdFx0XHRyYXcgPSB0cnVlO1xuXHRcdH1cblxuXHRcdGlmICggYnVsayApIHtcblxuXHRcdFx0Ly8gQnVsayBvcGVyYXRpb25zIHJ1biBhZ2FpbnN0IHRoZSBlbnRpcmUgc2V0XG5cdFx0XHRpZiAoIHJhdyApIHtcblx0XHRcdFx0Zm4uY2FsbCggZWxlbXMsIHZhbHVlICk7XG5cdFx0XHRcdGZuID0gbnVsbDtcblxuXHRcdFx0Ly8gLi4uZXhjZXB0IHdoZW4gZXhlY3V0aW5nIGZ1bmN0aW9uIHZhbHVlc1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0YnVsayA9IGZuO1xuXHRcdFx0XHRmbiA9IGZ1bmN0aW9uKCBlbGVtLCBfa2V5LCB2YWx1ZSApIHtcblx0XHRcdFx0XHRyZXR1cm4gYnVsay5jYWxsKCBqUXVlcnkoIGVsZW0gKSwgdmFsdWUgKTtcblx0XHRcdFx0fTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoIGZuICkge1xuXHRcdFx0Zm9yICggOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0XHRcdGZuKFxuXHRcdFx0XHRcdGVsZW1zWyBpIF0sIGtleSwgcmF3ID9cblx0XHRcdFx0XHRcdHZhbHVlIDpcblx0XHRcdFx0XHRcdHZhbHVlLmNhbGwoIGVsZW1zWyBpIF0sIGksIGZuKCBlbGVtc1sgaSBdLCBrZXkgKSApXG5cdFx0XHRcdCk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0aWYgKCBjaGFpbmFibGUgKSB7XG5cdFx0cmV0dXJuIGVsZW1zO1xuXHR9XG5cblx0Ly8gR2V0c1xuXHRpZiAoIGJ1bGsgKSB7XG5cdFx0cmV0dXJuIGZuLmNhbGwoIGVsZW1zICk7XG5cdH1cblxuXHRyZXR1cm4gbGVuID8gZm4oIGVsZW1zWyAwIF0sIGtleSApIDogZW1wdHlHZXQ7XG59O1xuXG5cbi8vIE1hdGNoZXMgZGFzaGVkIHN0cmluZyBmb3IgY2FtZWxpemluZ1xudmFyIHJtc1ByZWZpeCA9IC9eLW1zLS8sXG5cdHJkYXNoQWxwaGEgPSAvLShbYS16XSkvZztcblxuLy8gVXNlZCBieSBjYW1lbENhc2UgYXMgY2FsbGJhY2sgdG8gcmVwbGFjZSgpXG5mdW5jdGlvbiBmY2FtZWxDYXNlKCBfYWxsLCBsZXR0ZXIgKSB7XG5cdHJldHVybiBsZXR0ZXIudG9VcHBlckNhc2UoKTtcbn1cblxuLy8gQ29udmVydCBkYXNoZWQgdG8gY2FtZWxDYXNlOyB1c2VkIGJ5IHRoZSBjc3MgYW5kIGRhdGEgbW9kdWxlc1xuLy8gU3VwcG9ydDogSUUgPD05IC0gMTEsIEVkZ2UgMTIgLSAxNVxuLy8gTWljcm9zb2Z0IGZvcmdvdCB0byBodW1wIHRoZWlyIHZlbmRvciBwcmVmaXggKCM5NTcyKVxuZnVuY3Rpb24gY2FtZWxDYXNlKCBzdHJpbmcgKSB7XG5cdHJldHVybiBzdHJpbmcucmVwbGFjZSggcm1zUHJlZml4LCBcIm1zLVwiICkucmVwbGFjZSggcmRhc2hBbHBoYSwgZmNhbWVsQ2FzZSApO1xufVxudmFyIGFjY2VwdERhdGEgPSBmdW5jdGlvbiggb3duZXIgKSB7XG5cblx0Ly8gQWNjZXB0cyBvbmx5OlxuXHQvLyAgLSBOb2RlXG5cdC8vICAgIC0gTm9kZS5FTEVNRU5UX05PREVcblx0Ly8gICAgLSBOb2RlLkRPQ1VNRU5UX05PREVcblx0Ly8gIC0gT2JqZWN0XG5cdC8vICAgIC0gQW55XG5cdHJldHVybiBvd25lci5ub2RlVHlwZSA9PT0gMSB8fCBvd25lci5ub2RlVHlwZSA9PT0gOSB8fCAhKCArb3duZXIubm9kZVR5cGUgKTtcbn07XG5cblxuXG5cbmZ1bmN0aW9uIERhdGEoKSB7XG5cdHRoaXMuZXhwYW5kbyA9IGpRdWVyeS5leHBhbmRvICsgRGF0YS51aWQrKztcbn1cblxuRGF0YS51aWQgPSAxO1xuXG5EYXRhLnByb3RvdHlwZSA9IHtcblxuXHRjYWNoZTogZnVuY3Rpb24oIG93bmVyICkge1xuXG5cdFx0Ly8gQ2hlY2sgaWYgdGhlIG93bmVyIG9iamVjdCBhbHJlYWR5IGhhcyBhIGNhY2hlXG5cdFx0dmFyIHZhbHVlID0gb3duZXJbIHRoaXMuZXhwYW5kbyBdO1xuXG5cdFx0Ly8gSWYgbm90LCBjcmVhdGUgb25lXG5cdFx0aWYgKCAhdmFsdWUgKSB7XG5cdFx0XHR2YWx1ZSA9IHt9O1xuXG5cdFx0XHQvLyBXZSBjYW4gYWNjZXB0IGRhdGEgZm9yIG5vbi1lbGVtZW50IG5vZGVzIGluIG1vZGVybiBicm93c2Vycyxcblx0XHRcdC8vIGJ1dCB3ZSBzaG91bGQgbm90LCBzZWUgIzgzMzUuXG5cdFx0XHQvLyBBbHdheXMgcmV0dXJuIGFuIGVtcHR5IG9iamVjdC5cblx0XHRcdGlmICggYWNjZXB0RGF0YSggb3duZXIgKSApIHtcblxuXHRcdFx0XHQvLyBJZiBpdCBpcyBhIG5vZGUgdW5saWtlbHkgdG8gYmUgc3RyaW5naWZ5LWVkIG9yIGxvb3BlZCBvdmVyXG5cdFx0XHRcdC8vIHVzZSBwbGFpbiBhc3NpZ25tZW50XG5cdFx0XHRcdGlmICggb3duZXIubm9kZVR5cGUgKSB7XG5cdFx0XHRcdFx0b3duZXJbIHRoaXMuZXhwYW5kbyBdID0gdmFsdWU7XG5cblx0XHRcdFx0Ly8gT3RoZXJ3aXNlIHNlY3VyZSBpdCBpbiBhIG5vbi1lbnVtZXJhYmxlIHByb3BlcnR5XG5cdFx0XHRcdC8vIGNvbmZpZ3VyYWJsZSBtdXN0IGJlIHRydWUgdG8gYWxsb3cgdGhlIHByb3BlcnR5IHRvIGJlXG5cdFx0XHRcdC8vIGRlbGV0ZWQgd2hlbiBkYXRhIGlzIHJlbW92ZWRcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoIG93bmVyLCB0aGlzLmV4cGFuZG8sIHtcblx0XHRcdFx0XHRcdHZhbHVlOiB2YWx1ZSxcblx0XHRcdFx0XHRcdGNvbmZpZ3VyYWJsZTogdHJ1ZVxuXHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB2YWx1ZTtcblx0fSxcblx0c2V0OiBmdW5jdGlvbiggb3duZXIsIGRhdGEsIHZhbHVlICkge1xuXHRcdHZhciBwcm9wLFxuXHRcdFx0Y2FjaGUgPSB0aGlzLmNhY2hlKCBvd25lciApO1xuXG5cdFx0Ly8gSGFuZGxlOiBbIG93bmVyLCBrZXksIHZhbHVlIF0gYXJnc1xuXHRcdC8vIEFsd2F5cyB1c2UgY2FtZWxDYXNlIGtleSAoZ2gtMjI1Nylcblx0XHRpZiAoIHR5cGVvZiBkYXRhID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0Y2FjaGVbIGNhbWVsQ2FzZSggZGF0YSApIF0gPSB2YWx1ZTtcblxuXHRcdC8vIEhhbmRsZTogWyBvd25lciwgeyBwcm9wZXJ0aWVzIH0gXSBhcmdzXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gQ29weSB0aGUgcHJvcGVydGllcyBvbmUtYnktb25lIHRvIHRoZSBjYWNoZSBvYmplY3Rcblx0XHRcdGZvciAoIHByb3AgaW4gZGF0YSApIHtcblx0XHRcdFx0Y2FjaGVbIGNhbWVsQ2FzZSggcHJvcCApIF0gPSBkYXRhWyBwcm9wIF07XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiBjYWNoZTtcblx0fSxcblx0Z2V0OiBmdW5jdGlvbiggb3duZXIsIGtleSApIHtcblx0XHRyZXR1cm4ga2V5ID09PSB1bmRlZmluZWQgP1xuXHRcdFx0dGhpcy5jYWNoZSggb3duZXIgKSA6XG5cblx0XHRcdC8vIEFsd2F5cyB1c2UgY2FtZWxDYXNlIGtleSAoZ2gtMjI1Nylcblx0XHRcdG93bmVyWyB0aGlzLmV4cGFuZG8gXSAmJiBvd25lclsgdGhpcy5leHBhbmRvIF1bIGNhbWVsQ2FzZSgga2V5ICkgXTtcblx0fSxcblx0YWNjZXNzOiBmdW5jdGlvbiggb3duZXIsIGtleSwgdmFsdWUgKSB7XG5cblx0XHQvLyBJbiBjYXNlcyB3aGVyZSBlaXRoZXI6XG5cdFx0Ly9cblx0XHQvLyAgIDEuIE5vIGtleSB3YXMgc3BlY2lmaWVkXG5cdFx0Ly8gICAyLiBBIHN0cmluZyBrZXkgd2FzIHNwZWNpZmllZCwgYnV0IG5vIHZhbHVlIHByb3ZpZGVkXG5cdFx0Ly9cblx0XHQvLyBUYWtlIHRoZSBcInJlYWRcIiBwYXRoIGFuZCBhbGxvdyB0aGUgZ2V0IG1ldGhvZCB0byBkZXRlcm1pbmVcblx0XHQvLyB3aGljaCB2YWx1ZSB0byByZXR1cm4sIHJlc3BlY3RpdmVseSBlaXRoZXI6XG5cdFx0Ly9cblx0XHQvLyAgIDEuIFRoZSBlbnRpcmUgY2FjaGUgb2JqZWN0XG5cdFx0Ly8gICAyLiBUaGUgZGF0YSBzdG9yZWQgYXQgdGhlIGtleVxuXHRcdC8vXG5cdFx0aWYgKCBrZXkgPT09IHVuZGVmaW5lZCB8fFxuXHRcdFx0XHQoICgga2V5ICYmIHR5cGVvZiBrZXkgPT09IFwic3RyaW5nXCIgKSAmJiB2YWx1ZSA9PT0gdW5kZWZpbmVkICkgKSB7XG5cblx0XHRcdHJldHVybiB0aGlzLmdldCggb3duZXIsIGtleSApO1xuXHRcdH1cblxuXHRcdC8vIFdoZW4gdGhlIGtleSBpcyBub3QgYSBzdHJpbmcsIG9yIGJvdGggYSBrZXkgYW5kIHZhbHVlXG5cdFx0Ly8gYXJlIHNwZWNpZmllZCwgc2V0IG9yIGV4dGVuZCAoZXhpc3Rpbmcgb2JqZWN0cykgd2l0aCBlaXRoZXI6XG5cdFx0Ly9cblx0XHQvLyAgIDEuIEFuIG9iamVjdCBvZiBwcm9wZXJ0aWVzXG5cdFx0Ly8gICAyLiBBIGtleSBhbmQgdmFsdWVcblx0XHQvL1xuXHRcdHRoaXMuc2V0KCBvd25lciwga2V5LCB2YWx1ZSApO1xuXG5cdFx0Ly8gU2luY2UgdGhlIFwic2V0XCIgcGF0aCBjYW4gaGF2ZSB0d28gcG9zc2libGUgZW50cnkgcG9pbnRzXG5cdFx0Ly8gcmV0dXJuIHRoZSBleHBlY3RlZCBkYXRhIGJhc2VkIG9uIHdoaWNoIHBhdGggd2FzIHRha2VuWypdXG5cdFx0cmV0dXJuIHZhbHVlICE9PSB1bmRlZmluZWQgPyB2YWx1ZSA6IGtleTtcblx0fSxcblx0cmVtb3ZlOiBmdW5jdGlvbiggb3duZXIsIGtleSApIHtcblx0XHR2YXIgaSxcblx0XHRcdGNhY2hlID0gb3duZXJbIHRoaXMuZXhwYW5kbyBdO1xuXG5cdFx0aWYgKCBjYWNoZSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICgga2V5ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdC8vIFN1cHBvcnQgYXJyYXkgb3Igc3BhY2Ugc2VwYXJhdGVkIHN0cmluZyBvZiBrZXlzXG5cdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIGtleSApICkge1xuXG5cdFx0XHRcdC8vIElmIGtleSBpcyBhbiBhcnJheSBvZiBrZXlzLi4uXG5cdFx0XHRcdC8vIFdlIGFsd2F5cyBzZXQgY2FtZWxDYXNlIGtleXMsIHNvIHJlbW92ZSB0aGF0LlxuXHRcdFx0XHRrZXkgPSBrZXkubWFwKCBjYW1lbENhc2UgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGtleSA9IGNhbWVsQ2FzZSgga2V5ICk7XG5cblx0XHRcdFx0Ly8gSWYgYSBrZXkgd2l0aCB0aGUgc3BhY2VzIGV4aXN0cywgdXNlIGl0LlxuXHRcdFx0XHQvLyBPdGhlcndpc2UsIGNyZWF0ZSBhbiBhcnJheSBieSBtYXRjaGluZyBub24td2hpdGVzcGFjZVxuXHRcdFx0XHRrZXkgPSBrZXkgaW4gY2FjaGUgP1xuXHRcdFx0XHRcdFsga2V5IF0gOlxuXHRcdFx0XHRcdCgga2V5Lm1hdGNoKCBybm90aHRtbHdoaXRlICkgfHwgW10gKTtcblx0XHRcdH1cblxuXHRcdFx0aSA9IGtleS5sZW5ndGg7XG5cblx0XHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0XHRkZWxldGUgY2FjaGVbIGtleVsgaSBdIF07XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gUmVtb3ZlIHRoZSBleHBhbmRvIGlmIHRoZXJlJ3Mgbm8gbW9yZSBkYXRhXG5cdFx0aWYgKCBrZXkgPT09IHVuZGVmaW5lZCB8fCBqUXVlcnkuaXNFbXB0eU9iamVjdCggY2FjaGUgKSApIHtcblxuXHRcdFx0Ly8gU3VwcG9ydDogQ2hyb21lIDw9MzUgLSA0NVxuXHRcdFx0Ly8gV2Via2l0ICYgQmxpbmsgcGVyZm9ybWFuY2Ugc3VmZmVycyB3aGVuIGRlbGV0aW5nIHByb3BlcnRpZXNcblx0XHRcdC8vIGZyb20gRE9NIG5vZGVzLCBzbyBzZXQgdG8gdW5kZWZpbmVkIGluc3RlYWRcblx0XHRcdC8vIGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTM3ODYwNyAoYnVnIHJlc3RyaWN0ZWQpXG5cdFx0XHRpZiAoIG93bmVyLm5vZGVUeXBlICkge1xuXHRcdFx0XHRvd25lclsgdGhpcy5leHBhbmRvIF0gPSB1bmRlZmluZWQ7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRkZWxldGUgb3duZXJbIHRoaXMuZXhwYW5kbyBdO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblx0aGFzRGF0YTogZnVuY3Rpb24oIG93bmVyICkge1xuXHRcdHZhciBjYWNoZSA9IG93bmVyWyB0aGlzLmV4cGFuZG8gXTtcblx0XHRyZXR1cm4gY2FjaGUgIT09IHVuZGVmaW5lZCAmJiAhalF1ZXJ5LmlzRW1wdHlPYmplY3QoIGNhY2hlICk7XG5cdH1cbn07XG52YXIgZGF0YVByaXYgPSBuZXcgRGF0YSgpO1xuXG52YXIgZGF0YVVzZXIgPSBuZXcgRGF0YSgpO1xuXG5cblxuLy9cdEltcGxlbWVudGF0aW9uIFN1bW1hcnlcbi8vXG4vL1x0MS4gRW5mb3JjZSBBUEkgc3VyZmFjZSBhbmQgc2VtYW50aWMgY29tcGF0aWJpbGl0eSB3aXRoIDEuOS54IGJyYW5jaFxuLy9cdDIuIEltcHJvdmUgdGhlIG1vZHVsZSdzIG1haW50YWluYWJpbGl0eSBieSByZWR1Y2luZyB0aGUgc3RvcmFnZVxuLy9cdFx0cGF0aHMgdG8gYSBzaW5nbGUgbWVjaGFuaXNtLlxuLy9cdDMuIFVzZSB0aGUgc2FtZSBzaW5nbGUgbWVjaGFuaXNtIHRvIHN1cHBvcnQgXCJwcml2YXRlXCIgYW5kIFwidXNlclwiIGRhdGEuXG4vL1x0NC4gX05ldmVyXyBleHBvc2UgXCJwcml2YXRlXCIgZGF0YSB0byB1c2VyIGNvZGUgKFRPRE86IERyb3AgX2RhdGEsIF9yZW1vdmVEYXRhKVxuLy9cdDUuIEF2b2lkIGV4cG9zaW5nIGltcGxlbWVudGF0aW9uIGRldGFpbHMgb24gdXNlciBvYmplY3RzIChlZy4gZXhwYW5kbyBwcm9wZXJ0aWVzKVxuLy9cdDYuIFByb3ZpZGUgYSBjbGVhciBwYXRoIGZvciBpbXBsZW1lbnRhdGlvbiB1cGdyYWRlIHRvIFdlYWtNYXAgaW4gMjAxNFxuXG52YXIgcmJyYWNlID0gL14oPzpcXHtbXFx3XFxXXSpcXH18XFxbW1xcd1xcV10qXFxdKSQvLFxuXHRybXVsdGlEYXNoID0gL1tBLVpdL2c7XG5cbmZ1bmN0aW9uIGdldERhdGEoIGRhdGEgKSB7XG5cdGlmICggZGF0YSA9PT0gXCJ0cnVlXCIgKSB7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH1cblxuXHRpZiAoIGRhdGEgPT09IFwiZmFsc2VcIiApIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblxuXHRpZiAoIGRhdGEgPT09IFwibnVsbFwiICkge1xuXHRcdHJldHVybiBudWxsO1xuXHR9XG5cblx0Ly8gT25seSBjb252ZXJ0IHRvIGEgbnVtYmVyIGlmIGl0IGRvZXNuJ3QgY2hhbmdlIHRoZSBzdHJpbmdcblx0aWYgKCBkYXRhID09PSArZGF0YSArIFwiXCIgKSB7XG5cdFx0cmV0dXJuICtkYXRhO1xuXHR9XG5cblx0aWYgKCByYnJhY2UudGVzdCggZGF0YSApICkge1xuXHRcdHJldHVybiBKU09OLnBhcnNlKCBkYXRhICk7XG5cdH1cblxuXHRyZXR1cm4gZGF0YTtcbn1cblxuZnVuY3Rpb24gZGF0YUF0dHIoIGVsZW0sIGtleSwgZGF0YSApIHtcblx0dmFyIG5hbWU7XG5cblx0Ly8gSWYgbm90aGluZyB3YXMgZm91bmQgaW50ZXJuYWxseSwgdHJ5IHRvIGZldGNoIGFueVxuXHQvLyBkYXRhIGZyb20gdGhlIEhUTUw1IGRhdGEtKiBhdHRyaWJ1dGVcblx0aWYgKCBkYXRhID09PSB1bmRlZmluZWQgJiYgZWxlbS5ub2RlVHlwZSA9PT0gMSApIHtcblx0XHRuYW1lID0gXCJkYXRhLVwiICsga2V5LnJlcGxhY2UoIHJtdWx0aURhc2gsIFwiLSQmXCIgKS50b0xvd2VyQ2FzZSgpO1xuXHRcdGRhdGEgPSBlbGVtLmdldEF0dHJpYnV0ZSggbmFtZSApO1xuXG5cdFx0aWYgKCB0eXBlb2YgZGF0YSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdHRyeSB7XG5cdFx0XHRcdGRhdGEgPSBnZXREYXRhKCBkYXRhICk7XG5cdFx0XHR9IGNhdGNoICggZSApIHt9XG5cblx0XHRcdC8vIE1ha2Ugc3VyZSB3ZSBzZXQgdGhlIGRhdGEgc28gaXQgaXNuJ3QgY2hhbmdlZCBsYXRlclxuXHRcdFx0ZGF0YVVzZXIuc2V0KCBlbGVtLCBrZXksIGRhdGEgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZGF0YSA9IHVuZGVmaW5lZDtcblx0XHR9XG5cdH1cblx0cmV0dXJuIGRhdGE7XG59XG5cbmpRdWVyeS5leHRlbmQoIHtcblx0aGFzRGF0YTogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0cmV0dXJuIGRhdGFVc2VyLmhhc0RhdGEoIGVsZW0gKSB8fCBkYXRhUHJpdi5oYXNEYXRhKCBlbGVtICk7XG5cdH0sXG5cblx0ZGF0YTogZnVuY3Rpb24oIGVsZW0sIG5hbWUsIGRhdGEgKSB7XG5cdFx0cmV0dXJuIGRhdGFVc2VyLmFjY2VzcyggZWxlbSwgbmFtZSwgZGF0YSApO1xuXHR9LFxuXG5cdHJlbW92ZURhdGE6IGZ1bmN0aW9uKCBlbGVtLCBuYW1lICkge1xuXHRcdGRhdGFVc2VyLnJlbW92ZSggZWxlbSwgbmFtZSApO1xuXHR9LFxuXG5cdC8vIFRPRE86IE5vdyB0aGF0IGFsbCBjYWxscyB0byBfZGF0YSBhbmQgX3JlbW92ZURhdGEgaGF2ZSBiZWVuIHJlcGxhY2VkXG5cdC8vIHdpdGggZGlyZWN0IGNhbGxzIHRvIGRhdGFQcml2IG1ldGhvZHMsIHRoZXNlIGNhbiBiZSBkZXByZWNhdGVkLlxuXHRfZGF0YTogZnVuY3Rpb24oIGVsZW0sIG5hbWUsIGRhdGEgKSB7XG5cdFx0cmV0dXJuIGRhdGFQcml2LmFjY2VzcyggZWxlbSwgbmFtZSwgZGF0YSApO1xuXHR9LFxuXG5cdF9yZW1vdmVEYXRhOiBmdW5jdGlvbiggZWxlbSwgbmFtZSApIHtcblx0XHRkYXRhUHJpdi5yZW1vdmUoIGVsZW0sIG5hbWUgKTtcblx0fVxufSApO1xuXG5qUXVlcnkuZm4uZXh0ZW5kKCB7XG5cdGRhdGE6IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdHZhciBpLCBuYW1lLCBkYXRhLFxuXHRcdFx0ZWxlbSA9IHRoaXNbIDAgXSxcblx0XHRcdGF0dHJzID0gZWxlbSAmJiBlbGVtLmF0dHJpYnV0ZXM7XG5cblx0XHQvLyBHZXRzIGFsbCB2YWx1ZXNcblx0XHRpZiAoIGtleSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0aWYgKCB0aGlzLmxlbmd0aCApIHtcblx0XHRcdFx0ZGF0YSA9IGRhdGFVc2VyLmdldCggZWxlbSApO1xuXG5cdFx0XHRcdGlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSAmJiAhZGF0YVByaXYuZ2V0KCBlbGVtLCBcImhhc0RhdGFBdHRyc1wiICkgKSB7XG5cdFx0XHRcdFx0aSA9IGF0dHJzLmxlbmd0aDtcblx0XHRcdFx0XHR3aGlsZSAoIGktLSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gU3VwcG9ydDogSUUgMTEgb25seVxuXHRcdFx0XHRcdFx0Ly8gVGhlIGF0dHJzIGVsZW1lbnRzIGNhbiBiZSBudWxsICgjMTQ4OTQpXG5cdFx0XHRcdFx0XHRpZiAoIGF0dHJzWyBpIF0gKSB7XG5cdFx0XHRcdFx0XHRcdG5hbWUgPSBhdHRyc1sgaSBdLm5hbWU7XG5cdFx0XHRcdFx0XHRcdGlmICggbmFtZS5pbmRleE9mKCBcImRhdGEtXCIgKSA9PT0gMCApIHtcblx0XHRcdFx0XHRcdFx0XHRuYW1lID0gY2FtZWxDYXNlKCBuYW1lLnNsaWNlKCA1ICkgKTtcblx0XHRcdFx0XHRcdFx0XHRkYXRhQXR0ciggZWxlbSwgbmFtZSwgZGF0YVsgbmFtZSBdICk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZGF0YVByaXYuc2V0KCBlbGVtLCBcImhhc0RhdGFBdHRyc1wiLCB0cnVlICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGRhdGE7XG5cdFx0fVxuXG5cdFx0Ly8gU2V0cyBtdWx0aXBsZSB2YWx1ZXNcblx0XHRpZiAoIHR5cGVvZiBrZXkgPT09IFwib2JqZWN0XCIgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0ZGF0YVVzZXIuc2V0KCB0aGlzLCBrZXkgKTtcblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gYWNjZXNzKCB0aGlzLCBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0XHR2YXIgZGF0YTtcblxuXHRcdFx0Ly8gVGhlIGNhbGxpbmcgalF1ZXJ5IG9iamVjdCAoZWxlbWVudCBtYXRjaGVzKSBpcyBub3QgZW1wdHlcblx0XHRcdC8vIChhbmQgdGhlcmVmb3JlIGhhcyBhbiBlbGVtZW50IGFwcGVhcnMgYXQgdGhpc1sgMCBdKSBhbmQgdGhlXG5cdFx0XHQvLyBgdmFsdWVgIHBhcmFtZXRlciB3YXMgbm90IHVuZGVmaW5lZC4gQW4gZW1wdHkgalF1ZXJ5IG9iamVjdFxuXHRcdFx0Ly8gd2lsbCByZXN1bHQgaW4gYHVuZGVmaW5lZGAgZm9yIGVsZW0gPSB0aGlzWyAwIF0gd2hpY2ggd2lsbFxuXHRcdFx0Ly8gdGhyb3cgYW4gZXhjZXB0aW9uIGlmIGFuIGF0dGVtcHQgdG8gcmVhZCBhIGRhdGEgY2FjaGUgaXMgbWFkZS5cblx0XHRcdGlmICggZWxlbSAmJiB2YWx1ZSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdC8vIEF0dGVtcHQgdG8gZ2V0IGRhdGEgZnJvbSB0aGUgY2FjaGVcblx0XHRcdFx0Ly8gVGhlIGtleSB3aWxsIGFsd2F5cyBiZSBjYW1lbENhc2VkIGluIERhdGFcblx0XHRcdFx0ZGF0YSA9IGRhdGFVc2VyLmdldCggZWxlbSwga2V5ICk7XG5cdFx0XHRcdGlmICggZGF0YSAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdHJldHVybiBkYXRhO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gQXR0ZW1wdCB0byBcImRpc2NvdmVyXCIgdGhlIGRhdGEgaW5cblx0XHRcdFx0Ly8gSFRNTDUgY3VzdG9tIGRhdGEtKiBhdHRyc1xuXHRcdFx0XHRkYXRhID0gZGF0YUF0dHIoIGVsZW0sIGtleSApO1xuXHRcdFx0XHRpZiAoIGRhdGEgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0XHRyZXR1cm4gZGF0YTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFdlIHRyaWVkIHJlYWxseSBoYXJkLCBidXQgdGhlIGRhdGEgZG9lc24ndCBleGlzdC5cblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTZXQgdGhlIGRhdGEuLi5cblx0XHRcdHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cblx0XHRcdFx0Ly8gV2UgYWx3YXlzIHN0b3JlIHRoZSBjYW1lbENhc2VkIGtleVxuXHRcdFx0XHRkYXRhVXNlci5zZXQoIHRoaXMsIGtleSwgdmFsdWUgKTtcblx0XHRcdH0gKTtcblx0XHR9LCBudWxsLCB2YWx1ZSwgYXJndW1lbnRzLmxlbmd0aCA+IDEsIG51bGwsIHRydWUgKTtcblx0fSxcblxuXHRyZW1vdmVEYXRhOiBmdW5jdGlvbigga2V5ICkge1xuXHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0ZGF0YVVzZXIucmVtb3ZlKCB0aGlzLCBrZXkgKTtcblx0XHR9ICk7XG5cdH1cbn0gKTtcblxuXG5qUXVlcnkuZXh0ZW5kKCB7XG5cdHF1ZXVlOiBmdW5jdGlvbiggZWxlbSwgdHlwZSwgZGF0YSApIHtcblx0XHR2YXIgcXVldWU7XG5cblx0XHRpZiAoIGVsZW0gKSB7XG5cdFx0XHR0eXBlID0gKCB0eXBlIHx8IFwiZnhcIiApICsgXCJxdWV1ZVwiO1xuXHRcdFx0cXVldWUgPSBkYXRhUHJpdi5nZXQoIGVsZW0sIHR5cGUgKTtcblxuXHRcdFx0Ly8gU3BlZWQgdXAgZGVxdWV1ZSBieSBnZXR0aW5nIG91dCBxdWlja2x5IGlmIHRoaXMgaXMganVzdCBhIGxvb2t1cFxuXHRcdFx0aWYgKCBkYXRhICkge1xuXHRcdFx0XHRpZiAoICFxdWV1ZSB8fCBBcnJheS5pc0FycmF5KCBkYXRhICkgKSB7XG5cdFx0XHRcdFx0cXVldWUgPSBkYXRhUHJpdi5hY2Nlc3MoIGVsZW0sIHR5cGUsIGpRdWVyeS5tYWtlQXJyYXkoIGRhdGEgKSApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHF1ZXVlLnB1c2goIGRhdGEgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHF1ZXVlIHx8IFtdO1xuXHRcdH1cblx0fSxcblxuXHRkZXF1ZXVlOiBmdW5jdGlvbiggZWxlbSwgdHlwZSApIHtcblx0XHR0eXBlID0gdHlwZSB8fCBcImZ4XCI7XG5cblx0XHR2YXIgcXVldWUgPSBqUXVlcnkucXVldWUoIGVsZW0sIHR5cGUgKSxcblx0XHRcdHN0YXJ0TGVuZ3RoID0gcXVldWUubGVuZ3RoLFxuXHRcdFx0Zm4gPSBxdWV1ZS5zaGlmdCgpLFxuXHRcdFx0aG9va3MgPSBqUXVlcnkuX3F1ZXVlSG9va3MoIGVsZW0sIHR5cGUgKSxcblx0XHRcdG5leHQgPSBmdW5jdGlvbigpIHtcblx0XHRcdFx0alF1ZXJ5LmRlcXVldWUoIGVsZW0sIHR5cGUgKTtcblx0XHRcdH07XG5cblx0XHQvLyBJZiB0aGUgZnggcXVldWUgaXMgZGVxdWV1ZWQsIGFsd2F5cyByZW1vdmUgdGhlIHByb2dyZXNzIHNlbnRpbmVsXG5cdFx0aWYgKCBmbiA9PT0gXCJpbnByb2dyZXNzXCIgKSB7XG5cdFx0XHRmbiA9IHF1ZXVlLnNoaWZ0KCk7XG5cdFx0XHRzdGFydExlbmd0aC0tO1xuXHRcdH1cblxuXHRcdGlmICggZm4gKSB7XG5cblx0XHRcdC8vIEFkZCBhIHByb2dyZXNzIHNlbnRpbmVsIHRvIHByZXZlbnQgdGhlIGZ4IHF1ZXVlIGZyb20gYmVpbmdcblx0XHRcdC8vIGF1dG9tYXRpY2FsbHkgZGVxdWV1ZWRcblx0XHRcdGlmICggdHlwZSA9PT0gXCJmeFwiICkge1xuXHRcdFx0XHRxdWV1ZS51bnNoaWZ0KCBcImlucHJvZ3Jlc3NcIiApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBDbGVhciB1cCB0aGUgbGFzdCBxdWV1ZSBzdG9wIGZ1bmN0aW9uXG5cdFx0XHRkZWxldGUgaG9va3Muc3RvcDtcblx0XHRcdGZuLmNhbGwoIGVsZW0sIG5leHQsIGhvb2tzICk7XG5cdFx0fVxuXG5cdFx0aWYgKCAhc3RhcnRMZW5ndGggJiYgaG9va3MgKSB7XG5cdFx0XHRob29rcy5lbXB0eS5maXJlKCk7XG5cdFx0fVxuXHR9LFxuXG5cdC8vIE5vdCBwdWJsaWMgLSBnZW5lcmF0ZSBhIHF1ZXVlSG9va3Mgb2JqZWN0LCBvciByZXR1cm4gdGhlIGN1cnJlbnQgb25lXG5cdF9xdWV1ZUhvb2tzOiBmdW5jdGlvbiggZWxlbSwgdHlwZSApIHtcblx0XHR2YXIga2V5ID0gdHlwZSArIFwicXVldWVIb29rc1wiO1xuXHRcdHJldHVybiBkYXRhUHJpdi5nZXQoIGVsZW0sIGtleSApIHx8IGRhdGFQcml2LmFjY2VzcyggZWxlbSwga2V5LCB7XG5cdFx0XHRlbXB0eTogalF1ZXJ5LkNhbGxiYWNrcyggXCJvbmNlIG1lbW9yeVwiICkuYWRkKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0ZGF0YVByaXYucmVtb3ZlKCBlbGVtLCBbIHR5cGUgKyBcInF1ZXVlXCIsIGtleSBdICk7XG5cdFx0XHR9IClcblx0XHR9ICk7XG5cdH1cbn0gKTtcblxualF1ZXJ5LmZuLmV4dGVuZCgge1xuXHRxdWV1ZTogZnVuY3Rpb24oIHR5cGUsIGRhdGEgKSB7XG5cdFx0dmFyIHNldHRlciA9IDI7XG5cblx0XHRpZiAoIHR5cGVvZiB0eXBlICE9PSBcInN0cmluZ1wiICkge1xuXHRcdFx0ZGF0YSA9IHR5cGU7XG5cdFx0XHR0eXBlID0gXCJmeFwiO1xuXHRcdFx0c2V0dGVyLS07XG5cdFx0fVxuXG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoIDwgc2V0dGVyICkge1xuXHRcdFx0cmV0dXJuIGpRdWVyeS5xdWV1ZSggdGhpc1sgMCBdLCB0eXBlICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRhdGEgPT09IHVuZGVmaW5lZCA/XG5cdFx0XHR0aGlzIDpcblx0XHRcdHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBxdWV1ZSA9IGpRdWVyeS5xdWV1ZSggdGhpcywgdHlwZSwgZGF0YSApO1xuXG5cdFx0XHRcdC8vIEVuc3VyZSBhIGhvb2tzIGZvciB0aGlzIHF1ZXVlXG5cdFx0XHRcdGpRdWVyeS5fcXVldWVIb29rcyggdGhpcywgdHlwZSApO1xuXG5cdFx0XHRcdGlmICggdHlwZSA9PT0gXCJmeFwiICYmIHF1ZXVlWyAwIF0gIT09IFwiaW5wcm9ncmVzc1wiICkge1xuXHRcdFx0XHRcdGpRdWVyeS5kZXF1ZXVlKCB0aGlzLCB0eXBlICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0fSxcblx0ZGVxdWV1ZTogZnVuY3Rpb24oIHR5cGUgKSB7XG5cdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRqUXVlcnkuZGVxdWV1ZSggdGhpcywgdHlwZSApO1xuXHRcdH0gKTtcblx0fSxcblx0Y2xlYXJRdWV1ZTogZnVuY3Rpb24oIHR5cGUgKSB7XG5cdFx0cmV0dXJuIHRoaXMucXVldWUoIHR5cGUgfHwgXCJmeFwiLCBbXSApO1xuXHR9LFxuXG5cdC8vIEdldCBhIHByb21pc2UgcmVzb2x2ZWQgd2hlbiBxdWV1ZXMgb2YgYSBjZXJ0YWluIHR5cGVcblx0Ly8gYXJlIGVtcHRpZWQgKGZ4IGlzIHRoZSB0eXBlIGJ5IGRlZmF1bHQpXG5cdHByb21pc2U6IGZ1bmN0aW9uKCB0eXBlLCBvYmogKSB7XG5cdFx0dmFyIHRtcCxcblx0XHRcdGNvdW50ID0gMSxcblx0XHRcdGRlZmVyID0galF1ZXJ5LkRlZmVycmVkKCksXG5cdFx0XHRlbGVtZW50cyA9IHRoaXMsXG5cdFx0XHRpID0gdGhpcy5sZW5ndGgsXG5cdFx0XHRyZXNvbHZlID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggISggLS1jb3VudCApICkge1xuXHRcdFx0XHRcdGRlZmVyLnJlc29sdmVXaXRoKCBlbGVtZW50cywgWyBlbGVtZW50cyBdICk7XG5cdFx0XHRcdH1cblx0XHRcdH07XG5cblx0XHRpZiAoIHR5cGVvZiB0eXBlICE9PSBcInN0cmluZ1wiICkge1xuXHRcdFx0b2JqID0gdHlwZTtcblx0XHRcdHR5cGUgPSB1bmRlZmluZWQ7XG5cdFx0fVxuXHRcdHR5cGUgPSB0eXBlIHx8IFwiZnhcIjtcblxuXHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0dG1wID0gZGF0YVByaXYuZ2V0KCBlbGVtZW50c1sgaSBdLCB0eXBlICsgXCJxdWV1ZUhvb2tzXCIgKTtcblx0XHRcdGlmICggdG1wICYmIHRtcC5lbXB0eSApIHtcblx0XHRcdFx0Y291bnQrKztcblx0XHRcdFx0dG1wLmVtcHR5LmFkZCggcmVzb2x2ZSApO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXNvbHZlKCk7XG5cdFx0cmV0dXJuIGRlZmVyLnByb21pc2UoIG9iaiApO1xuXHR9XG59ICk7XG52YXIgcG51bSA9ICggL1srLV0/KD86XFxkKlxcLnwpXFxkKyg/OltlRV1bKy1dP1xcZCt8KS8gKS5zb3VyY2U7XG5cbnZhciByY3NzTnVtID0gbmV3IFJlZ0V4cCggXCJeKD86KFsrLV0pPXwpKFwiICsgcG51bSArIFwiKShbYS16JV0qKSRcIiwgXCJpXCIgKTtcblxuXG52YXIgY3NzRXhwYW5kID0gWyBcIlRvcFwiLCBcIlJpZ2h0XCIsIFwiQm90dG9tXCIsIFwiTGVmdFwiIF07XG5cbnZhciBkb2N1bWVudEVsZW1lbnQgPSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQ7XG5cblxuXG5cdHZhciBpc0F0dGFjaGVkID0gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4galF1ZXJ5LmNvbnRhaW5zKCBlbGVtLm93bmVyRG9jdW1lbnQsIGVsZW0gKTtcblx0XHR9LFxuXHRcdGNvbXBvc2VkID0geyBjb21wb3NlZDogdHJ1ZSB9O1xuXG5cdC8vIFN1cHBvcnQ6IElFIDkgLSAxMSssIEVkZ2UgMTIgLSAxOCssIGlPUyAxMC4wIC0gMTAuMiBvbmx5XG5cdC8vIENoZWNrIGF0dGFjaG1lbnQgYWNyb3NzIHNoYWRvdyBET00gYm91bmRhcmllcyB3aGVuIHBvc3NpYmxlIChnaC0zNTA0KVxuXHQvLyBTdXBwb3J0OiBpT1MgMTAuMC0xMC4yIG9ubHlcblx0Ly8gRWFybHkgaU9TIDEwIHZlcnNpb25zIHN1cHBvcnQgYGF0dGFjaFNoYWRvd2AgYnV0IG5vdCBgZ2V0Um9vdE5vZGVgLFxuXHQvLyBsZWFkaW5nIHRvIGVycm9ycy4gV2UgbmVlZCB0byBjaGVjayBmb3IgYGdldFJvb3ROb2RlYC5cblx0aWYgKCBkb2N1bWVudEVsZW1lbnQuZ2V0Um9vdE5vZGUgKSB7XG5cdFx0aXNBdHRhY2hlZCA9IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0cmV0dXJuIGpRdWVyeS5jb250YWlucyggZWxlbS5vd25lckRvY3VtZW50LCBlbGVtICkgfHxcblx0XHRcdFx0ZWxlbS5nZXRSb290Tm9kZSggY29tcG9zZWQgKSA9PT0gZWxlbS5vd25lckRvY3VtZW50O1xuXHRcdH07XG5cdH1cbnZhciBpc0hpZGRlbldpdGhpblRyZWUgPSBmdW5jdGlvbiggZWxlbSwgZWwgKSB7XG5cblx0XHQvLyBpc0hpZGRlbldpdGhpblRyZWUgbWlnaHQgYmUgY2FsbGVkIGZyb20galF1ZXJ5I2ZpbHRlciBmdW5jdGlvbjtcblx0XHQvLyBpbiB0aGF0IGNhc2UsIGVsZW1lbnQgd2lsbCBiZSBzZWNvbmQgYXJndW1lbnRcblx0XHRlbGVtID0gZWwgfHwgZWxlbTtcblxuXHRcdC8vIElubGluZSBzdHlsZSB0cnVtcHMgYWxsXG5cdFx0cmV0dXJuIGVsZW0uc3R5bGUuZGlzcGxheSA9PT0gXCJub25lXCIgfHxcblx0XHRcdGVsZW0uc3R5bGUuZGlzcGxheSA9PT0gXCJcIiAmJlxuXG5cdFx0XHQvLyBPdGhlcndpc2UsIGNoZWNrIGNvbXB1dGVkIHN0eWxlXG5cdFx0XHQvLyBTdXBwb3J0OiBGaXJlZm94IDw9NDMgLSA0NVxuXHRcdFx0Ly8gRGlzY29ubmVjdGVkIGVsZW1lbnRzIGNhbiBoYXZlIGNvbXB1dGVkIGRpc3BsYXk6IG5vbmUsIHNvIGZpcnN0IGNvbmZpcm0gdGhhdCBlbGVtIGlzXG5cdFx0XHQvLyBpbiB0aGUgZG9jdW1lbnQuXG5cdFx0XHRpc0F0dGFjaGVkKCBlbGVtICkgJiZcblxuXHRcdFx0alF1ZXJ5LmNzcyggZWxlbSwgXCJkaXNwbGF5XCIgKSA9PT0gXCJub25lXCI7XG5cdH07XG5cblxuXG5mdW5jdGlvbiBhZGp1c3RDU1MoIGVsZW0sIHByb3AsIHZhbHVlUGFydHMsIHR3ZWVuICkge1xuXHR2YXIgYWRqdXN0ZWQsIHNjYWxlLFxuXHRcdG1heEl0ZXJhdGlvbnMgPSAyMCxcblx0XHRjdXJyZW50VmFsdWUgPSB0d2VlbiA/XG5cdFx0XHRmdW5jdGlvbigpIHtcblx0XHRcdFx0cmV0dXJuIHR3ZWVuLmN1cigpO1xuXHRcdFx0fSA6XG5cdFx0XHRmdW5jdGlvbigpIHtcblx0XHRcdFx0cmV0dXJuIGpRdWVyeS5jc3MoIGVsZW0sIHByb3AsIFwiXCIgKTtcblx0XHRcdH0sXG5cdFx0aW5pdGlhbCA9IGN1cnJlbnRWYWx1ZSgpLFxuXHRcdHVuaXQgPSB2YWx1ZVBhcnRzICYmIHZhbHVlUGFydHNbIDMgXSB8fCAoIGpRdWVyeS5jc3NOdW1iZXJbIHByb3AgXSA/IFwiXCIgOiBcInB4XCIgKSxcblxuXHRcdC8vIFN0YXJ0aW5nIHZhbHVlIGNvbXB1dGF0aW9uIGlzIHJlcXVpcmVkIGZvciBwb3RlbnRpYWwgdW5pdCBtaXNtYXRjaGVzXG5cdFx0aW5pdGlhbEluVW5pdCA9IGVsZW0ubm9kZVR5cGUgJiZcblx0XHRcdCggalF1ZXJ5LmNzc051bWJlclsgcHJvcCBdIHx8IHVuaXQgIT09IFwicHhcIiAmJiAraW5pdGlhbCApICYmXG5cdFx0XHRyY3NzTnVtLmV4ZWMoIGpRdWVyeS5jc3MoIGVsZW0sIHByb3AgKSApO1xuXG5cdGlmICggaW5pdGlhbEluVW5pdCAmJiBpbml0aWFsSW5Vbml0WyAzIF0gIT09IHVuaXQgKSB7XG5cblx0XHQvLyBTdXBwb3J0OiBGaXJlZm94IDw9NTRcblx0XHQvLyBIYWx2ZSB0aGUgaXRlcmF0aW9uIHRhcmdldCB2YWx1ZSB0byBwcmV2ZW50IGludGVyZmVyZW5jZSBmcm9tIENTUyB1cHBlciBib3VuZHMgKGdoLTIxNDQpXG5cdFx0aW5pdGlhbCA9IGluaXRpYWwgLyAyO1xuXG5cdFx0Ly8gVHJ1c3QgdW5pdHMgcmVwb3J0ZWQgYnkgalF1ZXJ5LmNzc1xuXHRcdHVuaXQgPSB1bml0IHx8IGluaXRpYWxJblVuaXRbIDMgXTtcblxuXHRcdC8vIEl0ZXJhdGl2ZWx5IGFwcHJveGltYXRlIGZyb20gYSBub256ZXJvIHN0YXJ0aW5nIHBvaW50XG5cdFx0aW5pdGlhbEluVW5pdCA9ICtpbml0aWFsIHx8IDE7XG5cblx0XHR3aGlsZSAoIG1heEl0ZXJhdGlvbnMtLSApIHtcblxuXHRcdFx0Ly8gRXZhbHVhdGUgYW5kIHVwZGF0ZSBvdXIgYmVzdCBndWVzcyAoZG91YmxpbmcgZ3Vlc3NlcyB0aGF0IHplcm8gb3V0KS5cblx0XHRcdC8vIEZpbmlzaCBpZiB0aGUgc2NhbGUgZXF1YWxzIG9yIGNyb3NzZXMgMSAobWFraW5nIHRoZSBvbGQqbmV3IHByb2R1Y3Qgbm9uLXBvc2l0aXZlKS5cblx0XHRcdGpRdWVyeS5zdHlsZSggZWxlbSwgcHJvcCwgaW5pdGlhbEluVW5pdCArIHVuaXQgKTtcblx0XHRcdGlmICggKCAxIC0gc2NhbGUgKSAqICggMSAtICggc2NhbGUgPSBjdXJyZW50VmFsdWUoKSAvIGluaXRpYWwgfHwgMC41ICkgKSA8PSAwICkge1xuXHRcdFx0XHRtYXhJdGVyYXRpb25zID0gMDtcblx0XHRcdH1cblx0XHRcdGluaXRpYWxJblVuaXQgPSBpbml0aWFsSW5Vbml0IC8gc2NhbGU7XG5cblx0XHR9XG5cblx0XHRpbml0aWFsSW5Vbml0ID0gaW5pdGlhbEluVW5pdCAqIDI7XG5cdFx0alF1ZXJ5LnN0eWxlKCBlbGVtLCBwcm9wLCBpbml0aWFsSW5Vbml0ICsgdW5pdCApO1xuXG5cdFx0Ly8gTWFrZSBzdXJlIHdlIHVwZGF0ZSB0aGUgdHdlZW4gcHJvcGVydGllcyBsYXRlciBvblxuXHRcdHZhbHVlUGFydHMgPSB2YWx1ZVBhcnRzIHx8IFtdO1xuXHR9XG5cblx0aWYgKCB2YWx1ZVBhcnRzICkge1xuXHRcdGluaXRpYWxJblVuaXQgPSAraW5pdGlhbEluVW5pdCB8fCAraW5pdGlhbCB8fCAwO1xuXG5cdFx0Ly8gQXBwbHkgcmVsYXRpdmUgb2Zmc2V0ICgrPS8tPSkgaWYgc3BlY2lmaWVkXG5cdFx0YWRqdXN0ZWQgPSB2YWx1ZVBhcnRzWyAxIF0gP1xuXHRcdFx0aW5pdGlhbEluVW5pdCArICggdmFsdWVQYXJ0c1sgMSBdICsgMSApICogdmFsdWVQYXJ0c1sgMiBdIDpcblx0XHRcdCt2YWx1ZVBhcnRzWyAyIF07XG5cdFx0aWYgKCB0d2VlbiApIHtcblx0XHRcdHR3ZWVuLnVuaXQgPSB1bml0O1xuXHRcdFx0dHdlZW4uc3RhcnQgPSBpbml0aWFsSW5Vbml0O1xuXHRcdFx0dHdlZW4uZW5kID0gYWRqdXN0ZWQ7XG5cdFx0fVxuXHR9XG5cdHJldHVybiBhZGp1c3RlZDtcbn1cblxuXG52YXIgZGVmYXVsdERpc3BsYXlNYXAgPSB7fTtcblxuZnVuY3Rpb24gZ2V0RGVmYXVsdERpc3BsYXkoIGVsZW0gKSB7XG5cdHZhciB0ZW1wLFxuXHRcdGRvYyA9IGVsZW0ub3duZXJEb2N1bWVudCxcblx0XHRub2RlTmFtZSA9IGVsZW0ubm9kZU5hbWUsXG5cdFx0ZGlzcGxheSA9IGRlZmF1bHREaXNwbGF5TWFwWyBub2RlTmFtZSBdO1xuXG5cdGlmICggZGlzcGxheSApIHtcblx0XHRyZXR1cm4gZGlzcGxheTtcblx0fVxuXG5cdHRlbXAgPSBkb2MuYm9keS5hcHBlbmRDaGlsZCggZG9jLmNyZWF0ZUVsZW1lbnQoIG5vZGVOYW1lICkgKTtcblx0ZGlzcGxheSA9IGpRdWVyeS5jc3MoIHRlbXAsIFwiZGlzcGxheVwiICk7XG5cblx0dGVtcC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKCB0ZW1wICk7XG5cblx0aWYgKCBkaXNwbGF5ID09PSBcIm5vbmVcIiApIHtcblx0XHRkaXNwbGF5ID0gXCJibG9ja1wiO1xuXHR9XG5cdGRlZmF1bHREaXNwbGF5TWFwWyBub2RlTmFtZSBdID0gZGlzcGxheTtcblxuXHRyZXR1cm4gZGlzcGxheTtcbn1cblxuZnVuY3Rpb24gc2hvd0hpZGUoIGVsZW1lbnRzLCBzaG93ICkge1xuXHR2YXIgZGlzcGxheSwgZWxlbSxcblx0XHR2YWx1ZXMgPSBbXSxcblx0XHRpbmRleCA9IDAsXG5cdFx0bGVuZ3RoID0gZWxlbWVudHMubGVuZ3RoO1xuXG5cdC8vIERldGVybWluZSBuZXcgZGlzcGxheSB2YWx1ZSBmb3IgZWxlbWVudHMgdGhhdCBuZWVkIHRvIGNoYW5nZVxuXHRmb3IgKCA7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrICkge1xuXHRcdGVsZW0gPSBlbGVtZW50c1sgaW5kZXggXTtcblx0XHRpZiAoICFlbGVtLnN0eWxlICkge1xuXHRcdFx0Y29udGludWU7XG5cdFx0fVxuXG5cdFx0ZGlzcGxheSA9IGVsZW0uc3R5bGUuZGlzcGxheTtcblx0XHRpZiAoIHNob3cgKSB7XG5cblx0XHRcdC8vIFNpbmNlIHdlIGZvcmNlIHZpc2liaWxpdHkgdXBvbiBjYXNjYWRlLWhpZGRlbiBlbGVtZW50cywgYW4gaW1tZWRpYXRlIChhbmQgc2xvdylcblx0XHRcdC8vIGNoZWNrIGlzIHJlcXVpcmVkIGluIHRoaXMgZmlyc3QgbG9vcCB1bmxlc3Mgd2UgaGF2ZSBhIG5vbmVtcHR5IGRpc3BsYXkgdmFsdWUgKGVpdGhlclxuXHRcdFx0Ly8gaW5saW5lIG9yIGFib3V0LXRvLWJlLXJlc3RvcmVkKVxuXHRcdFx0aWYgKCBkaXNwbGF5ID09PSBcIm5vbmVcIiApIHtcblx0XHRcdFx0dmFsdWVzWyBpbmRleCBdID0gZGF0YVByaXYuZ2V0KCBlbGVtLCBcImRpc3BsYXlcIiApIHx8IG51bGw7XG5cdFx0XHRcdGlmICggIXZhbHVlc1sgaW5kZXggXSApIHtcblx0XHRcdFx0XHRlbGVtLnN0eWxlLmRpc3BsYXkgPSBcIlwiO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRpZiAoIGVsZW0uc3R5bGUuZGlzcGxheSA9PT0gXCJcIiAmJiBpc0hpZGRlbldpdGhpblRyZWUoIGVsZW0gKSApIHtcblx0XHRcdFx0dmFsdWVzWyBpbmRleCBdID0gZ2V0RGVmYXVsdERpc3BsYXkoIGVsZW0gKTtcblx0XHRcdH1cblx0XHR9IGVsc2Uge1xuXHRcdFx0aWYgKCBkaXNwbGF5ICE9PSBcIm5vbmVcIiApIHtcblx0XHRcdFx0dmFsdWVzWyBpbmRleCBdID0gXCJub25lXCI7XG5cblx0XHRcdFx0Ly8gUmVtZW1iZXIgd2hhdCB3ZSdyZSBvdmVyd3JpdGluZ1xuXHRcdFx0XHRkYXRhUHJpdi5zZXQoIGVsZW0sIFwiZGlzcGxheVwiLCBkaXNwbGF5ICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0Ly8gU2V0IHRoZSBkaXNwbGF5IG9mIHRoZSBlbGVtZW50cyBpbiBhIHNlY29uZCBsb29wIHRvIGF2b2lkIGNvbnN0YW50IHJlZmxvd1xuXHRmb3IgKCBpbmRleCA9IDA7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrICkge1xuXHRcdGlmICggdmFsdWVzWyBpbmRleCBdICE9IG51bGwgKSB7XG5cdFx0XHRlbGVtZW50c1sgaW5kZXggXS5zdHlsZS5kaXNwbGF5ID0gdmFsdWVzWyBpbmRleCBdO1xuXHRcdH1cblx0fVxuXG5cdHJldHVybiBlbGVtZW50cztcbn1cblxualF1ZXJ5LmZuLmV4dGVuZCgge1xuXHRzaG93OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gc2hvd0hpZGUoIHRoaXMsIHRydWUgKTtcblx0fSxcblx0aGlkZTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHNob3dIaWRlKCB0aGlzICk7XG5cdH0sXG5cdHRvZ2dsZTogZnVuY3Rpb24oIHN0YXRlICkge1xuXHRcdGlmICggdHlwZW9mIHN0YXRlID09PSBcImJvb2xlYW5cIiApIHtcblx0XHRcdHJldHVybiBzdGF0ZSA/IHRoaXMuc2hvdygpIDogdGhpcy5oaWRlKCk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoIGlzSGlkZGVuV2l0aGluVHJlZSggdGhpcyApICkge1xuXHRcdFx0XHRqUXVlcnkoIHRoaXMgKS5zaG93KCk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRqUXVlcnkoIHRoaXMgKS5oaWRlKCk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9XG59ICk7XG52YXIgcmNoZWNrYWJsZVR5cGUgPSAoIC9eKD86Y2hlY2tib3h8cmFkaW8pJC9pICk7XG5cbnZhciBydGFnTmFtZSA9ICggLzwoW2Etel1bXlxcL1xcMD5cXHgyMFxcdFxcclxcblxcZl0qKS9pICk7XG5cbnZhciByc2NyaXB0VHlwZSA9ICggL14kfF5tb2R1bGUkfFxcLyg/OmphdmF8ZWNtYSlzY3JpcHQvaSApO1xuXG5cblxuKCBmdW5jdGlvbigpIHtcblx0dmFyIGZyYWdtZW50ID0gZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpLFxuXHRcdGRpdiA9IGZyYWdtZW50LmFwcGVuZENoaWxkKCBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcImRpdlwiICkgKSxcblx0XHRpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwiaW5wdXRcIiApO1xuXG5cdC8vIFN1cHBvcnQ6IEFuZHJvaWQgNC4wIC0gNC4zIG9ubHlcblx0Ly8gQ2hlY2sgc3RhdGUgbG9zdCBpZiB0aGUgbmFtZSBpcyBzZXQgKCMxMTIxNylcblx0Ly8gU3VwcG9ydDogV2luZG93cyBXZWIgQXBwcyAoV1dBKVxuXHQvLyBgbmFtZWAgYW5kIGB0eXBlYCBtdXN0IHVzZSAuc2V0QXR0cmlidXRlIGZvciBXV0EgKCMxNDkwMSlcblx0aW5wdXQuc2V0QXR0cmlidXRlKCBcInR5cGVcIiwgXCJyYWRpb1wiICk7XG5cdGlucHV0LnNldEF0dHJpYnV0ZSggXCJjaGVja2VkXCIsIFwiY2hlY2tlZFwiICk7XG5cdGlucHV0LnNldEF0dHJpYnV0ZSggXCJuYW1lXCIsIFwidFwiICk7XG5cblx0ZGl2LmFwcGVuZENoaWxkKCBpbnB1dCApO1xuXG5cdC8vIFN1cHBvcnQ6IEFuZHJvaWQgPD00LjEgb25seVxuXHQvLyBPbGRlciBXZWJLaXQgZG9lc24ndCBjbG9uZSBjaGVja2VkIHN0YXRlIGNvcnJlY3RseSBpbiBmcmFnbWVudHNcblx0c3VwcG9ydC5jaGVja0Nsb25lID0gZGl2LmNsb25lTm9kZSggdHJ1ZSApLmNsb25lTm9kZSggdHJ1ZSApLmxhc3RDaGlsZC5jaGVja2VkO1xuXG5cdC8vIFN1cHBvcnQ6IElFIDw9MTEgb25seVxuXHQvLyBNYWtlIHN1cmUgdGV4dGFyZWEgKGFuZCBjaGVja2JveCkgZGVmYXVsdFZhbHVlIGlzIHByb3Blcmx5IGNsb25lZFxuXHRkaXYuaW5uZXJIVE1MID0gXCI8dGV4dGFyZWE+eDwvdGV4dGFyZWE+XCI7XG5cdHN1cHBvcnQubm9DbG9uZUNoZWNrZWQgPSAhIWRpdi5jbG9uZU5vZGUoIHRydWUgKS5sYXN0Q2hpbGQuZGVmYXVsdFZhbHVlO1xuXG5cdC8vIFN1cHBvcnQ6IElFIDw9OSBvbmx5XG5cdC8vIElFIDw9OSByZXBsYWNlcyA8b3B0aW9uPiB0YWdzIHdpdGggdGhlaXIgY29udGVudHMgd2hlbiBpbnNlcnRlZCBvdXRzaWRlIG9mXG5cdC8vIHRoZSBzZWxlY3QgZWxlbWVudC5cblx0ZGl2LmlubmVySFRNTCA9IFwiPG9wdGlvbj48L29wdGlvbj5cIjtcblx0c3VwcG9ydC5vcHRpb24gPSAhIWRpdi5sYXN0Q2hpbGQ7XG59ICkoKTtcblxuXG4vLyBXZSBoYXZlIHRvIGNsb3NlIHRoZXNlIHRhZ3MgdG8gc3VwcG9ydCBYSFRNTCAoIzEzMjAwKVxudmFyIHdyYXBNYXAgPSB7XG5cblx0Ly8gWEhUTUwgcGFyc2VycyBkbyBub3QgbWFnaWNhbGx5IGluc2VydCBlbGVtZW50cyBpbiB0aGVcblx0Ly8gc2FtZSB3YXkgdGhhdCB0YWcgc291cCBwYXJzZXJzIGRvLiBTbyB3ZSBjYW5ub3Qgc2hvcnRlblxuXHQvLyB0aGlzIGJ5IG9taXR0aW5nIDx0Ym9keT4gb3Igb3RoZXIgcmVxdWlyZWQgZWxlbWVudHMuXG5cdHRoZWFkOiBbIDEsIFwiPHRhYmxlPlwiLCBcIjwvdGFibGU+XCIgXSxcblx0Y29sOiBbIDIsIFwiPHRhYmxlPjxjb2xncm91cD5cIiwgXCI8L2NvbGdyb3VwPjwvdGFibGU+XCIgXSxcblx0dHI6IFsgMiwgXCI8dGFibGU+PHRib2R5PlwiLCBcIjwvdGJvZHk+PC90YWJsZT5cIiBdLFxuXHR0ZDogWyAzLCBcIjx0YWJsZT48dGJvZHk+PHRyPlwiLCBcIjwvdHI+PC90Ym9keT48L3RhYmxlPlwiIF0sXG5cblx0X2RlZmF1bHQ6IFsgMCwgXCJcIiwgXCJcIiBdXG59O1xuXG53cmFwTWFwLnRib2R5ID0gd3JhcE1hcC50Zm9vdCA9IHdyYXBNYXAuY29sZ3JvdXAgPSB3cmFwTWFwLmNhcHRpb24gPSB3cmFwTWFwLnRoZWFkO1xud3JhcE1hcC50aCA9IHdyYXBNYXAudGQ7XG5cbi8vIFN1cHBvcnQ6IElFIDw9OSBvbmx5XG5pZiAoICFzdXBwb3J0Lm9wdGlvbiApIHtcblx0d3JhcE1hcC5vcHRncm91cCA9IHdyYXBNYXAub3B0aW9uID0gWyAxLCBcIjxzZWxlY3QgbXVsdGlwbGU9J211bHRpcGxlJz5cIiwgXCI8L3NlbGVjdD5cIiBdO1xufVxuXG5cbmZ1bmN0aW9uIGdldEFsbCggY29udGV4dCwgdGFnICkge1xuXG5cdC8vIFN1cHBvcnQ6IElFIDw9OSAtIDExIG9ubHlcblx0Ly8gVXNlIHR5cGVvZiB0byBhdm9pZCB6ZXJvLWFyZ3VtZW50IG1ldGhvZCBpbnZvY2F0aW9uIG9uIGhvc3Qgb2JqZWN0cyAoIzE1MTUxKVxuXHR2YXIgcmV0O1xuXG5cdGlmICggdHlwZW9mIGNvbnRleHQuZ2V0RWxlbWVudHNCeVRhZ05hbWUgIT09IFwidW5kZWZpbmVkXCIgKSB7XG5cdFx0cmV0ID0gY29udGV4dC5nZXRFbGVtZW50c0J5VGFnTmFtZSggdGFnIHx8IFwiKlwiICk7XG5cblx0fSBlbHNlIGlmICggdHlwZW9mIGNvbnRleHQucXVlcnlTZWxlY3RvckFsbCAhPT0gXCJ1bmRlZmluZWRcIiApIHtcblx0XHRyZXQgPSBjb250ZXh0LnF1ZXJ5U2VsZWN0b3JBbGwoIHRhZyB8fCBcIipcIiApO1xuXG5cdH0gZWxzZSB7XG5cdFx0cmV0ID0gW107XG5cdH1cblxuXHRpZiAoIHRhZyA9PT0gdW5kZWZpbmVkIHx8IHRhZyAmJiBub2RlTmFtZSggY29udGV4dCwgdGFnICkgKSB7XG5cdFx0cmV0dXJuIGpRdWVyeS5tZXJnZSggWyBjb250ZXh0IF0sIHJldCApO1xuXHR9XG5cblx0cmV0dXJuIHJldDtcbn1cblxuXG4vLyBNYXJrIHNjcmlwdHMgYXMgaGF2aW5nIGFscmVhZHkgYmVlbiBldmFsdWF0ZWRcbmZ1bmN0aW9uIHNldEdsb2JhbEV2YWwoIGVsZW1zLCByZWZFbGVtZW50cyApIHtcblx0dmFyIGkgPSAwLFxuXHRcdGwgPSBlbGVtcy5sZW5ndGg7XG5cblx0Zm9yICggOyBpIDwgbDsgaSsrICkge1xuXHRcdGRhdGFQcml2LnNldChcblx0XHRcdGVsZW1zWyBpIF0sXG5cdFx0XHRcImdsb2JhbEV2YWxcIixcblx0XHRcdCFyZWZFbGVtZW50cyB8fCBkYXRhUHJpdi5nZXQoIHJlZkVsZW1lbnRzWyBpIF0sIFwiZ2xvYmFsRXZhbFwiIClcblx0XHQpO1xuXHR9XG59XG5cblxudmFyIHJodG1sID0gLzx8JiM/XFx3KzsvO1xuXG5mdW5jdGlvbiBidWlsZEZyYWdtZW50KCBlbGVtcywgY29udGV4dCwgc2NyaXB0cywgc2VsZWN0aW9uLCBpZ25vcmVkICkge1xuXHR2YXIgZWxlbSwgdG1wLCB0YWcsIHdyYXAsIGF0dGFjaGVkLCBqLFxuXHRcdGZyYWdtZW50ID0gY29udGV4dC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCksXG5cdFx0bm9kZXMgPSBbXSxcblx0XHRpID0gMCxcblx0XHRsID0gZWxlbXMubGVuZ3RoO1xuXG5cdGZvciAoIDsgaSA8IGw7IGkrKyApIHtcblx0XHRlbGVtID0gZWxlbXNbIGkgXTtcblxuXHRcdGlmICggZWxlbSB8fCBlbGVtID09PSAwICkge1xuXG5cdFx0XHQvLyBBZGQgbm9kZXMgZGlyZWN0bHlcblx0XHRcdGlmICggdG9UeXBlKCBlbGVtICkgPT09IFwib2JqZWN0XCIgKSB7XG5cblx0XHRcdFx0Ly8gU3VwcG9ydDogQW5kcm9pZCA8PTQuMCBvbmx5LCBQaGFudG9tSlMgMSBvbmx5XG5cdFx0XHRcdC8vIHB1c2guYXBwbHkoXywgYXJyYXlsaWtlKSB0aHJvd3Mgb24gYW5jaWVudCBXZWJLaXRcblx0XHRcdFx0alF1ZXJ5Lm1lcmdlKCBub2RlcywgZWxlbS5ub2RlVHlwZSA/IFsgZWxlbSBdIDogZWxlbSApO1xuXG5cdFx0XHQvLyBDb252ZXJ0IG5vbi1odG1sIGludG8gYSB0ZXh0IG5vZGVcblx0XHRcdH0gZWxzZSBpZiAoICFyaHRtbC50ZXN0KCBlbGVtICkgKSB7XG5cdFx0XHRcdG5vZGVzLnB1c2goIGNvbnRleHQuY3JlYXRlVGV4dE5vZGUoIGVsZW0gKSApO1xuXG5cdFx0XHQvLyBDb252ZXJ0IGh0bWwgaW50byBET00gbm9kZXNcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRtcCA9IHRtcCB8fCBmcmFnbWVudC5hcHBlbmRDaGlsZCggY29udGV4dC5jcmVhdGVFbGVtZW50KCBcImRpdlwiICkgKTtcblxuXHRcdFx0XHQvLyBEZXNlcmlhbGl6ZSBhIHN0YW5kYXJkIHJlcHJlc2VudGF0aW9uXG5cdFx0XHRcdHRhZyA9ICggcnRhZ05hbWUuZXhlYyggZWxlbSApIHx8IFsgXCJcIiwgXCJcIiBdIClbIDEgXS50b0xvd2VyQ2FzZSgpO1xuXHRcdFx0XHR3cmFwID0gd3JhcE1hcFsgdGFnIF0gfHwgd3JhcE1hcC5fZGVmYXVsdDtcblx0XHRcdFx0dG1wLmlubmVySFRNTCA9IHdyYXBbIDEgXSArIGpRdWVyeS5odG1sUHJlZmlsdGVyKCBlbGVtICkgKyB3cmFwWyAyIF07XG5cblx0XHRcdFx0Ly8gRGVzY2VuZCB0aHJvdWdoIHdyYXBwZXJzIHRvIHRoZSByaWdodCBjb250ZW50XG5cdFx0XHRcdGogPSB3cmFwWyAwIF07XG5cdFx0XHRcdHdoaWxlICggai0tICkge1xuXHRcdFx0XHRcdHRtcCA9IHRtcC5sYXN0Q2hpbGQ7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBTdXBwb3J0OiBBbmRyb2lkIDw9NC4wIG9ubHksIFBoYW50b21KUyAxIG9ubHlcblx0XHRcdFx0Ly8gcHVzaC5hcHBseShfLCBhcnJheWxpa2UpIHRocm93cyBvbiBhbmNpZW50IFdlYktpdFxuXHRcdFx0XHRqUXVlcnkubWVyZ2UoIG5vZGVzLCB0bXAuY2hpbGROb2RlcyApO1xuXG5cdFx0XHRcdC8vIFJlbWVtYmVyIHRoZSB0b3AtbGV2ZWwgY29udGFpbmVyXG5cdFx0XHRcdHRtcCA9IGZyYWdtZW50LmZpcnN0Q2hpbGQ7XG5cblx0XHRcdFx0Ly8gRW5zdXJlIHRoZSBjcmVhdGVkIG5vZGVzIGFyZSBvcnBoYW5lZCAoIzEyMzkyKVxuXHRcdFx0XHR0bXAudGV4dENvbnRlbnQgPSBcIlwiO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdC8vIFJlbW92ZSB3cmFwcGVyIGZyb20gZnJhZ21lbnRcblx0ZnJhZ21lbnQudGV4dENvbnRlbnQgPSBcIlwiO1xuXG5cdGkgPSAwO1xuXHR3aGlsZSAoICggZWxlbSA9IG5vZGVzWyBpKysgXSApICkge1xuXG5cdFx0Ly8gU2tpcCBlbGVtZW50cyBhbHJlYWR5IGluIHRoZSBjb250ZXh0IGNvbGxlY3Rpb24gKHRyYWMtNDA4Nylcblx0XHRpZiAoIHNlbGVjdGlvbiAmJiBqUXVlcnkuaW5BcnJheSggZWxlbSwgc2VsZWN0aW9uICkgPiAtMSApIHtcblx0XHRcdGlmICggaWdub3JlZCApIHtcblx0XHRcdFx0aWdub3JlZC5wdXNoKCBlbGVtICk7XG5cdFx0XHR9XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cblx0XHRhdHRhY2hlZCA9IGlzQXR0YWNoZWQoIGVsZW0gKTtcblxuXHRcdC8vIEFwcGVuZCB0byBmcmFnbWVudFxuXHRcdHRtcCA9IGdldEFsbCggZnJhZ21lbnQuYXBwZW5kQ2hpbGQoIGVsZW0gKSwgXCJzY3JpcHRcIiApO1xuXG5cdFx0Ly8gUHJlc2VydmUgc2NyaXB0IGV2YWx1YXRpb24gaGlzdG9yeVxuXHRcdGlmICggYXR0YWNoZWQgKSB7XG5cdFx0XHRzZXRHbG9iYWxFdmFsKCB0bXAgKTtcblx0XHR9XG5cblx0XHQvLyBDYXB0dXJlIGV4ZWN1dGFibGVzXG5cdFx0aWYgKCBzY3JpcHRzICkge1xuXHRcdFx0aiA9IDA7XG5cdFx0XHR3aGlsZSAoICggZWxlbSA9IHRtcFsgaisrIF0gKSApIHtcblx0XHRcdFx0aWYgKCByc2NyaXB0VHlwZS50ZXN0KCBlbGVtLnR5cGUgfHwgXCJcIiApICkge1xuXHRcdFx0XHRcdHNjcmlwdHMucHVzaCggZWxlbSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIGZyYWdtZW50O1xufVxuXG5cbnZhciBydHlwZW5hbWVzcGFjZSA9IC9eKFteLl0qKSg/OlxcLiguKyl8KS87XG5cbmZ1bmN0aW9uIHJldHVyblRydWUoKSB7XG5cdHJldHVybiB0cnVlO1xufVxuXG5mdW5jdGlvbiByZXR1cm5GYWxzZSgpIHtcblx0cmV0dXJuIGZhbHNlO1xufVxuXG4vLyBTdXBwb3J0OiBJRSA8PTkgLSAxMStcbi8vIGZvY3VzKCkgYW5kIGJsdXIoKSBhcmUgYXN5bmNocm9ub3VzLCBleGNlcHQgd2hlbiB0aGV5IGFyZSBuby1vcC5cbi8vIFNvIGV4cGVjdCBmb2N1cyB0byBiZSBzeW5jaHJvbm91cyB3aGVuIHRoZSBlbGVtZW50IGlzIGFscmVhZHkgYWN0aXZlLFxuLy8gYW5kIGJsdXIgdG8gYmUgc3luY2hyb25vdXMgd2hlbiB0aGUgZWxlbWVudCBpcyBub3QgYWxyZWFkeSBhY3RpdmUuXG4vLyAoZm9jdXMgYW5kIGJsdXIgYXJlIGFsd2F5cyBzeW5jaHJvbm91cyBpbiBvdGhlciBzdXBwb3J0ZWQgYnJvd3NlcnMsXG4vLyB0aGlzIGp1c3QgZGVmaW5lcyB3aGVuIHdlIGNhbiBjb3VudCBvbiBpdCkuXG5mdW5jdGlvbiBleHBlY3RTeW5jKCBlbGVtLCB0eXBlICkge1xuXHRyZXR1cm4gKCBlbGVtID09PSBzYWZlQWN0aXZlRWxlbWVudCgpICkgPT09ICggdHlwZSA9PT0gXCJmb2N1c1wiICk7XG59XG5cbi8vIFN1cHBvcnQ6IElFIDw9OSBvbmx5XG4vLyBBY2Nlc3NpbmcgZG9jdW1lbnQuYWN0aXZlRWxlbWVudCBjYW4gdGhyb3cgdW5leHBlY3RlZGx5XG4vLyBodHRwczovL2J1Z3MuanF1ZXJ5LmNvbS90aWNrZXQvMTMzOTNcbmZ1bmN0aW9uIHNhZmVBY3RpdmVFbGVtZW50KCkge1xuXHR0cnkge1xuXHRcdHJldHVybiBkb2N1bWVudC5hY3RpdmVFbGVtZW50O1xuXHR9IGNhdGNoICggZXJyICkgeyB9XG59XG5cbmZ1bmN0aW9uIG9uKCBlbGVtLCB0eXBlcywgc2VsZWN0b3IsIGRhdGEsIGZuLCBvbmUgKSB7XG5cdHZhciBvcmlnRm4sIHR5cGU7XG5cblx0Ly8gVHlwZXMgY2FuIGJlIGEgbWFwIG9mIHR5cGVzL2hhbmRsZXJzXG5cdGlmICggdHlwZW9mIHR5cGVzID09PSBcIm9iamVjdFwiICkge1xuXG5cdFx0Ly8gKCB0eXBlcy1PYmplY3QsIHNlbGVjdG9yLCBkYXRhIClcblx0XHRpZiAoIHR5cGVvZiBzZWxlY3RvciAhPT0gXCJzdHJpbmdcIiApIHtcblxuXHRcdFx0Ly8gKCB0eXBlcy1PYmplY3QsIGRhdGEgKVxuXHRcdFx0ZGF0YSA9IGRhdGEgfHwgc2VsZWN0b3I7XG5cdFx0XHRzZWxlY3RvciA9IHVuZGVmaW5lZDtcblx0XHR9XG5cdFx0Zm9yICggdHlwZSBpbiB0eXBlcyApIHtcblx0XHRcdG9uKCBlbGVtLCB0eXBlLCBzZWxlY3RvciwgZGF0YSwgdHlwZXNbIHR5cGUgXSwgb25lICk7XG5cdFx0fVxuXHRcdHJldHVybiBlbGVtO1xuXHR9XG5cblx0aWYgKCBkYXRhID09IG51bGwgJiYgZm4gPT0gbnVsbCApIHtcblxuXHRcdC8vICggdHlwZXMsIGZuIClcblx0XHRmbiA9IHNlbGVjdG9yO1xuXHRcdGRhdGEgPSBzZWxlY3RvciA9IHVuZGVmaW5lZDtcblx0fSBlbHNlIGlmICggZm4gPT0gbnVsbCApIHtcblx0XHRpZiAoIHR5cGVvZiBzZWxlY3RvciA9PT0gXCJzdHJpbmdcIiApIHtcblxuXHRcdFx0Ly8gKCB0eXBlcywgc2VsZWN0b3IsIGZuIClcblx0XHRcdGZuID0gZGF0YTtcblx0XHRcdGRhdGEgPSB1bmRlZmluZWQ7XG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gKCB0eXBlcywgZGF0YSwgZm4gKVxuXHRcdFx0Zm4gPSBkYXRhO1xuXHRcdFx0ZGF0YSA9IHNlbGVjdG9yO1xuXHRcdFx0c2VsZWN0b3IgPSB1bmRlZmluZWQ7XG5cdFx0fVxuXHR9XG5cdGlmICggZm4gPT09IGZhbHNlICkge1xuXHRcdGZuID0gcmV0dXJuRmFsc2U7XG5cdH0gZWxzZSBpZiAoICFmbiApIHtcblx0XHRyZXR1cm4gZWxlbTtcblx0fVxuXG5cdGlmICggb25lID09PSAxICkge1xuXHRcdG9yaWdGbiA9IGZuO1xuXHRcdGZuID0gZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0XHQvLyBDYW4gdXNlIGFuIGVtcHR5IHNldCwgc2luY2UgZXZlbnQgY29udGFpbnMgdGhlIGluZm9cblx0XHRcdGpRdWVyeSgpLm9mZiggZXZlbnQgKTtcblx0XHRcdHJldHVybiBvcmlnRm4uYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdH07XG5cblx0XHQvLyBVc2Ugc2FtZSBndWlkIHNvIGNhbGxlciBjYW4gcmVtb3ZlIHVzaW5nIG9yaWdGblxuXHRcdGZuLmd1aWQgPSBvcmlnRm4uZ3VpZCB8fCAoIG9yaWdGbi5ndWlkID0galF1ZXJ5Lmd1aWQrKyApO1xuXHR9XG5cdHJldHVybiBlbGVtLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdGpRdWVyeS5ldmVudC5hZGQoIHRoaXMsIHR5cGVzLCBmbiwgZGF0YSwgc2VsZWN0b3IgKTtcblx0fSApO1xufVxuXG4vKlxuICogSGVscGVyIGZ1bmN0aW9ucyBmb3IgbWFuYWdpbmcgZXZlbnRzIC0tIG5vdCBwYXJ0IG9mIHRoZSBwdWJsaWMgaW50ZXJmYWNlLlxuICogUHJvcHMgdG8gRGVhbiBFZHdhcmRzJyBhZGRFdmVudCBsaWJyYXJ5IGZvciBtYW55IG9mIHRoZSBpZGVhcy5cbiAqL1xualF1ZXJ5LmV2ZW50ID0ge1xuXG5cdGdsb2JhbDoge30sXG5cblx0YWRkOiBmdW5jdGlvbiggZWxlbSwgdHlwZXMsIGhhbmRsZXIsIGRhdGEsIHNlbGVjdG9yICkge1xuXG5cdFx0dmFyIGhhbmRsZU9iakluLCBldmVudEhhbmRsZSwgdG1wLFxuXHRcdFx0ZXZlbnRzLCB0LCBoYW5kbGVPYmosXG5cdFx0XHRzcGVjaWFsLCBoYW5kbGVycywgdHlwZSwgbmFtZXNwYWNlcywgb3JpZ1R5cGUsXG5cdFx0XHRlbGVtRGF0YSA9IGRhdGFQcml2LmdldCggZWxlbSApO1xuXG5cdFx0Ly8gT25seSBhdHRhY2ggZXZlbnRzIHRvIG9iamVjdHMgdGhhdCBhY2NlcHQgZGF0YVxuXHRcdGlmICggIWFjY2VwdERhdGEoIGVsZW0gKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBDYWxsZXIgY2FuIHBhc3MgaW4gYW4gb2JqZWN0IG9mIGN1c3RvbSBkYXRhIGluIGxpZXUgb2YgdGhlIGhhbmRsZXJcblx0XHRpZiAoIGhhbmRsZXIuaGFuZGxlciApIHtcblx0XHRcdGhhbmRsZU9iakluID0gaGFuZGxlcjtcblx0XHRcdGhhbmRsZXIgPSBoYW5kbGVPYmpJbi5oYW5kbGVyO1xuXHRcdFx0c2VsZWN0b3IgPSBoYW5kbGVPYmpJbi5zZWxlY3Rvcjtcblx0XHR9XG5cblx0XHQvLyBFbnN1cmUgdGhhdCBpbnZhbGlkIHNlbGVjdG9ycyB0aHJvdyBleGNlcHRpb25zIGF0IGF0dGFjaCB0aW1lXG5cdFx0Ly8gRXZhbHVhdGUgYWdhaW5zdCBkb2N1bWVudEVsZW1lbnQgaW4gY2FzZSBlbGVtIGlzIGEgbm9uLWVsZW1lbnQgbm9kZSAoZS5nLiwgZG9jdW1lbnQpXG5cdFx0aWYgKCBzZWxlY3RvciApIHtcblx0XHRcdGpRdWVyeS5maW5kLm1hdGNoZXNTZWxlY3RvciggZG9jdW1lbnRFbGVtZW50LCBzZWxlY3RvciApO1xuXHRcdH1cblxuXHRcdC8vIE1ha2Ugc3VyZSB0aGF0IHRoZSBoYW5kbGVyIGhhcyBhIHVuaXF1ZSBJRCwgdXNlZCB0byBmaW5kL3JlbW92ZSBpdCBsYXRlclxuXHRcdGlmICggIWhhbmRsZXIuZ3VpZCApIHtcblx0XHRcdGhhbmRsZXIuZ3VpZCA9IGpRdWVyeS5ndWlkKys7XG5cdFx0fVxuXG5cdFx0Ly8gSW5pdCB0aGUgZWxlbWVudCdzIGV2ZW50IHN0cnVjdHVyZSBhbmQgbWFpbiBoYW5kbGVyLCBpZiB0aGlzIGlzIHRoZSBmaXJzdFxuXHRcdGlmICggISggZXZlbnRzID0gZWxlbURhdGEuZXZlbnRzICkgKSB7XG5cdFx0XHRldmVudHMgPSBlbGVtRGF0YS5ldmVudHMgPSBPYmplY3QuY3JlYXRlKCBudWxsICk7XG5cdFx0fVxuXHRcdGlmICggISggZXZlbnRIYW5kbGUgPSBlbGVtRGF0YS5oYW5kbGUgKSApIHtcblx0XHRcdGV2ZW50SGFuZGxlID0gZWxlbURhdGEuaGFuZGxlID0gZnVuY3Rpb24oIGUgKSB7XG5cblx0XHRcdFx0Ly8gRGlzY2FyZCB0aGUgc2Vjb25kIGV2ZW50IG9mIGEgalF1ZXJ5LmV2ZW50LnRyaWdnZXIoKSBhbmRcblx0XHRcdFx0Ly8gd2hlbiBhbiBldmVudCBpcyBjYWxsZWQgYWZ0ZXIgYSBwYWdlIGhhcyB1bmxvYWRlZFxuXHRcdFx0XHRyZXR1cm4gdHlwZW9mIGpRdWVyeSAhPT0gXCJ1bmRlZmluZWRcIiAmJiBqUXVlcnkuZXZlbnQudHJpZ2dlcmVkICE9PSBlLnR5cGUgP1xuXHRcdFx0XHRcdGpRdWVyeS5ldmVudC5kaXNwYXRjaC5hcHBseSggZWxlbSwgYXJndW1lbnRzICkgOiB1bmRlZmluZWQ7XG5cdFx0XHR9O1xuXHRcdH1cblxuXHRcdC8vIEhhbmRsZSBtdWx0aXBsZSBldmVudHMgc2VwYXJhdGVkIGJ5IGEgc3BhY2Vcblx0XHR0eXBlcyA9ICggdHlwZXMgfHwgXCJcIiApLm1hdGNoKCBybm90aHRtbHdoaXRlICkgfHwgWyBcIlwiIF07XG5cdFx0dCA9IHR5cGVzLmxlbmd0aDtcblx0XHR3aGlsZSAoIHQtLSApIHtcblx0XHRcdHRtcCA9IHJ0eXBlbmFtZXNwYWNlLmV4ZWMoIHR5cGVzWyB0IF0gKSB8fCBbXTtcblx0XHRcdHR5cGUgPSBvcmlnVHlwZSA9IHRtcFsgMSBdO1xuXHRcdFx0bmFtZXNwYWNlcyA9ICggdG1wWyAyIF0gfHwgXCJcIiApLnNwbGl0KCBcIi5cIiApLnNvcnQoKTtcblxuXHRcdFx0Ly8gVGhlcmUgKm11c3QqIGJlIGEgdHlwZSwgbm8gYXR0YWNoaW5nIG5hbWVzcGFjZS1vbmx5IGhhbmRsZXJzXG5cdFx0XHRpZiAoICF0eXBlICkge1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gSWYgZXZlbnQgY2hhbmdlcyBpdHMgdHlwZSwgdXNlIHRoZSBzcGVjaWFsIGV2ZW50IGhhbmRsZXJzIGZvciB0aGUgY2hhbmdlZCB0eXBlXG5cdFx0XHRzcGVjaWFsID0galF1ZXJ5LmV2ZW50LnNwZWNpYWxbIHR5cGUgXSB8fCB7fTtcblxuXHRcdFx0Ly8gSWYgc2VsZWN0b3IgZGVmaW5lZCwgZGV0ZXJtaW5lIHNwZWNpYWwgZXZlbnQgYXBpIHR5cGUsIG90aGVyd2lzZSBnaXZlbiB0eXBlXG5cdFx0XHR0eXBlID0gKCBzZWxlY3RvciA/IHNwZWNpYWwuZGVsZWdhdGVUeXBlIDogc3BlY2lhbC5iaW5kVHlwZSApIHx8IHR5cGU7XG5cblx0XHRcdC8vIFVwZGF0ZSBzcGVjaWFsIGJhc2VkIG9uIG5ld2x5IHJlc2V0IHR5cGVcblx0XHRcdHNwZWNpYWwgPSBqUXVlcnkuZXZlbnQuc3BlY2lhbFsgdHlwZSBdIHx8IHt9O1xuXG5cdFx0XHQvLyBoYW5kbGVPYmogaXMgcGFzc2VkIHRvIGFsbCBldmVudCBoYW5kbGVyc1xuXHRcdFx0aGFuZGxlT2JqID0galF1ZXJ5LmV4dGVuZCgge1xuXHRcdFx0XHR0eXBlOiB0eXBlLFxuXHRcdFx0XHRvcmlnVHlwZTogb3JpZ1R5cGUsXG5cdFx0XHRcdGRhdGE6IGRhdGEsXG5cdFx0XHRcdGhhbmRsZXI6IGhhbmRsZXIsXG5cdFx0XHRcdGd1aWQ6IGhhbmRsZXIuZ3VpZCxcblx0XHRcdFx0c2VsZWN0b3I6IHNlbGVjdG9yLFxuXHRcdFx0XHRuZWVkc0NvbnRleHQ6IHNlbGVjdG9yICYmIGpRdWVyeS5leHByLm1hdGNoLm5lZWRzQ29udGV4dC50ZXN0KCBzZWxlY3RvciApLFxuXHRcdFx0XHRuYW1lc3BhY2U6IG5hbWVzcGFjZXMuam9pbiggXCIuXCIgKVxuXHRcdFx0fSwgaGFuZGxlT2JqSW4gKTtcblxuXHRcdFx0Ly8gSW5pdCB0aGUgZXZlbnQgaGFuZGxlciBxdWV1ZSBpZiB3ZSdyZSB0aGUgZmlyc3Rcblx0XHRcdGlmICggISggaGFuZGxlcnMgPSBldmVudHNbIHR5cGUgXSApICkge1xuXHRcdFx0XHRoYW5kbGVycyA9IGV2ZW50c1sgdHlwZSBdID0gW107XG5cdFx0XHRcdGhhbmRsZXJzLmRlbGVnYXRlQ291bnQgPSAwO1xuXG5cdFx0XHRcdC8vIE9ubHkgdXNlIGFkZEV2ZW50TGlzdGVuZXIgaWYgdGhlIHNwZWNpYWwgZXZlbnRzIGhhbmRsZXIgcmV0dXJucyBmYWxzZVxuXHRcdFx0XHRpZiAoICFzcGVjaWFsLnNldHVwIHx8XG5cdFx0XHRcdFx0c3BlY2lhbC5zZXR1cC5jYWxsKCBlbGVtLCBkYXRhLCBuYW1lc3BhY2VzLCBldmVudEhhbmRsZSApID09PSBmYWxzZSApIHtcblxuXHRcdFx0XHRcdGlmICggZWxlbS5hZGRFdmVudExpc3RlbmVyICkge1xuXHRcdFx0XHRcdFx0ZWxlbS5hZGRFdmVudExpc3RlbmVyKCB0eXBlLCBldmVudEhhbmRsZSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHNwZWNpYWwuYWRkICkge1xuXHRcdFx0XHRzcGVjaWFsLmFkZC5jYWxsKCBlbGVtLCBoYW5kbGVPYmogKTtcblxuXHRcdFx0XHRpZiAoICFoYW5kbGVPYmouaGFuZGxlci5ndWlkICkge1xuXHRcdFx0XHRcdGhhbmRsZU9iai5oYW5kbGVyLmd1aWQgPSBoYW5kbGVyLmd1aWQ7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Ly8gQWRkIHRvIHRoZSBlbGVtZW50J3MgaGFuZGxlciBsaXN0LCBkZWxlZ2F0ZXMgaW4gZnJvbnRcblx0XHRcdGlmICggc2VsZWN0b3IgKSB7XG5cdFx0XHRcdGhhbmRsZXJzLnNwbGljZSggaGFuZGxlcnMuZGVsZWdhdGVDb3VudCsrLCAwLCBoYW5kbGVPYmogKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGhhbmRsZXJzLnB1c2goIGhhbmRsZU9iaiApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBLZWVwIHRyYWNrIG9mIHdoaWNoIGV2ZW50cyBoYXZlIGV2ZXIgYmVlbiB1c2VkLCBmb3IgZXZlbnQgb3B0aW1pemF0aW9uXG5cdFx0XHRqUXVlcnkuZXZlbnQuZ2xvYmFsWyB0eXBlIF0gPSB0cnVlO1xuXHRcdH1cblxuXHR9LFxuXG5cdC8vIERldGFjaCBhbiBldmVudCBvciBzZXQgb2YgZXZlbnRzIGZyb20gYW4gZWxlbWVudFxuXHRyZW1vdmU6IGZ1bmN0aW9uKCBlbGVtLCB0eXBlcywgaGFuZGxlciwgc2VsZWN0b3IsIG1hcHBlZFR5cGVzICkge1xuXG5cdFx0dmFyIGosIG9yaWdDb3VudCwgdG1wLFxuXHRcdFx0ZXZlbnRzLCB0LCBoYW5kbGVPYmosXG5cdFx0XHRzcGVjaWFsLCBoYW5kbGVycywgdHlwZSwgbmFtZXNwYWNlcywgb3JpZ1R5cGUsXG5cdFx0XHRlbGVtRGF0YSA9IGRhdGFQcml2Lmhhc0RhdGEoIGVsZW0gKSAmJiBkYXRhUHJpdi5nZXQoIGVsZW0gKTtcblxuXHRcdGlmICggIWVsZW1EYXRhIHx8ICEoIGV2ZW50cyA9IGVsZW1EYXRhLmV2ZW50cyApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIE9uY2UgZm9yIGVhY2ggdHlwZS5uYW1lc3BhY2UgaW4gdHlwZXM7IHR5cGUgbWF5IGJlIG9taXR0ZWRcblx0XHR0eXBlcyA9ICggdHlwZXMgfHwgXCJcIiApLm1hdGNoKCBybm90aHRtbHdoaXRlICkgfHwgWyBcIlwiIF07XG5cdFx0dCA9IHR5cGVzLmxlbmd0aDtcblx0XHR3aGlsZSAoIHQtLSApIHtcblx0XHRcdHRtcCA9IHJ0eXBlbmFtZXNwYWNlLmV4ZWMoIHR5cGVzWyB0IF0gKSB8fCBbXTtcblx0XHRcdHR5cGUgPSBvcmlnVHlwZSA9IHRtcFsgMSBdO1xuXHRcdFx0bmFtZXNwYWNlcyA9ICggdG1wWyAyIF0gfHwgXCJcIiApLnNwbGl0KCBcIi5cIiApLnNvcnQoKTtcblxuXHRcdFx0Ly8gVW5iaW5kIGFsbCBldmVudHMgKG9uIHRoaXMgbmFtZXNwYWNlLCBpZiBwcm92aWRlZCkgZm9yIHRoZSBlbGVtZW50XG5cdFx0XHRpZiAoICF0eXBlICkge1xuXHRcdFx0XHRmb3IgKCB0eXBlIGluIGV2ZW50cyApIHtcblx0XHRcdFx0XHRqUXVlcnkuZXZlbnQucmVtb3ZlKCBlbGVtLCB0eXBlICsgdHlwZXNbIHQgXSwgaGFuZGxlciwgc2VsZWN0b3IsIHRydWUgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0c3BlY2lhbCA9IGpRdWVyeS5ldmVudC5zcGVjaWFsWyB0eXBlIF0gfHwge307XG5cdFx0XHR0eXBlID0gKCBzZWxlY3RvciA/IHNwZWNpYWwuZGVsZWdhdGVUeXBlIDogc3BlY2lhbC5iaW5kVHlwZSApIHx8IHR5cGU7XG5cdFx0XHRoYW5kbGVycyA9IGV2ZW50c1sgdHlwZSBdIHx8IFtdO1xuXHRcdFx0dG1wID0gdG1wWyAyIF0gJiZcblx0XHRcdFx0bmV3IFJlZ0V4cCggXCIoXnxcXFxcLilcIiArIG5hbWVzcGFjZXMuam9pbiggXCJcXFxcLig/Oi4qXFxcXC58KVwiICkgKyBcIihcXFxcLnwkKVwiICk7XG5cblx0XHRcdC8vIFJlbW92ZSBtYXRjaGluZyBldmVudHNcblx0XHRcdG9yaWdDb3VudCA9IGogPSBoYW5kbGVycy5sZW5ndGg7XG5cdFx0XHR3aGlsZSAoIGotLSApIHtcblx0XHRcdFx0aGFuZGxlT2JqID0gaGFuZGxlcnNbIGogXTtcblxuXHRcdFx0XHRpZiAoICggbWFwcGVkVHlwZXMgfHwgb3JpZ1R5cGUgPT09IGhhbmRsZU9iai5vcmlnVHlwZSApICYmXG5cdFx0XHRcdFx0KCAhaGFuZGxlciB8fCBoYW5kbGVyLmd1aWQgPT09IGhhbmRsZU9iai5ndWlkICkgJiZcblx0XHRcdFx0XHQoICF0bXAgfHwgdG1wLnRlc3QoIGhhbmRsZU9iai5uYW1lc3BhY2UgKSApICYmXG5cdFx0XHRcdFx0KCAhc2VsZWN0b3IgfHwgc2VsZWN0b3IgPT09IGhhbmRsZU9iai5zZWxlY3RvciB8fFxuXHRcdFx0XHRcdFx0c2VsZWN0b3IgPT09IFwiKipcIiAmJiBoYW5kbGVPYmouc2VsZWN0b3IgKSApIHtcblx0XHRcdFx0XHRoYW5kbGVycy5zcGxpY2UoIGosIDEgKTtcblxuXHRcdFx0XHRcdGlmICggaGFuZGxlT2JqLnNlbGVjdG9yICkge1xuXHRcdFx0XHRcdFx0aGFuZGxlcnMuZGVsZWdhdGVDb3VudC0tO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRpZiAoIHNwZWNpYWwucmVtb3ZlICkge1xuXHRcdFx0XHRcdFx0c3BlY2lhbC5yZW1vdmUuY2FsbCggZWxlbSwgaGFuZGxlT2JqICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vIFJlbW92ZSBnZW5lcmljIGV2ZW50IGhhbmRsZXIgaWYgd2UgcmVtb3ZlZCBzb21ldGhpbmcgYW5kIG5vIG1vcmUgaGFuZGxlcnMgZXhpc3Rcblx0XHRcdC8vIChhdm9pZHMgcG90ZW50aWFsIGZvciBlbmRsZXNzIHJlY3Vyc2lvbiBkdXJpbmcgcmVtb3ZhbCBvZiBzcGVjaWFsIGV2ZW50IGhhbmRsZXJzKVxuXHRcdFx0aWYgKCBvcmlnQ291bnQgJiYgIWhhbmRsZXJzLmxlbmd0aCApIHtcblx0XHRcdFx0aWYgKCAhc3BlY2lhbC50ZWFyZG93biB8fFxuXHRcdFx0XHRcdHNwZWNpYWwudGVhcmRvd24uY2FsbCggZWxlbSwgbmFtZXNwYWNlcywgZWxlbURhdGEuaGFuZGxlICkgPT09IGZhbHNlICkge1xuXG5cdFx0XHRcdFx0alF1ZXJ5LnJlbW92ZUV2ZW50KCBlbGVtLCB0eXBlLCBlbGVtRGF0YS5oYW5kbGUgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGRlbGV0ZSBldmVudHNbIHR5cGUgXTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBSZW1vdmUgZGF0YSBhbmQgdGhlIGV4cGFuZG8gaWYgaXQncyBubyBsb25nZXIgdXNlZFxuXHRcdGlmICggalF1ZXJ5LmlzRW1wdHlPYmplY3QoIGV2ZW50cyApICkge1xuXHRcdFx0ZGF0YVByaXYucmVtb3ZlKCBlbGVtLCBcImhhbmRsZSBldmVudHNcIiApO1xuXHRcdH1cblx0fSxcblxuXHRkaXNwYXRjaDogZnVuY3Rpb24oIG5hdGl2ZUV2ZW50ICkge1xuXG5cdFx0dmFyIGksIGosIHJldCwgbWF0Y2hlZCwgaGFuZGxlT2JqLCBoYW5kbGVyUXVldWUsXG5cdFx0XHRhcmdzID0gbmV3IEFycmF5KCBhcmd1bWVudHMubGVuZ3RoICksXG5cblx0XHRcdC8vIE1ha2UgYSB3cml0YWJsZSBqUXVlcnkuRXZlbnQgZnJvbSB0aGUgbmF0aXZlIGV2ZW50IG9iamVjdFxuXHRcdFx0ZXZlbnQgPSBqUXVlcnkuZXZlbnQuZml4KCBuYXRpdmVFdmVudCApLFxuXG5cdFx0XHRoYW5kbGVycyA9IChcblx0XHRcdFx0ZGF0YVByaXYuZ2V0KCB0aGlzLCBcImV2ZW50c1wiICkgfHwgT2JqZWN0LmNyZWF0ZSggbnVsbCApXG5cdFx0XHQpWyBldmVudC50eXBlIF0gfHwgW10sXG5cdFx0XHRzcGVjaWFsID0galF1ZXJ5LmV2ZW50LnNwZWNpYWxbIGV2ZW50LnR5cGUgXSB8fCB7fTtcblxuXHRcdC8vIFVzZSB0aGUgZml4LWVkIGpRdWVyeS5FdmVudCByYXRoZXIgdGhhbiB0aGUgKHJlYWQtb25seSkgbmF0aXZlIGV2ZW50XG5cdFx0YXJnc1sgMCBdID0gZXZlbnQ7XG5cblx0XHRmb3IgKCBpID0gMTsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKyApIHtcblx0XHRcdGFyZ3NbIGkgXSA9IGFyZ3VtZW50c1sgaSBdO1xuXHRcdH1cblxuXHRcdGV2ZW50LmRlbGVnYXRlVGFyZ2V0ID0gdGhpcztcblxuXHRcdC8vIENhbGwgdGhlIHByZURpc3BhdGNoIGhvb2sgZm9yIHRoZSBtYXBwZWQgdHlwZSwgYW5kIGxldCBpdCBiYWlsIGlmIGRlc2lyZWRcblx0XHRpZiAoIHNwZWNpYWwucHJlRGlzcGF0Y2ggJiYgc3BlY2lhbC5wcmVEaXNwYXRjaC5jYWxsKCB0aGlzLCBldmVudCApID09PSBmYWxzZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBEZXRlcm1pbmUgaGFuZGxlcnNcblx0XHRoYW5kbGVyUXVldWUgPSBqUXVlcnkuZXZlbnQuaGFuZGxlcnMuY2FsbCggdGhpcywgZXZlbnQsIGhhbmRsZXJzICk7XG5cblx0XHQvLyBSdW4gZGVsZWdhdGVzIGZpcnN0OyB0aGV5IG1heSB3YW50IHRvIHN0b3AgcHJvcGFnYXRpb24gYmVuZWF0aCB1c1xuXHRcdGkgPSAwO1xuXHRcdHdoaWxlICggKCBtYXRjaGVkID0gaGFuZGxlclF1ZXVlWyBpKysgXSApICYmICFldmVudC5pc1Byb3BhZ2F0aW9uU3RvcHBlZCgpICkge1xuXHRcdFx0ZXZlbnQuY3VycmVudFRhcmdldCA9IG1hdGNoZWQuZWxlbTtcblxuXHRcdFx0aiA9IDA7XG5cdFx0XHR3aGlsZSAoICggaGFuZGxlT2JqID0gbWF0Y2hlZC5oYW5kbGVyc1sgaisrIF0gKSAmJlxuXHRcdFx0XHQhZXZlbnQuaXNJbW1lZGlhdGVQcm9wYWdhdGlvblN0b3BwZWQoKSApIHtcblxuXHRcdFx0XHQvLyBJZiB0aGUgZXZlbnQgaXMgbmFtZXNwYWNlZCwgdGhlbiBlYWNoIGhhbmRsZXIgaXMgb25seSBpbnZva2VkIGlmIGl0IGlzXG5cdFx0XHRcdC8vIHNwZWNpYWxseSB1bml2ZXJzYWwgb3IgaXRzIG5hbWVzcGFjZXMgYXJlIGEgc3VwZXJzZXQgb2YgdGhlIGV2ZW50J3MuXG5cdFx0XHRcdGlmICggIWV2ZW50LnJuYW1lc3BhY2UgfHwgaGFuZGxlT2JqLm5hbWVzcGFjZSA9PT0gZmFsc2UgfHxcblx0XHRcdFx0XHRldmVudC5ybmFtZXNwYWNlLnRlc3QoIGhhbmRsZU9iai5uYW1lc3BhY2UgKSApIHtcblxuXHRcdFx0XHRcdGV2ZW50LmhhbmRsZU9iaiA9IGhhbmRsZU9iajtcblx0XHRcdFx0XHRldmVudC5kYXRhID0gaGFuZGxlT2JqLmRhdGE7XG5cblx0XHRcdFx0XHRyZXQgPSAoICggalF1ZXJ5LmV2ZW50LnNwZWNpYWxbIGhhbmRsZU9iai5vcmlnVHlwZSBdIHx8IHt9ICkuaGFuZGxlIHx8XG5cdFx0XHRcdFx0XHRoYW5kbGVPYmouaGFuZGxlciApLmFwcGx5KCBtYXRjaGVkLmVsZW0sIGFyZ3MgKTtcblxuXHRcdFx0XHRcdGlmICggcmV0ICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0XHRpZiAoICggZXZlbnQucmVzdWx0ID0gcmV0ICkgPT09IGZhbHNlICkge1xuXHRcdFx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdFx0XHRldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBDYWxsIHRoZSBwb3N0RGlzcGF0Y2ggaG9vayBmb3IgdGhlIG1hcHBlZCB0eXBlXG5cdFx0aWYgKCBzcGVjaWFsLnBvc3REaXNwYXRjaCApIHtcblx0XHRcdHNwZWNpYWwucG9zdERpc3BhdGNoLmNhbGwoIHRoaXMsIGV2ZW50ICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGV2ZW50LnJlc3VsdDtcblx0fSxcblxuXHRoYW5kbGVyczogZnVuY3Rpb24oIGV2ZW50LCBoYW5kbGVycyApIHtcblx0XHR2YXIgaSwgaGFuZGxlT2JqLCBzZWwsIG1hdGNoZWRIYW5kbGVycywgbWF0Y2hlZFNlbGVjdG9ycyxcblx0XHRcdGhhbmRsZXJRdWV1ZSA9IFtdLFxuXHRcdFx0ZGVsZWdhdGVDb3VudCA9IGhhbmRsZXJzLmRlbGVnYXRlQ291bnQsXG5cdFx0XHRjdXIgPSBldmVudC50YXJnZXQ7XG5cblx0XHQvLyBGaW5kIGRlbGVnYXRlIGhhbmRsZXJzXG5cdFx0aWYgKCBkZWxlZ2F0ZUNvdW50ICYmXG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFIDw9OVxuXHRcdFx0Ly8gQmxhY2staG9sZSBTVkcgPHVzZT4gaW5zdGFuY2UgdHJlZXMgKHRyYWMtMTMxODApXG5cdFx0XHRjdXIubm9kZVR5cGUgJiZcblxuXHRcdFx0Ly8gU3VwcG9ydDogRmlyZWZveCA8PTQyXG5cdFx0XHQvLyBTdXBwcmVzcyBzcGVjLXZpb2xhdGluZyBjbGlja3MgaW5kaWNhdGluZyBhIG5vbi1wcmltYXJ5IHBvaW50ZXIgYnV0dG9uICh0cmFjLTM4NjEpXG5cdFx0XHQvLyBodHRwczovL3d3dy53My5vcmcvVFIvRE9NLUxldmVsLTMtRXZlbnRzLyNldmVudC10eXBlLWNsaWNrXG5cdFx0XHQvLyBTdXBwb3J0OiBJRSAxMSBvbmx5XG5cdFx0XHQvLyAuLi5idXQgbm90IGFycm93IGtleSBcImNsaWNrc1wiIG9mIHJhZGlvIGlucHV0cywgd2hpY2ggY2FuIGhhdmUgYGJ1dHRvbmAgLTEgKGdoLTIzNDMpXG5cdFx0XHQhKCBldmVudC50eXBlID09PSBcImNsaWNrXCIgJiYgZXZlbnQuYnV0dG9uID49IDEgKSApIHtcblxuXHRcdFx0Zm9yICggOyBjdXIgIT09IHRoaXM7IGN1ciA9IGN1ci5wYXJlbnROb2RlIHx8IHRoaXMgKSB7XG5cblx0XHRcdFx0Ly8gRG9uJ3QgY2hlY2sgbm9uLWVsZW1lbnRzICgjMTMyMDgpXG5cdFx0XHRcdC8vIERvbid0IHByb2Nlc3MgY2xpY2tzIG9uIGRpc2FibGVkIGVsZW1lbnRzICgjNjkxMSwgIzgxNjUsICMxMTM4MiwgIzExNzY0KVxuXHRcdFx0XHRpZiAoIGN1ci5ub2RlVHlwZSA9PT0gMSAmJiAhKCBldmVudC50eXBlID09PSBcImNsaWNrXCIgJiYgY3VyLmRpc2FibGVkID09PSB0cnVlICkgKSB7XG5cdFx0XHRcdFx0bWF0Y2hlZEhhbmRsZXJzID0gW107XG5cdFx0XHRcdFx0bWF0Y2hlZFNlbGVjdG9ycyA9IHt9O1xuXHRcdFx0XHRcdGZvciAoIGkgPSAwOyBpIDwgZGVsZWdhdGVDb3VudDsgaSsrICkge1xuXHRcdFx0XHRcdFx0aGFuZGxlT2JqID0gaGFuZGxlcnNbIGkgXTtcblxuXHRcdFx0XHRcdFx0Ly8gRG9uJ3QgY29uZmxpY3Qgd2l0aCBPYmplY3QucHJvdG90eXBlIHByb3BlcnRpZXMgKCMxMzIwMylcblx0XHRcdFx0XHRcdHNlbCA9IGhhbmRsZU9iai5zZWxlY3RvciArIFwiIFwiO1xuXG5cdFx0XHRcdFx0XHRpZiAoIG1hdGNoZWRTZWxlY3RvcnNbIHNlbCBdID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0XHRcdG1hdGNoZWRTZWxlY3RvcnNbIHNlbCBdID0gaGFuZGxlT2JqLm5lZWRzQ29udGV4dCA/XG5cdFx0XHRcdFx0XHRcdFx0alF1ZXJ5KCBzZWwsIHRoaXMgKS5pbmRleCggY3VyICkgPiAtMSA6XG5cdFx0XHRcdFx0XHRcdFx0alF1ZXJ5LmZpbmQoIHNlbCwgdGhpcywgbnVsbCwgWyBjdXIgXSApLmxlbmd0aDtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGlmICggbWF0Y2hlZFNlbGVjdG9yc1sgc2VsIF0gKSB7XG5cdFx0XHRcdFx0XHRcdG1hdGNoZWRIYW5kbGVycy5wdXNoKCBoYW5kbGVPYmogKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKCBtYXRjaGVkSGFuZGxlcnMubGVuZ3RoICkge1xuXHRcdFx0XHRcdFx0aGFuZGxlclF1ZXVlLnB1c2goIHsgZWxlbTogY3VyLCBoYW5kbGVyczogbWF0Y2hlZEhhbmRsZXJzIH0gKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBBZGQgdGhlIHJlbWFpbmluZyAoZGlyZWN0bHktYm91bmQpIGhhbmRsZXJzXG5cdFx0Y3VyID0gdGhpcztcblx0XHRpZiAoIGRlbGVnYXRlQ291bnQgPCBoYW5kbGVycy5sZW5ndGggKSB7XG5cdFx0XHRoYW5kbGVyUXVldWUucHVzaCggeyBlbGVtOiBjdXIsIGhhbmRsZXJzOiBoYW5kbGVycy5zbGljZSggZGVsZWdhdGVDb3VudCApIH0gKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gaGFuZGxlclF1ZXVlO1xuXHR9LFxuXG5cdGFkZFByb3A6IGZ1bmN0aW9uKCBuYW1lLCBob29rICkge1xuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSggalF1ZXJ5LkV2ZW50LnByb3RvdHlwZSwgbmFtZSwge1xuXHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcblx0XHRcdGNvbmZpZ3VyYWJsZTogdHJ1ZSxcblxuXHRcdFx0Z2V0OiBpc0Z1bmN0aW9uKCBob29rICkgP1xuXHRcdFx0XHRmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRpZiAoIHRoaXMub3JpZ2luYWxFdmVudCApIHtcblx0XHRcdFx0XHRcdHJldHVybiBob29rKCB0aGlzLm9yaWdpbmFsRXZlbnQgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gOlxuXHRcdFx0XHRmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRpZiAoIHRoaXMub3JpZ2luYWxFdmVudCApIHtcblx0XHRcdFx0XHRcdHJldHVybiB0aGlzLm9yaWdpbmFsRXZlbnRbIG5hbWUgXTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0sXG5cblx0XHRcdHNldDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoIHRoaXMsIG5hbWUsIHtcblx0XHRcdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxuXHRcdFx0XHRcdGNvbmZpZ3VyYWJsZTogdHJ1ZSxcblx0XHRcdFx0XHR3cml0YWJsZTogdHJ1ZSxcblx0XHRcdFx0XHR2YWx1ZTogdmFsdWVcblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRmaXg6IGZ1bmN0aW9uKCBvcmlnaW5hbEV2ZW50ICkge1xuXHRcdHJldHVybiBvcmlnaW5hbEV2ZW50WyBqUXVlcnkuZXhwYW5kbyBdID9cblx0XHRcdG9yaWdpbmFsRXZlbnQgOlxuXHRcdFx0bmV3IGpRdWVyeS5FdmVudCggb3JpZ2luYWxFdmVudCApO1xuXHR9LFxuXG5cdHNwZWNpYWw6IHtcblx0XHRsb2FkOiB7XG5cblx0XHRcdC8vIFByZXZlbnQgdHJpZ2dlcmVkIGltYWdlLmxvYWQgZXZlbnRzIGZyb20gYnViYmxpbmcgdG8gd2luZG93LmxvYWRcblx0XHRcdG5vQnViYmxlOiB0cnVlXG5cdFx0fSxcblx0XHRjbGljazoge1xuXG5cdFx0XHQvLyBVdGlsaXplIG5hdGl2ZSBldmVudCB0byBlbnN1cmUgY29ycmVjdCBzdGF0ZSBmb3IgY2hlY2thYmxlIGlucHV0c1xuXHRcdFx0c2V0dXA6IGZ1bmN0aW9uKCBkYXRhICkge1xuXG5cdFx0XHRcdC8vIEZvciBtdXR1YWwgY29tcHJlc3NpYmlsaXR5IHdpdGggX2RlZmF1bHQsIHJlcGxhY2UgYHRoaXNgIGFjY2VzcyB3aXRoIGEgbG9jYWwgdmFyLlxuXHRcdFx0XHQvLyBgfHwgZGF0YWAgaXMgZGVhZCBjb2RlIG1lYW50IG9ubHkgdG8gcHJlc2VydmUgdGhlIHZhcmlhYmxlIHRocm91Z2ggbWluaWZpY2F0aW9uLlxuXHRcdFx0XHR2YXIgZWwgPSB0aGlzIHx8IGRhdGE7XG5cblx0XHRcdFx0Ly8gQ2xhaW0gdGhlIGZpcnN0IGhhbmRsZXJcblx0XHRcdFx0aWYgKCByY2hlY2thYmxlVHlwZS50ZXN0KCBlbC50eXBlICkgJiZcblx0XHRcdFx0XHRlbC5jbGljayAmJiBub2RlTmFtZSggZWwsIFwiaW5wdXRcIiApICkge1xuXG5cdFx0XHRcdFx0Ly8gZGF0YVByaXYuc2V0KCBlbCwgXCJjbGlja1wiLCAuLi4gKVxuXHRcdFx0XHRcdGxldmVyYWdlTmF0aXZlKCBlbCwgXCJjbGlja1wiLCByZXR1cm5UcnVlICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBSZXR1cm4gZmFsc2UgdG8gYWxsb3cgbm9ybWFsIHByb2Nlc3NpbmcgaW4gdGhlIGNhbGxlclxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9LFxuXHRcdFx0dHJpZ2dlcjogZnVuY3Rpb24oIGRhdGEgKSB7XG5cblx0XHRcdFx0Ly8gRm9yIG11dHVhbCBjb21wcmVzc2liaWxpdHkgd2l0aCBfZGVmYXVsdCwgcmVwbGFjZSBgdGhpc2AgYWNjZXNzIHdpdGggYSBsb2NhbCB2YXIuXG5cdFx0XHRcdC8vIGB8fCBkYXRhYCBpcyBkZWFkIGNvZGUgbWVhbnQgb25seSB0byBwcmVzZXJ2ZSB0aGUgdmFyaWFibGUgdGhyb3VnaCBtaW5pZmljYXRpb24uXG5cdFx0XHRcdHZhciBlbCA9IHRoaXMgfHwgZGF0YTtcblxuXHRcdFx0XHQvLyBGb3JjZSBzZXR1cCBiZWZvcmUgdHJpZ2dlcmluZyBhIGNsaWNrXG5cdFx0XHRcdGlmICggcmNoZWNrYWJsZVR5cGUudGVzdCggZWwudHlwZSApICYmXG5cdFx0XHRcdFx0ZWwuY2xpY2sgJiYgbm9kZU5hbWUoIGVsLCBcImlucHV0XCIgKSApIHtcblxuXHRcdFx0XHRcdGxldmVyYWdlTmF0aXZlKCBlbCwgXCJjbGlja1wiICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBSZXR1cm4gbm9uLWZhbHNlIHRvIGFsbG93IG5vcm1hbCBldmVudC1wYXRoIHByb3BhZ2F0aW9uXG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fSxcblxuXHRcdFx0Ly8gRm9yIGNyb3NzLWJyb3dzZXIgY29uc2lzdGVuY3ksIHN1cHByZXNzIG5hdGl2ZSAuY2xpY2soKSBvbiBsaW5rc1xuXHRcdFx0Ly8gQWxzbyBwcmV2ZW50IGl0IGlmIHdlJ3JlIGN1cnJlbnRseSBpbnNpZGUgYSBsZXZlcmFnZWQgbmF0aXZlLWV2ZW50IHN0YWNrXG5cdFx0XHRfZGVmYXVsdDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHR2YXIgdGFyZ2V0ID0gZXZlbnQudGFyZ2V0O1xuXHRcdFx0XHRyZXR1cm4gcmNoZWNrYWJsZVR5cGUudGVzdCggdGFyZ2V0LnR5cGUgKSAmJlxuXHRcdFx0XHRcdHRhcmdldC5jbGljayAmJiBub2RlTmFtZSggdGFyZ2V0LCBcImlucHV0XCIgKSAmJlxuXHRcdFx0XHRcdGRhdGFQcml2LmdldCggdGFyZ2V0LCBcImNsaWNrXCIgKSB8fFxuXHRcdFx0XHRcdG5vZGVOYW1lKCB0YXJnZXQsIFwiYVwiICk7XG5cdFx0XHR9XG5cdFx0fSxcblxuXHRcdGJlZm9yZXVubG9hZDoge1xuXHRcdFx0cG9zdERpc3BhdGNoOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHRcdFx0Ly8gU3VwcG9ydDogRmlyZWZveCAyMCtcblx0XHRcdFx0Ly8gRmlyZWZveCBkb2Vzbid0IGFsZXJ0IGlmIHRoZSByZXR1cm5WYWx1ZSBmaWVsZCBpcyBub3Qgc2V0LlxuXHRcdFx0XHRpZiAoIGV2ZW50LnJlc3VsdCAhPT0gdW5kZWZpbmVkICYmIGV2ZW50Lm9yaWdpbmFsRXZlbnQgKSB7XG5cdFx0XHRcdFx0ZXZlbnQub3JpZ2luYWxFdmVudC5yZXR1cm5WYWx1ZSA9IGV2ZW50LnJlc3VsdDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxufTtcblxuLy8gRW5zdXJlIHRoZSBwcmVzZW5jZSBvZiBhbiBldmVudCBsaXN0ZW5lciB0aGF0IGhhbmRsZXMgbWFudWFsbHktdHJpZ2dlcmVkXG4vLyBzeW50aGV0aWMgZXZlbnRzIGJ5IGludGVycnVwdGluZyBwcm9ncmVzcyB1bnRpbCByZWludm9rZWQgaW4gcmVzcG9uc2UgdG9cbi8vICpuYXRpdmUqIGV2ZW50cyB0aGF0IGl0IGZpcmVzIGRpcmVjdGx5LCBlbnN1cmluZyB0aGF0IHN0YXRlIGNoYW5nZXMgaGF2ZVxuLy8gYWxyZWFkeSBvY2N1cnJlZCBiZWZvcmUgb3RoZXIgbGlzdGVuZXJzIGFyZSBpbnZva2VkLlxuZnVuY3Rpb24gbGV2ZXJhZ2VOYXRpdmUoIGVsLCB0eXBlLCBleHBlY3RTeW5jICkge1xuXG5cdC8vIE1pc3NpbmcgZXhwZWN0U3luYyBpbmRpY2F0ZXMgYSB0cmlnZ2VyIGNhbGwsIHdoaWNoIG11c3QgZm9yY2Ugc2V0dXAgdGhyb3VnaCBqUXVlcnkuZXZlbnQuYWRkXG5cdGlmICggIWV4cGVjdFN5bmMgKSB7XG5cdFx0aWYgKCBkYXRhUHJpdi5nZXQoIGVsLCB0eXBlICkgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdGpRdWVyeS5ldmVudC5hZGQoIGVsLCB0eXBlLCByZXR1cm5UcnVlICk7XG5cdFx0fVxuXHRcdHJldHVybjtcblx0fVxuXG5cdC8vIFJlZ2lzdGVyIHRoZSBjb250cm9sbGVyIGFzIGEgc3BlY2lhbCB1bml2ZXJzYWwgaGFuZGxlciBmb3IgYWxsIGV2ZW50IG5hbWVzcGFjZXNcblx0ZGF0YVByaXYuc2V0KCBlbCwgdHlwZSwgZmFsc2UgKTtcblx0alF1ZXJ5LmV2ZW50LmFkZCggZWwsIHR5cGUsIHtcblx0XHRuYW1lc3BhY2U6IGZhbHNlLFxuXHRcdGhhbmRsZXI6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdHZhciBub3RBc3luYywgcmVzdWx0LFxuXHRcdFx0XHRzYXZlZCA9IGRhdGFQcml2LmdldCggdGhpcywgdHlwZSApO1xuXG5cdFx0XHRpZiAoICggZXZlbnQuaXNUcmlnZ2VyICYgMSApICYmIHRoaXNbIHR5cGUgXSApIHtcblxuXHRcdFx0XHQvLyBJbnRlcnJ1cHQgcHJvY2Vzc2luZyBvZiB0aGUgb3V0ZXIgc3ludGhldGljIC50cmlnZ2VyKCllZCBldmVudFxuXHRcdFx0XHQvLyBTYXZlZCBkYXRhIHNob3VsZCBiZSBmYWxzZSBpbiBzdWNoIGNhc2VzLCBidXQgbWlnaHQgYmUgYSBsZWZ0b3ZlciBjYXB0dXJlIG9iamVjdFxuXHRcdFx0XHQvLyBmcm9tIGFuIGFzeW5jIG5hdGl2ZSBoYW5kbGVyIChnaC00MzUwKVxuXHRcdFx0XHRpZiAoICFzYXZlZC5sZW5ndGggKSB7XG5cblx0XHRcdFx0XHQvLyBTdG9yZSBhcmd1bWVudHMgZm9yIHVzZSB3aGVuIGhhbmRsaW5nIHRoZSBpbm5lciBuYXRpdmUgZXZlbnRcblx0XHRcdFx0XHQvLyBUaGVyZSB3aWxsIGFsd2F5cyBiZSBhdCBsZWFzdCBvbmUgYXJndW1lbnQgKGFuIGV2ZW50IG9iamVjdCksIHNvIHRoaXMgYXJyYXlcblx0XHRcdFx0XHQvLyB3aWxsIG5vdCBiZSBjb25mdXNlZCB3aXRoIGEgbGVmdG92ZXIgY2FwdHVyZSBvYmplY3QuXG5cdFx0XHRcdFx0c2F2ZWQgPSBzbGljZS5jYWxsKCBhcmd1bWVudHMgKTtcblx0XHRcdFx0XHRkYXRhUHJpdi5zZXQoIHRoaXMsIHR5cGUsIHNhdmVkICk7XG5cblx0XHRcdFx0XHQvLyBUcmlnZ2VyIHRoZSBuYXRpdmUgZXZlbnQgYW5kIGNhcHR1cmUgaXRzIHJlc3VsdFxuXHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFIDw9OSAtIDExK1xuXHRcdFx0XHRcdC8vIGZvY3VzKCkgYW5kIGJsdXIoKSBhcmUgYXN5bmNocm9ub3VzXG5cdFx0XHRcdFx0bm90QXN5bmMgPSBleHBlY3RTeW5jKCB0aGlzLCB0eXBlICk7XG5cdFx0XHRcdFx0dGhpc1sgdHlwZSBdKCk7XG5cdFx0XHRcdFx0cmVzdWx0ID0gZGF0YVByaXYuZ2V0KCB0aGlzLCB0eXBlICk7XG5cdFx0XHRcdFx0aWYgKCBzYXZlZCAhPT0gcmVzdWx0IHx8IG5vdEFzeW5jICkge1xuXHRcdFx0XHRcdFx0ZGF0YVByaXYuc2V0KCB0aGlzLCB0eXBlLCBmYWxzZSApO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRyZXN1bHQgPSB7fTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKCBzYXZlZCAhPT0gcmVzdWx0ICkge1xuXG5cdFx0XHRcdFx0XHQvLyBDYW5jZWwgdGhlIG91dGVyIHN5bnRoZXRpYyBldmVudFxuXHRcdFx0XHRcdFx0ZXZlbnQuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7XG5cdFx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0XHRcdFx0XHQvLyBTdXBwb3J0OiBDaHJvbWUgODYrXG5cdFx0XHRcdFx0XHQvLyBJbiBDaHJvbWUsIGlmIGFuIGVsZW1lbnQgaGF2aW5nIGEgZm9jdXNvdXQgaGFuZGxlciBpcyBibHVycmVkIGJ5XG5cdFx0XHRcdFx0XHQvLyBjbGlja2luZyBvdXRzaWRlIG9mIGl0LCBpdCBpbnZva2VzIHRoZSBoYW5kbGVyIHN5bmNocm9ub3VzbHkuIElmXG5cdFx0XHRcdFx0XHQvLyB0aGF0IGhhbmRsZXIgY2FsbHMgYC5yZW1vdmUoKWAgb24gdGhlIGVsZW1lbnQsIHRoZSBkYXRhIGlzIGNsZWFyZWQsXG5cdFx0XHRcdFx0XHQvLyBsZWF2aW5nIGByZXN1bHRgIHVuZGVmaW5lZC4gV2UgbmVlZCB0byBndWFyZCBhZ2FpbnN0IHRoaXMuXG5cdFx0XHRcdFx0XHRyZXR1cm4gcmVzdWx0ICYmIHJlc3VsdC52YWx1ZTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gSWYgdGhpcyBpcyBhbiBpbm5lciBzeW50aGV0aWMgZXZlbnQgZm9yIGFuIGV2ZW50IHdpdGggYSBidWJibGluZyBzdXJyb2dhdGVcblx0XHRcdFx0Ly8gKGZvY3VzIG9yIGJsdXIpLCBhc3N1bWUgdGhhdCB0aGUgc3Vycm9nYXRlIGFscmVhZHkgcHJvcGFnYXRlZCBmcm9tIHRyaWdnZXJpbmcgdGhlXG5cdFx0XHRcdC8vIG5hdGl2ZSBldmVudCBhbmQgcHJldmVudCB0aGF0IGZyb20gaGFwcGVuaW5nIGFnYWluIGhlcmUuXG5cdFx0XHRcdC8vIFRoaXMgdGVjaG5pY2FsbHkgZ2V0cyB0aGUgb3JkZXJpbmcgd3Jvbmcgdy5yLnQuIHRvIGAudHJpZ2dlcigpYCAoaW4gd2hpY2ggdGhlXG5cdFx0XHRcdC8vIGJ1YmJsaW5nIHN1cnJvZ2F0ZSBwcm9wYWdhdGVzICphZnRlciogdGhlIG5vbi1idWJibGluZyBiYXNlKSwgYnV0IHRoYXQgc2VlbXNcblx0XHRcdFx0Ly8gbGVzcyBiYWQgdGhhbiBkdXBsaWNhdGlvbi5cblx0XHRcdFx0fSBlbHNlIGlmICggKCBqUXVlcnkuZXZlbnQuc3BlY2lhbFsgdHlwZSBdIHx8IHt9ICkuZGVsZWdhdGVUeXBlICkge1xuXHRcdFx0XHRcdGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdFx0XHR9XG5cblx0XHRcdC8vIElmIHRoaXMgaXMgYSBuYXRpdmUgZXZlbnQgdHJpZ2dlcmVkIGFib3ZlLCBldmVyeXRoaW5nIGlzIG5vdyBpbiBvcmRlclxuXHRcdFx0Ly8gRmlyZSBhbiBpbm5lciBzeW50aGV0aWMgZXZlbnQgd2l0aCB0aGUgb3JpZ2luYWwgYXJndW1lbnRzXG5cdFx0XHR9IGVsc2UgaWYgKCBzYXZlZC5sZW5ndGggKSB7XG5cblx0XHRcdFx0Ly8gLi4uYW5kIGNhcHR1cmUgdGhlIHJlc3VsdFxuXHRcdFx0XHRkYXRhUHJpdi5zZXQoIHRoaXMsIHR5cGUsIHtcblx0XHRcdFx0XHR2YWx1ZTogalF1ZXJ5LmV2ZW50LnRyaWdnZXIoXG5cblx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFIDw9OSAtIDExK1xuXHRcdFx0XHRcdFx0Ly8gRXh0ZW5kIHdpdGggdGhlIHByb3RvdHlwZSB0byByZXNldCB0aGUgYWJvdmUgc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKClcblx0XHRcdFx0XHRcdGpRdWVyeS5leHRlbmQoIHNhdmVkWyAwIF0sIGpRdWVyeS5FdmVudC5wcm90b3R5cGUgKSxcblx0XHRcdFx0XHRcdHNhdmVkLnNsaWNlKCAxICksXG5cdFx0XHRcdFx0XHR0aGlzXG5cdFx0XHRcdFx0KVxuXHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0Ly8gQWJvcnQgaGFuZGxpbmcgb2YgdGhlIG5hdGl2ZSBldmVudFxuXHRcdFx0XHRldmVudC5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcblx0XHRcdH1cblx0XHR9XG5cdH0gKTtcbn1cblxualF1ZXJ5LnJlbW92ZUV2ZW50ID0gZnVuY3Rpb24oIGVsZW0sIHR5cGUsIGhhbmRsZSApIHtcblxuXHQvLyBUaGlzIFwiaWZcIiBpcyBuZWVkZWQgZm9yIHBsYWluIG9iamVjdHNcblx0aWYgKCBlbGVtLnJlbW92ZUV2ZW50TGlzdGVuZXIgKSB7XG5cdFx0ZWxlbS5yZW1vdmVFdmVudExpc3RlbmVyKCB0eXBlLCBoYW5kbGUgKTtcblx0fVxufTtcblxualF1ZXJ5LkV2ZW50ID0gZnVuY3Rpb24oIHNyYywgcHJvcHMgKSB7XG5cblx0Ly8gQWxsb3cgaW5zdGFudGlhdGlvbiB3aXRob3V0IHRoZSAnbmV3JyBrZXl3b3JkXG5cdGlmICggISggdGhpcyBpbnN0YW5jZW9mIGpRdWVyeS5FdmVudCApICkge1xuXHRcdHJldHVybiBuZXcgalF1ZXJ5LkV2ZW50KCBzcmMsIHByb3BzICk7XG5cdH1cblxuXHQvLyBFdmVudCBvYmplY3Rcblx0aWYgKCBzcmMgJiYgc3JjLnR5cGUgKSB7XG5cdFx0dGhpcy5vcmlnaW5hbEV2ZW50ID0gc3JjO1xuXHRcdHRoaXMudHlwZSA9IHNyYy50eXBlO1xuXG5cdFx0Ly8gRXZlbnRzIGJ1YmJsaW5nIHVwIHRoZSBkb2N1bWVudCBtYXkgaGF2ZSBiZWVuIG1hcmtlZCBhcyBwcmV2ZW50ZWRcblx0XHQvLyBieSBhIGhhbmRsZXIgbG93ZXIgZG93biB0aGUgdHJlZTsgcmVmbGVjdCB0aGUgY29ycmVjdCB2YWx1ZS5cblx0XHR0aGlzLmlzRGVmYXVsdFByZXZlbnRlZCA9IHNyYy5kZWZhdWx0UHJldmVudGVkIHx8XG5cdFx0XHRcdHNyYy5kZWZhdWx0UHJldmVudGVkID09PSB1bmRlZmluZWQgJiZcblxuXHRcdFx0XHQvLyBTdXBwb3J0OiBBbmRyb2lkIDw9Mi4zIG9ubHlcblx0XHRcdFx0c3JjLnJldHVyblZhbHVlID09PSBmYWxzZSA/XG5cdFx0XHRyZXR1cm5UcnVlIDpcblx0XHRcdHJldHVybkZhbHNlO1xuXG5cdFx0Ly8gQ3JlYXRlIHRhcmdldCBwcm9wZXJ0aWVzXG5cdFx0Ly8gU3VwcG9ydDogU2FmYXJpIDw9NiAtIDcgb25seVxuXHRcdC8vIFRhcmdldCBzaG91bGQgbm90IGJlIGEgdGV4dCBub2RlICgjNTA0LCAjMTMxNDMpXG5cdFx0dGhpcy50YXJnZXQgPSAoIHNyYy50YXJnZXQgJiYgc3JjLnRhcmdldC5ub2RlVHlwZSA9PT0gMyApID9cblx0XHRcdHNyYy50YXJnZXQucGFyZW50Tm9kZSA6XG5cdFx0XHRzcmMudGFyZ2V0O1xuXG5cdFx0dGhpcy5jdXJyZW50VGFyZ2V0ID0gc3JjLmN1cnJlbnRUYXJnZXQ7XG5cdFx0dGhpcy5yZWxhdGVkVGFyZ2V0ID0gc3JjLnJlbGF0ZWRUYXJnZXQ7XG5cblx0Ly8gRXZlbnQgdHlwZVxuXHR9IGVsc2Uge1xuXHRcdHRoaXMudHlwZSA9IHNyYztcblx0fVxuXG5cdC8vIFB1dCBleHBsaWNpdGx5IHByb3ZpZGVkIHByb3BlcnRpZXMgb250byB0aGUgZXZlbnQgb2JqZWN0XG5cdGlmICggcHJvcHMgKSB7XG5cdFx0alF1ZXJ5LmV4dGVuZCggdGhpcywgcHJvcHMgKTtcblx0fVxuXG5cdC8vIENyZWF0ZSBhIHRpbWVzdGFtcCBpZiBpbmNvbWluZyBldmVudCBkb2Vzbid0IGhhdmUgb25lXG5cdHRoaXMudGltZVN0YW1wID0gc3JjICYmIHNyYy50aW1lU3RhbXAgfHwgRGF0ZS5ub3coKTtcblxuXHQvLyBNYXJrIGl0IGFzIGZpeGVkXG5cdHRoaXNbIGpRdWVyeS5leHBhbmRvIF0gPSB0cnVlO1xufTtcblxuLy8galF1ZXJ5LkV2ZW50IGlzIGJhc2VkIG9uIERPTTMgRXZlbnRzIGFzIHNwZWNpZmllZCBieSB0aGUgRUNNQVNjcmlwdCBMYW5ndWFnZSBCaW5kaW5nXG4vLyBodHRwczovL3d3dy53My5vcmcvVFIvMjAwMy9XRC1ET00tTGV2ZWwtMy1FdmVudHMtMjAwMzAzMzEvZWNtYS1zY3JpcHQtYmluZGluZy5odG1sXG5qUXVlcnkuRXZlbnQucHJvdG90eXBlID0ge1xuXHRjb25zdHJ1Y3RvcjogalF1ZXJ5LkV2ZW50LFxuXHRpc0RlZmF1bHRQcmV2ZW50ZWQ6IHJldHVybkZhbHNlLFxuXHRpc1Byb3BhZ2F0aW9uU3RvcHBlZDogcmV0dXJuRmFsc2UsXG5cdGlzSW1tZWRpYXRlUHJvcGFnYXRpb25TdG9wcGVkOiByZXR1cm5GYWxzZSxcblx0aXNTaW11bGF0ZWQ6IGZhbHNlLFxuXG5cdHByZXZlbnREZWZhdWx0OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgZSA9IHRoaXMub3JpZ2luYWxFdmVudDtcblxuXHRcdHRoaXMuaXNEZWZhdWx0UHJldmVudGVkID0gcmV0dXJuVHJ1ZTtcblxuXHRcdGlmICggZSAmJiAhdGhpcy5pc1NpbXVsYXRlZCApIHtcblx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHR9XG5cdH0sXG5cdHN0b3BQcm9wYWdhdGlvbjogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGUgPSB0aGlzLm9yaWdpbmFsRXZlbnQ7XG5cblx0XHR0aGlzLmlzUHJvcGFnYXRpb25TdG9wcGVkID0gcmV0dXJuVHJ1ZTtcblxuXHRcdGlmICggZSAmJiAhdGhpcy5pc1NpbXVsYXRlZCApIHtcblx0XHRcdGUuc3RvcFByb3BhZ2F0aW9uKCk7XG5cdFx0fVxuXHR9LFxuXHRzdG9wSW1tZWRpYXRlUHJvcGFnYXRpb246IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBlID0gdGhpcy5vcmlnaW5hbEV2ZW50O1xuXG5cdFx0dGhpcy5pc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZCA9IHJldHVyblRydWU7XG5cblx0XHRpZiAoIGUgJiYgIXRoaXMuaXNTaW11bGF0ZWQgKSB7XG5cdFx0XHRlLnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpO1xuXHRcdH1cblxuXHRcdHRoaXMuc3RvcFByb3BhZ2F0aW9uKCk7XG5cdH1cbn07XG5cbi8vIEluY2x1ZGVzIGFsbCBjb21tb24gZXZlbnQgcHJvcHMgaW5jbHVkaW5nIEtleUV2ZW50IGFuZCBNb3VzZUV2ZW50IHNwZWNpZmljIHByb3BzXG5qUXVlcnkuZWFjaCgge1xuXHRhbHRLZXk6IHRydWUsXG5cdGJ1YmJsZXM6IHRydWUsXG5cdGNhbmNlbGFibGU6IHRydWUsXG5cdGNoYW5nZWRUb3VjaGVzOiB0cnVlLFxuXHRjdHJsS2V5OiB0cnVlLFxuXHRkZXRhaWw6IHRydWUsXG5cdGV2ZW50UGhhc2U6IHRydWUsXG5cdG1ldGFLZXk6IHRydWUsXG5cdHBhZ2VYOiB0cnVlLFxuXHRwYWdlWTogdHJ1ZSxcblx0c2hpZnRLZXk6IHRydWUsXG5cdHZpZXc6IHRydWUsXG5cdFwiY2hhclwiOiB0cnVlLFxuXHRjb2RlOiB0cnVlLFxuXHRjaGFyQ29kZTogdHJ1ZSxcblx0a2V5OiB0cnVlLFxuXHRrZXlDb2RlOiB0cnVlLFxuXHRidXR0b246IHRydWUsXG5cdGJ1dHRvbnM6IHRydWUsXG5cdGNsaWVudFg6IHRydWUsXG5cdGNsaWVudFk6IHRydWUsXG5cdG9mZnNldFg6IHRydWUsXG5cdG9mZnNldFk6IHRydWUsXG5cdHBvaW50ZXJJZDogdHJ1ZSxcblx0cG9pbnRlclR5cGU6IHRydWUsXG5cdHNjcmVlblg6IHRydWUsXG5cdHNjcmVlblk6IHRydWUsXG5cdHRhcmdldFRvdWNoZXM6IHRydWUsXG5cdHRvRWxlbWVudDogdHJ1ZSxcblx0dG91Y2hlczogdHJ1ZSxcblx0d2hpY2g6IHRydWVcbn0sIGpRdWVyeS5ldmVudC5hZGRQcm9wICk7XG5cbmpRdWVyeS5lYWNoKCB7IGZvY3VzOiBcImZvY3VzaW5cIiwgYmx1cjogXCJmb2N1c291dFwiIH0sIGZ1bmN0aW9uKCB0eXBlLCBkZWxlZ2F0ZVR5cGUgKSB7XG5cdGpRdWVyeS5ldmVudC5zcGVjaWFsWyB0eXBlIF0gPSB7XG5cblx0XHQvLyBVdGlsaXplIG5hdGl2ZSBldmVudCBpZiBwb3NzaWJsZSBzbyBibHVyL2ZvY3VzIHNlcXVlbmNlIGlzIGNvcnJlY3Rcblx0XHRzZXR1cDogZnVuY3Rpb24oKSB7XG5cblx0XHRcdC8vIENsYWltIHRoZSBmaXJzdCBoYW5kbGVyXG5cdFx0XHQvLyBkYXRhUHJpdi5zZXQoIHRoaXMsIFwiZm9jdXNcIiwgLi4uIClcblx0XHRcdC8vIGRhdGFQcml2LnNldCggdGhpcywgXCJibHVyXCIsIC4uLiApXG5cdFx0XHRsZXZlcmFnZU5hdGl2ZSggdGhpcywgdHlwZSwgZXhwZWN0U3luYyApO1xuXG5cdFx0XHQvLyBSZXR1cm4gZmFsc2UgdG8gYWxsb3cgbm9ybWFsIHByb2Nlc3NpbmcgaW4gdGhlIGNhbGxlclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH0sXG5cdFx0dHJpZ2dlcjogZnVuY3Rpb24oKSB7XG5cblx0XHRcdC8vIEZvcmNlIHNldHVwIGJlZm9yZSB0cmlnZ2VyXG5cdFx0XHRsZXZlcmFnZU5hdGl2ZSggdGhpcywgdHlwZSApO1xuXG5cdFx0XHQvLyBSZXR1cm4gbm9uLWZhbHNlIHRvIGFsbG93IG5vcm1hbCBldmVudC1wYXRoIHByb3BhZ2F0aW9uXG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9LFxuXG5cdFx0Ly8gU3VwcHJlc3MgbmF0aXZlIGZvY3VzIG9yIGJsdXIgYXMgaXQncyBhbHJlYWR5IGJlaW5nIGZpcmVkXG5cdFx0Ly8gaW4gbGV2ZXJhZ2VOYXRpdmUuXG5cdFx0X2RlZmF1bHQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fSxcblxuXHRcdGRlbGVnYXRlVHlwZTogZGVsZWdhdGVUeXBlXG5cdH07XG59ICk7XG5cbi8vIENyZWF0ZSBtb3VzZWVudGVyL2xlYXZlIGV2ZW50cyB1c2luZyBtb3VzZW92ZXIvb3V0IGFuZCBldmVudC10aW1lIGNoZWNrc1xuLy8gc28gdGhhdCBldmVudCBkZWxlZ2F0aW9uIHdvcmtzIGluIGpRdWVyeS5cbi8vIERvIHRoZSBzYW1lIGZvciBwb2ludGVyZW50ZXIvcG9pbnRlcmxlYXZlIGFuZCBwb2ludGVyb3Zlci9wb2ludGVyb3V0XG4vL1xuLy8gU3VwcG9ydDogU2FmYXJpIDcgb25seVxuLy8gU2FmYXJpIHNlbmRzIG1vdXNlZW50ZXIgdG9vIG9mdGVuOyBzZWU6XG4vLyBodHRwczovL2J1Z3MuY2hyb21pdW0ub3JnL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD00NzAyNThcbi8vIGZvciB0aGUgZGVzY3JpcHRpb24gb2YgdGhlIGJ1ZyAoaXQgZXhpc3RlZCBpbiBvbGRlciBDaHJvbWUgdmVyc2lvbnMgYXMgd2VsbCkuXG5qUXVlcnkuZWFjaCgge1xuXHRtb3VzZWVudGVyOiBcIm1vdXNlb3ZlclwiLFxuXHRtb3VzZWxlYXZlOiBcIm1vdXNlb3V0XCIsXG5cdHBvaW50ZXJlbnRlcjogXCJwb2ludGVyb3ZlclwiLFxuXHRwb2ludGVybGVhdmU6IFwicG9pbnRlcm91dFwiXG59LCBmdW5jdGlvbiggb3JpZywgZml4ICkge1xuXHRqUXVlcnkuZXZlbnQuc3BlY2lhbFsgb3JpZyBdID0ge1xuXHRcdGRlbGVnYXRlVHlwZTogZml4LFxuXHRcdGJpbmRUeXBlOiBmaXgsXG5cblx0XHRoYW5kbGU6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdHZhciByZXQsXG5cdFx0XHRcdHRhcmdldCA9IHRoaXMsXG5cdFx0XHRcdHJlbGF0ZWQgPSBldmVudC5yZWxhdGVkVGFyZ2V0LFxuXHRcdFx0XHRoYW5kbGVPYmogPSBldmVudC5oYW5kbGVPYmo7XG5cblx0XHRcdC8vIEZvciBtb3VzZWVudGVyL2xlYXZlIGNhbGwgdGhlIGhhbmRsZXIgaWYgcmVsYXRlZCBpcyBvdXRzaWRlIHRoZSB0YXJnZXQuXG5cdFx0XHQvLyBOQjogTm8gcmVsYXRlZFRhcmdldCBpZiB0aGUgbW91c2UgbGVmdC9lbnRlcmVkIHRoZSBicm93c2VyIHdpbmRvd1xuXHRcdFx0aWYgKCAhcmVsYXRlZCB8fCAoIHJlbGF0ZWQgIT09IHRhcmdldCAmJiAhalF1ZXJ5LmNvbnRhaW5zKCB0YXJnZXQsIHJlbGF0ZWQgKSApICkge1xuXHRcdFx0XHRldmVudC50eXBlID0gaGFuZGxlT2JqLm9yaWdUeXBlO1xuXHRcdFx0XHRyZXQgPSBoYW5kbGVPYmouaGFuZGxlci5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHRcdGV2ZW50LnR5cGUgPSBmaXg7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gcmV0O1xuXHRcdH1cblx0fTtcbn0gKTtcblxualF1ZXJ5LmZuLmV4dGVuZCgge1xuXG5cdG9uOiBmdW5jdGlvbiggdHlwZXMsIHNlbGVjdG9yLCBkYXRhLCBmbiApIHtcblx0XHRyZXR1cm4gb24oIHRoaXMsIHR5cGVzLCBzZWxlY3RvciwgZGF0YSwgZm4gKTtcblx0fSxcblx0b25lOiBmdW5jdGlvbiggdHlwZXMsIHNlbGVjdG9yLCBkYXRhLCBmbiApIHtcblx0XHRyZXR1cm4gb24oIHRoaXMsIHR5cGVzLCBzZWxlY3RvciwgZGF0YSwgZm4sIDEgKTtcblx0fSxcblx0b2ZmOiBmdW5jdGlvbiggdHlwZXMsIHNlbGVjdG9yLCBmbiApIHtcblx0XHR2YXIgaGFuZGxlT2JqLCB0eXBlO1xuXHRcdGlmICggdHlwZXMgJiYgdHlwZXMucHJldmVudERlZmF1bHQgJiYgdHlwZXMuaGFuZGxlT2JqICkge1xuXG5cdFx0XHQvLyAoIGV2ZW50ICkgIGRpc3BhdGNoZWQgalF1ZXJ5LkV2ZW50XG5cdFx0XHRoYW5kbGVPYmogPSB0eXBlcy5oYW5kbGVPYmo7XG5cdFx0XHRqUXVlcnkoIHR5cGVzLmRlbGVnYXRlVGFyZ2V0ICkub2ZmKFxuXHRcdFx0XHRoYW5kbGVPYmoubmFtZXNwYWNlID9cblx0XHRcdFx0XHRoYW5kbGVPYmoub3JpZ1R5cGUgKyBcIi5cIiArIGhhbmRsZU9iai5uYW1lc3BhY2UgOlxuXHRcdFx0XHRcdGhhbmRsZU9iai5vcmlnVHlwZSxcblx0XHRcdFx0aGFuZGxlT2JqLnNlbGVjdG9yLFxuXHRcdFx0XHRoYW5kbGVPYmouaGFuZGxlclxuXHRcdFx0KTtcblx0XHRcdHJldHVybiB0aGlzO1xuXHRcdH1cblx0XHRpZiAoIHR5cGVvZiB0eXBlcyA9PT0gXCJvYmplY3RcIiApIHtcblxuXHRcdFx0Ly8gKCB0eXBlcy1vYmplY3QgWywgc2VsZWN0b3JdIClcblx0XHRcdGZvciAoIHR5cGUgaW4gdHlwZXMgKSB7XG5cdFx0XHRcdHRoaXMub2ZmKCB0eXBlLCBzZWxlY3RvciwgdHlwZXNbIHR5cGUgXSApO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0fVxuXHRcdGlmICggc2VsZWN0b3IgPT09IGZhbHNlIHx8IHR5cGVvZiBzZWxlY3RvciA9PT0gXCJmdW5jdGlvblwiICkge1xuXG5cdFx0XHQvLyAoIHR5cGVzIFssIGZuXSApXG5cdFx0XHRmbiA9IHNlbGVjdG9yO1xuXHRcdFx0c2VsZWN0b3IgPSB1bmRlZmluZWQ7XG5cdFx0fVxuXHRcdGlmICggZm4gPT09IGZhbHNlICkge1xuXHRcdFx0Zm4gPSByZXR1cm5GYWxzZTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRqUXVlcnkuZXZlbnQucmVtb3ZlKCB0aGlzLCB0eXBlcywgZm4sIHNlbGVjdG9yICk7XG5cdFx0fSApO1xuXHR9XG59ICk7XG5cblxudmFyXG5cblx0Ly8gU3VwcG9ydDogSUUgPD0xMCAtIDExLCBFZGdlIDEyIC0gMTMgb25seVxuXHQvLyBJbiBJRS9FZGdlIHVzaW5nIHJlZ2V4IGdyb3VwcyBoZXJlIGNhdXNlcyBzZXZlcmUgc2xvd2Rvd25zLlxuXHQvLyBTZWUgaHR0cHM6Ly9jb25uZWN0Lm1pY3Jvc29mdC5jb20vSUUvZmVlZGJhY2svZGV0YWlscy8xNzM2NTEyL1xuXHRybm9Jbm5lcmh0bWwgPSAvPHNjcmlwdHw8c3R5bGV8PGxpbmsvaSxcblxuXHQvLyBjaGVja2VkPVwiY2hlY2tlZFwiIG9yIGNoZWNrZWRcblx0cmNoZWNrZWQgPSAvY2hlY2tlZFxccyooPzpbXj1dfD1cXHMqLmNoZWNrZWQuKS9pLFxuXHRyY2xlYW5TY3JpcHQgPSAvXlxccyo8ISg/OlxcW0NEQVRBXFxbfC0tKXwoPzpcXF1cXF18LS0pPlxccyokL2c7XG5cbi8vIFByZWZlciBhIHRib2R5IG92ZXIgaXRzIHBhcmVudCB0YWJsZSBmb3IgY29udGFpbmluZyBuZXcgcm93c1xuZnVuY3Rpb24gbWFuaXB1bGF0aW9uVGFyZ2V0KCBlbGVtLCBjb250ZW50ICkge1xuXHRpZiAoIG5vZGVOYW1lKCBlbGVtLCBcInRhYmxlXCIgKSAmJlxuXHRcdG5vZGVOYW1lKCBjb250ZW50Lm5vZGVUeXBlICE9PSAxMSA/IGNvbnRlbnQgOiBjb250ZW50LmZpcnN0Q2hpbGQsIFwidHJcIiApICkge1xuXG5cdFx0cmV0dXJuIGpRdWVyeSggZWxlbSApLmNoaWxkcmVuKCBcInRib2R5XCIgKVsgMCBdIHx8IGVsZW07XG5cdH1cblxuXHRyZXR1cm4gZWxlbTtcbn1cblxuLy8gUmVwbGFjZS9yZXN0b3JlIHRoZSB0eXBlIGF0dHJpYnV0ZSBvZiBzY3JpcHQgZWxlbWVudHMgZm9yIHNhZmUgRE9NIG1hbmlwdWxhdGlvblxuZnVuY3Rpb24gZGlzYWJsZVNjcmlwdCggZWxlbSApIHtcblx0ZWxlbS50eXBlID0gKCBlbGVtLmdldEF0dHJpYnV0ZSggXCJ0eXBlXCIgKSAhPT0gbnVsbCApICsgXCIvXCIgKyBlbGVtLnR5cGU7XG5cdHJldHVybiBlbGVtO1xufVxuZnVuY3Rpb24gcmVzdG9yZVNjcmlwdCggZWxlbSApIHtcblx0aWYgKCAoIGVsZW0udHlwZSB8fCBcIlwiICkuc2xpY2UoIDAsIDUgKSA9PT0gXCJ0cnVlL1wiICkge1xuXHRcdGVsZW0udHlwZSA9IGVsZW0udHlwZS5zbGljZSggNSApO1xuXHR9IGVsc2Uge1xuXHRcdGVsZW0ucmVtb3ZlQXR0cmlidXRlKCBcInR5cGVcIiApO1xuXHR9XG5cblx0cmV0dXJuIGVsZW07XG59XG5cbmZ1bmN0aW9uIGNsb25lQ29weUV2ZW50KCBzcmMsIGRlc3QgKSB7XG5cdHZhciBpLCBsLCB0eXBlLCBwZGF0YU9sZCwgdWRhdGFPbGQsIHVkYXRhQ3VyLCBldmVudHM7XG5cblx0aWYgKCBkZXN0Lm5vZGVUeXBlICE9PSAxICkge1xuXHRcdHJldHVybjtcblx0fVxuXG5cdC8vIDEuIENvcHkgcHJpdmF0ZSBkYXRhOiBldmVudHMsIGhhbmRsZXJzLCBldGMuXG5cdGlmICggZGF0YVByaXYuaGFzRGF0YSggc3JjICkgKSB7XG5cdFx0cGRhdGFPbGQgPSBkYXRhUHJpdi5nZXQoIHNyYyApO1xuXHRcdGV2ZW50cyA9IHBkYXRhT2xkLmV2ZW50cztcblxuXHRcdGlmICggZXZlbnRzICkge1xuXHRcdFx0ZGF0YVByaXYucmVtb3ZlKCBkZXN0LCBcImhhbmRsZSBldmVudHNcIiApO1xuXG5cdFx0XHRmb3IgKCB0eXBlIGluIGV2ZW50cyApIHtcblx0XHRcdFx0Zm9yICggaSA9IDAsIGwgPSBldmVudHNbIHR5cGUgXS5sZW5ndGg7IGkgPCBsOyBpKysgKSB7XG5cdFx0XHRcdFx0alF1ZXJ5LmV2ZW50LmFkZCggZGVzdCwgdHlwZSwgZXZlbnRzWyB0eXBlIF1bIGkgXSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0Ly8gMi4gQ29weSB1c2VyIGRhdGFcblx0aWYgKCBkYXRhVXNlci5oYXNEYXRhKCBzcmMgKSApIHtcblx0XHR1ZGF0YU9sZCA9IGRhdGFVc2VyLmFjY2Vzcyggc3JjICk7XG5cdFx0dWRhdGFDdXIgPSBqUXVlcnkuZXh0ZW5kKCB7fSwgdWRhdGFPbGQgKTtcblxuXHRcdGRhdGFVc2VyLnNldCggZGVzdCwgdWRhdGFDdXIgKTtcblx0fVxufVxuXG4vLyBGaXggSUUgYnVncywgc2VlIHN1cHBvcnQgdGVzdHNcbmZ1bmN0aW9uIGZpeElucHV0KCBzcmMsIGRlc3QgKSB7XG5cdHZhciBub2RlTmFtZSA9IGRlc3Qubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtcblxuXHQvLyBGYWlscyB0byBwZXJzaXN0IHRoZSBjaGVja2VkIHN0YXRlIG9mIGEgY2xvbmVkIGNoZWNrYm94IG9yIHJhZGlvIGJ1dHRvbi5cblx0aWYgKCBub2RlTmFtZSA9PT0gXCJpbnB1dFwiICYmIHJjaGVja2FibGVUeXBlLnRlc3QoIHNyYy50eXBlICkgKSB7XG5cdFx0ZGVzdC5jaGVja2VkID0gc3JjLmNoZWNrZWQ7XG5cblx0Ly8gRmFpbHMgdG8gcmV0dXJuIHRoZSBzZWxlY3RlZCBvcHRpb24gdG8gdGhlIGRlZmF1bHQgc2VsZWN0ZWQgc3RhdGUgd2hlbiBjbG9uaW5nIG9wdGlvbnNcblx0fSBlbHNlIGlmICggbm9kZU5hbWUgPT09IFwiaW5wdXRcIiB8fCBub2RlTmFtZSA9PT0gXCJ0ZXh0YXJlYVwiICkge1xuXHRcdGRlc3QuZGVmYXVsdFZhbHVlID0gc3JjLmRlZmF1bHRWYWx1ZTtcblx0fVxufVxuXG5mdW5jdGlvbiBkb21NYW5pcCggY29sbGVjdGlvbiwgYXJncywgY2FsbGJhY2ssIGlnbm9yZWQgKSB7XG5cblx0Ly8gRmxhdHRlbiBhbnkgbmVzdGVkIGFycmF5c1xuXHRhcmdzID0gZmxhdCggYXJncyApO1xuXG5cdHZhciBmcmFnbWVudCwgZmlyc3QsIHNjcmlwdHMsIGhhc1NjcmlwdHMsIG5vZGUsIGRvYyxcblx0XHRpID0gMCxcblx0XHRsID0gY29sbGVjdGlvbi5sZW5ndGgsXG5cdFx0aU5vQ2xvbmUgPSBsIC0gMSxcblx0XHR2YWx1ZSA9IGFyZ3NbIDAgXSxcblx0XHR2YWx1ZUlzRnVuY3Rpb24gPSBpc0Z1bmN0aW9uKCB2YWx1ZSApO1xuXG5cdC8vIFdlIGNhbid0IGNsb25lTm9kZSBmcmFnbWVudHMgdGhhdCBjb250YWluIGNoZWNrZWQsIGluIFdlYktpdFxuXHRpZiAoIHZhbHVlSXNGdW5jdGlvbiB8fFxuXHRcdFx0KCBsID4gMSAmJiB0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIgJiZcblx0XHRcdFx0IXN1cHBvcnQuY2hlY2tDbG9uZSAmJiByY2hlY2tlZC50ZXN0KCB2YWx1ZSApICkgKSB7XG5cdFx0cmV0dXJuIGNvbGxlY3Rpb24uZWFjaCggZnVuY3Rpb24oIGluZGV4ICkge1xuXHRcdFx0dmFyIHNlbGYgPSBjb2xsZWN0aW9uLmVxKCBpbmRleCApO1xuXHRcdFx0aWYgKCB2YWx1ZUlzRnVuY3Rpb24gKSB7XG5cdFx0XHRcdGFyZ3NbIDAgXSA9IHZhbHVlLmNhbGwoIHRoaXMsIGluZGV4LCBzZWxmLmh0bWwoKSApO1xuXHRcdFx0fVxuXHRcdFx0ZG9tTWFuaXAoIHNlbGYsIGFyZ3MsIGNhbGxiYWNrLCBpZ25vcmVkICk7XG5cdFx0fSApO1xuXHR9XG5cblx0aWYgKCBsICkge1xuXHRcdGZyYWdtZW50ID0gYnVpbGRGcmFnbWVudCggYXJncywgY29sbGVjdGlvblsgMCBdLm93bmVyRG9jdW1lbnQsIGZhbHNlLCBjb2xsZWN0aW9uLCBpZ25vcmVkICk7XG5cdFx0Zmlyc3QgPSBmcmFnbWVudC5maXJzdENoaWxkO1xuXG5cdFx0aWYgKCBmcmFnbWVudC5jaGlsZE5vZGVzLmxlbmd0aCA9PT0gMSApIHtcblx0XHRcdGZyYWdtZW50ID0gZmlyc3Q7XG5cdFx0fVxuXG5cdFx0Ly8gUmVxdWlyZSBlaXRoZXIgbmV3IGNvbnRlbnQgb3IgYW4gaW50ZXJlc3QgaW4gaWdub3JlZCBlbGVtZW50cyB0byBpbnZva2UgdGhlIGNhbGxiYWNrXG5cdFx0aWYgKCBmaXJzdCB8fCBpZ25vcmVkICkge1xuXHRcdFx0c2NyaXB0cyA9IGpRdWVyeS5tYXAoIGdldEFsbCggZnJhZ21lbnQsIFwic2NyaXB0XCIgKSwgZGlzYWJsZVNjcmlwdCApO1xuXHRcdFx0aGFzU2NyaXB0cyA9IHNjcmlwdHMubGVuZ3RoO1xuXG5cdFx0XHQvLyBVc2UgdGhlIG9yaWdpbmFsIGZyYWdtZW50IGZvciB0aGUgbGFzdCBpdGVtXG5cdFx0XHQvLyBpbnN0ZWFkIG9mIHRoZSBmaXJzdCBiZWNhdXNlIGl0IGNhbiBlbmQgdXBcblx0XHRcdC8vIGJlaW5nIGVtcHRpZWQgaW5jb3JyZWN0bHkgaW4gY2VydGFpbiBzaXR1YXRpb25zICgjODA3MCkuXG5cdFx0XHRmb3IgKCA7IGkgPCBsOyBpKysgKSB7XG5cdFx0XHRcdG5vZGUgPSBmcmFnbWVudDtcblxuXHRcdFx0XHRpZiAoIGkgIT09IGlOb0Nsb25lICkge1xuXHRcdFx0XHRcdG5vZGUgPSBqUXVlcnkuY2xvbmUoIG5vZGUsIHRydWUsIHRydWUgKTtcblxuXHRcdFx0XHRcdC8vIEtlZXAgcmVmZXJlbmNlcyB0byBjbG9uZWQgc2NyaXB0cyBmb3IgbGF0ZXIgcmVzdG9yYXRpb25cblx0XHRcdFx0XHRpZiAoIGhhc1NjcmlwdHMgKSB7XG5cblx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IEFuZHJvaWQgPD00LjAgb25seSwgUGhhbnRvbUpTIDEgb25seVxuXHRcdFx0XHRcdFx0Ly8gcHVzaC5hcHBseShfLCBhcnJheWxpa2UpIHRocm93cyBvbiBhbmNpZW50IFdlYktpdFxuXHRcdFx0XHRcdFx0alF1ZXJ5Lm1lcmdlKCBzY3JpcHRzLCBnZXRBbGwoIG5vZGUsIFwic2NyaXB0XCIgKSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGNhbGxiYWNrLmNhbGwoIGNvbGxlY3Rpb25bIGkgXSwgbm9kZSwgaSApO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGhhc1NjcmlwdHMgKSB7XG5cdFx0XHRcdGRvYyA9IHNjcmlwdHNbIHNjcmlwdHMubGVuZ3RoIC0gMSBdLm93bmVyRG9jdW1lbnQ7XG5cblx0XHRcdFx0Ly8gUmVlbmFibGUgc2NyaXB0c1xuXHRcdFx0XHRqUXVlcnkubWFwKCBzY3JpcHRzLCByZXN0b3JlU2NyaXB0ICk7XG5cblx0XHRcdFx0Ly8gRXZhbHVhdGUgZXhlY3V0YWJsZSBzY3JpcHRzIG9uIGZpcnN0IGRvY3VtZW50IGluc2VydGlvblxuXHRcdFx0XHRmb3IgKCBpID0gMDsgaSA8IGhhc1NjcmlwdHM7IGkrKyApIHtcblx0XHRcdFx0XHRub2RlID0gc2NyaXB0c1sgaSBdO1xuXHRcdFx0XHRcdGlmICggcnNjcmlwdFR5cGUudGVzdCggbm9kZS50eXBlIHx8IFwiXCIgKSAmJlxuXHRcdFx0XHRcdFx0IWRhdGFQcml2LmFjY2Vzcyggbm9kZSwgXCJnbG9iYWxFdmFsXCIgKSAmJlxuXHRcdFx0XHRcdFx0alF1ZXJ5LmNvbnRhaW5zKCBkb2MsIG5vZGUgKSApIHtcblxuXHRcdFx0XHRcdFx0aWYgKCBub2RlLnNyYyAmJiAoIG5vZGUudHlwZSB8fCBcIlwiICkudG9Mb3dlckNhc2UoKSAgIT09IFwibW9kdWxlXCIgKSB7XG5cblx0XHRcdFx0XHRcdFx0Ly8gT3B0aW9uYWwgQUpBWCBkZXBlbmRlbmN5LCBidXQgd29uJ3QgcnVuIHNjcmlwdHMgaWYgbm90IHByZXNlbnRcblx0XHRcdFx0XHRcdFx0aWYgKCBqUXVlcnkuX2V2YWxVcmwgJiYgIW5vZGUubm9Nb2R1bGUgKSB7XG5cdFx0XHRcdFx0XHRcdFx0alF1ZXJ5Ll9ldmFsVXJsKCBub2RlLnNyYywge1xuXHRcdFx0XHRcdFx0XHRcdFx0bm9uY2U6IG5vZGUubm9uY2UgfHwgbm9kZS5nZXRBdHRyaWJ1dGUoIFwibm9uY2VcIiApXG5cdFx0XHRcdFx0XHRcdFx0fSwgZG9jICk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdERPTUV2YWwoIG5vZGUudGV4dENvbnRlbnQucmVwbGFjZSggcmNsZWFuU2NyaXB0LCBcIlwiICksIG5vZGUsIGRvYyApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdHJldHVybiBjb2xsZWN0aW9uO1xufVxuXG5mdW5jdGlvbiByZW1vdmUoIGVsZW0sIHNlbGVjdG9yLCBrZWVwRGF0YSApIHtcblx0dmFyIG5vZGUsXG5cdFx0bm9kZXMgPSBzZWxlY3RvciA/IGpRdWVyeS5maWx0ZXIoIHNlbGVjdG9yLCBlbGVtICkgOiBlbGVtLFxuXHRcdGkgPSAwO1xuXG5cdGZvciAoIDsgKCBub2RlID0gbm9kZXNbIGkgXSApICE9IG51bGw7IGkrKyApIHtcblx0XHRpZiAoICFrZWVwRGF0YSAmJiBub2RlLm5vZGVUeXBlID09PSAxICkge1xuXHRcdFx0alF1ZXJ5LmNsZWFuRGF0YSggZ2V0QWxsKCBub2RlICkgKTtcblx0XHR9XG5cblx0XHRpZiAoIG5vZGUucGFyZW50Tm9kZSApIHtcblx0XHRcdGlmICgga2VlcERhdGEgJiYgaXNBdHRhY2hlZCggbm9kZSApICkge1xuXHRcdFx0XHRzZXRHbG9iYWxFdmFsKCBnZXRBbGwoIG5vZGUsIFwic2NyaXB0XCIgKSApO1xuXHRcdFx0fVxuXHRcdFx0bm9kZS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKCBub2RlICk7XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIGVsZW07XG59XG5cbmpRdWVyeS5leHRlbmQoIHtcblx0aHRtbFByZWZpbHRlcjogZnVuY3Rpb24oIGh0bWwgKSB7XG5cdFx0cmV0dXJuIGh0bWw7XG5cdH0sXG5cblx0Y2xvbmU6IGZ1bmN0aW9uKCBlbGVtLCBkYXRhQW5kRXZlbnRzLCBkZWVwRGF0YUFuZEV2ZW50cyApIHtcblx0XHR2YXIgaSwgbCwgc3JjRWxlbWVudHMsIGRlc3RFbGVtZW50cyxcblx0XHRcdGNsb25lID0gZWxlbS5jbG9uZU5vZGUoIHRydWUgKSxcblx0XHRcdGluUGFnZSA9IGlzQXR0YWNoZWQoIGVsZW0gKTtcblxuXHRcdC8vIEZpeCBJRSBjbG9uaW5nIGlzc3Vlc1xuXHRcdGlmICggIXN1cHBvcnQubm9DbG9uZUNoZWNrZWQgJiYgKCBlbGVtLm5vZGVUeXBlID09PSAxIHx8IGVsZW0ubm9kZVR5cGUgPT09IDExICkgJiZcblx0XHRcdFx0IWpRdWVyeS5pc1hNTERvYyggZWxlbSApICkge1xuXG5cdFx0XHQvLyBXZSBlc2NoZXcgU2l6emxlIGhlcmUgZm9yIHBlcmZvcm1hbmNlIHJlYXNvbnM6IGh0dHBzOi8vanNwZXJmLmNvbS9nZXRhbGwtdnMtc2l6emxlLzJcblx0XHRcdGRlc3RFbGVtZW50cyA9IGdldEFsbCggY2xvbmUgKTtcblx0XHRcdHNyY0VsZW1lbnRzID0gZ2V0QWxsKCBlbGVtICk7XG5cblx0XHRcdGZvciAoIGkgPSAwLCBsID0gc3JjRWxlbWVudHMubGVuZ3RoOyBpIDwgbDsgaSsrICkge1xuXHRcdFx0XHRmaXhJbnB1dCggc3JjRWxlbWVudHNbIGkgXSwgZGVzdEVsZW1lbnRzWyBpIF0gKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBDb3B5IHRoZSBldmVudHMgZnJvbSB0aGUgb3JpZ2luYWwgdG8gdGhlIGNsb25lXG5cdFx0aWYgKCBkYXRhQW5kRXZlbnRzICkge1xuXHRcdFx0aWYgKCBkZWVwRGF0YUFuZEV2ZW50cyApIHtcblx0XHRcdFx0c3JjRWxlbWVudHMgPSBzcmNFbGVtZW50cyB8fCBnZXRBbGwoIGVsZW0gKTtcblx0XHRcdFx0ZGVzdEVsZW1lbnRzID0gZGVzdEVsZW1lbnRzIHx8IGdldEFsbCggY2xvbmUgKTtcblxuXHRcdFx0XHRmb3IgKCBpID0gMCwgbCA9IHNyY0VsZW1lbnRzLmxlbmd0aDsgaSA8IGw7IGkrKyApIHtcblx0XHRcdFx0XHRjbG9uZUNvcHlFdmVudCggc3JjRWxlbWVudHNbIGkgXSwgZGVzdEVsZW1lbnRzWyBpIF0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Y2xvbmVDb3B5RXZlbnQoIGVsZW0sIGNsb25lICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gUHJlc2VydmUgc2NyaXB0IGV2YWx1YXRpb24gaGlzdG9yeVxuXHRcdGRlc3RFbGVtZW50cyA9IGdldEFsbCggY2xvbmUsIFwic2NyaXB0XCIgKTtcblx0XHRpZiAoIGRlc3RFbGVtZW50cy5sZW5ndGggPiAwICkge1xuXHRcdFx0c2V0R2xvYmFsRXZhbCggZGVzdEVsZW1lbnRzLCAhaW5QYWdlICYmIGdldEFsbCggZWxlbSwgXCJzY3JpcHRcIiApICk7XG5cdFx0fVxuXG5cdFx0Ly8gUmV0dXJuIHRoZSBjbG9uZWQgc2V0XG5cdFx0cmV0dXJuIGNsb25lO1xuXHR9LFxuXG5cdGNsZWFuRGF0YTogZnVuY3Rpb24oIGVsZW1zICkge1xuXHRcdHZhciBkYXRhLCBlbGVtLCB0eXBlLFxuXHRcdFx0c3BlY2lhbCA9IGpRdWVyeS5ldmVudC5zcGVjaWFsLFxuXHRcdFx0aSA9IDA7XG5cblx0XHRmb3IgKCA7ICggZWxlbSA9IGVsZW1zWyBpIF0gKSAhPT0gdW5kZWZpbmVkOyBpKysgKSB7XG5cdFx0XHRpZiAoIGFjY2VwdERhdGEoIGVsZW0gKSApIHtcblx0XHRcdFx0aWYgKCAoIGRhdGEgPSBlbGVtWyBkYXRhUHJpdi5leHBhbmRvIF0gKSApIHtcblx0XHRcdFx0XHRpZiAoIGRhdGEuZXZlbnRzICkge1xuXHRcdFx0XHRcdFx0Zm9yICggdHlwZSBpbiBkYXRhLmV2ZW50cyApIHtcblx0XHRcdFx0XHRcdFx0aWYgKCBzcGVjaWFsWyB0eXBlIF0gKSB7XG5cdFx0XHRcdFx0XHRcdFx0alF1ZXJ5LmV2ZW50LnJlbW92ZSggZWxlbSwgdHlwZSApO1xuXG5cdFx0XHRcdFx0XHRcdC8vIFRoaXMgaXMgYSBzaG9ydGN1dCB0byBhdm9pZCBqUXVlcnkuZXZlbnQucmVtb3ZlJ3Mgb3ZlcmhlYWRcblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHRqUXVlcnkucmVtb3ZlRXZlbnQoIGVsZW0sIHR5cGUsIGRhdGEuaGFuZGxlICk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBTdXBwb3J0OiBDaHJvbWUgPD0zNSAtIDQ1K1xuXHRcdFx0XHRcdC8vIEFzc2lnbiB1bmRlZmluZWQgaW5zdGVhZCBvZiB1c2luZyBkZWxldGUsIHNlZSBEYXRhI3JlbW92ZVxuXHRcdFx0XHRcdGVsZW1bIGRhdGFQcml2LmV4cGFuZG8gXSA9IHVuZGVmaW5lZDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIGVsZW1bIGRhdGFVc2VyLmV4cGFuZG8gXSApIHtcblxuXHRcdFx0XHRcdC8vIFN1cHBvcnQ6IENocm9tZSA8PTM1IC0gNDUrXG5cdFx0XHRcdFx0Ly8gQXNzaWduIHVuZGVmaW5lZCBpbnN0ZWFkIG9mIHVzaW5nIGRlbGV0ZSwgc2VlIERhdGEjcmVtb3ZlXG5cdFx0XHRcdFx0ZWxlbVsgZGF0YVVzZXIuZXhwYW5kbyBdID0gdW5kZWZpbmVkO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG59ICk7XG5cbmpRdWVyeS5mbi5leHRlbmQoIHtcblx0ZGV0YWNoOiBmdW5jdGlvbiggc2VsZWN0b3IgKSB7XG5cdFx0cmV0dXJuIHJlbW92ZSggdGhpcywgc2VsZWN0b3IsIHRydWUgKTtcblx0fSxcblxuXHRyZW1vdmU6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHRyZXR1cm4gcmVtb3ZlKCB0aGlzLCBzZWxlY3RvciApO1xuXHR9LFxuXG5cdHRleHQ6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRyZXR1cm4gYWNjZXNzKCB0aGlzLCBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0XHRyZXR1cm4gdmFsdWUgPT09IHVuZGVmaW5lZCA/XG5cdFx0XHRcdGpRdWVyeS50ZXh0KCB0aGlzICkgOlxuXHRcdFx0XHR0aGlzLmVtcHR5KCkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0aWYgKCB0aGlzLm5vZGVUeXBlID09PSAxIHx8IHRoaXMubm9kZVR5cGUgPT09IDExIHx8IHRoaXMubm9kZVR5cGUgPT09IDkgKSB7XG5cdFx0XHRcdFx0XHR0aGlzLnRleHRDb250ZW50ID0gdmFsdWU7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0fSwgbnVsbCwgdmFsdWUsIGFyZ3VtZW50cy5sZW5ndGggKTtcblx0fSxcblxuXHRhcHBlbmQ6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiBkb21NYW5pcCggdGhpcywgYXJndW1lbnRzLCBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdGlmICggdGhpcy5ub2RlVHlwZSA9PT0gMSB8fCB0aGlzLm5vZGVUeXBlID09PSAxMSB8fCB0aGlzLm5vZGVUeXBlID09PSA5ICkge1xuXHRcdFx0XHR2YXIgdGFyZ2V0ID0gbWFuaXB1bGF0aW9uVGFyZ2V0KCB0aGlzLCBlbGVtICk7XG5cdFx0XHRcdHRhcmdldC5hcHBlbmRDaGlsZCggZWxlbSApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRwcmVwZW5kOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gZG9tTWFuaXAoIHRoaXMsIGFyZ3VtZW50cywgZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRpZiAoIHRoaXMubm9kZVR5cGUgPT09IDEgfHwgdGhpcy5ub2RlVHlwZSA9PT0gMTEgfHwgdGhpcy5ub2RlVHlwZSA9PT0gOSApIHtcblx0XHRcdFx0dmFyIHRhcmdldCA9IG1hbmlwdWxhdGlvblRhcmdldCggdGhpcywgZWxlbSApO1xuXHRcdFx0XHR0YXJnZXQuaW5zZXJ0QmVmb3JlKCBlbGVtLCB0YXJnZXQuZmlyc3RDaGlsZCApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRiZWZvcmU6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiBkb21NYW5pcCggdGhpcywgYXJndW1lbnRzLCBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdGlmICggdGhpcy5wYXJlbnROb2RlICkge1xuXHRcdFx0XHR0aGlzLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKCBlbGVtLCB0aGlzICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdGFmdGVyOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gZG9tTWFuaXAoIHRoaXMsIGFyZ3VtZW50cywgZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRpZiAoIHRoaXMucGFyZW50Tm9kZSApIHtcblx0XHRcdFx0dGhpcy5wYXJlbnROb2RlLmluc2VydEJlZm9yZSggZWxlbSwgdGhpcy5uZXh0U2libGluZyApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRlbXB0eTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGVsZW0sXG5cdFx0XHRpID0gMDtcblxuXHRcdGZvciAoIDsgKCBlbGVtID0gdGhpc1sgaSBdICkgIT0gbnVsbDsgaSsrICkge1xuXHRcdFx0aWYgKCBlbGVtLm5vZGVUeXBlID09PSAxICkge1xuXG5cdFx0XHRcdC8vIFByZXZlbnQgbWVtb3J5IGxlYWtzXG5cdFx0XHRcdGpRdWVyeS5jbGVhbkRhdGEoIGdldEFsbCggZWxlbSwgZmFsc2UgKSApO1xuXG5cdFx0XHRcdC8vIFJlbW92ZSBhbnkgcmVtYWluaW5nIG5vZGVzXG5cdFx0XHRcdGVsZW0udGV4dENvbnRlbnQgPSBcIlwiO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdGNsb25lOiBmdW5jdGlvbiggZGF0YUFuZEV2ZW50cywgZGVlcERhdGFBbmRFdmVudHMgKSB7XG5cdFx0ZGF0YUFuZEV2ZW50cyA9IGRhdGFBbmRFdmVudHMgPT0gbnVsbCA/IGZhbHNlIDogZGF0YUFuZEV2ZW50cztcblx0XHRkZWVwRGF0YUFuZEV2ZW50cyA9IGRlZXBEYXRhQW5kRXZlbnRzID09IG51bGwgPyBkYXRhQW5kRXZlbnRzIDogZGVlcERhdGFBbmRFdmVudHM7XG5cblx0XHRyZXR1cm4gdGhpcy5tYXAoIGZ1bmN0aW9uKCkge1xuXHRcdFx0cmV0dXJuIGpRdWVyeS5jbG9uZSggdGhpcywgZGF0YUFuZEV2ZW50cywgZGVlcERhdGFBbmRFdmVudHMgKTtcblx0XHR9ICk7XG5cdH0sXG5cblx0aHRtbDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHJldHVybiBhY2Nlc3MoIHRoaXMsIGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRcdHZhciBlbGVtID0gdGhpc1sgMCBdIHx8IHt9LFxuXHRcdFx0XHRpID0gMCxcblx0XHRcdFx0bCA9IHRoaXMubGVuZ3RoO1xuXG5cdFx0XHRpZiAoIHZhbHVlID09PSB1bmRlZmluZWQgJiYgZWxlbS5ub2RlVHlwZSA9PT0gMSApIHtcblx0XHRcdFx0cmV0dXJuIGVsZW0uaW5uZXJIVE1MO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTZWUgaWYgd2UgY2FuIHRha2UgYSBzaG9ydGN1dCBhbmQganVzdCB1c2UgaW5uZXJIVE1MXG5cdFx0XHRpZiAoIHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiAmJiAhcm5vSW5uZXJodG1sLnRlc3QoIHZhbHVlICkgJiZcblx0XHRcdFx0IXdyYXBNYXBbICggcnRhZ05hbWUuZXhlYyggdmFsdWUgKSB8fCBbIFwiXCIsIFwiXCIgXSApWyAxIF0udG9Mb3dlckNhc2UoKSBdICkge1xuXG5cdFx0XHRcdHZhbHVlID0galF1ZXJ5Lmh0bWxQcmVmaWx0ZXIoIHZhbHVlICk7XG5cblx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRmb3IgKCA7IGkgPCBsOyBpKysgKSB7XG5cdFx0XHRcdFx0XHRlbGVtID0gdGhpc1sgaSBdIHx8IHt9O1xuXG5cdFx0XHRcdFx0XHQvLyBSZW1vdmUgZWxlbWVudCBub2RlcyBhbmQgcHJldmVudCBtZW1vcnkgbGVha3Ncblx0XHRcdFx0XHRcdGlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSApIHtcblx0XHRcdFx0XHRcdFx0alF1ZXJ5LmNsZWFuRGF0YSggZ2V0QWxsKCBlbGVtLCBmYWxzZSApICk7XG5cdFx0XHRcdFx0XHRcdGVsZW0uaW5uZXJIVE1MID0gdmFsdWU7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0ZWxlbSA9IDA7XG5cblx0XHRcdFx0Ly8gSWYgdXNpbmcgaW5uZXJIVE1MIHRocm93cyBhbiBleGNlcHRpb24sIHVzZSB0aGUgZmFsbGJhY2sgbWV0aG9kXG5cdFx0XHRcdH0gY2F0Y2ggKCBlICkge31cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBlbGVtICkge1xuXHRcdFx0XHR0aGlzLmVtcHR5KCkuYXBwZW5kKCB2YWx1ZSApO1xuXHRcdFx0fVxuXHRcdH0sIG51bGwsIHZhbHVlLCBhcmd1bWVudHMubGVuZ3RoICk7XG5cdH0sXG5cblx0cmVwbGFjZVdpdGg6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBpZ25vcmVkID0gW107XG5cblx0XHQvLyBNYWtlIHRoZSBjaGFuZ2VzLCByZXBsYWNpbmcgZWFjaCBub24taWdub3JlZCBjb250ZXh0IGVsZW1lbnQgd2l0aCB0aGUgbmV3IGNvbnRlbnRcblx0XHRyZXR1cm4gZG9tTWFuaXAoIHRoaXMsIGFyZ3VtZW50cywgZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHR2YXIgcGFyZW50ID0gdGhpcy5wYXJlbnROb2RlO1xuXG5cdFx0XHRpZiAoIGpRdWVyeS5pbkFycmF5KCB0aGlzLCBpZ25vcmVkICkgPCAwICkge1xuXHRcdFx0XHRqUXVlcnkuY2xlYW5EYXRhKCBnZXRBbGwoIHRoaXMgKSApO1xuXHRcdFx0XHRpZiAoIHBhcmVudCApIHtcblx0XHRcdFx0XHRwYXJlbnQucmVwbGFjZUNoaWxkKCBlbGVtLCB0aGlzICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdC8vIEZvcmNlIGNhbGxiYWNrIGludm9jYXRpb25cblx0XHR9LCBpZ25vcmVkICk7XG5cdH1cbn0gKTtcblxualF1ZXJ5LmVhY2goIHtcblx0YXBwZW5kVG86IFwiYXBwZW5kXCIsXG5cdHByZXBlbmRUbzogXCJwcmVwZW5kXCIsXG5cdGluc2VydEJlZm9yZTogXCJiZWZvcmVcIixcblx0aW5zZXJ0QWZ0ZXI6IFwiYWZ0ZXJcIixcblx0cmVwbGFjZUFsbDogXCJyZXBsYWNlV2l0aFwiXG59LCBmdW5jdGlvbiggbmFtZSwgb3JpZ2luYWwgKSB7XG5cdGpRdWVyeS5mblsgbmFtZSBdID0gZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdHZhciBlbGVtcyxcblx0XHRcdHJldCA9IFtdLFxuXHRcdFx0aW5zZXJ0ID0galF1ZXJ5KCBzZWxlY3RvciApLFxuXHRcdFx0bGFzdCA9IGluc2VydC5sZW5ndGggLSAxLFxuXHRcdFx0aSA9IDA7XG5cblx0XHRmb3IgKCA7IGkgPD0gbGFzdDsgaSsrICkge1xuXHRcdFx0ZWxlbXMgPSBpID09PSBsYXN0ID8gdGhpcyA6IHRoaXMuY2xvbmUoIHRydWUgKTtcblx0XHRcdGpRdWVyeSggaW5zZXJ0WyBpIF0gKVsgb3JpZ2luYWwgXSggZWxlbXMgKTtcblxuXHRcdFx0Ly8gU3VwcG9ydDogQW5kcm9pZCA8PTQuMCBvbmx5LCBQaGFudG9tSlMgMSBvbmx5XG5cdFx0XHQvLyAuZ2V0KCkgYmVjYXVzZSBwdXNoLmFwcGx5KF8sIGFycmF5bGlrZSkgdGhyb3dzIG9uIGFuY2llbnQgV2ViS2l0XG5cdFx0XHRwdXNoLmFwcGx5KCByZXQsIGVsZW1zLmdldCgpICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMucHVzaFN0YWNrKCByZXQgKTtcblx0fTtcbn0gKTtcbnZhciBybnVtbm9ucHggPSBuZXcgUmVnRXhwKCBcIl4oXCIgKyBwbnVtICsgXCIpKD8hcHgpW2EteiVdKyRcIiwgXCJpXCIgKTtcblxudmFyIGdldFN0eWxlcyA9IGZ1bmN0aW9uKCBlbGVtICkge1xuXG5cdFx0Ly8gU3VwcG9ydDogSUUgPD0xMSBvbmx5LCBGaXJlZm94IDw9MzAgKCMxNTA5OCwgIzE0MTUwKVxuXHRcdC8vIElFIHRocm93cyBvbiBlbGVtZW50cyBjcmVhdGVkIGluIHBvcHVwc1xuXHRcdC8vIEZGIG1lYW53aGlsZSB0aHJvd3Mgb24gZnJhbWUgZWxlbWVudHMgdGhyb3VnaCBcImRlZmF1bHRWaWV3LmdldENvbXB1dGVkU3R5bGVcIlxuXHRcdHZhciB2aWV3ID0gZWxlbS5vd25lckRvY3VtZW50LmRlZmF1bHRWaWV3O1xuXG5cdFx0aWYgKCAhdmlldyB8fCAhdmlldy5vcGVuZXIgKSB7XG5cdFx0XHR2aWV3ID0gd2luZG93O1xuXHRcdH1cblxuXHRcdHJldHVybiB2aWV3LmdldENvbXB1dGVkU3R5bGUoIGVsZW0gKTtcblx0fTtcblxudmFyIHN3YXAgPSBmdW5jdGlvbiggZWxlbSwgb3B0aW9ucywgY2FsbGJhY2sgKSB7XG5cdHZhciByZXQsIG5hbWUsXG5cdFx0b2xkID0ge307XG5cblx0Ly8gUmVtZW1iZXIgdGhlIG9sZCB2YWx1ZXMsIGFuZCBpbnNlcnQgdGhlIG5ldyBvbmVzXG5cdGZvciAoIG5hbWUgaW4gb3B0aW9ucyApIHtcblx0XHRvbGRbIG5hbWUgXSA9IGVsZW0uc3R5bGVbIG5hbWUgXTtcblx0XHRlbGVtLnN0eWxlWyBuYW1lIF0gPSBvcHRpb25zWyBuYW1lIF07XG5cdH1cblxuXHRyZXQgPSBjYWxsYmFjay5jYWxsKCBlbGVtICk7XG5cblx0Ly8gUmV2ZXJ0IHRoZSBvbGQgdmFsdWVzXG5cdGZvciAoIG5hbWUgaW4gb3B0aW9ucyApIHtcblx0XHRlbGVtLnN0eWxlWyBuYW1lIF0gPSBvbGRbIG5hbWUgXTtcblx0fVxuXG5cdHJldHVybiByZXQ7XG59O1xuXG5cbnZhciByYm94U3R5bGUgPSBuZXcgUmVnRXhwKCBjc3NFeHBhbmQuam9pbiggXCJ8XCIgKSwgXCJpXCIgKTtcblxuXG5cbiggZnVuY3Rpb24oKSB7XG5cblx0Ly8gRXhlY3V0aW5nIGJvdGggcGl4ZWxQb3NpdGlvbiAmIGJveFNpemluZ1JlbGlhYmxlIHRlc3RzIHJlcXVpcmUgb25seSBvbmUgbGF5b3V0XG5cdC8vIHNvIHRoZXkncmUgZXhlY3V0ZWQgYXQgdGhlIHNhbWUgdGltZSB0byBzYXZlIHRoZSBzZWNvbmQgY29tcHV0YXRpb24uXG5cdGZ1bmN0aW9uIGNvbXB1dGVTdHlsZVRlc3RzKCkge1xuXG5cdFx0Ly8gVGhpcyBpcyBhIHNpbmdsZXRvbiwgd2UgbmVlZCB0byBleGVjdXRlIGl0IG9ubHkgb25jZVxuXHRcdGlmICggIWRpdiApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRjb250YWluZXIuc3R5bGUuY3NzVGV4dCA9IFwicG9zaXRpb246YWJzb2x1dGU7bGVmdDotMTExMTFweDt3aWR0aDo2MHB4O1wiICtcblx0XHRcdFwibWFyZ2luLXRvcDoxcHg7cGFkZGluZzowO2JvcmRlcjowXCI7XG5cdFx0ZGl2LnN0eWxlLmNzc1RleHQgPVxuXHRcdFx0XCJwb3NpdGlvbjpyZWxhdGl2ZTtkaXNwbGF5OmJsb2NrO2JveC1zaXppbmc6Ym9yZGVyLWJveDtvdmVyZmxvdzpzY3JvbGw7XCIgK1xuXHRcdFx0XCJtYXJnaW46YXV0bztib3JkZXI6MXB4O3BhZGRpbmc6MXB4O1wiICtcblx0XHRcdFwid2lkdGg6NjAlO3RvcDoxJVwiO1xuXHRcdGRvY3VtZW50RWxlbWVudC5hcHBlbmRDaGlsZCggY29udGFpbmVyICkuYXBwZW5kQ2hpbGQoIGRpdiApO1xuXG5cdFx0dmFyIGRpdlN0eWxlID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUoIGRpdiApO1xuXHRcdHBpeGVsUG9zaXRpb25WYWwgPSBkaXZTdHlsZS50b3AgIT09IFwiMSVcIjtcblxuXHRcdC8vIFN1cHBvcnQ6IEFuZHJvaWQgNC4wIC0gNC4zIG9ubHksIEZpcmVmb3ggPD0zIC0gNDRcblx0XHRyZWxpYWJsZU1hcmdpbkxlZnRWYWwgPSByb3VuZFBpeGVsTWVhc3VyZXMoIGRpdlN0eWxlLm1hcmdpbkxlZnQgKSA9PT0gMTI7XG5cblx0XHQvLyBTdXBwb3J0OiBBbmRyb2lkIDQuMCAtIDQuMyBvbmx5LCBTYWZhcmkgPD05LjEgLSAxMC4xLCBpT1MgPD03LjAgLSA5LjNcblx0XHQvLyBTb21lIHN0eWxlcyBjb21lIGJhY2sgd2l0aCBwZXJjZW50YWdlIHZhbHVlcywgZXZlbiB0aG91Z2ggdGhleSBzaG91bGRuJ3Rcblx0XHRkaXYuc3R5bGUucmlnaHQgPSBcIjYwJVwiO1xuXHRcdHBpeGVsQm94U3R5bGVzVmFsID0gcm91bmRQaXhlbE1lYXN1cmVzKCBkaXZTdHlsZS5yaWdodCApID09PSAzNjtcblxuXHRcdC8vIFN1cHBvcnQ6IElFIDkgLSAxMSBvbmx5XG5cdFx0Ly8gRGV0ZWN0IG1pc3JlcG9ydGluZyBvZiBjb250ZW50IGRpbWVuc2lvbnMgZm9yIGJveC1zaXppbmc6Ym9yZGVyLWJveCBlbGVtZW50c1xuXHRcdGJveFNpemluZ1JlbGlhYmxlVmFsID0gcm91bmRQaXhlbE1lYXN1cmVzKCBkaXZTdHlsZS53aWR0aCApID09PSAzNjtcblxuXHRcdC8vIFN1cHBvcnQ6IElFIDkgb25seVxuXHRcdC8vIERldGVjdCBvdmVyZmxvdzpzY3JvbGwgc2NyZXdpbmVzcyAoZ2gtMzY5OSlcblx0XHQvLyBTdXBwb3J0OiBDaHJvbWUgPD02NFxuXHRcdC8vIERvbid0IGdldCB0cmlja2VkIHdoZW4gem9vbSBhZmZlY3RzIG9mZnNldFdpZHRoIChnaC00MDI5KVxuXHRcdGRpdi5zdHlsZS5wb3NpdGlvbiA9IFwiYWJzb2x1dGVcIjtcblx0XHRzY3JvbGxib3hTaXplVmFsID0gcm91bmRQaXhlbE1lYXN1cmVzKCBkaXYub2Zmc2V0V2lkdGggLyAzICkgPT09IDEyO1xuXG5cdFx0ZG9jdW1lbnRFbGVtZW50LnJlbW92ZUNoaWxkKCBjb250YWluZXIgKTtcblxuXHRcdC8vIE51bGxpZnkgdGhlIGRpdiBzbyBpdCB3b3VsZG4ndCBiZSBzdG9yZWQgaW4gdGhlIG1lbW9yeSBhbmRcblx0XHQvLyBpdCB3aWxsIGFsc28gYmUgYSBzaWduIHRoYXQgY2hlY2tzIGFscmVhZHkgcGVyZm9ybWVkXG5cdFx0ZGl2ID0gbnVsbDtcblx0fVxuXG5cdGZ1bmN0aW9uIHJvdW5kUGl4ZWxNZWFzdXJlcyggbWVhc3VyZSApIHtcblx0XHRyZXR1cm4gTWF0aC5yb3VuZCggcGFyc2VGbG9hdCggbWVhc3VyZSApICk7XG5cdH1cblxuXHR2YXIgcGl4ZWxQb3NpdGlvblZhbCwgYm94U2l6aW5nUmVsaWFibGVWYWwsIHNjcm9sbGJveFNpemVWYWwsIHBpeGVsQm94U3R5bGVzVmFsLFxuXHRcdHJlbGlhYmxlVHJEaW1lbnNpb25zVmFsLCByZWxpYWJsZU1hcmdpbkxlZnRWYWwsXG5cdFx0Y29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggXCJkaXZcIiApLFxuXHRcdGRpdiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwiZGl2XCIgKTtcblxuXHQvLyBGaW5pc2ggZWFybHkgaW4gbGltaXRlZCAobm9uLWJyb3dzZXIpIGVudmlyb25tZW50c1xuXHRpZiAoICFkaXYuc3R5bGUgKSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cblx0Ly8gU3VwcG9ydDogSUUgPD05IC0gMTEgb25seVxuXHQvLyBTdHlsZSBvZiBjbG9uZWQgZWxlbWVudCBhZmZlY3RzIHNvdXJjZSBlbGVtZW50IGNsb25lZCAoIzg5MDgpXG5cdGRpdi5zdHlsZS5iYWNrZ3JvdW5kQ2xpcCA9IFwiY29udGVudC1ib3hcIjtcblx0ZGl2LmNsb25lTm9kZSggdHJ1ZSApLnN0eWxlLmJhY2tncm91bmRDbGlwID0gXCJcIjtcblx0c3VwcG9ydC5jbGVhckNsb25lU3R5bGUgPSBkaXYuc3R5bGUuYmFja2dyb3VuZENsaXAgPT09IFwiY29udGVudC1ib3hcIjtcblxuXHRqUXVlcnkuZXh0ZW5kKCBzdXBwb3J0LCB7XG5cdFx0Ym94U2l6aW5nUmVsaWFibGU6IGZ1bmN0aW9uKCkge1xuXHRcdFx0Y29tcHV0ZVN0eWxlVGVzdHMoKTtcblx0XHRcdHJldHVybiBib3hTaXppbmdSZWxpYWJsZVZhbDtcblx0XHR9LFxuXHRcdHBpeGVsQm94U3R5bGVzOiBmdW5jdGlvbigpIHtcblx0XHRcdGNvbXB1dGVTdHlsZVRlc3RzKCk7XG5cdFx0XHRyZXR1cm4gcGl4ZWxCb3hTdHlsZXNWYWw7XG5cdFx0fSxcblx0XHRwaXhlbFBvc2l0aW9uOiBmdW5jdGlvbigpIHtcblx0XHRcdGNvbXB1dGVTdHlsZVRlc3RzKCk7XG5cdFx0XHRyZXR1cm4gcGl4ZWxQb3NpdGlvblZhbDtcblx0XHR9LFxuXHRcdHJlbGlhYmxlTWFyZ2luTGVmdDogZnVuY3Rpb24oKSB7XG5cdFx0XHRjb21wdXRlU3R5bGVUZXN0cygpO1xuXHRcdFx0cmV0dXJuIHJlbGlhYmxlTWFyZ2luTGVmdFZhbDtcblx0XHR9LFxuXHRcdHNjcm9sbGJveFNpemU6IGZ1bmN0aW9uKCkge1xuXHRcdFx0Y29tcHV0ZVN0eWxlVGVzdHMoKTtcblx0XHRcdHJldHVybiBzY3JvbGxib3hTaXplVmFsO1xuXHRcdH0sXG5cblx0XHQvLyBTdXBwb3J0OiBJRSA5IC0gMTErLCBFZGdlIDE1IC0gMTgrXG5cdFx0Ly8gSUUvRWRnZSBtaXNyZXBvcnQgYGdldENvbXB1dGVkU3R5bGVgIG9mIHRhYmxlIHJvd3Mgd2l0aCB3aWR0aC9oZWlnaHRcblx0XHQvLyBzZXQgaW4gQ1NTIHdoaWxlIGBvZmZzZXQqYCBwcm9wZXJ0aWVzIHJlcG9ydCBjb3JyZWN0IHZhbHVlcy5cblx0XHQvLyBCZWhhdmlvciBpbiBJRSA5IGlzIG1vcmUgc3VidGxlIHRoYW4gaW4gbmV3ZXIgdmVyc2lvbnMgJiBpdCBwYXNzZXNcblx0XHQvLyBzb21lIHZlcnNpb25zIG9mIHRoaXMgdGVzdDsgbWFrZSBzdXJlIG5vdCB0byBtYWtlIGl0IHBhc3MgdGhlcmUhXG5cdFx0Ly9cblx0XHQvLyBTdXBwb3J0OiBGaXJlZm94IDcwK1xuXHRcdC8vIE9ubHkgRmlyZWZveCBpbmNsdWRlcyBib3JkZXIgd2lkdGhzXG5cdFx0Ly8gaW4gY29tcHV0ZWQgZGltZW5zaW9ucy4gKGdoLTQ1MjkpXG5cdFx0cmVsaWFibGVUckRpbWVuc2lvbnM6IGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHRhYmxlLCB0ciwgdHJDaGlsZCwgdHJTdHlsZTtcblx0XHRcdGlmICggcmVsaWFibGVUckRpbWVuc2lvbnNWYWwgPT0gbnVsbCApIHtcblx0XHRcdFx0dGFibGUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcInRhYmxlXCIgKTtcblx0XHRcdFx0dHIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcInRyXCIgKTtcblx0XHRcdFx0dHJDaGlsZCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwiZGl2XCIgKTtcblxuXHRcdFx0XHR0YWJsZS5zdHlsZS5jc3NUZXh0ID0gXCJwb3NpdGlvbjphYnNvbHV0ZTtsZWZ0Oi0xMTExMXB4O2JvcmRlci1jb2xsYXBzZTpzZXBhcmF0ZVwiO1xuXHRcdFx0XHR0ci5zdHlsZS5jc3NUZXh0ID0gXCJib3JkZXI6MXB4IHNvbGlkXCI7XG5cblx0XHRcdFx0Ly8gU3VwcG9ydDogQ2hyb21lIDg2K1xuXHRcdFx0XHQvLyBIZWlnaHQgc2V0IHRocm91Z2ggY3NzVGV4dCBkb2VzIG5vdCBnZXQgYXBwbGllZC5cblx0XHRcdFx0Ly8gQ29tcHV0ZWQgaGVpZ2h0IHRoZW4gY29tZXMgYmFjayBhcyAwLlxuXHRcdFx0XHR0ci5zdHlsZS5oZWlnaHQgPSBcIjFweFwiO1xuXHRcdFx0XHR0ckNoaWxkLnN0eWxlLmhlaWdodCA9IFwiOXB4XCI7XG5cblx0XHRcdFx0Ly8gU3VwcG9ydDogQW5kcm9pZCA4IENocm9tZSA4Nitcblx0XHRcdFx0Ly8gSW4gb3VyIGJvZHlCYWNrZ3JvdW5kLmh0bWwgaWZyYW1lLFxuXHRcdFx0XHQvLyBkaXNwbGF5IGZvciBhbGwgZGl2IGVsZW1lbnRzIGlzIHNldCB0byBcImlubGluZVwiLFxuXHRcdFx0XHQvLyB3aGljaCBjYXVzZXMgYSBwcm9ibGVtIG9ubHkgaW4gQW5kcm9pZCA4IENocm9tZSA4Ni5cblx0XHRcdFx0Ly8gRW5zdXJpbmcgdGhlIGRpdiBpcyBkaXNwbGF5OiBibG9ja1xuXHRcdFx0XHQvLyBnZXRzIGFyb3VuZCB0aGlzIGlzc3VlLlxuXHRcdFx0XHR0ckNoaWxkLnN0eWxlLmRpc3BsYXkgPSBcImJsb2NrXCI7XG5cblx0XHRcdFx0ZG9jdW1lbnRFbGVtZW50XG5cdFx0XHRcdFx0LmFwcGVuZENoaWxkKCB0YWJsZSApXG5cdFx0XHRcdFx0LmFwcGVuZENoaWxkKCB0ciApXG5cdFx0XHRcdFx0LmFwcGVuZENoaWxkKCB0ckNoaWxkICk7XG5cblx0XHRcdFx0dHJTdHlsZSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKCB0ciApO1xuXHRcdFx0XHRyZWxpYWJsZVRyRGltZW5zaW9uc1ZhbCA9ICggcGFyc2VJbnQoIHRyU3R5bGUuaGVpZ2h0LCAxMCApICtcblx0XHRcdFx0XHRwYXJzZUludCggdHJTdHlsZS5ib3JkZXJUb3BXaWR0aCwgMTAgKSArXG5cdFx0XHRcdFx0cGFyc2VJbnQoIHRyU3R5bGUuYm9yZGVyQm90dG9tV2lkdGgsIDEwICkgKSA9PT0gdHIub2Zmc2V0SGVpZ2h0O1xuXG5cdFx0XHRcdGRvY3VtZW50RWxlbWVudC5yZW1vdmVDaGlsZCggdGFibGUgKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiByZWxpYWJsZVRyRGltZW5zaW9uc1ZhbDtcblx0XHR9XG5cdH0gKTtcbn0gKSgpO1xuXG5cbmZ1bmN0aW9uIGN1ckNTUyggZWxlbSwgbmFtZSwgY29tcHV0ZWQgKSB7XG5cdHZhciB3aWR0aCwgbWluV2lkdGgsIG1heFdpZHRoLCByZXQsXG5cblx0XHQvLyBTdXBwb3J0OiBGaXJlZm94IDUxK1xuXHRcdC8vIFJldHJpZXZpbmcgc3R5bGUgYmVmb3JlIGNvbXB1dGVkIHNvbWVob3dcblx0XHQvLyBmaXhlcyBhbiBpc3N1ZSB3aXRoIGdldHRpbmcgd3JvbmcgdmFsdWVzXG5cdFx0Ly8gb24gZGV0YWNoZWQgZWxlbWVudHNcblx0XHRzdHlsZSA9IGVsZW0uc3R5bGU7XG5cblx0Y29tcHV0ZWQgPSBjb21wdXRlZCB8fCBnZXRTdHlsZXMoIGVsZW0gKTtcblxuXHQvLyBnZXRQcm9wZXJ0eVZhbHVlIGlzIG5lZWRlZCBmb3I6XG5cdC8vICAgLmNzcygnZmlsdGVyJykgKElFIDkgb25seSwgIzEyNTM3KVxuXHQvLyAgIC5jc3MoJy0tY3VzdG9tUHJvcGVydHkpICgjMzE0NClcblx0aWYgKCBjb21wdXRlZCApIHtcblx0XHRyZXQgPSBjb21wdXRlZC5nZXRQcm9wZXJ0eVZhbHVlKCBuYW1lICkgfHwgY29tcHV0ZWRbIG5hbWUgXTtcblxuXHRcdGlmICggcmV0ID09PSBcIlwiICYmICFpc0F0dGFjaGVkKCBlbGVtICkgKSB7XG5cdFx0XHRyZXQgPSBqUXVlcnkuc3R5bGUoIGVsZW0sIG5hbWUgKTtcblx0XHR9XG5cblx0XHQvLyBBIHRyaWJ1dGUgdG8gdGhlIFwiYXdlc29tZSBoYWNrIGJ5IERlYW4gRWR3YXJkc1wiXG5cdFx0Ly8gQW5kcm9pZCBCcm93c2VyIHJldHVybnMgcGVyY2VudGFnZSBmb3Igc29tZSB2YWx1ZXMsXG5cdFx0Ly8gYnV0IHdpZHRoIHNlZW1zIHRvIGJlIHJlbGlhYmx5IHBpeGVscy5cblx0XHQvLyBUaGlzIGlzIGFnYWluc3QgdGhlIENTU09NIGRyYWZ0IHNwZWM6XG5cdFx0Ly8gaHR0cHM6Ly9kcmFmdHMuY3Nzd2cub3JnL2Nzc29tLyNyZXNvbHZlZC12YWx1ZXNcblx0XHRpZiAoICFzdXBwb3J0LnBpeGVsQm94U3R5bGVzKCkgJiYgcm51bW5vbnB4LnRlc3QoIHJldCApICYmIHJib3hTdHlsZS50ZXN0KCBuYW1lICkgKSB7XG5cblx0XHRcdC8vIFJlbWVtYmVyIHRoZSBvcmlnaW5hbCB2YWx1ZXNcblx0XHRcdHdpZHRoID0gc3R5bGUud2lkdGg7XG5cdFx0XHRtaW5XaWR0aCA9IHN0eWxlLm1pbldpZHRoO1xuXHRcdFx0bWF4V2lkdGggPSBzdHlsZS5tYXhXaWR0aDtcblxuXHRcdFx0Ly8gUHV0IGluIHRoZSBuZXcgdmFsdWVzIHRvIGdldCBhIGNvbXB1dGVkIHZhbHVlIG91dFxuXHRcdFx0c3R5bGUubWluV2lkdGggPSBzdHlsZS5tYXhXaWR0aCA9IHN0eWxlLndpZHRoID0gcmV0O1xuXHRcdFx0cmV0ID0gY29tcHV0ZWQud2lkdGg7XG5cblx0XHRcdC8vIFJldmVydCB0aGUgY2hhbmdlZCB2YWx1ZXNcblx0XHRcdHN0eWxlLndpZHRoID0gd2lkdGg7XG5cdFx0XHRzdHlsZS5taW5XaWR0aCA9IG1pbldpZHRoO1xuXHRcdFx0c3R5bGUubWF4V2lkdGggPSBtYXhXaWR0aDtcblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gcmV0ICE9PSB1bmRlZmluZWQgP1xuXG5cdFx0Ly8gU3VwcG9ydDogSUUgPD05IC0gMTEgb25seVxuXHRcdC8vIElFIHJldHVybnMgekluZGV4IHZhbHVlIGFzIGFuIGludGVnZXIuXG5cdFx0cmV0ICsgXCJcIiA6XG5cdFx0cmV0O1xufVxuXG5cbmZ1bmN0aW9uIGFkZEdldEhvb2tJZiggY29uZGl0aW9uRm4sIGhvb2tGbiApIHtcblxuXHQvLyBEZWZpbmUgdGhlIGhvb2ssIHdlJ2xsIGNoZWNrIG9uIHRoZSBmaXJzdCBydW4gaWYgaXQncyByZWFsbHkgbmVlZGVkLlxuXHRyZXR1cm4ge1xuXHRcdGdldDogZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoIGNvbmRpdGlvbkZuKCkgKSB7XG5cblx0XHRcdFx0Ly8gSG9vayBub3QgbmVlZGVkIChvciBpdCdzIG5vdCBwb3NzaWJsZSB0byB1c2UgaXQgZHVlXG5cdFx0XHRcdC8vIHRvIG1pc3NpbmcgZGVwZW5kZW5jeSksIHJlbW92ZSBpdC5cblx0XHRcdFx0ZGVsZXRlIHRoaXMuZ2V0O1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdC8vIEhvb2sgbmVlZGVkOyByZWRlZmluZSBpdCBzbyB0aGF0IHRoZSBzdXBwb3J0IHRlc3QgaXMgbm90IGV4ZWN1dGVkIGFnYWluLlxuXHRcdFx0cmV0dXJuICggdGhpcy5nZXQgPSBob29rRm4gKS5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0fVxuXHR9O1xufVxuXG5cbnZhciBjc3NQcmVmaXhlcyA9IFsgXCJXZWJraXRcIiwgXCJNb3pcIiwgXCJtc1wiIF0sXG5cdGVtcHR5U3R5bGUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcImRpdlwiICkuc3R5bGUsXG5cdHZlbmRvclByb3BzID0ge307XG5cbi8vIFJldHVybiBhIHZlbmRvci1wcmVmaXhlZCBwcm9wZXJ0eSBvciB1bmRlZmluZWRcbmZ1bmN0aW9uIHZlbmRvclByb3BOYW1lKCBuYW1lICkge1xuXG5cdC8vIENoZWNrIGZvciB2ZW5kb3IgcHJlZml4ZWQgbmFtZXNcblx0dmFyIGNhcE5hbWUgPSBuYW1lWyAwIF0udG9VcHBlckNhc2UoKSArIG5hbWUuc2xpY2UoIDEgKSxcblx0XHRpID0gY3NzUHJlZml4ZXMubGVuZ3RoO1xuXG5cdHdoaWxlICggaS0tICkge1xuXHRcdG5hbWUgPSBjc3NQcmVmaXhlc1sgaSBdICsgY2FwTmFtZTtcblx0XHRpZiAoIG5hbWUgaW4gZW1wdHlTdHlsZSApIHtcblx0XHRcdHJldHVybiBuYW1lO1xuXHRcdH1cblx0fVxufVxuXG4vLyBSZXR1cm4gYSBwb3RlbnRpYWxseS1tYXBwZWQgalF1ZXJ5LmNzc1Byb3BzIG9yIHZlbmRvciBwcmVmaXhlZCBwcm9wZXJ0eVxuZnVuY3Rpb24gZmluYWxQcm9wTmFtZSggbmFtZSApIHtcblx0dmFyIGZpbmFsID0galF1ZXJ5LmNzc1Byb3BzWyBuYW1lIF0gfHwgdmVuZG9yUHJvcHNbIG5hbWUgXTtcblxuXHRpZiAoIGZpbmFsICkge1xuXHRcdHJldHVybiBmaW5hbDtcblx0fVxuXHRpZiAoIG5hbWUgaW4gZW1wdHlTdHlsZSApIHtcblx0XHRyZXR1cm4gbmFtZTtcblx0fVxuXHRyZXR1cm4gdmVuZG9yUHJvcHNbIG5hbWUgXSA9IHZlbmRvclByb3BOYW1lKCBuYW1lICkgfHwgbmFtZTtcbn1cblxuXG52YXJcblxuXHQvLyBTd2FwcGFibGUgaWYgZGlzcGxheSBpcyBub25lIG9yIHN0YXJ0cyB3aXRoIHRhYmxlXG5cdC8vIGV4Y2VwdCBcInRhYmxlXCIsIFwidGFibGUtY2VsbFwiLCBvciBcInRhYmxlLWNhcHRpb25cIlxuXHQvLyBTZWUgaGVyZSBmb3IgZGlzcGxheSB2YWx1ZXM6IGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvQ1NTL2Rpc3BsYXlcblx0cmRpc3BsYXlzd2FwID0gL14obm9uZXx0YWJsZSg/IS1jW2VhXSkuKykvLFxuXHRyY3VzdG9tUHJvcCA9IC9eLS0vLFxuXHRjc3NTaG93ID0geyBwb3NpdGlvbjogXCJhYnNvbHV0ZVwiLCB2aXNpYmlsaXR5OiBcImhpZGRlblwiLCBkaXNwbGF5OiBcImJsb2NrXCIgfSxcblx0Y3NzTm9ybWFsVHJhbnNmb3JtID0ge1xuXHRcdGxldHRlclNwYWNpbmc6IFwiMFwiLFxuXHRcdGZvbnRXZWlnaHQ6IFwiNDAwXCJcblx0fTtcblxuZnVuY3Rpb24gc2V0UG9zaXRpdmVOdW1iZXIoIF9lbGVtLCB2YWx1ZSwgc3VidHJhY3QgKSB7XG5cblx0Ly8gQW55IHJlbGF0aXZlICgrLy0pIHZhbHVlcyBoYXZlIGFscmVhZHkgYmVlblxuXHQvLyBub3JtYWxpemVkIGF0IHRoaXMgcG9pbnRcblx0dmFyIG1hdGNoZXMgPSByY3NzTnVtLmV4ZWMoIHZhbHVlICk7XG5cdHJldHVybiBtYXRjaGVzID9cblxuXHRcdC8vIEd1YXJkIGFnYWluc3QgdW5kZWZpbmVkIFwic3VidHJhY3RcIiwgZS5nLiwgd2hlbiB1c2VkIGFzIGluIGNzc0hvb2tzXG5cdFx0TWF0aC5tYXgoIDAsIG1hdGNoZXNbIDIgXSAtICggc3VidHJhY3QgfHwgMCApICkgKyAoIG1hdGNoZXNbIDMgXSB8fCBcInB4XCIgKSA6XG5cdFx0dmFsdWU7XG59XG5cbmZ1bmN0aW9uIGJveE1vZGVsQWRqdXN0bWVudCggZWxlbSwgZGltZW5zaW9uLCBib3gsIGlzQm9yZGVyQm94LCBzdHlsZXMsIGNvbXB1dGVkVmFsICkge1xuXHR2YXIgaSA9IGRpbWVuc2lvbiA9PT0gXCJ3aWR0aFwiID8gMSA6IDAsXG5cdFx0ZXh0cmEgPSAwLFxuXHRcdGRlbHRhID0gMDtcblxuXHQvLyBBZGp1c3RtZW50IG1heSBub3QgYmUgbmVjZXNzYXJ5XG5cdGlmICggYm94ID09PSAoIGlzQm9yZGVyQm94ID8gXCJib3JkZXJcIiA6IFwiY29udGVudFwiICkgKSB7XG5cdFx0cmV0dXJuIDA7XG5cdH1cblxuXHRmb3IgKCA7IGkgPCA0OyBpICs9IDIgKSB7XG5cblx0XHQvLyBCb3RoIGJveCBtb2RlbHMgZXhjbHVkZSBtYXJnaW5cblx0XHRpZiAoIGJveCA9PT0gXCJtYXJnaW5cIiApIHtcblx0XHRcdGRlbHRhICs9IGpRdWVyeS5jc3MoIGVsZW0sIGJveCArIGNzc0V4cGFuZFsgaSBdLCB0cnVlLCBzdHlsZXMgKTtcblx0XHR9XG5cblx0XHQvLyBJZiB3ZSBnZXQgaGVyZSB3aXRoIGEgY29udGVudC1ib3gsIHdlJ3JlIHNlZWtpbmcgXCJwYWRkaW5nXCIgb3IgXCJib3JkZXJcIiBvciBcIm1hcmdpblwiXG5cdFx0aWYgKCAhaXNCb3JkZXJCb3ggKSB7XG5cblx0XHRcdC8vIEFkZCBwYWRkaW5nXG5cdFx0XHRkZWx0YSArPSBqUXVlcnkuY3NzKCBlbGVtLCBcInBhZGRpbmdcIiArIGNzc0V4cGFuZFsgaSBdLCB0cnVlLCBzdHlsZXMgKTtcblxuXHRcdFx0Ly8gRm9yIFwiYm9yZGVyXCIgb3IgXCJtYXJnaW5cIiwgYWRkIGJvcmRlclxuXHRcdFx0aWYgKCBib3ggIT09IFwicGFkZGluZ1wiICkge1xuXHRcdFx0XHRkZWx0YSArPSBqUXVlcnkuY3NzKCBlbGVtLCBcImJvcmRlclwiICsgY3NzRXhwYW5kWyBpIF0gKyBcIldpZHRoXCIsIHRydWUsIHN0eWxlcyApO1xuXG5cdFx0XHQvLyBCdXQgc3RpbGwga2VlcCB0cmFjayBvZiBpdCBvdGhlcndpc2Vcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGV4dHJhICs9IGpRdWVyeS5jc3MoIGVsZW0sIFwiYm9yZGVyXCIgKyBjc3NFeHBhbmRbIGkgXSArIFwiV2lkdGhcIiwgdHJ1ZSwgc3R5bGVzICk7XG5cdFx0XHR9XG5cblx0XHQvLyBJZiB3ZSBnZXQgaGVyZSB3aXRoIGEgYm9yZGVyLWJveCAoY29udGVudCArIHBhZGRpbmcgKyBib3JkZXIpLCB3ZSdyZSBzZWVraW5nIFwiY29udGVudFwiIG9yXG5cdFx0Ly8gXCJwYWRkaW5nXCIgb3IgXCJtYXJnaW5cIlxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIEZvciBcImNvbnRlbnRcIiwgc3VidHJhY3QgcGFkZGluZ1xuXHRcdFx0aWYgKCBib3ggPT09IFwiY29udGVudFwiICkge1xuXHRcdFx0XHRkZWx0YSAtPSBqUXVlcnkuY3NzKCBlbGVtLCBcInBhZGRpbmdcIiArIGNzc0V4cGFuZFsgaSBdLCB0cnVlLCBzdHlsZXMgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gRm9yIFwiY29udGVudFwiIG9yIFwicGFkZGluZ1wiLCBzdWJ0cmFjdCBib3JkZXJcblx0XHRcdGlmICggYm94ICE9PSBcIm1hcmdpblwiICkge1xuXHRcdFx0XHRkZWx0YSAtPSBqUXVlcnkuY3NzKCBlbGVtLCBcImJvcmRlclwiICsgY3NzRXhwYW5kWyBpIF0gKyBcIldpZHRoXCIsIHRydWUsIHN0eWxlcyApO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdC8vIEFjY291bnQgZm9yIHBvc2l0aXZlIGNvbnRlbnQtYm94IHNjcm9sbCBndXR0ZXIgd2hlbiByZXF1ZXN0ZWQgYnkgcHJvdmlkaW5nIGNvbXB1dGVkVmFsXG5cdGlmICggIWlzQm9yZGVyQm94ICYmIGNvbXB1dGVkVmFsID49IDAgKSB7XG5cblx0XHQvLyBvZmZzZXRXaWR0aC9vZmZzZXRIZWlnaHQgaXMgYSByb3VuZGVkIHN1bSBvZiBjb250ZW50LCBwYWRkaW5nLCBzY3JvbGwgZ3V0dGVyLCBhbmQgYm9yZGVyXG5cdFx0Ly8gQXNzdW1pbmcgaW50ZWdlciBzY3JvbGwgZ3V0dGVyLCBzdWJ0cmFjdCB0aGUgcmVzdCBhbmQgcm91bmQgZG93blxuXHRcdGRlbHRhICs9IE1hdGgubWF4KCAwLCBNYXRoLmNlaWwoXG5cdFx0XHRlbGVtWyBcIm9mZnNldFwiICsgZGltZW5zaW9uWyAwIF0udG9VcHBlckNhc2UoKSArIGRpbWVuc2lvbi5zbGljZSggMSApIF0gLVxuXHRcdFx0Y29tcHV0ZWRWYWwgLVxuXHRcdFx0ZGVsdGEgLVxuXHRcdFx0ZXh0cmEgLVxuXHRcdFx0MC41XG5cblx0XHQvLyBJZiBvZmZzZXRXaWR0aC9vZmZzZXRIZWlnaHQgaXMgdW5rbm93biwgdGhlbiB3ZSBjYW4ndCBkZXRlcm1pbmUgY29udGVudC1ib3ggc2Nyb2xsIGd1dHRlclxuXHRcdC8vIFVzZSBhbiBleHBsaWNpdCB6ZXJvIHRvIGF2b2lkIE5hTiAoZ2gtMzk2NClcblx0XHQpICkgfHwgMDtcblx0fVxuXG5cdHJldHVybiBkZWx0YTtcbn1cblxuZnVuY3Rpb24gZ2V0V2lkdGhPckhlaWdodCggZWxlbSwgZGltZW5zaW9uLCBleHRyYSApIHtcblxuXHQvLyBTdGFydCB3aXRoIGNvbXB1dGVkIHN0eWxlXG5cdHZhciBzdHlsZXMgPSBnZXRTdHlsZXMoIGVsZW0gKSxcblxuXHRcdC8vIFRvIGF2b2lkIGZvcmNpbmcgYSByZWZsb3csIG9ubHkgZmV0Y2ggYm94U2l6aW5nIGlmIHdlIG5lZWQgaXQgKGdoLTQzMjIpLlxuXHRcdC8vIEZha2UgY29udGVudC1ib3ggdW50aWwgd2Uga25vdyBpdCdzIG5lZWRlZCB0byBrbm93IHRoZSB0cnVlIHZhbHVlLlxuXHRcdGJveFNpemluZ05lZWRlZCA9ICFzdXBwb3J0LmJveFNpemluZ1JlbGlhYmxlKCkgfHwgZXh0cmEsXG5cdFx0aXNCb3JkZXJCb3ggPSBib3hTaXppbmdOZWVkZWQgJiZcblx0XHRcdGpRdWVyeS5jc3MoIGVsZW0sIFwiYm94U2l6aW5nXCIsIGZhbHNlLCBzdHlsZXMgKSA9PT0gXCJib3JkZXItYm94XCIsXG5cdFx0dmFsdWVJc0JvcmRlckJveCA9IGlzQm9yZGVyQm94LFxuXG5cdFx0dmFsID0gY3VyQ1NTKCBlbGVtLCBkaW1lbnNpb24sIHN0eWxlcyApLFxuXHRcdG9mZnNldFByb3AgPSBcIm9mZnNldFwiICsgZGltZW5zaW9uWyAwIF0udG9VcHBlckNhc2UoKSArIGRpbWVuc2lvbi5zbGljZSggMSApO1xuXG5cdC8vIFN1cHBvcnQ6IEZpcmVmb3ggPD01NFxuXHQvLyBSZXR1cm4gYSBjb25mb3VuZGluZyBub24tcGl4ZWwgdmFsdWUgb3IgZmVpZ24gaWdub3JhbmNlLCBhcyBhcHByb3ByaWF0ZS5cblx0aWYgKCBybnVtbm9ucHgudGVzdCggdmFsICkgKSB7XG5cdFx0aWYgKCAhZXh0cmEgKSB7XG5cdFx0XHRyZXR1cm4gdmFsO1xuXHRcdH1cblx0XHR2YWwgPSBcImF1dG9cIjtcblx0fVxuXG5cblx0Ly8gU3VwcG9ydDogSUUgOSAtIDExIG9ubHlcblx0Ly8gVXNlIG9mZnNldFdpZHRoL29mZnNldEhlaWdodCBmb3Igd2hlbiBib3ggc2l6aW5nIGlzIHVucmVsaWFibGUuXG5cdC8vIEluIHRob3NlIGNhc2VzLCB0aGUgY29tcHV0ZWQgdmFsdWUgY2FuIGJlIHRydXN0ZWQgdG8gYmUgYm9yZGVyLWJveC5cblx0aWYgKCAoICFzdXBwb3J0LmJveFNpemluZ1JlbGlhYmxlKCkgJiYgaXNCb3JkZXJCb3ggfHxcblxuXHRcdC8vIFN1cHBvcnQ6IElFIDEwIC0gMTErLCBFZGdlIDE1IC0gMTgrXG5cdFx0Ly8gSUUvRWRnZSBtaXNyZXBvcnQgYGdldENvbXB1dGVkU3R5bGVgIG9mIHRhYmxlIHJvd3Mgd2l0aCB3aWR0aC9oZWlnaHRcblx0XHQvLyBzZXQgaW4gQ1NTIHdoaWxlIGBvZmZzZXQqYCBwcm9wZXJ0aWVzIHJlcG9ydCBjb3JyZWN0IHZhbHVlcy5cblx0XHQvLyBJbnRlcmVzdGluZ2x5LCBpbiBzb21lIGNhc2VzIElFIDkgZG9lc24ndCBzdWZmZXIgZnJvbSB0aGlzIGlzc3VlLlxuXHRcdCFzdXBwb3J0LnJlbGlhYmxlVHJEaW1lbnNpb25zKCkgJiYgbm9kZU5hbWUoIGVsZW0sIFwidHJcIiApIHx8XG5cblx0XHQvLyBGYWxsIGJhY2sgdG8gb2Zmc2V0V2lkdGgvb2Zmc2V0SGVpZ2h0IHdoZW4gdmFsdWUgaXMgXCJhdXRvXCJcblx0XHQvLyBUaGlzIGhhcHBlbnMgZm9yIGlubGluZSBlbGVtZW50cyB3aXRoIG5vIGV4cGxpY2l0IHNldHRpbmcgKGdoLTM1NzEpXG5cdFx0dmFsID09PSBcImF1dG9cIiB8fFxuXG5cdFx0Ly8gU3VwcG9ydDogQW5kcm9pZCA8PTQuMSAtIDQuMyBvbmx5XG5cdFx0Ly8gQWxzbyB1c2Ugb2Zmc2V0V2lkdGgvb2Zmc2V0SGVpZ2h0IGZvciBtaXNyZXBvcnRlZCBpbmxpbmUgZGltZW5zaW9ucyAoZ2gtMzYwMilcblx0XHQhcGFyc2VGbG9hdCggdmFsICkgJiYgalF1ZXJ5LmNzcyggZWxlbSwgXCJkaXNwbGF5XCIsIGZhbHNlLCBzdHlsZXMgKSA9PT0gXCJpbmxpbmVcIiApICYmXG5cblx0XHQvLyBNYWtlIHN1cmUgdGhlIGVsZW1lbnQgaXMgdmlzaWJsZSAmIGNvbm5lY3RlZFxuXHRcdGVsZW0uZ2V0Q2xpZW50UmVjdHMoKS5sZW5ndGggKSB7XG5cblx0XHRpc0JvcmRlckJveCA9IGpRdWVyeS5jc3MoIGVsZW0sIFwiYm94U2l6aW5nXCIsIGZhbHNlLCBzdHlsZXMgKSA9PT0gXCJib3JkZXItYm94XCI7XG5cblx0XHQvLyBXaGVyZSBhdmFpbGFibGUsIG9mZnNldFdpZHRoL29mZnNldEhlaWdodCBhcHByb3hpbWF0ZSBib3JkZXIgYm94IGRpbWVuc2lvbnMuXG5cdFx0Ly8gV2hlcmUgbm90IGF2YWlsYWJsZSAoZS5nLiwgU1ZHKSwgYXNzdW1lIHVucmVsaWFibGUgYm94LXNpemluZyBhbmQgaW50ZXJwcmV0IHRoZVxuXHRcdC8vIHJldHJpZXZlZCB2YWx1ZSBhcyBhIGNvbnRlbnQgYm94IGRpbWVuc2lvbi5cblx0XHR2YWx1ZUlzQm9yZGVyQm94ID0gb2Zmc2V0UHJvcCBpbiBlbGVtO1xuXHRcdGlmICggdmFsdWVJc0JvcmRlckJveCApIHtcblx0XHRcdHZhbCA9IGVsZW1bIG9mZnNldFByb3AgXTtcblx0XHR9XG5cdH1cblxuXHQvLyBOb3JtYWxpemUgXCJcIiBhbmQgYXV0b1xuXHR2YWwgPSBwYXJzZUZsb2F0KCB2YWwgKSB8fCAwO1xuXG5cdC8vIEFkanVzdCBmb3IgdGhlIGVsZW1lbnQncyBib3ggbW9kZWxcblx0cmV0dXJuICggdmFsICtcblx0XHRib3hNb2RlbEFkanVzdG1lbnQoXG5cdFx0XHRlbGVtLFxuXHRcdFx0ZGltZW5zaW9uLFxuXHRcdFx0ZXh0cmEgfHwgKCBpc0JvcmRlckJveCA/IFwiYm9yZGVyXCIgOiBcImNvbnRlbnRcIiApLFxuXHRcdFx0dmFsdWVJc0JvcmRlckJveCxcblx0XHRcdHN0eWxlcyxcblxuXHRcdFx0Ly8gUHJvdmlkZSB0aGUgY3VycmVudCBjb21wdXRlZCBzaXplIHRvIHJlcXVlc3Qgc2Nyb2xsIGd1dHRlciBjYWxjdWxhdGlvbiAoZ2gtMzU4OSlcblx0XHRcdHZhbFxuXHRcdClcblx0KSArIFwicHhcIjtcbn1cblxualF1ZXJ5LmV4dGVuZCgge1xuXG5cdC8vIEFkZCBpbiBzdHlsZSBwcm9wZXJ0eSBob29rcyBmb3Igb3ZlcnJpZGluZyB0aGUgZGVmYXVsdFxuXHQvLyBiZWhhdmlvciBvZiBnZXR0aW5nIGFuZCBzZXR0aW5nIGEgc3R5bGUgcHJvcGVydHlcblx0Y3NzSG9va3M6IHtcblx0XHRvcGFjaXR5OiB7XG5cdFx0XHRnZXQ6IGZ1bmN0aW9uKCBlbGVtLCBjb21wdXRlZCApIHtcblx0XHRcdFx0aWYgKCBjb21wdXRlZCApIHtcblxuXHRcdFx0XHRcdC8vIFdlIHNob3VsZCBhbHdheXMgZ2V0IGEgbnVtYmVyIGJhY2sgZnJvbSBvcGFjaXR5XG5cdFx0XHRcdFx0dmFyIHJldCA9IGN1ckNTUyggZWxlbSwgXCJvcGFjaXR5XCIgKTtcblx0XHRcdFx0XHRyZXR1cm4gcmV0ID09PSBcIlwiID8gXCIxXCIgOiByZXQ7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0Ly8gRG9uJ3QgYXV0b21hdGljYWxseSBhZGQgXCJweFwiIHRvIHRoZXNlIHBvc3NpYmx5LXVuaXRsZXNzIHByb3BlcnRpZXNcblx0Y3NzTnVtYmVyOiB7XG5cdFx0XCJhbmltYXRpb25JdGVyYXRpb25Db3VudFwiOiB0cnVlLFxuXHRcdFwiY29sdW1uQ291bnRcIjogdHJ1ZSxcblx0XHRcImZpbGxPcGFjaXR5XCI6IHRydWUsXG5cdFx0XCJmbGV4R3Jvd1wiOiB0cnVlLFxuXHRcdFwiZmxleFNocmlua1wiOiB0cnVlLFxuXHRcdFwiZm9udFdlaWdodFwiOiB0cnVlLFxuXHRcdFwiZ3JpZEFyZWFcIjogdHJ1ZSxcblx0XHRcImdyaWRDb2x1bW5cIjogdHJ1ZSxcblx0XHRcImdyaWRDb2x1bW5FbmRcIjogdHJ1ZSxcblx0XHRcImdyaWRDb2x1bW5TdGFydFwiOiB0cnVlLFxuXHRcdFwiZ3JpZFJvd1wiOiB0cnVlLFxuXHRcdFwiZ3JpZFJvd0VuZFwiOiB0cnVlLFxuXHRcdFwiZ3JpZFJvd1N0YXJ0XCI6IHRydWUsXG5cdFx0XCJsaW5lSGVpZ2h0XCI6IHRydWUsXG5cdFx0XCJvcGFjaXR5XCI6IHRydWUsXG5cdFx0XCJvcmRlclwiOiB0cnVlLFxuXHRcdFwib3JwaGFuc1wiOiB0cnVlLFxuXHRcdFwid2lkb3dzXCI6IHRydWUsXG5cdFx0XCJ6SW5kZXhcIjogdHJ1ZSxcblx0XHRcInpvb21cIjogdHJ1ZVxuXHR9LFxuXG5cdC8vIEFkZCBpbiBwcm9wZXJ0aWVzIHdob3NlIG5hbWVzIHlvdSB3aXNoIHRvIGZpeCBiZWZvcmVcblx0Ly8gc2V0dGluZyBvciBnZXR0aW5nIHRoZSB2YWx1ZVxuXHRjc3NQcm9wczoge30sXG5cblx0Ly8gR2V0IGFuZCBzZXQgdGhlIHN0eWxlIHByb3BlcnR5IG9uIGEgRE9NIE5vZGVcblx0c3R5bGU6IGZ1bmN0aW9uKCBlbGVtLCBuYW1lLCB2YWx1ZSwgZXh0cmEgKSB7XG5cblx0XHQvLyBEb24ndCBzZXQgc3R5bGVzIG9uIHRleHQgYW5kIGNvbW1lbnQgbm9kZXNcblx0XHRpZiAoICFlbGVtIHx8IGVsZW0ubm9kZVR5cGUgPT09IDMgfHwgZWxlbS5ub2RlVHlwZSA9PT0gOCB8fCAhZWxlbS5zdHlsZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBNYWtlIHN1cmUgdGhhdCB3ZSdyZSB3b3JraW5nIHdpdGggdGhlIHJpZ2h0IG5hbWVcblx0XHR2YXIgcmV0LCB0eXBlLCBob29rcyxcblx0XHRcdG9yaWdOYW1lID0gY2FtZWxDYXNlKCBuYW1lICksXG5cdFx0XHRpc0N1c3RvbVByb3AgPSByY3VzdG9tUHJvcC50ZXN0KCBuYW1lICksXG5cdFx0XHRzdHlsZSA9IGVsZW0uc3R5bGU7XG5cblx0XHQvLyBNYWtlIHN1cmUgdGhhdCB3ZSdyZSB3b3JraW5nIHdpdGggdGhlIHJpZ2h0IG5hbWUuIFdlIGRvbid0XG5cdFx0Ly8gd2FudCB0byBxdWVyeSB0aGUgdmFsdWUgaWYgaXQgaXMgYSBDU1MgY3VzdG9tIHByb3BlcnR5XG5cdFx0Ly8gc2luY2UgdGhleSBhcmUgdXNlci1kZWZpbmVkLlxuXHRcdGlmICggIWlzQ3VzdG9tUHJvcCApIHtcblx0XHRcdG5hbWUgPSBmaW5hbFByb3BOYW1lKCBvcmlnTmFtZSApO1xuXHRcdH1cblxuXHRcdC8vIEdldHMgaG9vayBmb3IgdGhlIHByZWZpeGVkIHZlcnNpb24sIHRoZW4gdW5wcmVmaXhlZCB2ZXJzaW9uXG5cdFx0aG9va3MgPSBqUXVlcnkuY3NzSG9va3NbIG5hbWUgXSB8fCBqUXVlcnkuY3NzSG9va3NbIG9yaWdOYW1lIF07XG5cblx0XHQvLyBDaGVjayBpZiB3ZSdyZSBzZXR0aW5nIGEgdmFsdWVcblx0XHRpZiAoIHZhbHVlICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHR0eXBlID0gdHlwZW9mIHZhbHVlO1xuXG5cdFx0XHQvLyBDb252ZXJ0IFwiKz1cIiBvciBcIi09XCIgdG8gcmVsYXRpdmUgbnVtYmVycyAoIzczNDUpXG5cdFx0XHRpZiAoIHR5cGUgPT09IFwic3RyaW5nXCIgJiYgKCByZXQgPSByY3NzTnVtLmV4ZWMoIHZhbHVlICkgKSAmJiByZXRbIDEgXSApIHtcblx0XHRcdFx0dmFsdWUgPSBhZGp1c3RDU1MoIGVsZW0sIG5hbWUsIHJldCApO1xuXG5cdFx0XHRcdC8vIEZpeGVzIGJ1ZyAjOTIzN1xuXHRcdFx0XHR0eXBlID0gXCJudW1iZXJcIjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gTWFrZSBzdXJlIHRoYXQgbnVsbCBhbmQgTmFOIHZhbHVlcyBhcmVuJ3Qgc2V0ICgjNzExNilcblx0XHRcdGlmICggdmFsdWUgPT0gbnVsbCB8fCB2YWx1ZSAhPT0gdmFsdWUgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gSWYgYSBudW1iZXIgd2FzIHBhc3NlZCBpbiwgYWRkIHRoZSB1bml0IChleGNlcHQgZm9yIGNlcnRhaW4gQ1NTIHByb3BlcnRpZXMpXG5cdFx0XHQvLyBUaGUgaXNDdXN0b21Qcm9wIGNoZWNrIGNhbiBiZSByZW1vdmVkIGluIGpRdWVyeSA0LjAgd2hlbiB3ZSBvbmx5IGF1dG8tYXBwZW5kXG5cdFx0XHQvLyBcInB4XCIgdG8gYSBmZXcgaGFyZGNvZGVkIHZhbHVlcy5cblx0XHRcdGlmICggdHlwZSA9PT0gXCJudW1iZXJcIiAmJiAhaXNDdXN0b21Qcm9wICkge1xuXHRcdFx0XHR2YWx1ZSArPSByZXQgJiYgcmV0WyAzIF0gfHwgKCBqUXVlcnkuY3NzTnVtYmVyWyBvcmlnTmFtZSBdID8gXCJcIiA6IFwicHhcIiApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBiYWNrZ3JvdW5kLSogcHJvcHMgYWZmZWN0IG9yaWdpbmFsIGNsb25lJ3MgdmFsdWVzXG5cdFx0XHRpZiAoICFzdXBwb3J0LmNsZWFyQ2xvbmVTdHlsZSAmJiB2YWx1ZSA9PT0gXCJcIiAmJiBuYW1lLmluZGV4T2YoIFwiYmFja2dyb3VuZFwiICkgPT09IDAgKSB7XG5cdFx0XHRcdHN0eWxlWyBuYW1lIF0gPSBcImluaGVyaXRcIjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gSWYgYSBob29rIHdhcyBwcm92aWRlZCwgdXNlIHRoYXQgdmFsdWUsIG90aGVyd2lzZSBqdXN0IHNldCB0aGUgc3BlY2lmaWVkIHZhbHVlXG5cdFx0XHRpZiAoICFob29rcyB8fCAhKCBcInNldFwiIGluIGhvb2tzICkgfHxcblx0XHRcdFx0KCB2YWx1ZSA9IGhvb2tzLnNldCggZWxlbSwgdmFsdWUsIGV4dHJhICkgKSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGlmICggaXNDdXN0b21Qcm9wICkge1xuXHRcdFx0XHRcdHN0eWxlLnNldFByb3BlcnR5KCBuYW1lLCB2YWx1ZSApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHN0eWxlWyBuYW1lIF0gPSB2YWx1ZTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gSWYgYSBob29rIHdhcyBwcm92aWRlZCBnZXQgdGhlIG5vbi1jb21wdXRlZCB2YWx1ZSBmcm9tIHRoZXJlXG5cdFx0XHRpZiAoIGhvb2tzICYmIFwiZ2V0XCIgaW4gaG9va3MgJiZcblx0XHRcdFx0KCByZXQgPSBob29rcy5nZXQoIGVsZW0sIGZhbHNlLCBleHRyYSApICkgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRyZXR1cm4gcmV0O1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBPdGhlcndpc2UganVzdCBnZXQgdGhlIHZhbHVlIGZyb20gdGhlIHN0eWxlIG9iamVjdFxuXHRcdFx0cmV0dXJuIHN0eWxlWyBuYW1lIF07XG5cdFx0fVxuXHR9LFxuXG5cdGNzczogZnVuY3Rpb24oIGVsZW0sIG5hbWUsIGV4dHJhLCBzdHlsZXMgKSB7XG5cdFx0dmFyIHZhbCwgbnVtLCBob29rcyxcblx0XHRcdG9yaWdOYW1lID0gY2FtZWxDYXNlKCBuYW1lICksXG5cdFx0XHRpc0N1c3RvbVByb3AgPSByY3VzdG9tUHJvcC50ZXN0KCBuYW1lICk7XG5cblx0XHQvLyBNYWtlIHN1cmUgdGhhdCB3ZSdyZSB3b3JraW5nIHdpdGggdGhlIHJpZ2h0IG5hbWUuIFdlIGRvbid0XG5cdFx0Ly8gd2FudCB0byBtb2RpZnkgdGhlIHZhbHVlIGlmIGl0IGlzIGEgQ1NTIGN1c3RvbSBwcm9wZXJ0eVxuXHRcdC8vIHNpbmNlIHRoZXkgYXJlIHVzZXItZGVmaW5lZC5cblx0XHRpZiAoICFpc0N1c3RvbVByb3AgKSB7XG5cdFx0XHRuYW1lID0gZmluYWxQcm9wTmFtZSggb3JpZ05hbWUgKTtcblx0XHR9XG5cblx0XHQvLyBUcnkgcHJlZml4ZWQgbmFtZSBmb2xsb3dlZCBieSB0aGUgdW5wcmVmaXhlZCBuYW1lXG5cdFx0aG9va3MgPSBqUXVlcnkuY3NzSG9va3NbIG5hbWUgXSB8fCBqUXVlcnkuY3NzSG9va3NbIG9yaWdOYW1lIF07XG5cblx0XHQvLyBJZiBhIGhvb2sgd2FzIHByb3ZpZGVkIGdldCB0aGUgY29tcHV0ZWQgdmFsdWUgZnJvbSB0aGVyZVxuXHRcdGlmICggaG9va3MgJiYgXCJnZXRcIiBpbiBob29rcyApIHtcblx0XHRcdHZhbCA9IGhvb2tzLmdldCggZWxlbSwgdHJ1ZSwgZXh0cmEgKTtcblx0XHR9XG5cblx0XHQvLyBPdGhlcndpc2UsIGlmIGEgd2F5IHRvIGdldCB0aGUgY29tcHV0ZWQgdmFsdWUgZXhpc3RzLCB1c2UgdGhhdFxuXHRcdGlmICggdmFsID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHR2YWwgPSBjdXJDU1MoIGVsZW0sIG5hbWUsIHN0eWxlcyApO1xuXHRcdH1cblxuXHRcdC8vIENvbnZlcnQgXCJub3JtYWxcIiB0byBjb21wdXRlZCB2YWx1ZVxuXHRcdGlmICggdmFsID09PSBcIm5vcm1hbFwiICYmIG5hbWUgaW4gY3NzTm9ybWFsVHJhbnNmb3JtICkge1xuXHRcdFx0dmFsID0gY3NzTm9ybWFsVHJhbnNmb3JtWyBuYW1lIF07XG5cdFx0fVxuXG5cdFx0Ly8gTWFrZSBudW1lcmljIGlmIGZvcmNlZCBvciBhIHF1YWxpZmllciB3YXMgcHJvdmlkZWQgYW5kIHZhbCBsb29rcyBudW1lcmljXG5cdFx0aWYgKCBleHRyYSA9PT0gXCJcIiB8fCBleHRyYSApIHtcblx0XHRcdG51bSA9IHBhcnNlRmxvYXQoIHZhbCApO1xuXHRcdFx0cmV0dXJuIGV4dHJhID09PSB0cnVlIHx8IGlzRmluaXRlKCBudW0gKSA/IG51bSB8fCAwIDogdmFsO1xuXHRcdH1cblxuXHRcdHJldHVybiB2YWw7XG5cdH1cbn0gKTtcblxualF1ZXJ5LmVhY2goIFsgXCJoZWlnaHRcIiwgXCJ3aWR0aFwiIF0sIGZ1bmN0aW9uKCBfaSwgZGltZW5zaW9uICkge1xuXHRqUXVlcnkuY3NzSG9va3NbIGRpbWVuc2lvbiBdID0ge1xuXHRcdGdldDogZnVuY3Rpb24oIGVsZW0sIGNvbXB1dGVkLCBleHRyYSApIHtcblx0XHRcdGlmICggY29tcHV0ZWQgKSB7XG5cblx0XHRcdFx0Ly8gQ2VydGFpbiBlbGVtZW50cyBjYW4gaGF2ZSBkaW1lbnNpb24gaW5mbyBpZiB3ZSBpbnZpc2libHkgc2hvdyB0aGVtXG5cdFx0XHRcdC8vIGJ1dCBpdCBtdXN0IGhhdmUgYSBjdXJyZW50IGRpc3BsYXkgc3R5bGUgdGhhdCB3b3VsZCBiZW5lZml0XG5cdFx0XHRcdHJldHVybiByZGlzcGxheXN3YXAudGVzdCggalF1ZXJ5LmNzcyggZWxlbSwgXCJkaXNwbGF5XCIgKSApICYmXG5cblx0XHRcdFx0XHQvLyBTdXBwb3J0OiBTYWZhcmkgOCtcblx0XHRcdFx0XHQvLyBUYWJsZSBjb2x1bW5zIGluIFNhZmFyaSBoYXZlIG5vbi16ZXJvIG9mZnNldFdpZHRoICYgemVyb1xuXHRcdFx0XHRcdC8vIGdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLndpZHRoIHVubGVzcyBkaXNwbGF5IGlzIGNoYW5nZWQuXG5cdFx0XHRcdFx0Ly8gU3VwcG9ydDogSUUgPD0xMSBvbmx5XG5cdFx0XHRcdFx0Ly8gUnVubmluZyBnZXRCb3VuZGluZ0NsaWVudFJlY3Qgb24gYSBkaXNjb25uZWN0ZWQgbm9kZVxuXHRcdFx0XHRcdC8vIGluIElFIHRocm93cyBhbiBlcnJvci5cblx0XHRcdFx0XHQoICFlbGVtLmdldENsaWVudFJlY3RzKCkubGVuZ3RoIHx8ICFlbGVtLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLndpZHRoICkgP1xuXHRcdFx0XHRcdHN3YXAoIGVsZW0sIGNzc1Nob3csIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIGdldFdpZHRoT3JIZWlnaHQoIGVsZW0sIGRpbWVuc2lvbiwgZXh0cmEgKTtcblx0XHRcdFx0XHR9ICkgOlxuXHRcdFx0XHRcdGdldFdpZHRoT3JIZWlnaHQoIGVsZW0sIGRpbWVuc2lvbiwgZXh0cmEgKTtcblx0XHRcdH1cblx0XHR9LFxuXG5cdFx0c2V0OiBmdW5jdGlvbiggZWxlbSwgdmFsdWUsIGV4dHJhICkge1xuXHRcdFx0dmFyIG1hdGNoZXMsXG5cdFx0XHRcdHN0eWxlcyA9IGdldFN0eWxlcyggZWxlbSApLFxuXG5cdFx0XHRcdC8vIE9ubHkgcmVhZCBzdHlsZXMucG9zaXRpb24gaWYgdGhlIHRlc3QgaGFzIGEgY2hhbmNlIHRvIGZhaWxcblx0XHRcdFx0Ly8gdG8gYXZvaWQgZm9yY2luZyBhIHJlZmxvdy5cblx0XHRcdFx0c2Nyb2xsYm94U2l6ZUJ1Z2d5ID0gIXN1cHBvcnQuc2Nyb2xsYm94U2l6ZSgpICYmXG5cdFx0XHRcdFx0c3R5bGVzLnBvc2l0aW9uID09PSBcImFic29sdXRlXCIsXG5cblx0XHRcdFx0Ly8gVG8gYXZvaWQgZm9yY2luZyBhIHJlZmxvdywgb25seSBmZXRjaCBib3hTaXppbmcgaWYgd2UgbmVlZCBpdCAoZ2gtMzk5MSlcblx0XHRcdFx0Ym94U2l6aW5nTmVlZGVkID0gc2Nyb2xsYm94U2l6ZUJ1Z2d5IHx8IGV4dHJhLFxuXHRcdFx0XHRpc0JvcmRlckJveCA9IGJveFNpemluZ05lZWRlZCAmJlxuXHRcdFx0XHRcdGpRdWVyeS5jc3MoIGVsZW0sIFwiYm94U2l6aW5nXCIsIGZhbHNlLCBzdHlsZXMgKSA9PT0gXCJib3JkZXItYm94XCIsXG5cdFx0XHRcdHN1YnRyYWN0ID0gZXh0cmEgP1xuXHRcdFx0XHRcdGJveE1vZGVsQWRqdXN0bWVudChcblx0XHRcdFx0XHRcdGVsZW0sXG5cdFx0XHRcdFx0XHRkaW1lbnNpb24sXG5cdFx0XHRcdFx0XHRleHRyYSxcblx0XHRcdFx0XHRcdGlzQm9yZGVyQm94LFxuXHRcdFx0XHRcdFx0c3R5bGVzXG5cdFx0XHRcdFx0KSA6XG5cdFx0XHRcdFx0MDtcblxuXHRcdFx0Ly8gQWNjb3VudCBmb3IgdW5yZWxpYWJsZSBib3JkZXItYm94IGRpbWVuc2lvbnMgYnkgY29tcGFyaW5nIG9mZnNldCogdG8gY29tcHV0ZWQgYW5kXG5cdFx0XHQvLyBmYWtpbmcgYSBjb250ZW50LWJveCB0byBnZXQgYm9yZGVyIGFuZCBwYWRkaW5nIChnaC0zNjk5KVxuXHRcdFx0aWYgKCBpc0JvcmRlckJveCAmJiBzY3JvbGxib3hTaXplQnVnZ3kgKSB7XG5cdFx0XHRcdHN1YnRyYWN0IC09IE1hdGguY2VpbChcblx0XHRcdFx0XHRlbGVtWyBcIm9mZnNldFwiICsgZGltZW5zaW9uWyAwIF0udG9VcHBlckNhc2UoKSArIGRpbWVuc2lvbi5zbGljZSggMSApIF0gLVxuXHRcdFx0XHRcdHBhcnNlRmxvYXQoIHN0eWxlc1sgZGltZW5zaW9uIF0gKSAtXG5cdFx0XHRcdFx0Ym94TW9kZWxBZGp1c3RtZW50KCBlbGVtLCBkaW1lbnNpb24sIFwiYm9yZGVyXCIsIGZhbHNlLCBzdHlsZXMgKSAtXG5cdFx0XHRcdFx0MC41XG5cdFx0XHRcdCk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIENvbnZlcnQgdG8gcGl4ZWxzIGlmIHZhbHVlIGFkanVzdG1lbnQgaXMgbmVlZGVkXG5cdFx0XHRpZiAoIHN1YnRyYWN0ICYmICggbWF0Y2hlcyA9IHJjc3NOdW0uZXhlYyggdmFsdWUgKSApICYmXG5cdFx0XHRcdCggbWF0Y2hlc1sgMyBdIHx8IFwicHhcIiApICE9PSBcInB4XCIgKSB7XG5cblx0XHRcdFx0ZWxlbS5zdHlsZVsgZGltZW5zaW9uIF0gPSB2YWx1ZTtcblx0XHRcdFx0dmFsdWUgPSBqUXVlcnkuY3NzKCBlbGVtLCBkaW1lbnNpb24gKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHNldFBvc2l0aXZlTnVtYmVyKCBlbGVtLCB2YWx1ZSwgc3VidHJhY3QgKTtcblx0XHR9XG5cdH07XG59ICk7XG5cbmpRdWVyeS5jc3NIb29rcy5tYXJnaW5MZWZ0ID0gYWRkR2V0SG9va0lmKCBzdXBwb3J0LnJlbGlhYmxlTWFyZ2luTGVmdCxcblx0ZnVuY3Rpb24oIGVsZW0sIGNvbXB1dGVkICkge1xuXHRcdGlmICggY29tcHV0ZWQgKSB7XG5cdFx0XHRyZXR1cm4gKCBwYXJzZUZsb2F0KCBjdXJDU1MoIGVsZW0sIFwibWFyZ2luTGVmdFwiICkgKSB8fFxuXHRcdFx0XHRlbGVtLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQgLVxuXHRcdFx0XHRcdHN3YXAoIGVsZW0sIHsgbWFyZ2luTGVmdDogMCB9LCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdHJldHVybiBlbGVtLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQ7XG5cdFx0XHRcdFx0fSApXG5cdFx0XHQpICsgXCJweFwiO1xuXHRcdH1cblx0fVxuKTtcblxuLy8gVGhlc2UgaG9va3MgYXJlIHVzZWQgYnkgYW5pbWF0ZSB0byBleHBhbmQgcHJvcGVydGllc1xualF1ZXJ5LmVhY2goIHtcblx0bWFyZ2luOiBcIlwiLFxuXHRwYWRkaW5nOiBcIlwiLFxuXHRib3JkZXI6IFwiV2lkdGhcIlxufSwgZnVuY3Rpb24oIHByZWZpeCwgc3VmZml4ICkge1xuXHRqUXVlcnkuY3NzSG9va3NbIHByZWZpeCArIHN1ZmZpeCBdID0ge1xuXHRcdGV4cGFuZDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdFx0dmFyIGkgPSAwLFxuXHRcdFx0XHRleHBhbmRlZCA9IHt9LFxuXG5cdFx0XHRcdC8vIEFzc3VtZXMgYSBzaW5nbGUgbnVtYmVyIGlmIG5vdCBhIHN0cmluZ1xuXHRcdFx0XHRwYXJ0cyA9IHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiA/IHZhbHVlLnNwbGl0KCBcIiBcIiApIDogWyB2YWx1ZSBdO1xuXG5cdFx0XHRmb3IgKCA7IGkgPCA0OyBpKysgKSB7XG5cdFx0XHRcdGV4cGFuZGVkWyBwcmVmaXggKyBjc3NFeHBhbmRbIGkgXSArIHN1ZmZpeCBdID1cblx0XHRcdFx0XHRwYXJ0c1sgaSBdIHx8IHBhcnRzWyBpIC0gMiBdIHx8IHBhcnRzWyAwIF07XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBleHBhbmRlZDtcblx0XHR9XG5cdH07XG5cblx0aWYgKCBwcmVmaXggIT09IFwibWFyZ2luXCIgKSB7XG5cdFx0alF1ZXJ5LmNzc0hvb2tzWyBwcmVmaXggKyBzdWZmaXggXS5zZXQgPSBzZXRQb3NpdGl2ZU51bWJlcjtcblx0fVxufSApO1xuXG5qUXVlcnkuZm4uZXh0ZW5kKCB7XG5cdGNzczogZnVuY3Rpb24oIG5hbWUsIHZhbHVlICkge1xuXHRcdHJldHVybiBhY2Nlc3MoIHRoaXMsIGZ1bmN0aW9uKCBlbGVtLCBuYW1lLCB2YWx1ZSApIHtcblx0XHRcdHZhciBzdHlsZXMsIGxlbixcblx0XHRcdFx0bWFwID0ge30sXG5cdFx0XHRcdGkgPSAwO1xuXG5cdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIG5hbWUgKSApIHtcblx0XHRcdFx0c3R5bGVzID0gZ2V0U3R5bGVzKCBlbGVtICk7XG5cdFx0XHRcdGxlbiA9IG5hbWUubGVuZ3RoO1xuXG5cdFx0XHRcdGZvciAoIDsgaSA8IGxlbjsgaSsrICkge1xuXHRcdFx0XHRcdG1hcFsgbmFtZVsgaSBdIF0gPSBqUXVlcnkuY3NzKCBlbGVtLCBuYW1lWyBpIF0sIGZhbHNlLCBzdHlsZXMgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiBtYXA7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB2YWx1ZSAhPT0gdW5kZWZpbmVkID9cblx0XHRcdFx0alF1ZXJ5LnN0eWxlKCBlbGVtLCBuYW1lLCB2YWx1ZSApIDpcblx0XHRcdFx0alF1ZXJ5LmNzcyggZWxlbSwgbmFtZSApO1xuXHRcdH0sIG5hbWUsIHZhbHVlLCBhcmd1bWVudHMubGVuZ3RoID4gMSApO1xuXHR9XG59ICk7XG5cblxuZnVuY3Rpb24gVHdlZW4oIGVsZW0sIG9wdGlvbnMsIHByb3AsIGVuZCwgZWFzaW5nICkge1xuXHRyZXR1cm4gbmV3IFR3ZWVuLnByb3RvdHlwZS5pbml0KCBlbGVtLCBvcHRpb25zLCBwcm9wLCBlbmQsIGVhc2luZyApO1xufVxualF1ZXJ5LlR3ZWVuID0gVHdlZW47XG5cblR3ZWVuLnByb3RvdHlwZSA9IHtcblx0Y29uc3RydWN0b3I6IFR3ZWVuLFxuXHRpbml0OiBmdW5jdGlvbiggZWxlbSwgb3B0aW9ucywgcHJvcCwgZW5kLCBlYXNpbmcsIHVuaXQgKSB7XG5cdFx0dGhpcy5lbGVtID0gZWxlbTtcblx0XHR0aGlzLnByb3AgPSBwcm9wO1xuXHRcdHRoaXMuZWFzaW5nID0gZWFzaW5nIHx8IGpRdWVyeS5lYXNpbmcuX2RlZmF1bHQ7XG5cdFx0dGhpcy5vcHRpb25zID0gb3B0aW9ucztcblx0XHR0aGlzLnN0YXJ0ID0gdGhpcy5ub3cgPSB0aGlzLmN1cigpO1xuXHRcdHRoaXMuZW5kID0gZW5kO1xuXHRcdHRoaXMudW5pdCA9IHVuaXQgfHwgKCBqUXVlcnkuY3NzTnVtYmVyWyBwcm9wIF0gPyBcIlwiIDogXCJweFwiICk7XG5cdH0sXG5cdGN1cjogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGhvb2tzID0gVHdlZW4ucHJvcEhvb2tzWyB0aGlzLnByb3AgXTtcblxuXHRcdHJldHVybiBob29rcyAmJiBob29rcy5nZXQgP1xuXHRcdFx0aG9va3MuZ2V0KCB0aGlzICkgOlxuXHRcdFx0VHdlZW4ucHJvcEhvb2tzLl9kZWZhdWx0LmdldCggdGhpcyApO1xuXHR9LFxuXHRydW46IGZ1bmN0aW9uKCBwZXJjZW50ICkge1xuXHRcdHZhciBlYXNlZCxcblx0XHRcdGhvb2tzID0gVHdlZW4ucHJvcEhvb2tzWyB0aGlzLnByb3AgXTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmR1cmF0aW9uICkge1xuXHRcdFx0dGhpcy5wb3MgPSBlYXNlZCA9IGpRdWVyeS5lYXNpbmdbIHRoaXMuZWFzaW5nIF0oXG5cdFx0XHRcdHBlcmNlbnQsIHRoaXMub3B0aW9ucy5kdXJhdGlvbiAqIHBlcmNlbnQsIDAsIDEsIHRoaXMub3B0aW9ucy5kdXJhdGlvblxuXHRcdFx0KTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5wb3MgPSBlYXNlZCA9IHBlcmNlbnQ7XG5cdFx0fVxuXHRcdHRoaXMubm93ID0gKCB0aGlzLmVuZCAtIHRoaXMuc3RhcnQgKSAqIGVhc2VkICsgdGhpcy5zdGFydDtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLnN0ZXAgKSB7XG5cdFx0XHR0aGlzLm9wdGlvbnMuc3RlcC5jYWxsKCB0aGlzLmVsZW0sIHRoaXMubm93LCB0aGlzICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBob29rcyAmJiBob29rcy5zZXQgKSB7XG5cdFx0XHRob29rcy5zZXQoIHRoaXMgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0VHdlZW4ucHJvcEhvb2tzLl9kZWZhdWx0LnNldCggdGhpcyApO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcztcblx0fVxufTtcblxuVHdlZW4ucHJvdG90eXBlLmluaXQucHJvdG90eXBlID0gVHdlZW4ucHJvdG90eXBlO1xuXG5Ud2Vlbi5wcm9wSG9va3MgPSB7XG5cdF9kZWZhdWx0OiB7XG5cdFx0Z2V0OiBmdW5jdGlvbiggdHdlZW4gKSB7XG5cdFx0XHR2YXIgcmVzdWx0O1xuXG5cdFx0XHQvLyBVc2UgYSBwcm9wZXJ0eSBvbiB0aGUgZWxlbWVudCBkaXJlY3RseSB3aGVuIGl0IGlzIG5vdCBhIERPTSBlbGVtZW50LFxuXHRcdFx0Ly8gb3Igd2hlbiB0aGVyZSBpcyBubyBtYXRjaGluZyBzdHlsZSBwcm9wZXJ0eSB0aGF0IGV4aXN0cy5cblx0XHRcdGlmICggdHdlZW4uZWxlbS5ub2RlVHlwZSAhPT0gMSB8fFxuXHRcdFx0XHR0d2Vlbi5lbGVtWyB0d2Vlbi5wcm9wIF0gIT0gbnVsbCAmJiB0d2Vlbi5lbGVtLnN0eWxlWyB0d2Vlbi5wcm9wIF0gPT0gbnVsbCApIHtcblx0XHRcdFx0cmV0dXJuIHR3ZWVuLmVsZW1bIHR3ZWVuLnByb3AgXTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gUGFzc2luZyBhbiBlbXB0eSBzdHJpbmcgYXMgYSAzcmQgcGFyYW1ldGVyIHRvIC5jc3Mgd2lsbCBhdXRvbWF0aWNhbGx5XG5cdFx0XHQvLyBhdHRlbXB0IGEgcGFyc2VGbG9hdCBhbmQgZmFsbGJhY2sgdG8gYSBzdHJpbmcgaWYgdGhlIHBhcnNlIGZhaWxzLlxuXHRcdFx0Ly8gU2ltcGxlIHZhbHVlcyBzdWNoIGFzIFwiMTBweFwiIGFyZSBwYXJzZWQgdG8gRmxvYXQ7XG5cdFx0XHQvLyBjb21wbGV4IHZhbHVlcyBzdWNoIGFzIFwicm90YXRlKDFyYWQpXCIgYXJlIHJldHVybmVkIGFzLWlzLlxuXHRcdFx0cmVzdWx0ID0galF1ZXJ5LmNzcyggdHdlZW4uZWxlbSwgdHdlZW4ucHJvcCwgXCJcIiApO1xuXG5cdFx0XHQvLyBFbXB0eSBzdHJpbmdzLCBudWxsLCB1bmRlZmluZWQgYW5kIFwiYXV0b1wiIGFyZSBjb252ZXJ0ZWQgdG8gMC5cblx0XHRcdHJldHVybiAhcmVzdWx0IHx8IHJlc3VsdCA9PT0gXCJhdXRvXCIgPyAwIDogcmVzdWx0O1xuXHRcdH0sXG5cdFx0c2V0OiBmdW5jdGlvbiggdHdlZW4gKSB7XG5cblx0XHRcdC8vIFVzZSBzdGVwIGhvb2sgZm9yIGJhY2sgY29tcGF0LlxuXHRcdFx0Ly8gVXNlIGNzc0hvb2sgaWYgaXRzIHRoZXJlLlxuXHRcdFx0Ly8gVXNlIC5zdHlsZSBpZiBhdmFpbGFibGUgYW5kIHVzZSBwbGFpbiBwcm9wZXJ0aWVzIHdoZXJlIGF2YWlsYWJsZS5cblx0XHRcdGlmICggalF1ZXJ5LmZ4LnN0ZXBbIHR3ZWVuLnByb3AgXSApIHtcblx0XHRcdFx0alF1ZXJ5LmZ4LnN0ZXBbIHR3ZWVuLnByb3AgXSggdHdlZW4gKTtcblx0XHRcdH0gZWxzZSBpZiAoIHR3ZWVuLmVsZW0ubm9kZVR5cGUgPT09IDEgJiYgKFxuXHRcdFx0XHRqUXVlcnkuY3NzSG9va3NbIHR3ZWVuLnByb3AgXSB8fFxuXHRcdFx0XHRcdHR3ZWVuLmVsZW0uc3R5bGVbIGZpbmFsUHJvcE5hbWUoIHR3ZWVuLnByb3AgKSBdICE9IG51bGwgKSApIHtcblx0XHRcdFx0alF1ZXJ5LnN0eWxlKCB0d2Vlbi5lbGVtLCB0d2Vlbi5wcm9wLCB0d2Vlbi5ub3cgKyB0d2Vlbi51bml0ICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0d2Vlbi5lbGVtWyB0d2Vlbi5wcm9wIF0gPSB0d2Vlbi5ub3c7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG59O1xuXG4vLyBTdXBwb3J0OiBJRSA8PTkgb25seVxuLy8gUGFuaWMgYmFzZWQgYXBwcm9hY2ggdG8gc2V0dGluZyB0aGluZ3Mgb24gZGlzY29ubmVjdGVkIG5vZGVzXG5Ud2Vlbi5wcm9wSG9va3Muc2Nyb2xsVG9wID0gVHdlZW4ucHJvcEhvb2tzLnNjcm9sbExlZnQgPSB7XG5cdHNldDogZnVuY3Rpb24oIHR3ZWVuICkge1xuXHRcdGlmICggdHdlZW4uZWxlbS5ub2RlVHlwZSAmJiB0d2Vlbi5lbGVtLnBhcmVudE5vZGUgKSB7XG5cdFx0XHR0d2Vlbi5lbGVtWyB0d2Vlbi5wcm9wIF0gPSB0d2Vlbi5ub3c7XG5cdFx0fVxuXHR9XG59O1xuXG5qUXVlcnkuZWFzaW5nID0ge1xuXHRsaW5lYXI6IGZ1bmN0aW9uKCBwICkge1xuXHRcdHJldHVybiBwO1xuXHR9LFxuXHRzd2luZzogZnVuY3Rpb24oIHAgKSB7XG5cdFx0cmV0dXJuIDAuNSAtIE1hdGguY29zKCBwICogTWF0aC5QSSApIC8gMjtcblx0fSxcblx0X2RlZmF1bHQ6IFwic3dpbmdcIlxufTtcblxualF1ZXJ5LmZ4ID0gVHdlZW4ucHJvdG90eXBlLmluaXQ7XG5cbi8vIEJhY2sgY29tcGF0IDwxLjggZXh0ZW5zaW9uIHBvaW50XG5qUXVlcnkuZnguc3RlcCA9IHt9O1xuXG5cblxuXG52YXJcblx0ZnhOb3csIGluUHJvZ3Jlc3MsXG5cdHJmeHR5cGVzID0gL14oPzp0b2dnbGV8c2hvd3xoaWRlKSQvLFxuXHRycnVuID0gL3F1ZXVlSG9va3MkLztcblxuZnVuY3Rpb24gc2NoZWR1bGUoKSB7XG5cdGlmICggaW5Qcm9ncmVzcyApIHtcblx0XHRpZiAoIGRvY3VtZW50LmhpZGRlbiA9PT0gZmFsc2UgJiYgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSApIHtcblx0XHRcdHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoIHNjaGVkdWxlICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHdpbmRvdy5zZXRUaW1lb3V0KCBzY2hlZHVsZSwgalF1ZXJ5LmZ4LmludGVydmFsICk7XG5cdFx0fVxuXG5cdFx0alF1ZXJ5LmZ4LnRpY2soKTtcblx0fVxufVxuXG4vLyBBbmltYXRpb25zIGNyZWF0ZWQgc3luY2hyb25vdXNseSB3aWxsIHJ1biBzeW5jaHJvbm91c2x5XG5mdW5jdGlvbiBjcmVhdGVGeE5vdygpIHtcblx0d2luZG93LnNldFRpbWVvdXQoIGZ1bmN0aW9uKCkge1xuXHRcdGZ4Tm93ID0gdW5kZWZpbmVkO1xuXHR9ICk7XG5cdHJldHVybiAoIGZ4Tm93ID0gRGF0ZS5ub3coKSApO1xufVxuXG4vLyBHZW5lcmF0ZSBwYXJhbWV0ZXJzIHRvIGNyZWF0ZSBhIHN0YW5kYXJkIGFuaW1hdGlvblxuZnVuY3Rpb24gZ2VuRngoIHR5cGUsIGluY2x1ZGVXaWR0aCApIHtcblx0dmFyIHdoaWNoLFxuXHRcdGkgPSAwLFxuXHRcdGF0dHJzID0geyBoZWlnaHQ6IHR5cGUgfTtcblxuXHQvLyBJZiB3ZSBpbmNsdWRlIHdpZHRoLCBzdGVwIHZhbHVlIGlzIDEgdG8gZG8gYWxsIGNzc0V4cGFuZCB2YWx1ZXMsXG5cdC8vIG90aGVyd2lzZSBzdGVwIHZhbHVlIGlzIDIgdG8gc2tpcCBvdmVyIExlZnQgYW5kIFJpZ2h0XG5cdGluY2x1ZGVXaWR0aCA9IGluY2x1ZGVXaWR0aCA/IDEgOiAwO1xuXHRmb3IgKCA7IGkgPCA0OyBpICs9IDIgLSBpbmNsdWRlV2lkdGggKSB7XG5cdFx0d2hpY2ggPSBjc3NFeHBhbmRbIGkgXTtcblx0XHRhdHRyc1sgXCJtYXJnaW5cIiArIHdoaWNoIF0gPSBhdHRyc1sgXCJwYWRkaW5nXCIgKyB3aGljaCBdID0gdHlwZTtcblx0fVxuXG5cdGlmICggaW5jbHVkZVdpZHRoICkge1xuXHRcdGF0dHJzLm9wYWNpdHkgPSBhdHRycy53aWR0aCA9IHR5cGU7XG5cdH1cblxuXHRyZXR1cm4gYXR0cnM7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZVR3ZWVuKCB2YWx1ZSwgcHJvcCwgYW5pbWF0aW9uICkge1xuXHR2YXIgdHdlZW4sXG5cdFx0Y29sbGVjdGlvbiA9ICggQW5pbWF0aW9uLnR3ZWVuZXJzWyBwcm9wIF0gfHwgW10gKS5jb25jYXQoIEFuaW1hdGlvbi50d2VlbmVyc1sgXCIqXCIgXSApLFxuXHRcdGluZGV4ID0gMCxcblx0XHRsZW5ndGggPSBjb2xsZWN0aW9uLmxlbmd0aDtcblx0Zm9yICggOyBpbmRleCA8IGxlbmd0aDsgaW5kZXgrKyApIHtcblx0XHRpZiAoICggdHdlZW4gPSBjb2xsZWN0aW9uWyBpbmRleCBdLmNhbGwoIGFuaW1hdGlvbiwgcHJvcCwgdmFsdWUgKSApICkge1xuXG5cdFx0XHQvLyBXZSdyZSBkb25lIHdpdGggdGhpcyBwcm9wZXJ0eVxuXHRcdFx0cmV0dXJuIHR3ZWVuO1xuXHRcdH1cblx0fVxufVxuXG5mdW5jdGlvbiBkZWZhdWx0UHJlZmlsdGVyKCBlbGVtLCBwcm9wcywgb3B0cyApIHtcblx0dmFyIHByb3AsIHZhbHVlLCB0b2dnbGUsIGhvb2tzLCBvbGRmaXJlLCBwcm9wVHdlZW4sIHJlc3RvcmVEaXNwbGF5LCBkaXNwbGF5LFxuXHRcdGlzQm94ID0gXCJ3aWR0aFwiIGluIHByb3BzIHx8IFwiaGVpZ2h0XCIgaW4gcHJvcHMsXG5cdFx0YW5pbSA9IHRoaXMsXG5cdFx0b3JpZyA9IHt9LFxuXHRcdHN0eWxlID0gZWxlbS5zdHlsZSxcblx0XHRoaWRkZW4gPSBlbGVtLm5vZGVUeXBlICYmIGlzSGlkZGVuV2l0aGluVHJlZSggZWxlbSApLFxuXHRcdGRhdGFTaG93ID0gZGF0YVByaXYuZ2V0KCBlbGVtLCBcImZ4c2hvd1wiICk7XG5cblx0Ly8gUXVldWUtc2tpcHBpbmcgYW5pbWF0aW9ucyBoaWphY2sgdGhlIGZ4IGhvb2tzXG5cdGlmICggIW9wdHMucXVldWUgKSB7XG5cdFx0aG9va3MgPSBqUXVlcnkuX3F1ZXVlSG9va3MoIGVsZW0sIFwiZnhcIiApO1xuXHRcdGlmICggaG9va3MudW5xdWV1ZWQgPT0gbnVsbCApIHtcblx0XHRcdGhvb2tzLnVucXVldWVkID0gMDtcblx0XHRcdG9sZGZpcmUgPSBob29rcy5lbXB0eS5maXJlO1xuXHRcdFx0aG9va3MuZW1wdHkuZmlyZSA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoICFob29rcy51bnF1ZXVlZCApIHtcblx0XHRcdFx0XHRvbGRmaXJlKCk7XG5cdFx0XHRcdH1cblx0XHRcdH07XG5cdFx0fVxuXHRcdGhvb2tzLnVucXVldWVkKys7XG5cblx0XHRhbmltLmFsd2F5cyggZnVuY3Rpb24oKSB7XG5cblx0XHRcdC8vIEVuc3VyZSB0aGUgY29tcGxldGUgaGFuZGxlciBpcyBjYWxsZWQgYmVmb3JlIHRoaXMgY29tcGxldGVzXG5cdFx0XHRhbmltLmFsd2F5cyggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGhvb2tzLnVucXVldWVkLS07XG5cdFx0XHRcdGlmICggIWpRdWVyeS5xdWV1ZSggZWxlbSwgXCJmeFwiICkubGVuZ3RoICkge1xuXHRcdFx0XHRcdGhvb2tzLmVtcHR5LmZpcmUoKTtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcdH0gKTtcblx0fVxuXG5cdC8vIERldGVjdCBzaG93L2hpZGUgYW5pbWF0aW9uc1xuXHRmb3IgKCBwcm9wIGluIHByb3BzICkge1xuXHRcdHZhbHVlID0gcHJvcHNbIHByb3AgXTtcblx0XHRpZiAoIHJmeHR5cGVzLnRlc3QoIHZhbHVlICkgKSB7XG5cdFx0XHRkZWxldGUgcHJvcHNbIHByb3AgXTtcblx0XHRcdHRvZ2dsZSA9IHRvZ2dsZSB8fCB2YWx1ZSA9PT0gXCJ0b2dnbGVcIjtcblx0XHRcdGlmICggdmFsdWUgPT09ICggaGlkZGVuID8gXCJoaWRlXCIgOiBcInNob3dcIiApICkge1xuXG5cdFx0XHRcdC8vIFByZXRlbmQgdG8gYmUgaGlkZGVuIGlmIHRoaXMgaXMgYSBcInNob3dcIiBhbmRcblx0XHRcdFx0Ly8gdGhlcmUgaXMgc3RpbGwgZGF0YSBmcm9tIGEgc3RvcHBlZCBzaG93L2hpZGVcblx0XHRcdFx0aWYgKCB2YWx1ZSA9PT0gXCJzaG93XCIgJiYgZGF0YVNob3cgJiYgZGF0YVNob3dbIHByb3AgXSAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdGhpZGRlbiA9IHRydWU7XG5cblx0XHRcdFx0Ly8gSWdub3JlIGFsbCBvdGhlciBuby1vcCBzaG93L2hpZGUgZGF0YVxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRvcmlnWyBwcm9wIF0gPSBkYXRhU2hvdyAmJiBkYXRhU2hvd1sgcHJvcCBdIHx8IGpRdWVyeS5zdHlsZSggZWxlbSwgcHJvcCApO1xuXHRcdH1cblx0fVxuXG5cdC8vIEJhaWwgb3V0IGlmIHRoaXMgaXMgYSBuby1vcCBsaWtlIC5oaWRlKCkuaGlkZSgpXG5cdHByb3BUd2VlbiA9ICFqUXVlcnkuaXNFbXB0eU9iamVjdCggcHJvcHMgKTtcblx0aWYgKCAhcHJvcFR3ZWVuICYmIGpRdWVyeS5pc0VtcHR5T2JqZWN0KCBvcmlnICkgKSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cblx0Ly8gUmVzdHJpY3QgXCJvdmVyZmxvd1wiIGFuZCBcImRpc3BsYXlcIiBzdHlsZXMgZHVyaW5nIGJveCBhbmltYXRpb25zXG5cdGlmICggaXNCb3ggJiYgZWxlbS5ub2RlVHlwZSA9PT0gMSApIHtcblxuXHRcdC8vIFN1cHBvcnQ6IElFIDw9OSAtIDExLCBFZGdlIDEyIC0gMTVcblx0XHQvLyBSZWNvcmQgYWxsIDMgb3ZlcmZsb3cgYXR0cmlidXRlcyBiZWNhdXNlIElFIGRvZXMgbm90IGluZmVyIHRoZSBzaG9ydGhhbmRcblx0XHQvLyBmcm9tIGlkZW50aWNhbGx5LXZhbHVlZCBvdmVyZmxvd1ggYW5kIG92ZXJmbG93WSBhbmQgRWRnZSBqdXN0IG1pcnJvcnNcblx0XHQvLyB0aGUgb3ZlcmZsb3dYIHZhbHVlIHRoZXJlLlxuXHRcdG9wdHMub3ZlcmZsb3cgPSBbIHN0eWxlLm92ZXJmbG93LCBzdHlsZS5vdmVyZmxvd1gsIHN0eWxlLm92ZXJmbG93WSBdO1xuXG5cdFx0Ly8gSWRlbnRpZnkgYSBkaXNwbGF5IHR5cGUsIHByZWZlcnJpbmcgb2xkIHNob3cvaGlkZSBkYXRhIG92ZXIgdGhlIENTUyBjYXNjYWRlXG5cdFx0cmVzdG9yZURpc3BsYXkgPSBkYXRhU2hvdyAmJiBkYXRhU2hvdy5kaXNwbGF5O1xuXHRcdGlmICggcmVzdG9yZURpc3BsYXkgPT0gbnVsbCApIHtcblx0XHRcdHJlc3RvcmVEaXNwbGF5ID0gZGF0YVByaXYuZ2V0KCBlbGVtLCBcImRpc3BsYXlcIiApO1xuXHRcdH1cblx0XHRkaXNwbGF5ID0galF1ZXJ5LmNzcyggZWxlbSwgXCJkaXNwbGF5XCIgKTtcblx0XHRpZiAoIGRpc3BsYXkgPT09IFwibm9uZVwiICkge1xuXHRcdFx0aWYgKCByZXN0b3JlRGlzcGxheSApIHtcblx0XHRcdFx0ZGlzcGxheSA9IHJlc3RvcmVEaXNwbGF5O1xuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBHZXQgbm9uZW1wdHkgdmFsdWUocykgYnkgdGVtcG9yYXJpbHkgZm9yY2luZyB2aXNpYmlsaXR5XG5cdFx0XHRcdHNob3dIaWRlKCBbIGVsZW0gXSwgdHJ1ZSApO1xuXHRcdFx0XHRyZXN0b3JlRGlzcGxheSA9IGVsZW0uc3R5bGUuZGlzcGxheSB8fCByZXN0b3JlRGlzcGxheTtcblx0XHRcdFx0ZGlzcGxheSA9IGpRdWVyeS5jc3MoIGVsZW0sIFwiZGlzcGxheVwiICk7XG5cdFx0XHRcdHNob3dIaWRlKCBbIGVsZW0gXSApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIEFuaW1hdGUgaW5saW5lIGVsZW1lbnRzIGFzIGlubGluZS1ibG9ja1xuXHRcdGlmICggZGlzcGxheSA9PT0gXCJpbmxpbmVcIiB8fCBkaXNwbGF5ID09PSBcImlubGluZS1ibG9ja1wiICYmIHJlc3RvcmVEaXNwbGF5ICE9IG51bGwgKSB7XG5cdFx0XHRpZiAoIGpRdWVyeS5jc3MoIGVsZW0sIFwiZmxvYXRcIiApID09PSBcIm5vbmVcIiApIHtcblxuXHRcdFx0XHQvLyBSZXN0b3JlIHRoZSBvcmlnaW5hbCBkaXNwbGF5IHZhbHVlIGF0IHRoZSBlbmQgb2YgcHVyZSBzaG93L2hpZGUgYW5pbWF0aW9uc1xuXHRcdFx0XHRpZiAoICFwcm9wVHdlZW4gKSB7XG5cdFx0XHRcdFx0YW5pbS5kb25lKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdHN0eWxlLmRpc3BsYXkgPSByZXN0b3JlRGlzcGxheTtcblx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdFx0aWYgKCByZXN0b3JlRGlzcGxheSA9PSBudWxsICkge1xuXHRcdFx0XHRcdFx0ZGlzcGxheSA9IHN0eWxlLmRpc3BsYXk7XG5cdFx0XHRcdFx0XHRyZXN0b3JlRGlzcGxheSA9IGRpc3BsYXkgPT09IFwibm9uZVwiID8gXCJcIiA6IGRpc3BsYXk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdHN0eWxlLmRpc3BsYXkgPSBcImlubGluZS1ibG9ja1wiO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdGlmICggb3B0cy5vdmVyZmxvdyApIHtcblx0XHRzdHlsZS5vdmVyZmxvdyA9IFwiaGlkZGVuXCI7XG5cdFx0YW5pbS5hbHdheXMoIGZ1bmN0aW9uKCkge1xuXHRcdFx0c3R5bGUub3ZlcmZsb3cgPSBvcHRzLm92ZXJmbG93WyAwIF07XG5cdFx0XHRzdHlsZS5vdmVyZmxvd1ggPSBvcHRzLm92ZXJmbG93WyAxIF07XG5cdFx0XHRzdHlsZS5vdmVyZmxvd1kgPSBvcHRzLm92ZXJmbG93WyAyIF07XG5cdFx0fSApO1xuXHR9XG5cblx0Ly8gSW1wbGVtZW50IHNob3cvaGlkZSBhbmltYXRpb25zXG5cdHByb3BUd2VlbiA9IGZhbHNlO1xuXHRmb3IgKCBwcm9wIGluIG9yaWcgKSB7XG5cblx0XHQvLyBHZW5lcmFsIHNob3cvaGlkZSBzZXR1cCBmb3IgdGhpcyBlbGVtZW50IGFuaW1hdGlvblxuXHRcdGlmICggIXByb3BUd2VlbiApIHtcblx0XHRcdGlmICggZGF0YVNob3cgKSB7XG5cdFx0XHRcdGlmICggXCJoaWRkZW5cIiBpbiBkYXRhU2hvdyApIHtcblx0XHRcdFx0XHRoaWRkZW4gPSBkYXRhU2hvdy5oaWRkZW47XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGRhdGFTaG93ID0gZGF0YVByaXYuYWNjZXNzKCBlbGVtLCBcImZ4c2hvd1wiLCB7IGRpc3BsYXk6IHJlc3RvcmVEaXNwbGF5IH0gKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gU3RvcmUgaGlkZGVuL3Zpc2libGUgZm9yIHRvZ2dsZSBzbyBgLnN0b3AoKS50b2dnbGUoKWAgXCJyZXZlcnNlc1wiXG5cdFx0XHRpZiAoIHRvZ2dsZSApIHtcblx0XHRcdFx0ZGF0YVNob3cuaGlkZGVuID0gIWhpZGRlbjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gU2hvdyBlbGVtZW50cyBiZWZvcmUgYW5pbWF0aW5nIHRoZW1cblx0XHRcdGlmICggaGlkZGVuICkge1xuXHRcdFx0XHRzaG93SGlkZSggWyBlbGVtIF0sIHRydWUgKTtcblx0XHRcdH1cblxuXHRcdFx0LyogZXNsaW50LWRpc2FibGUgbm8tbG9vcC1mdW5jICovXG5cblx0XHRcdGFuaW0uZG9uZSggZnVuY3Rpb24oKSB7XG5cblx0XHRcdFx0LyogZXNsaW50LWVuYWJsZSBuby1sb29wLWZ1bmMgKi9cblxuXHRcdFx0XHQvLyBUaGUgZmluYWwgc3RlcCBvZiBhIFwiaGlkZVwiIGFuaW1hdGlvbiBpcyBhY3R1YWxseSBoaWRpbmcgdGhlIGVsZW1lbnRcblx0XHRcdFx0aWYgKCAhaGlkZGVuICkge1xuXHRcdFx0XHRcdHNob3dIaWRlKCBbIGVsZW0gXSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGRhdGFQcml2LnJlbW92ZSggZWxlbSwgXCJmeHNob3dcIiApO1xuXHRcdFx0XHRmb3IgKCBwcm9wIGluIG9yaWcgKSB7XG5cdFx0XHRcdFx0alF1ZXJ5LnN0eWxlKCBlbGVtLCBwcm9wLCBvcmlnWyBwcm9wIF0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdC8vIFBlci1wcm9wZXJ0eSBzZXR1cFxuXHRcdHByb3BUd2VlbiA9IGNyZWF0ZVR3ZWVuKCBoaWRkZW4gPyBkYXRhU2hvd1sgcHJvcCBdIDogMCwgcHJvcCwgYW5pbSApO1xuXHRcdGlmICggISggcHJvcCBpbiBkYXRhU2hvdyApICkge1xuXHRcdFx0ZGF0YVNob3dbIHByb3AgXSA9IHByb3BUd2Vlbi5zdGFydDtcblx0XHRcdGlmICggaGlkZGVuICkge1xuXHRcdFx0XHRwcm9wVHdlZW4uZW5kID0gcHJvcFR3ZWVuLnN0YXJ0O1xuXHRcdFx0XHRwcm9wVHdlZW4uc3RhcnQgPSAwO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxufVxuXG5mdW5jdGlvbiBwcm9wRmlsdGVyKCBwcm9wcywgc3BlY2lhbEVhc2luZyApIHtcblx0dmFyIGluZGV4LCBuYW1lLCBlYXNpbmcsIHZhbHVlLCBob29rcztcblxuXHQvLyBjYW1lbENhc2UsIHNwZWNpYWxFYXNpbmcgYW5kIGV4cGFuZCBjc3NIb29rIHBhc3Ncblx0Zm9yICggaW5kZXggaW4gcHJvcHMgKSB7XG5cdFx0bmFtZSA9IGNhbWVsQ2FzZSggaW5kZXggKTtcblx0XHRlYXNpbmcgPSBzcGVjaWFsRWFzaW5nWyBuYW1lIF07XG5cdFx0dmFsdWUgPSBwcm9wc1sgaW5kZXggXTtcblx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIHZhbHVlICkgKSB7XG5cdFx0XHRlYXNpbmcgPSB2YWx1ZVsgMSBdO1xuXHRcdFx0dmFsdWUgPSBwcm9wc1sgaW5kZXggXSA9IHZhbHVlWyAwIF07XG5cdFx0fVxuXG5cdFx0aWYgKCBpbmRleCAhPT0gbmFtZSApIHtcblx0XHRcdHByb3BzWyBuYW1lIF0gPSB2YWx1ZTtcblx0XHRcdGRlbGV0ZSBwcm9wc1sgaW5kZXggXTtcblx0XHR9XG5cblx0XHRob29rcyA9IGpRdWVyeS5jc3NIb29rc1sgbmFtZSBdO1xuXHRcdGlmICggaG9va3MgJiYgXCJleHBhbmRcIiBpbiBob29rcyApIHtcblx0XHRcdHZhbHVlID0gaG9va3MuZXhwYW5kKCB2YWx1ZSApO1xuXHRcdFx0ZGVsZXRlIHByb3BzWyBuYW1lIF07XG5cblx0XHRcdC8vIE5vdCBxdWl0ZSAkLmV4dGVuZCwgdGhpcyB3b24ndCBvdmVyd3JpdGUgZXhpc3Rpbmcga2V5cy5cblx0XHRcdC8vIFJldXNpbmcgJ2luZGV4JyBiZWNhdXNlIHdlIGhhdmUgdGhlIGNvcnJlY3QgXCJuYW1lXCJcblx0XHRcdGZvciAoIGluZGV4IGluIHZhbHVlICkge1xuXHRcdFx0XHRpZiAoICEoIGluZGV4IGluIHByb3BzICkgKSB7XG5cdFx0XHRcdFx0cHJvcHNbIGluZGV4IF0gPSB2YWx1ZVsgaW5kZXggXTtcblx0XHRcdFx0XHRzcGVjaWFsRWFzaW5nWyBpbmRleCBdID0gZWFzaW5nO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdHNwZWNpYWxFYXNpbmdbIG5hbWUgXSA9IGVhc2luZztcblx0XHR9XG5cdH1cbn1cblxuZnVuY3Rpb24gQW5pbWF0aW9uKCBlbGVtLCBwcm9wZXJ0aWVzLCBvcHRpb25zICkge1xuXHR2YXIgcmVzdWx0LFxuXHRcdHN0b3BwZWQsXG5cdFx0aW5kZXggPSAwLFxuXHRcdGxlbmd0aCA9IEFuaW1hdGlvbi5wcmVmaWx0ZXJzLmxlbmd0aCxcblx0XHRkZWZlcnJlZCA9IGpRdWVyeS5EZWZlcnJlZCgpLmFsd2F5cyggZnVuY3Rpb24oKSB7XG5cblx0XHRcdC8vIERvbid0IG1hdGNoIGVsZW0gaW4gdGhlIDphbmltYXRlZCBzZWxlY3RvclxuXHRcdFx0ZGVsZXRlIHRpY2suZWxlbTtcblx0XHR9ICksXG5cdFx0dGljayA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYgKCBzdG9wcGVkICkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHR2YXIgY3VycmVudFRpbWUgPSBmeE5vdyB8fCBjcmVhdGVGeE5vdygpLFxuXHRcdFx0XHRyZW1haW5pbmcgPSBNYXRoLm1heCggMCwgYW5pbWF0aW9uLnN0YXJ0VGltZSArIGFuaW1hdGlvbi5kdXJhdGlvbiAtIGN1cnJlbnRUaW1lICksXG5cblx0XHRcdFx0Ly8gU3VwcG9ydDogQW5kcm9pZCAyLjMgb25seVxuXHRcdFx0XHQvLyBBcmNoYWljIGNyYXNoIGJ1ZyB3b24ndCBhbGxvdyB1cyB0byB1c2UgYDEgLSAoIDAuNSB8fCAwIClgICgjMTI0OTcpXG5cdFx0XHRcdHRlbXAgPSByZW1haW5pbmcgLyBhbmltYXRpb24uZHVyYXRpb24gfHwgMCxcblx0XHRcdFx0cGVyY2VudCA9IDEgLSB0ZW1wLFxuXHRcdFx0XHRpbmRleCA9IDAsXG5cdFx0XHRcdGxlbmd0aCA9IGFuaW1hdGlvbi50d2VlbnMubGVuZ3RoO1xuXG5cdFx0XHRmb3IgKCA7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrICkge1xuXHRcdFx0XHRhbmltYXRpb24udHdlZW5zWyBpbmRleCBdLnJ1biggcGVyY2VudCApO1xuXHRcdFx0fVxuXG5cdFx0XHRkZWZlcnJlZC5ub3RpZnlXaXRoKCBlbGVtLCBbIGFuaW1hdGlvbiwgcGVyY2VudCwgcmVtYWluaW5nIF0gKTtcblxuXHRcdFx0Ly8gSWYgdGhlcmUncyBtb3JlIHRvIGRvLCB5aWVsZFxuXHRcdFx0aWYgKCBwZXJjZW50IDwgMSAmJiBsZW5ndGggKSB7XG5cdFx0XHRcdHJldHVybiByZW1haW5pbmc7XG5cdFx0XHR9XG5cblx0XHRcdC8vIElmIHRoaXMgd2FzIGFuIGVtcHR5IGFuaW1hdGlvbiwgc3ludGhlc2l6ZSBhIGZpbmFsIHByb2dyZXNzIG5vdGlmaWNhdGlvblxuXHRcdFx0aWYgKCAhbGVuZ3RoICkge1xuXHRcdFx0XHRkZWZlcnJlZC5ub3RpZnlXaXRoKCBlbGVtLCBbIGFuaW1hdGlvbiwgMSwgMCBdICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFJlc29sdmUgdGhlIGFuaW1hdGlvbiBhbmQgcmVwb3J0IGl0cyBjb25jbHVzaW9uXG5cdFx0XHRkZWZlcnJlZC5yZXNvbHZlV2l0aCggZWxlbSwgWyBhbmltYXRpb24gXSApO1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH0sXG5cdFx0YW5pbWF0aW9uID0gZGVmZXJyZWQucHJvbWlzZSgge1xuXHRcdFx0ZWxlbTogZWxlbSxcblx0XHRcdHByb3BzOiBqUXVlcnkuZXh0ZW5kKCB7fSwgcHJvcGVydGllcyApLFxuXHRcdFx0b3B0czogalF1ZXJ5LmV4dGVuZCggdHJ1ZSwge1xuXHRcdFx0XHRzcGVjaWFsRWFzaW5nOiB7fSxcblx0XHRcdFx0ZWFzaW5nOiBqUXVlcnkuZWFzaW5nLl9kZWZhdWx0XG5cdFx0XHR9LCBvcHRpb25zICksXG5cdFx0XHRvcmlnaW5hbFByb3BlcnRpZXM6IHByb3BlcnRpZXMsXG5cdFx0XHRvcmlnaW5hbE9wdGlvbnM6IG9wdGlvbnMsXG5cdFx0XHRzdGFydFRpbWU6IGZ4Tm93IHx8IGNyZWF0ZUZ4Tm93KCksXG5cdFx0XHRkdXJhdGlvbjogb3B0aW9ucy5kdXJhdGlvbixcblx0XHRcdHR3ZWVuczogW10sXG5cdFx0XHRjcmVhdGVUd2VlbjogZnVuY3Rpb24oIHByb3AsIGVuZCApIHtcblx0XHRcdFx0dmFyIHR3ZWVuID0galF1ZXJ5LlR3ZWVuKCBlbGVtLCBhbmltYXRpb24ub3B0cywgcHJvcCwgZW5kLFxuXHRcdFx0XHRcdGFuaW1hdGlvbi5vcHRzLnNwZWNpYWxFYXNpbmdbIHByb3AgXSB8fCBhbmltYXRpb24ub3B0cy5lYXNpbmcgKTtcblx0XHRcdFx0YW5pbWF0aW9uLnR3ZWVucy5wdXNoKCB0d2VlbiApO1xuXHRcdFx0XHRyZXR1cm4gdHdlZW47XG5cdFx0XHR9LFxuXHRcdFx0c3RvcDogZnVuY3Rpb24oIGdvdG9FbmQgKSB7XG5cdFx0XHRcdHZhciBpbmRleCA9IDAsXG5cblx0XHRcdFx0XHQvLyBJZiB3ZSBhcmUgZ29pbmcgdG8gdGhlIGVuZCwgd2Ugd2FudCB0byBydW4gYWxsIHRoZSB0d2VlbnNcblx0XHRcdFx0XHQvLyBvdGhlcndpc2Ugd2Ugc2tpcCB0aGlzIHBhcnRcblx0XHRcdFx0XHRsZW5ndGggPSBnb3RvRW5kID8gYW5pbWF0aW9uLnR3ZWVucy5sZW5ndGggOiAwO1xuXHRcdFx0XHRpZiAoIHN0b3BwZWQgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHRcdH1cblx0XHRcdFx0c3RvcHBlZCA9IHRydWU7XG5cdFx0XHRcdGZvciAoIDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KysgKSB7XG5cdFx0XHRcdFx0YW5pbWF0aW9uLnR3ZWVuc1sgaW5kZXggXS5ydW4oIDEgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFJlc29sdmUgd2hlbiB3ZSBwbGF5ZWQgdGhlIGxhc3QgZnJhbWU7IG90aGVyd2lzZSwgcmVqZWN0XG5cdFx0XHRcdGlmICggZ290b0VuZCApIHtcblx0XHRcdFx0XHRkZWZlcnJlZC5ub3RpZnlXaXRoKCBlbGVtLCBbIGFuaW1hdGlvbiwgMSwgMCBdICk7XG5cdFx0XHRcdFx0ZGVmZXJyZWQucmVzb2x2ZVdpdGgoIGVsZW0sIFsgYW5pbWF0aW9uLCBnb3RvRW5kIF0gKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRkZWZlcnJlZC5yZWplY3RXaXRoKCBlbGVtLCBbIGFuaW1hdGlvbiwgZ290b0VuZCBdICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9XG5cdFx0fSApLFxuXHRcdHByb3BzID0gYW5pbWF0aW9uLnByb3BzO1xuXG5cdHByb3BGaWx0ZXIoIHByb3BzLCBhbmltYXRpb24ub3B0cy5zcGVjaWFsRWFzaW5nICk7XG5cblx0Zm9yICggOyBpbmRleCA8IGxlbmd0aDsgaW5kZXgrKyApIHtcblx0XHRyZXN1bHQgPSBBbmltYXRpb24ucHJlZmlsdGVyc1sgaW5kZXggXS5jYWxsKCBhbmltYXRpb24sIGVsZW0sIHByb3BzLCBhbmltYXRpb24ub3B0cyApO1xuXHRcdGlmICggcmVzdWx0ICkge1xuXHRcdFx0aWYgKCBpc0Z1bmN0aW9uKCByZXN1bHQuc3RvcCApICkge1xuXHRcdFx0XHRqUXVlcnkuX3F1ZXVlSG9va3MoIGFuaW1hdGlvbi5lbGVtLCBhbmltYXRpb24ub3B0cy5xdWV1ZSApLnN0b3AgPVxuXHRcdFx0XHRcdHJlc3VsdC5zdG9wLmJpbmQoIHJlc3VsdCApO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHJlc3VsdDtcblx0XHR9XG5cdH1cblxuXHRqUXVlcnkubWFwKCBwcm9wcywgY3JlYXRlVHdlZW4sIGFuaW1hdGlvbiApO1xuXG5cdGlmICggaXNGdW5jdGlvbiggYW5pbWF0aW9uLm9wdHMuc3RhcnQgKSApIHtcblx0XHRhbmltYXRpb24ub3B0cy5zdGFydC5jYWxsKCBlbGVtLCBhbmltYXRpb24gKTtcblx0fVxuXG5cdC8vIEF0dGFjaCBjYWxsYmFja3MgZnJvbSBvcHRpb25zXG5cdGFuaW1hdGlvblxuXHRcdC5wcm9ncmVzcyggYW5pbWF0aW9uLm9wdHMucHJvZ3Jlc3MgKVxuXHRcdC5kb25lKCBhbmltYXRpb24ub3B0cy5kb25lLCBhbmltYXRpb24ub3B0cy5jb21wbGV0ZSApXG5cdFx0LmZhaWwoIGFuaW1hdGlvbi5vcHRzLmZhaWwgKVxuXHRcdC5hbHdheXMoIGFuaW1hdGlvbi5vcHRzLmFsd2F5cyApO1xuXG5cdGpRdWVyeS5meC50aW1lcihcblx0XHRqUXVlcnkuZXh0ZW5kKCB0aWNrLCB7XG5cdFx0XHRlbGVtOiBlbGVtLFxuXHRcdFx0YW5pbTogYW5pbWF0aW9uLFxuXHRcdFx0cXVldWU6IGFuaW1hdGlvbi5vcHRzLnF1ZXVlXG5cdFx0fSApXG5cdCk7XG5cblx0cmV0dXJuIGFuaW1hdGlvbjtcbn1cblxualF1ZXJ5LkFuaW1hdGlvbiA9IGpRdWVyeS5leHRlbmQoIEFuaW1hdGlvbiwge1xuXG5cdHR3ZWVuZXJzOiB7XG5cdFx0XCIqXCI6IFsgZnVuY3Rpb24oIHByb3AsIHZhbHVlICkge1xuXHRcdFx0dmFyIHR3ZWVuID0gdGhpcy5jcmVhdGVUd2VlbiggcHJvcCwgdmFsdWUgKTtcblx0XHRcdGFkanVzdENTUyggdHdlZW4uZWxlbSwgcHJvcCwgcmNzc051bS5leGVjKCB2YWx1ZSApLCB0d2VlbiApO1xuXHRcdFx0cmV0dXJuIHR3ZWVuO1xuXHRcdH0gXVxuXHR9LFxuXG5cdHR3ZWVuZXI6IGZ1bmN0aW9uKCBwcm9wcywgY2FsbGJhY2sgKSB7XG5cdFx0aWYgKCBpc0Z1bmN0aW9uKCBwcm9wcyApICkge1xuXHRcdFx0Y2FsbGJhY2sgPSBwcm9wcztcblx0XHRcdHByb3BzID0gWyBcIipcIiBdO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRwcm9wcyA9IHByb3BzLm1hdGNoKCBybm90aHRtbHdoaXRlICk7XG5cdFx0fVxuXG5cdFx0dmFyIHByb3AsXG5cdFx0XHRpbmRleCA9IDAsXG5cdFx0XHRsZW5ndGggPSBwcm9wcy5sZW5ndGg7XG5cblx0XHRmb3IgKCA7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrICkge1xuXHRcdFx0cHJvcCA9IHByb3BzWyBpbmRleCBdO1xuXHRcdFx0QW5pbWF0aW9uLnR3ZWVuZXJzWyBwcm9wIF0gPSBBbmltYXRpb24udHdlZW5lcnNbIHByb3AgXSB8fCBbXTtcblx0XHRcdEFuaW1hdGlvbi50d2VlbmVyc1sgcHJvcCBdLnVuc2hpZnQoIGNhbGxiYWNrICk7XG5cdFx0fVxuXHR9LFxuXG5cdHByZWZpbHRlcnM6IFsgZGVmYXVsdFByZWZpbHRlciBdLFxuXG5cdHByZWZpbHRlcjogZnVuY3Rpb24oIGNhbGxiYWNrLCBwcmVwZW5kICkge1xuXHRcdGlmICggcHJlcGVuZCApIHtcblx0XHRcdEFuaW1hdGlvbi5wcmVmaWx0ZXJzLnVuc2hpZnQoIGNhbGxiYWNrICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdEFuaW1hdGlvbi5wcmVmaWx0ZXJzLnB1c2goIGNhbGxiYWNrICk7XG5cdFx0fVxuXHR9XG59ICk7XG5cbmpRdWVyeS5zcGVlZCA9IGZ1bmN0aW9uKCBzcGVlZCwgZWFzaW5nLCBmbiApIHtcblx0dmFyIG9wdCA9IHNwZWVkICYmIHR5cGVvZiBzcGVlZCA9PT0gXCJvYmplY3RcIiA/IGpRdWVyeS5leHRlbmQoIHt9LCBzcGVlZCApIDoge1xuXHRcdGNvbXBsZXRlOiBmbiB8fCAhZm4gJiYgZWFzaW5nIHx8XG5cdFx0XHRpc0Z1bmN0aW9uKCBzcGVlZCApICYmIHNwZWVkLFxuXHRcdGR1cmF0aW9uOiBzcGVlZCxcblx0XHRlYXNpbmc6IGZuICYmIGVhc2luZyB8fCBlYXNpbmcgJiYgIWlzRnVuY3Rpb24oIGVhc2luZyApICYmIGVhc2luZ1xuXHR9O1xuXG5cdC8vIEdvIHRvIHRoZSBlbmQgc3RhdGUgaWYgZnggYXJlIG9mZlxuXHRpZiAoIGpRdWVyeS5meC5vZmYgKSB7XG5cdFx0b3B0LmR1cmF0aW9uID0gMDtcblxuXHR9IGVsc2Uge1xuXHRcdGlmICggdHlwZW9mIG9wdC5kdXJhdGlvbiAhPT0gXCJudW1iZXJcIiApIHtcblx0XHRcdGlmICggb3B0LmR1cmF0aW9uIGluIGpRdWVyeS5meC5zcGVlZHMgKSB7XG5cdFx0XHRcdG9wdC5kdXJhdGlvbiA9IGpRdWVyeS5meC5zcGVlZHNbIG9wdC5kdXJhdGlvbiBdO1xuXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRvcHQuZHVyYXRpb24gPSBqUXVlcnkuZnguc3BlZWRzLl9kZWZhdWx0O1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdC8vIE5vcm1hbGl6ZSBvcHQucXVldWUgLSB0cnVlL3VuZGVmaW5lZC9udWxsIC0+IFwiZnhcIlxuXHRpZiAoIG9wdC5xdWV1ZSA9PSBudWxsIHx8IG9wdC5xdWV1ZSA9PT0gdHJ1ZSApIHtcblx0XHRvcHQucXVldWUgPSBcImZ4XCI7XG5cdH1cblxuXHQvLyBRdWV1ZWluZ1xuXHRvcHQub2xkID0gb3B0LmNvbXBsZXRlO1xuXG5cdG9wdC5jb21wbGV0ZSA9IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggaXNGdW5jdGlvbiggb3B0Lm9sZCApICkge1xuXHRcdFx0b3B0Lm9sZC5jYWxsKCB0aGlzICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBvcHQucXVldWUgKSB7XG5cdFx0XHRqUXVlcnkuZGVxdWV1ZSggdGhpcywgb3B0LnF1ZXVlICk7XG5cdFx0fVxuXHR9O1xuXG5cdHJldHVybiBvcHQ7XG59O1xuXG5qUXVlcnkuZm4uZXh0ZW5kKCB7XG5cdGZhZGVUbzogZnVuY3Rpb24oIHNwZWVkLCB0bywgZWFzaW5nLCBjYWxsYmFjayApIHtcblxuXHRcdC8vIFNob3cgYW55IGhpZGRlbiBlbGVtZW50cyBhZnRlciBzZXR0aW5nIG9wYWNpdHkgdG8gMFxuXHRcdHJldHVybiB0aGlzLmZpbHRlciggaXNIaWRkZW5XaXRoaW5UcmVlICkuY3NzKCBcIm9wYWNpdHlcIiwgMCApLnNob3coKVxuXG5cdFx0XHQvLyBBbmltYXRlIHRvIHRoZSB2YWx1ZSBzcGVjaWZpZWRcblx0XHRcdC5lbmQoKS5hbmltYXRlKCB7IG9wYWNpdHk6IHRvIH0sIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICk7XG5cdH0sXG5cdGFuaW1hdGU6IGZ1bmN0aW9uKCBwcm9wLCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApIHtcblx0XHR2YXIgZW1wdHkgPSBqUXVlcnkuaXNFbXB0eU9iamVjdCggcHJvcCApLFxuXHRcdFx0b3B0YWxsID0galF1ZXJ5LnNwZWVkKCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApLFxuXHRcdFx0ZG9BbmltYXRpb24gPSBmdW5jdGlvbigpIHtcblxuXHRcdFx0XHQvLyBPcGVyYXRlIG9uIGEgY29weSBvZiBwcm9wIHNvIHBlci1wcm9wZXJ0eSBlYXNpbmcgd29uJ3QgYmUgbG9zdFxuXHRcdFx0XHR2YXIgYW5pbSA9IEFuaW1hdGlvbiggdGhpcywgalF1ZXJ5LmV4dGVuZCgge30sIHByb3AgKSwgb3B0YWxsICk7XG5cblx0XHRcdFx0Ly8gRW1wdHkgYW5pbWF0aW9ucywgb3IgZmluaXNoaW5nIHJlc29sdmVzIGltbWVkaWF0ZWx5XG5cdFx0XHRcdGlmICggZW1wdHkgfHwgZGF0YVByaXYuZ2V0KCB0aGlzLCBcImZpbmlzaFwiICkgKSB7XG5cdFx0XHRcdFx0YW5pbS5zdG9wKCB0cnVlICk7XG5cdFx0XHRcdH1cblx0XHRcdH07XG5cblx0XHRkb0FuaW1hdGlvbi5maW5pc2ggPSBkb0FuaW1hdGlvbjtcblxuXHRcdHJldHVybiBlbXB0eSB8fCBvcHRhbGwucXVldWUgPT09IGZhbHNlID9cblx0XHRcdHRoaXMuZWFjaCggZG9BbmltYXRpb24gKSA6XG5cdFx0XHR0aGlzLnF1ZXVlKCBvcHRhbGwucXVldWUsIGRvQW5pbWF0aW9uICk7XG5cdH0sXG5cdHN0b3A6IGZ1bmN0aW9uKCB0eXBlLCBjbGVhclF1ZXVlLCBnb3RvRW5kICkge1xuXHRcdHZhciBzdG9wUXVldWUgPSBmdW5jdGlvbiggaG9va3MgKSB7XG5cdFx0XHR2YXIgc3RvcCA9IGhvb2tzLnN0b3A7XG5cdFx0XHRkZWxldGUgaG9va3Muc3RvcDtcblx0XHRcdHN0b3AoIGdvdG9FbmQgKTtcblx0XHR9O1xuXG5cdFx0aWYgKCB0eXBlb2YgdHlwZSAhPT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdGdvdG9FbmQgPSBjbGVhclF1ZXVlO1xuXHRcdFx0Y2xlYXJRdWV1ZSA9IHR5cGU7XG5cdFx0XHR0eXBlID0gdW5kZWZpbmVkO1xuXHRcdH1cblx0XHRpZiAoIGNsZWFyUXVldWUgKSB7XG5cdFx0XHR0aGlzLnF1ZXVlKCB0eXBlIHx8IFwiZnhcIiwgW10gKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBkZXF1ZXVlID0gdHJ1ZSxcblx0XHRcdFx0aW5kZXggPSB0eXBlICE9IG51bGwgJiYgdHlwZSArIFwicXVldWVIb29rc1wiLFxuXHRcdFx0XHR0aW1lcnMgPSBqUXVlcnkudGltZXJzLFxuXHRcdFx0XHRkYXRhID0gZGF0YVByaXYuZ2V0KCB0aGlzICk7XG5cblx0XHRcdGlmICggaW5kZXggKSB7XG5cdFx0XHRcdGlmICggZGF0YVsgaW5kZXggXSAmJiBkYXRhWyBpbmRleCBdLnN0b3AgKSB7XG5cdFx0XHRcdFx0c3RvcFF1ZXVlKCBkYXRhWyBpbmRleCBdICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGZvciAoIGluZGV4IGluIGRhdGEgKSB7XG5cdFx0XHRcdFx0aWYgKCBkYXRhWyBpbmRleCBdICYmIGRhdGFbIGluZGV4IF0uc3RvcCAmJiBycnVuLnRlc3QoIGluZGV4ICkgKSB7XG5cdFx0XHRcdFx0XHRzdG9wUXVldWUoIGRhdGFbIGluZGV4IF0gKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Zm9yICggaW5kZXggPSB0aW1lcnMubGVuZ3RoOyBpbmRleC0tOyApIHtcblx0XHRcdFx0aWYgKCB0aW1lcnNbIGluZGV4IF0uZWxlbSA9PT0gdGhpcyAmJlxuXHRcdFx0XHRcdCggdHlwZSA9PSBudWxsIHx8IHRpbWVyc1sgaW5kZXggXS5xdWV1ZSA9PT0gdHlwZSApICkge1xuXG5cdFx0XHRcdFx0dGltZXJzWyBpbmRleCBdLmFuaW0uc3RvcCggZ290b0VuZCApO1xuXHRcdFx0XHRcdGRlcXVldWUgPSBmYWxzZTtcblx0XHRcdFx0XHR0aW1lcnMuc3BsaWNlKCBpbmRleCwgMSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vIFN0YXJ0IHRoZSBuZXh0IGluIHRoZSBxdWV1ZSBpZiB0aGUgbGFzdCBzdGVwIHdhc24ndCBmb3JjZWQuXG5cdFx0XHQvLyBUaW1lcnMgY3VycmVudGx5IHdpbGwgY2FsbCB0aGVpciBjb21wbGV0ZSBjYWxsYmFja3MsIHdoaWNoXG5cdFx0XHQvLyB3aWxsIGRlcXVldWUgYnV0IG9ubHkgaWYgdGhleSB3ZXJlIGdvdG9FbmQuXG5cdFx0XHRpZiAoIGRlcXVldWUgfHwgIWdvdG9FbmQgKSB7XG5cdFx0XHRcdGpRdWVyeS5kZXF1ZXVlKCB0aGlzLCB0eXBlICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXHRmaW5pc2g6IGZ1bmN0aW9uKCB0eXBlICkge1xuXHRcdGlmICggdHlwZSAhPT0gZmFsc2UgKSB7XG5cdFx0XHR0eXBlID0gdHlwZSB8fCBcImZ4XCI7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGluZGV4LFxuXHRcdFx0XHRkYXRhID0gZGF0YVByaXYuZ2V0KCB0aGlzICksXG5cdFx0XHRcdHF1ZXVlID0gZGF0YVsgdHlwZSArIFwicXVldWVcIiBdLFxuXHRcdFx0XHRob29rcyA9IGRhdGFbIHR5cGUgKyBcInF1ZXVlSG9va3NcIiBdLFxuXHRcdFx0XHR0aW1lcnMgPSBqUXVlcnkudGltZXJzLFxuXHRcdFx0XHRsZW5ndGggPSBxdWV1ZSA/IHF1ZXVlLmxlbmd0aCA6IDA7XG5cblx0XHRcdC8vIEVuYWJsZSBmaW5pc2hpbmcgZmxhZyBvbiBwcml2YXRlIGRhdGFcblx0XHRcdGRhdGEuZmluaXNoID0gdHJ1ZTtcblxuXHRcdFx0Ly8gRW1wdHkgdGhlIHF1ZXVlIGZpcnN0XG5cdFx0XHRqUXVlcnkucXVldWUoIHRoaXMsIHR5cGUsIFtdICk7XG5cblx0XHRcdGlmICggaG9va3MgJiYgaG9va3Muc3RvcCApIHtcblx0XHRcdFx0aG9va3Muc3RvcC5jYWxsKCB0aGlzLCB0cnVlICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIExvb2sgZm9yIGFueSBhY3RpdmUgYW5pbWF0aW9ucywgYW5kIGZpbmlzaCB0aGVtXG5cdFx0XHRmb3IgKCBpbmRleCA9IHRpbWVycy5sZW5ndGg7IGluZGV4LS07ICkge1xuXHRcdFx0XHRpZiAoIHRpbWVyc1sgaW5kZXggXS5lbGVtID09PSB0aGlzICYmIHRpbWVyc1sgaW5kZXggXS5xdWV1ZSA9PT0gdHlwZSApIHtcblx0XHRcdFx0XHR0aW1lcnNbIGluZGV4IF0uYW5pbS5zdG9wKCB0cnVlICk7XG5cdFx0XHRcdFx0dGltZXJzLnNwbGljZSggaW5kZXgsIDEgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBMb29rIGZvciBhbnkgYW5pbWF0aW9ucyBpbiB0aGUgb2xkIHF1ZXVlIGFuZCBmaW5pc2ggdGhlbVxuXHRcdFx0Zm9yICggaW5kZXggPSAwOyBpbmRleCA8IGxlbmd0aDsgaW5kZXgrKyApIHtcblx0XHRcdFx0aWYgKCBxdWV1ZVsgaW5kZXggXSAmJiBxdWV1ZVsgaW5kZXggXS5maW5pc2ggKSB7XG5cdFx0XHRcdFx0cXVldWVbIGluZGV4IF0uZmluaXNoLmNhbGwoIHRoaXMgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBUdXJuIG9mZiBmaW5pc2hpbmcgZmxhZ1xuXHRcdFx0ZGVsZXRlIGRhdGEuZmluaXNoO1xuXHRcdH0gKTtcblx0fVxufSApO1xuXG5qUXVlcnkuZWFjaCggWyBcInRvZ2dsZVwiLCBcInNob3dcIiwgXCJoaWRlXCIgXSwgZnVuY3Rpb24oIF9pLCBuYW1lICkge1xuXHR2YXIgY3NzRm4gPSBqUXVlcnkuZm5bIG5hbWUgXTtcblx0alF1ZXJ5LmZuWyBuYW1lIF0gPSBmdW5jdGlvbiggc3BlZWQsIGVhc2luZywgY2FsbGJhY2sgKSB7XG5cdFx0cmV0dXJuIHNwZWVkID09IG51bGwgfHwgdHlwZW9mIHNwZWVkID09PSBcImJvb2xlYW5cIiA/XG5cdFx0XHRjc3NGbi5hcHBseSggdGhpcywgYXJndW1lbnRzICkgOlxuXHRcdFx0dGhpcy5hbmltYXRlKCBnZW5GeCggbmFtZSwgdHJ1ZSApLCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApO1xuXHR9O1xufSApO1xuXG4vLyBHZW5lcmF0ZSBzaG9ydGN1dHMgZm9yIGN1c3RvbSBhbmltYXRpb25zXG5qUXVlcnkuZWFjaCgge1xuXHRzbGlkZURvd246IGdlbkZ4KCBcInNob3dcIiApLFxuXHRzbGlkZVVwOiBnZW5GeCggXCJoaWRlXCIgKSxcblx0c2xpZGVUb2dnbGU6IGdlbkZ4KCBcInRvZ2dsZVwiICksXG5cdGZhZGVJbjogeyBvcGFjaXR5OiBcInNob3dcIiB9LFxuXHRmYWRlT3V0OiB7IG9wYWNpdHk6IFwiaGlkZVwiIH0sXG5cdGZhZGVUb2dnbGU6IHsgb3BhY2l0eTogXCJ0b2dnbGVcIiB9XG59LCBmdW5jdGlvbiggbmFtZSwgcHJvcHMgKSB7XG5cdGpRdWVyeS5mblsgbmFtZSBdID0gZnVuY3Rpb24oIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICkge1xuXHRcdHJldHVybiB0aGlzLmFuaW1hdGUoIHByb3BzLCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApO1xuXHR9O1xufSApO1xuXG5qUXVlcnkudGltZXJzID0gW107XG5qUXVlcnkuZngudGljayA9IGZ1bmN0aW9uKCkge1xuXHR2YXIgdGltZXIsXG5cdFx0aSA9IDAsXG5cdFx0dGltZXJzID0galF1ZXJ5LnRpbWVycztcblxuXHRmeE5vdyA9IERhdGUubm93KCk7XG5cblx0Zm9yICggOyBpIDwgdGltZXJzLmxlbmd0aDsgaSsrICkge1xuXHRcdHRpbWVyID0gdGltZXJzWyBpIF07XG5cblx0XHQvLyBSdW4gdGhlIHRpbWVyIGFuZCBzYWZlbHkgcmVtb3ZlIGl0IHdoZW4gZG9uZSAoYWxsb3dpbmcgZm9yIGV4dGVybmFsIHJlbW92YWwpXG5cdFx0aWYgKCAhdGltZXIoKSAmJiB0aW1lcnNbIGkgXSA9PT0gdGltZXIgKSB7XG5cdFx0XHR0aW1lcnMuc3BsaWNlKCBpLS0sIDEgKTtcblx0XHR9XG5cdH1cblxuXHRpZiAoICF0aW1lcnMubGVuZ3RoICkge1xuXHRcdGpRdWVyeS5meC5zdG9wKCk7XG5cdH1cblx0ZnhOb3cgPSB1bmRlZmluZWQ7XG59O1xuXG5qUXVlcnkuZngudGltZXIgPSBmdW5jdGlvbiggdGltZXIgKSB7XG5cdGpRdWVyeS50aW1lcnMucHVzaCggdGltZXIgKTtcblx0alF1ZXJ5LmZ4LnN0YXJ0KCk7XG59O1xuXG5qUXVlcnkuZnguaW50ZXJ2YWwgPSAxMztcbmpRdWVyeS5meC5zdGFydCA9IGZ1bmN0aW9uKCkge1xuXHRpZiAoIGluUHJvZ3Jlc3MgKSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cblx0aW5Qcm9ncmVzcyA9IHRydWU7XG5cdHNjaGVkdWxlKCk7XG59O1xuXG5qUXVlcnkuZnguc3RvcCA9IGZ1bmN0aW9uKCkge1xuXHRpblByb2dyZXNzID0gbnVsbDtcbn07XG5cbmpRdWVyeS5meC5zcGVlZHMgPSB7XG5cdHNsb3c6IDYwMCxcblx0ZmFzdDogMjAwLFxuXG5cdC8vIERlZmF1bHQgc3BlZWRcblx0X2RlZmF1bHQ6IDQwMFxufTtcblxuXG4vLyBCYXNlZCBvZmYgb2YgdGhlIHBsdWdpbiBieSBDbGludCBIZWxmZXJzLCB3aXRoIHBlcm1pc3Npb24uXG4vLyBodHRwczovL3dlYi5hcmNoaXZlLm9yZy93ZWIvMjAxMDAzMjQwMTQ3NDcvaHR0cDovL2JsaW5kc2lnbmFscy5jb20vaW5kZXgucGhwLzIwMDkvMDcvanF1ZXJ5LWRlbGF5L1xualF1ZXJ5LmZuLmRlbGF5ID0gZnVuY3Rpb24oIHRpbWUsIHR5cGUgKSB7XG5cdHRpbWUgPSBqUXVlcnkuZnggPyBqUXVlcnkuZnguc3BlZWRzWyB0aW1lIF0gfHwgdGltZSA6IHRpbWU7XG5cdHR5cGUgPSB0eXBlIHx8IFwiZnhcIjtcblxuXHRyZXR1cm4gdGhpcy5xdWV1ZSggdHlwZSwgZnVuY3Rpb24oIG5leHQsIGhvb2tzICkge1xuXHRcdHZhciB0aW1lb3V0ID0gd2luZG93LnNldFRpbWVvdXQoIG5leHQsIHRpbWUgKTtcblx0XHRob29rcy5zdG9wID0gZnVuY3Rpb24oKSB7XG5cdFx0XHR3aW5kb3cuY2xlYXJUaW1lb3V0KCB0aW1lb3V0ICk7XG5cdFx0fTtcblx0fSApO1xufTtcblxuXG4oIGZ1bmN0aW9uKCkge1xuXHR2YXIgaW5wdXQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcImlucHV0XCIgKSxcblx0XHRzZWxlY3QgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcInNlbGVjdFwiICksXG5cdFx0b3B0ID0gc2VsZWN0LmFwcGVuZENoaWxkKCBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcIm9wdGlvblwiICkgKTtcblxuXHRpbnB1dC50eXBlID0gXCJjaGVja2JveFwiO1xuXG5cdC8vIFN1cHBvcnQ6IEFuZHJvaWQgPD00LjMgb25seVxuXHQvLyBEZWZhdWx0IHZhbHVlIGZvciBhIGNoZWNrYm94IHNob3VsZCBiZSBcIm9uXCJcblx0c3VwcG9ydC5jaGVja09uID0gaW5wdXQudmFsdWUgIT09IFwiXCI7XG5cblx0Ly8gU3VwcG9ydDogSUUgPD0xMSBvbmx5XG5cdC8vIE11c3QgYWNjZXNzIHNlbGVjdGVkSW5kZXggdG8gbWFrZSBkZWZhdWx0IG9wdGlvbnMgc2VsZWN0XG5cdHN1cHBvcnQub3B0U2VsZWN0ZWQgPSBvcHQuc2VsZWN0ZWQ7XG5cblx0Ly8gU3VwcG9ydDogSUUgPD0xMSBvbmx5XG5cdC8vIEFuIGlucHV0IGxvc2VzIGl0cyB2YWx1ZSBhZnRlciBiZWNvbWluZyBhIHJhZGlvXG5cdGlucHV0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggXCJpbnB1dFwiICk7XG5cdGlucHV0LnZhbHVlID0gXCJ0XCI7XG5cdGlucHV0LnR5cGUgPSBcInJhZGlvXCI7XG5cdHN1cHBvcnQucmFkaW9WYWx1ZSA9IGlucHV0LnZhbHVlID09PSBcInRcIjtcbn0gKSgpO1xuXG5cbnZhciBib29sSG9vayxcblx0YXR0ckhhbmRsZSA9IGpRdWVyeS5leHByLmF0dHJIYW5kbGU7XG5cbmpRdWVyeS5mbi5leHRlbmQoIHtcblx0YXR0cjogZnVuY3Rpb24oIG5hbWUsIHZhbHVlICkge1xuXHRcdHJldHVybiBhY2Nlc3MoIHRoaXMsIGpRdWVyeS5hdHRyLCBuYW1lLCB2YWx1ZSwgYXJndW1lbnRzLmxlbmd0aCA+IDEgKTtcblx0fSxcblxuXHRyZW1vdmVBdHRyOiBmdW5jdGlvbiggbmFtZSApIHtcblx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdGpRdWVyeS5yZW1vdmVBdHRyKCB0aGlzLCBuYW1lICk7XG5cdFx0fSApO1xuXHR9XG59ICk7XG5cbmpRdWVyeS5leHRlbmQoIHtcblx0YXR0cjogZnVuY3Rpb24oIGVsZW0sIG5hbWUsIHZhbHVlICkge1xuXHRcdHZhciByZXQsIGhvb2tzLFxuXHRcdFx0blR5cGUgPSBlbGVtLm5vZGVUeXBlO1xuXG5cdFx0Ly8gRG9uJ3QgZ2V0L3NldCBhdHRyaWJ1dGVzIG9uIHRleHQsIGNvbW1lbnQgYW5kIGF0dHJpYnV0ZSBub2Rlc1xuXHRcdGlmICggblR5cGUgPT09IDMgfHwgblR5cGUgPT09IDggfHwgblR5cGUgPT09IDIgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gRmFsbGJhY2sgdG8gcHJvcCB3aGVuIGF0dHJpYnV0ZXMgYXJlIG5vdCBzdXBwb3J0ZWRcblx0XHRpZiAoIHR5cGVvZiBlbGVtLmdldEF0dHJpYnV0ZSA9PT0gXCJ1bmRlZmluZWRcIiApIHtcblx0XHRcdHJldHVybiBqUXVlcnkucHJvcCggZWxlbSwgbmFtZSwgdmFsdWUgKTtcblx0XHR9XG5cblx0XHQvLyBBdHRyaWJ1dGUgaG9va3MgYXJlIGRldGVybWluZWQgYnkgdGhlIGxvd2VyY2FzZSB2ZXJzaW9uXG5cdFx0Ly8gR3JhYiBuZWNlc3NhcnkgaG9vayBpZiBvbmUgaXMgZGVmaW5lZFxuXHRcdGlmICggblR5cGUgIT09IDEgfHwgIWpRdWVyeS5pc1hNTERvYyggZWxlbSApICkge1xuXHRcdFx0aG9va3MgPSBqUXVlcnkuYXR0ckhvb2tzWyBuYW1lLnRvTG93ZXJDYXNlKCkgXSB8fFxuXHRcdFx0XHQoIGpRdWVyeS5leHByLm1hdGNoLmJvb2wudGVzdCggbmFtZSApID8gYm9vbEhvb2sgOiB1bmRlZmluZWQgKTtcblx0XHR9XG5cblx0XHRpZiAoIHZhbHVlICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRpZiAoIHZhbHVlID09PSBudWxsICkge1xuXHRcdFx0XHRqUXVlcnkucmVtb3ZlQXR0ciggZWxlbSwgbmFtZSApO1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdGlmICggaG9va3MgJiYgXCJzZXRcIiBpbiBob29rcyAmJlxuXHRcdFx0XHQoIHJldCA9IGhvb2tzLnNldCggZWxlbSwgdmFsdWUsIG5hbWUgKSApICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdHJldHVybiByZXQ7XG5cdFx0XHR9XG5cblx0XHRcdGVsZW0uc2V0QXR0cmlidXRlKCBuYW1lLCB2YWx1ZSArIFwiXCIgKTtcblx0XHRcdHJldHVybiB2YWx1ZTtcblx0XHR9XG5cblx0XHRpZiAoIGhvb2tzICYmIFwiZ2V0XCIgaW4gaG9va3MgJiYgKCByZXQgPSBob29rcy5nZXQoIGVsZW0sIG5hbWUgKSApICE9PSBudWxsICkge1xuXHRcdFx0cmV0dXJuIHJldDtcblx0XHR9XG5cblx0XHRyZXQgPSBqUXVlcnkuZmluZC5hdHRyKCBlbGVtLCBuYW1lICk7XG5cblx0XHQvLyBOb24tZXhpc3RlbnQgYXR0cmlidXRlcyByZXR1cm4gbnVsbCwgd2Ugbm9ybWFsaXplIHRvIHVuZGVmaW5lZFxuXHRcdHJldHVybiByZXQgPT0gbnVsbCA/IHVuZGVmaW5lZCA6IHJldDtcblx0fSxcblxuXHRhdHRySG9va3M6IHtcblx0XHR0eXBlOiB7XG5cdFx0XHRzZXQ6IGZ1bmN0aW9uKCBlbGVtLCB2YWx1ZSApIHtcblx0XHRcdFx0aWYgKCAhc3VwcG9ydC5yYWRpb1ZhbHVlICYmIHZhbHVlID09PSBcInJhZGlvXCIgJiZcblx0XHRcdFx0XHRub2RlTmFtZSggZWxlbSwgXCJpbnB1dFwiICkgKSB7XG5cdFx0XHRcdFx0dmFyIHZhbCA9IGVsZW0udmFsdWU7XG5cdFx0XHRcdFx0ZWxlbS5zZXRBdHRyaWJ1dGUoIFwidHlwZVwiLCB2YWx1ZSApO1xuXHRcdFx0XHRcdGlmICggdmFsICkge1xuXHRcdFx0XHRcdFx0ZWxlbS52YWx1ZSA9IHZhbDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cmV0dXJuIHZhbHVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXG5cdHJlbW92ZUF0dHI6IGZ1bmN0aW9uKCBlbGVtLCB2YWx1ZSApIHtcblx0XHR2YXIgbmFtZSxcblx0XHRcdGkgPSAwLFxuXG5cdFx0XHQvLyBBdHRyaWJ1dGUgbmFtZXMgY2FuIGNvbnRhaW4gbm9uLUhUTUwgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzXG5cdFx0XHQvLyBodHRwczovL2h0bWwuc3BlYy53aGF0d2cub3JnL211bHRpcGFnZS9zeW50YXguaHRtbCNhdHRyaWJ1dGVzLTJcblx0XHRcdGF0dHJOYW1lcyA9IHZhbHVlICYmIHZhbHVlLm1hdGNoKCBybm90aHRtbHdoaXRlICk7XG5cblx0XHRpZiAoIGF0dHJOYW1lcyAmJiBlbGVtLm5vZGVUeXBlID09PSAxICkge1xuXHRcdFx0d2hpbGUgKCAoIG5hbWUgPSBhdHRyTmFtZXNbIGkrKyBdICkgKSB7XG5cdFx0XHRcdGVsZW0ucmVtb3ZlQXR0cmlidXRlKCBuYW1lICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG59ICk7XG5cbi8vIEhvb2tzIGZvciBib29sZWFuIGF0dHJpYnV0ZXNcbmJvb2xIb29rID0ge1xuXHRzZXQ6IGZ1bmN0aW9uKCBlbGVtLCB2YWx1ZSwgbmFtZSApIHtcblx0XHRpZiAoIHZhbHVlID09PSBmYWxzZSApIHtcblxuXHRcdFx0Ly8gUmVtb3ZlIGJvb2xlYW4gYXR0cmlidXRlcyB3aGVuIHNldCB0byBmYWxzZVxuXHRcdFx0alF1ZXJ5LnJlbW92ZUF0dHIoIGVsZW0sIG5hbWUgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZWxlbS5zZXRBdHRyaWJ1dGUoIG5hbWUsIG5hbWUgKTtcblx0XHR9XG5cdFx0cmV0dXJuIG5hbWU7XG5cdH1cbn07XG5cbmpRdWVyeS5lYWNoKCBqUXVlcnkuZXhwci5tYXRjaC5ib29sLnNvdXJjZS5tYXRjaCggL1xcdysvZyApLCBmdW5jdGlvbiggX2ksIG5hbWUgKSB7XG5cdHZhciBnZXR0ZXIgPSBhdHRySGFuZGxlWyBuYW1lIF0gfHwgalF1ZXJ5LmZpbmQuYXR0cjtcblxuXHRhdHRySGFuZGxlWyBuYW1lIF0gPSBmdW5jdGlvbiggZWxlbSwgbmFtZSwgaXNYTUwgKSB7XG5cdFx0dmFyIHJldCwgaGFuZGxlLFxuXHRcdFx0bG93ZXJjYXNlTmFtZSA9IG5hbWUudG9Mb3dlckNhc2UoKTtcblxuXHRcdGlmICggIWlzWE1MICkge1xuXG5cdFx0XHQvLyBBdm9pZCBhbiBpbmZpbml0ZSBsb29wIGJ5IHRlbXBvcmFyaWx5IHJlbW92aW5nIHRoaXMgZnVuY3Rpb24gZnJvbSB0aGUgZ2V0dGVyXG5cdFx0XHRoYW5kbGUgPSBhdHRySGFuZGxlWyBsb3dlcmNhc2VOYW1lIF07XG5cdFx0XHRhdHRySGFuZGxlWyBsb3dlcmNhc2VOYW1lIF0gPSByZXQ7XG5cdFx0XHRyZXQgPSBnZXR0ZXIoIGVsZW0sIG5hbWUsIGlzWE1MICkgIT0gbnVsbCA/XG5cdFx0XHRcdGxvd2VyY2FzZU5hbWUgOlxuXHRcdFx0XHRudWxsO1xuXHRcdFx0YXR0ckhhbmRsZVsgbG93ZXJjYXNlTmFtZSBdID0gaGFuZGxlO1xuXHRcdH1cblx0XHRyZXR1cm4gcmV0O1xuXHR9O1xufSApO1xuXG5cblxuXG52YXIgcmZvY3VzYWJsZSA9IC9eKD86aW5wdXR8c2VsZWN0fHRleHRhcmVhfGJ1dHRvbikkL2ksXG5cdHJjbGlja2FibGUgPSAvXig/OmF8YXJlYSkkL2k7XG5cbmpRdWVyeS5mbi5leHRlbmQoIHtcblx0cHJvcDogZnVuY3Rpb24oIG5hbWUsIHZhbHVlICkge1xuXHRcdHJldHVybiBhY2Nlc3MoIHRoaXMsIGpRdWVyeS5wcm9wLCBuYW1lLCB2YWx1ZSwgYXJndW1lbnRzLmxlbmd0aCA+IDEgKTtcblx0fSxcblxuXHRyZW1vdmVQcm9wOiBmdW5jdGlvbiggbmFtZSApIHtcblx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdGRlbGV0ZSB0aGlzWyBqUXVlcnkucHJvcEZpeFsgbmFtZSBdIHx8IG5hbWUgXTtcblx0XHR9ICk7XG5cdH1cbn0gKTtcblxualF1ZXJ5LmV4dGVuZCgge1xuXHRwcm9wOiBmdW5jdGlvbiggZWxlbSwgbmFtZSwgdmFsdWUgKSB7XG5cdFx0dmFyIHJldCwgaG9va3MsXG5cdFx0XHRuVHlwZSA9IGVsZW0ubm9kZVR5cGU7XG5cblx0XHQvLyBEb24ndCBnZXQvc2V0IHByb3BlcnRpZXMgb24gdGV4dCwgY29tbWVudCBhbmQgYXR0cmlidXRlIG5vZGVzXG5cdFx0aWYgKCBuVHlwZSA9PT0gMyB8fCBuVHlwZSA9PT0gOCB8fCBuVHlwZSA9PT0gMiApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIG5UeXBlICE9PSAxIHx8ICFqUXVlcnkuaXNYTUxEb2MoIGVsZW0gKSApIHtcblxuXHRcdFx0Ly8gRml4IG5hbWUgYW5kIGF0dGFjaCBob29rc1xuXHRcdFx0bmFtZSA9IGpRdWVyeS5wcm9wRml4WyBuYW1lIF0gfHwgbmFtZTtcblx0XHRcdGhvb2tzID0galF1ZXJ5LnByb3BIb29rc1sgbmFtZSBdO1xuXHRcdH1cblxuXHRcdGlmICggdmFsdWUgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdGlmICggaG9va3MgJiYgXCJzZXRcIiBpbiBob29rcyAmJlxuXHRcdFx0XHQoIHJldCA9IGhvb2tzLnNldCggZWxlbSwgdmFsdWUsIG5hbWUgKSApICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdHJldHVybiByZXQ7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiAoIGVsZW1bIG5hbWUgXSA9IHZhbHVlICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBob29rcyAmJiBcImdldFwiIGluIGhvb2tzICYmICggcmV0ID0gaG9va3MuZ2V0KCBlbGVtLCBuYW1lICkgKSAhPT0gbnVsbCApIHtcblx0XHRcdHJldHVybiByZXQ7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGVsZW1bIG5hbWUgXTtcblx0fSxcblxuXHRwcm9wSG9va3M6IHtcblx0XHR0YWJJbmRleDoge1xuXHRcdFx0Z2V0OiBmdW5jdGlvbiggZWxlbSApIHtcblxuXHRcdFx0XHQvLyBTdXBwb3J0OiBJRSA8PTkgLSAxMSBvbmx5XG5cdFx0XHRcdC8vIGVsZW0udGFiSW5kZXggZG9lc24ndCBhbHdheXMgcmV0dXJuIHRoZVxuXHRcdFx0XHQvLyBjb3JyZWN0IHZhbHVlIHdoZW4gaXQgaGFzbid0IGJlZW4gZXhwbGljaXRseSBzZXRcblx0XHRcdFx0Ly8gaHR0cHM6Ly93ZWIuYXJjaGl2ZS5vcmcvd2ViLzIwMTQxMTE2MjMzMzQ3L2h0dHA6Ly9mbHVpZHByb2plY3Qub3JnL2Jsb2cvMjAwOC8wMS8wOS9nZXR0aW5nLXNldHRpbmctYW5kLXJlbW92aW5nLXRhYmluZGV4LXZhbHVlcy13aXRoLWphdmFzY3JpcHQvXG5cdFx0XHRcdC8vIFVzZSBwcm9wZXIgYXR0cmlidXRlIHJldHJpZXZhbCgjMTIwNzIpXG5cdFx0XHRcdHZhciB0YWJpbmRleCA9IGpRdWVyeS5maW5kLmF0dHIoIGVsZW0sIFwidGFiaW5kZXhcIiApO1xuXG5cdFx0XHRcdGlmICggdGFiaW5kZXggKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHBhcnNlSW50KCB0YWJpbmRleCwgMTAgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmIChcblx0XHRcdFx0XHRyZm9jdXNhYmxlLnRlc3QoIGVsZW0ubm9kZU5hbWUgKSB8fFxuXHRcdFx0XHRcdHJjbGlja2FibGUudGVzdCggZWxlbS5ub2RlTmFtZSApICYmXG5cdFx0XHRcdFx0ZWxlbS5ocmVmXG5cdFx0XHRcdCkge1xuXHRcdFx0XHRcdHJldHVybiAwO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0cmV0dXJuIC0xO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblxuXHRwcm9wRml4OiB7XG5cdFx0XCJmb3JcIjogXCJodG1sRm9yXCIsXG5cdFx0XCJjbGFzc1wiOiBcImNsYXNzTmFtZVwiXG5cdH1cbn0gKTtcblxuLy8gU3VwcG9ydDogSUUgPD0xMSBvbmx5XG4vLyBBY2Nlc3NpbmcgdGhlIHNlbGVjdGVkSW5kZXggcHJvcGVydHlcbi8vIGZvcmNlcyB0aGUgYnJvd3NlciB0byByZXNwZWN0IHNldHRpbmcgc2VsZWN0ZWRcbi8vIG9uIHRoZSBvcHRpb25cbi8vIFRoZSBnZXR0ZXIgZW5zdXJlcyBhIGRlZmF1bHQgb3B0aW9uIGlzIHNlbGVjdGVkXG4vLyB3aGVuIGluIGFuIG9wdGdyb3VwXG4vLyBlc2xpbnQgcnVsZSBcIm5vLXVudXNlZC1leHByZXNzaW9uc1wiIGlzIGRpc2FibGVkIGZvciB0aGlzIGNvZGVcbi8vIHNpbmNlIGl0IGNvbnNpZGVycyBzdWNoIGFjY2Vzc2lvbnMgbm9vcFxuaWYgKCAhc3VwcG9ydC5vcHRTZWxlY3RlZCApIHtcblx0alF1ZXJ5LnByb3BIb29rcy5zZWxlY3RlZCA9IHtcblx0XHRnZXQ6IGZ1bmN0aW9uKCBlbGVtICkge1xuXG5cdFx0XHQvKiBlc2xpbnQgbm8tdW51c2VkLWV4cHJlc3Npb25zOiBcIm9mZlwiICovXG5cblx0XHRcdHZhciBwYXJlbnQgPSBlbGVtLnBhcmVudE5vZGU7XG5cdFx0XHRpZiAoIHBhcmVudCAmJiBwYXJlbnQucGFyZW50Tm9kZSApIHtcblx0XHRcdFx0cGFyZW50LnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleDtcblx0XHRcdH1cblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH0sXG5cdFx0c2V0OiBmdW5jdGlvbiggZWxlbSApIHtcblxuXHRcdFx0LyogZXNsaW50IG5vLXVudXNlZC1leHByZXNzaW9uczogXCJvZmZcIiAqL1xuXG5cdFx0XHR2YXIgcGFyZW50ID0gZWxlbS5wYXJlbnROb2RlO1xuXHRcdFx0aWYgKCBwYXJlbnQgKSB7XG5cdFx0XHRcdHBhcmVudC5zZWxlY3RlZEluZGV4O1xuXG5cdFx0XHRcdGlmICggcGFyZW50LnBhcmVudE5vZGUgKSB7XG5cdFx0XHRcdFx0cGFyZW50LnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fTtcbn1cblxualF1ZXJ5LmVhY2goIFtcblx0XCJ0YWJJbmRleFwiLFxuXHRcInJlYWRPbmx5XCIsXG5cdFwibWF4TGVuZ3RoXCIsXG5cdFwiY2VsbFNwYWNpbmdcIixcblx0XCJjZWxsUGFkZGluZ1wiLFxuXHRcInJvd1NwYW5cIixcblx0XCJjb2xTcGFuXCIsXG5cdFwidXNlTWFwXCIsXG5cdFwiZnJhbWVCb3JkZXJcIixcblx0XCJjb250ZW50RWRpdGFibGVcIlxuXSwgZnVuY3Rpb24oKSB7XG5cdGpRdWVyeS5wcm9wRml4WyB0aGlzLnRvTG93ZXJDYXNlKCkgXSA9IHRoaXM7XG59ICk7XG5cblxuXG5cblx0Ly8gU3RyaXAgYW5kIGNvbGxhcHNlIHdoaXRlc3BhY2UgYWNjb3JkaW5nIHRvIEhUTUwgc3BlY1xuXHQvLyBodHRwczovL2luZnJhLnNwZWMud2hhdHdnLm9yZy8jc3RyaXAtYW5kLWNvbGxhcHNlLWFzY2lpLXdoaXRlc3BhY2Vcblx0ZnVuY3Rpb24gc3RyaXBBbmRDb2xsYXBzZSggdmFsdWUgKSB7XG5cdFx0dmFyIHRva2VucyA9IHZhbHVlLm1hdGNoKCBybm90aHRtbHdoaXRlICkgfHwgW107XG5cdFx0cmV0dXJuIHRva2Vucy5qb2luKCBcIiBcIiApO1xuXHR9XG5cblxuZnVuY3Rpb24gZ2V0Q2xhc3MoIGVsZW0gKSB7XG5cdHJldHVybiBlbGVtLmdldEF0dHJpYnV0ZSAmJiBlbGVtLmdldEF0dHJpYnV0ZSggXCJjbGFzc1wiICkgfHwgXCJcIjtcbn1cblxuZnVuY3Rpb24gY2xhc3Nlc1RvQXJyYXkoIHZhbHVlICkge1xuXHRpZiAoIEFycmF5LmlzQXJyYXkoIHZhbHVlICkgKSB7XG5cdFx0cmV0dXJuIHZhbHVlO1xuXHR9XG5cdGlmICggdHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiICkge1xuXHRcdHJldHVybiB2YWx1ZS5tYXRjaCggcm5vdGh0bWx3aGl0ZSApIHx8IFtdO1xuXHR9XG5cdHJldHVybiBbXTtcbn1cblxualF1ZXJ5LmZuLmV4dGVuZCgge1xuXHRhZGRDbGFzczogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHZhciBjbGFzc2VzLCBlbGVtLCBjdXIsIGN1clZhbHVlLCBjbGF6eiwgaiwgZmluYWxWYWx1ZSxcblx0XHRcdGkgPSAwO1xuXG5cdFx0aWYgKCBpc0Z1bmN0aW9uKCB2YWx1ZSApICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oIGogKSB7XG5cdFx0XHRcdGpRdWVyeSggdGhpcyApLmFkZENsYXNzKCB2YWx1ZS5jYWxsKCB0aGlzLCBqLCBnZXRDbGFzcyggdGhpcyApICkgKTtcblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHRjbGFzc2VzID0gY2xhc3Nlc1RvQXJyYXkoIHZhbHVlICk7XG5cblx0XHRpZiAoIGNsYXNzZXMubGVuZ3RoICkge1xuXHRcdFx0d2hpbGUgKCAoIGVsZW0gPSB0aGlzWyBpKysgXSApICkge1xuXHRcdFx0XHRjdXJWYWx1ZSA9IGdldENsYXNzKCBlbGVtICk7XG5cdFx0XHRcdGN1ciA9IGVsZW0ubm9kZVR5cGUgPT09IDEgJiYgKCBcIiBcIiArIHN0cmlwQW5kQ29sbGFwc2UoIGN1clZhbHVlICkgKyBcIiBcIiApO1xuXG5cdFx0XHRcdGlmICggY3VyICkge1xuXHRcdFx0XHRcdGogPSAwO1xuXHRcdFx0XHRcdHdoaWxlICggKCBjbGF6eiA9IGNsYXNzZXNbIGorKyBdICkgKSB7XG5cdFx0XHRcdFx0XHRpZiAoIGN1ci5pbmRleE9mKCBcIiBcIiArIGNsYXp6ICsgXCIgXCIgKSA8IDAgKSB7XG5cdFx0XHRcdFx0XHRcdGN1ciArPSBjbGF6eiArIFwiIFwiO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIE9ubHkgYXNzaWduIGlmIGRpZmZlcmVudCB0byBhdm9pZCB1bm5lZWRlZCByZW5kZXJpbmcuXG5cdFx0XHRcdFx0ZmluYWxWYWx1ZSA9IHN0cmlwQW5kQ29sbGFwc2UoIGN1ciApO1xuXHRcdFx0XHRcdGlmICggY3VyVmFsdWUgIT09IGZpbmFsVmFsdWUgKSB7XG5cdFx0XHRcdFx0XHRlbGVtLnNldEF0dHJpYnV0ZSggXCJjbGFzc1wiLCBmaW5hbFZhbHVlICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0cmVtb3ZlQ2xhc3M6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR2YXIgY2xhc3NlcywgZWxlbSwgY3VyLCBjdXJWYWx1ZSwgY2xhenosIGosIGZpbmFsVmFsdWUsXG5cdFx0XHRpID0gMDtcblxuXHRcdGlmICggaXNGdW5jdGlvbiggdmFsdWUgKSApIHtcblx0XHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCBqICkge1xuXHRcdFx0XHRqUXVlcnkoIHRoaXMgKS5yZW1vdmVDbGFzcyggdmFsdWUuY2FsbCggdGhpcywgaiwgZ2V0Q2xhc3MoIHRoaXMgKSApICk7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0aWYgKCAhYXJndW1lbnRzLmxlbmd0aCApIHtcblx0XHRcdHJldHVybiB0aGlzLmF0dHIoIFwiY2xhc3NcIiwgXCJcIiApO1xuXHRcdH1cblxuXHRcdGNsYXNzZXMgPSBjbGFzc2VzVG9BcnJheSggdmFsdWUgKTtcblxuXHRcdGlmICggY2xhc3Nlcy5sZW5ndGggKSB7XG5cdFx0XHR3aGlsZSAoICggZWxlbSA9IHRoaXNbIGkrKyBdICkgKSB7XG5cdFx0XHRcdGN1clZhbHVlID0gZ2V0Q2xhc3MoIGVsZW0gKTtcblxuXHRcdFx0XHQvLyBUaGlzIGV4cHJlc3Npb24gaXMgaGVyZSBmb3IgYmV0dGVyIGNvbXByZXNzaWJpbGl0eSAoc2VlIGFkZENsYXNzKVxuXHRcdFx0XHRjdXIgPSBlbGVtLm5vZGVUeXBlID09PSAxICYmICggXCIgXCIgKyBzdHJpcEFuZENvbGxhcHNlKCBjdXJWYWx1ZSApICsgXCIgXCIgKTtcblxuXHRcdFx0XHRpZiAoIGN1ciApIHtcblx0XHRcdFx0XHRqID0gMDtcblx0XHRcdFx0XHR3aGlsZSAoICggY2xhenogPSBjbGFzc2VzWyBqKysgXSApICkge1xuXG5cdFx0XHRcdFx0XHQvLyBSZW1vdmUgKmFsbCogaW5zdGFuY2VzXG5cdFx0XHRcdFx0XHR3aGlsZSAoIGN1ci5pbmRleE9mKCBcIiBcIiArIGNsYXp6ICsgXCIgXCIgKSA+IC0xICkge1xuXHRcdFx0XHRcdFx0XHRjdXIgPSBjdXIucmVwbGFjZSggXCIgXCIgKyBjbGF6eiArIFwiIFwiLCBcIiBcIiApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIE9ubHkgYXNzaWduIGlmIGRpZmZlcmVudCB0byBhdm9pZCB1bm5lZWRlZCByZW5kZXJpbmcuXG5cdFx0XHRcdFx0ZmluYWxWYWx1ZSA9IHN0cmlwQW5kQ29sbGFwc2UoIGN1ciApO1xuXHRcdFx0XHRcdGlmICggY3VyVmFsdWUgIT09IGZpbmFsVmFsdWUgKSB7XG5cdFx0XHRcdFx0XHRlbGVtLnNldEF0dHJpYnV0ZSggXCJjbGFzc1wiLCBmaW5hbFZhbHVlICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0dG9nZ2xlQ2xhc3M6IGZ1bmN0aW9uKCB2YWx1ZSwgc3RhdGVWYWwgKSB7XG5cdFx0dmFyIHR5cGUgPSB0eXBlb2YgdmFsdWUsXG5cdFx0XHRpc1ZhbGlkVmFsdWUgPSB0eXBlID09PSBcInN0cmluZ1wiIHx8IEFycmF5LmlzQXJyYXkoIHZhbHVlICk7XG5cblx0XHRpZiAoIHR5cGVvZiBzdGF0ZVZhbCA9PT0gXCJib29sZWFuXCIgJiYgaXNWYWxpZFZhbHVlICkge1xuXHRcdFx0cmV0dXJuIHN0YXRlVmFsID8gdGhpcy5hZGRDbGFzcyggdmFsdWUgKSA6IHRoaXMucmVtb3ZlQ2xhc3MoIHZhbHVlICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBpc0Z1bmN0aW9uKCB2YWx1ZSApICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oIGkgKSB7XG5cdFx0XHRcdGpRdWVyeSggdGhpcyApLnRvZ2dsZUNsYXNzKFxuXHRcdFx0XHRcdHZhbHVlLmNhbGwoIHRoaXMsIGksIGdldENsYXNzKCB0aGlzICksIHN0YXRlVmFsICksXG5cdFx0XHRcdFx0c3RhdGVWYWxcblx0XHRcdFx0KTtcblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBjbGFzc05hbWUsIGksIHNlbGYsIGNsYXNzTmFtZXM7XG5cblx0XHRcdGlmICggaXNWYWxpZFZhbHVlICkge1xuXG5cdFx0XHRcdC8vIFRvZ2dsZSBpbmRpdmlkdWFsIGNsYXNzIG5hbWVzXG5cdFx0XHRcdGkgPSAwO1xuXHRcdFx0XHRzZWxmID0galF1ZXJ5KCB0aGlzICk7XG5cdFx0XHRcdGNsYXNzTmFtZXMgPSBjbGFzc2VzVG9BcnJheSggdmFsdWUgKTtcblxuXHRcdFx0XHR3aGlsZSAoICggY2xhc3NOYW1lID0gY2xhc3NOYW1lc1sgaSsrIF0gKSApIHtcblxuXHRcdFx0XHRcdC8vIENoZWNrIGVhY2ggY2xhc3NOYW1lIGdpdmVuLCBzcGFjZSBzZXBhcmF0ZWQgbGlzdFxuXHRcdFx0XHRcdGlmICggc2VsZi5oYXNDbGFzcyggY2xhc3NOYW1lICkgKSB7XG5cdFx0XHRcdFx0XHRzZWxmLnJlbW92ZUNsYXNzKCBjbGFzc05hbWUgKTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0c2VsZi5hZGRDbGFzcyggY2xhc3NOYW1lICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdC8vIFRvZ2dsZSB3aG9sZSBjbGFzcyBuYW1lXG5cdFx0XHR9IGVsc2UgaWYgKCB2YWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHR5cGUgPT09IFwiYm9vbGVhblwiICkge1xuXHRcdFx0XHRjbGFzc05hbWUgPSBnZXRDbGFzcyggdGhpcyApO1xuXHRcdFx0XHRpZiAoIGNsYXNzTmFtZSApIHtcblxuXHRcdFx0XHRcdC8vIFN0b3JlIGNsYXNzTmFtZSBpZiBzZXRcblx0XHRcdFx0XHRkYXRhUHJpdi5zZXQoIHRoaXMsIFwiX19jbGFzc05hbWVfX1wiLCBjbGFzc05hbWUgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIElmIHRoZSBlbGVtZW50IGhhcyBhIGNsYXNzIG5hbWUgb3IgaWYgd2UncmUgcGFzc2VkIGBmYWxzZWAsXG5cdFx0XHRcdC8vIHRoZW4gcmVtb3ZlIHRoZSB3aG9sZSBjbGFzc25hbWUgKGlmIHRoZXJlIHdhcyBvbmUsIHRoZSBhYm92ZSBzYXZlZCBpdCkuXG5cdFx0XHRcdC8vIE90aGVyd2lzZSBicmluZyBiYWNrIHdoYXRldmVyIHdhcyBwcmV2aW91c2x5IHNhdmVkIChpZiBhbnl0aGluZyksXG5cdFx0XHRcdC8vIGZhbGxpbmcgYmFjayB0byB0aGUgZW1wdHkgc3RyaW5nIGlmIG5vdGhpbmcgd2FzIHN0b3JlZC5cblx0XHRcdFx0aWYgKCB0aGlzLnNldEF0dHJpYnV0ZSApIHtcblx0XHRcdFx0XHR0aGlzLnNldEF0dHJpYnV0ZSggXCJjbGFzc1wiLFxuXHRcdFx0XHRcdFx0Y2xhc3NOYW1lIHx8IHZhbHVlID09PSBmYWxzZSA/XG5cdFx0XHRcdFx0XHRcdFwiXCIgOlxuXHRcdFx0XHRcdFx0XHRkYXRhUHJpdi5nZXQoIHRoaXMsIFwiX19jbGFzc05hbWVfX1wiICkgfHwgXCJcIlxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0aGFzQ2xhc3M6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHR2YXIgY2xhc3NOYW1lLCBlbGVtLFxuXHRcdFx0aSA9IDA7XG5cblx0XHRjbGFzc05hbWUgPSBcIiBcIiArIHNlbGVjdG9yICsgXCIgXCI7XG5cdFx0d2hpbGUgKCAoIGVsZW0gPSB0aGlzWyBpKysgXSApICkge1xuXHRcdFx0aWYgKCBlbGVtLm5vZGVUeXBlID09PSAxICYmXG5cdFx0XHRcdCggXCIgXCIgKyBzdHJpcEFuZENvbGxhcHNlKCBnZXRDbGFzcyggZWxlbSApICkgKyBcIiBcIiApLmluZGV4T2YoIGNsYXNzTmFtZSApID4gLTEgKSB7XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiBmYWxzZTtcblx0fVxufSApO1xuXG5cblxuXG52YXIgcnJldHVybiA9IC9cXHIvZztcblxualF1ZXJ5LmZuLmV4dGVuZCgge1xuXHR2YWw6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR2YXIgaG9va3MsIHJldCwgdmFsdWVJc0Z1bmN0aW9uLFxuXHRcdFx0ZWxlbSA9IHRoaXNbIDAgXTtcblxuXHRcdGlmICggIWFyZ3VtZW50cy5sZW5ndGggKSB7XG5cdFx0XHRpZiAoIGVsZW0gKSB7XG5cdFx0XHRcdGhvb2tzID0galF1ZXJ5LnZhbEhvb2tzWyBlbGVtLnR5cGUgXSB8fFxuXHRcdFx0XHRcdGpRdWVyeS52YWxIb29rc1sgZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpIF07XG5cblx0XHRcdFx0aWYgKCBob29rcyAmJlxuXHRcdFx0XHRcdFwiZ2V0XCIgaW4gaG9va3MgJiZcblx0XHRcdFx0XHQoIHJldCA9IGhvb2tzLmdldCggZWxlbSwgXCJ2YWx1ZVwiICkgKSAhPT0gdW5kZWZpbmVkXG5cdFx0XHRcdCkge1xuXHRcdFx0XHRcdHJldHVybiByZXQ7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXQgPSBlbGVtLnZhbHVlO1xuXG5cdFx0XHRcdC8vIEhhbmRsZSBtb3N0IGNvbW1vbiBzdHJpbmcgY2FzZXNcblx0XHRcdFx0aWYgKCB0eXBlb2YgcmV0ID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0XHRcdHJldHVybiByZXQucmVwbGFjZSggcnJldHVybiwgXCJcIiApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gSGFuZGxlIGNhc2VzIHdoZXJlIHZhbHVlIGlzIG51bGwvdW5kZWYgb3IgbnVtYmVyXG5cdFx0XHRcdHJldHVybiByZXQgPT0gbnVsbCA/IFwiXCIgOiByZXQ7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR2YWx1ZUlzRnVuY3Rpb24gPSBpc0Z1bmN0aW9uKCB2YWx1ZSApO1xuXG5cdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oIGkgKSB7XG5cdFx0XHR2YXIgdmFsO1xuXG5cdFx0XHRpZiAoIHRoaXMubm9kZVR5cGUgIT09IDEgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCB2YWx1ZUlzRnVuY3Rpb24gKSB7XG5cdFx0XHRcdHZhbCA9IHZhbHVlLmNhbGwoIHRoaXMsIGksIGpRdWVyeSggdGhpcyApLnZhbCgpICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR2YWwgPSB2YWx1ZTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gVHJlYXQgbnVsbC91bmRlZmluZWQgYXMgXCJcIjsgY29udmVydCBudW1iZXJzIHRvIHN0cmluZ1xuXHRcdFx0aWYgKCB2YWwgPT0gbnVsbCApIHtcblx0XHRcdFx0dmFsID0gXCJcIjtcblxuXHRcdFx0fSBlbHNlIGlmICggdHlwZW9mIHZhbCA9PT0gXCJudW1iZXJcIiApIHtcblx0XHRcdFx0dmFsICs9IFwiXCI7XG5cblx0XHRcdH0gZWxzZSBpZiAoIEFycmF5LmlzQXJyYXkoIHZhbCApICkge1xuXHRcdFx0XHR2YWwgPSBqUXVlcnkubWFwKCB2YWwsIGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRcdFx0XHRyZXR1cm4gdmFsdWUgPT0gbnVsbCA/IFwiXCIgOiB2YWx1ZSArIFwiXCI7XG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblxuXHRcdFx0aG9va3MgPSBqUXVlcnkudmFsSG9va3NbIHRoaXMudHlwZSBdIHx8IGpRdWVyeS52YWxIb29rc1sgdGhpcy5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpIF07XG5cblx0XHRcdC8vIElmIHNldCByZXR1cm5zIHVuZGVmaW5lZCwgZmFsbCBiYWNrIHRvIG5vcm1hbCBzZXR0aW5nXG5cdFx0XHRpZiAoICFob29rcyB8fCAhKCBcInNldFwiIGluIGhvb2tzICkgfHwgaG9va3Muc2V0KCB0aGlzLCB2YWwsIFwidmFsdWVcIiApID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdHRoaXMudmFsdWUgPSB2YWw7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9XG59ICk7XG5cbmpRdWVyeS5leHRlbmQoIHtcblx0dmFsSG9va3M6IHtcblx0XHRvcHRpb246IHtcblx0XHRcdGdldDogZnVuY3Rpb24oIGVsZW0gKSB7XG5cblx0XHRcdFx0dmFyIHZhbCA9IGpRdWVyeS5maW5kLmF0dHIoIGVsZW0sIFwidmFsdWVcIiApO1xuXHRcdFx0XHRyZXR1cm4gdmFsICE9IG51bGwgP1xuXHRcdFx0XHRcdHZhbCA6XG5cblx0XHRcdFx0XHQvLyBTdXBwb3J0OiBJRSA8PTEwIC0gMTEgb25seVxuXHRcdFx0XHRcdC8vIG9wdGlvbi50ZXh0IHRocm93cyBleGNlcHRpb25zICgjMTQ2ODYsICMxNDg1OClcblx0XHRcdFx0XHQvLyBTdHJpcCBhbmQgY29sbGFwc2Ugd2hpdGVzcGFjZVxuXHRcdFx0XHRcdC8vIGh0dHBzOi8vaHRtbC5zcGVjLndoYXR3Zy5vcmcvI3N0cmlwLWFuZC1jb2xsYXBzZS13aGl0ZXNwYWNlXG5cdFx0XHRcdFx0c3RyaXBBbmRDb2xsYXBzZSggalF1ZXJ5LnRleHQoIGVsZW0gKSApO1xuXHRcdFx0fVxuXHRcdH0sXG5cdFx0c2VsZWN0OiB7XG5cdFx0XHRnZXQ6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHR2YXIgdmFsdWUsIG9wdGlvbiwgaSxcblx0XHRcdFx0XHRvcHRpb25zID0gZWxlbS5vcHRpb25zLFxuXHRcdFx0XHRcdGluZGV4ID0gZWxlbS5zZWxlY3RlZEluZGV4LFxuXHRcdFx0XHRcdG9uZSA9IGVsZW0udHlwZSA9PT0gXCJzZWxlY3Qtb25lXCIsXG5cdFx0XHRcdFx0dmFsdWVzID0gb25lID8gbnVsbCA6IFtdLFxuXHRcdFx0XHRcdG1heCA9IG9uZSA/IGluZGV4ICsgMSA6IG9wdGlvbnMubGVuZ3RoO1xuXG5cdFx0XHRcdGlmICggaW5kZXggPCAwICkge1xuXHRcdFx0XHRcdGkgPSBtYXg7XG5cblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRpID0gb25lID8gaW5kZXggOiAwO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gTG9vcCB0aHJvdWdoIGFsbCB0aGUgc2VsZWN0ZWQgb3B0aW9uc1xuXHRcdFx0XHRmb3IgKCA7IGkgPCBtYXg7IGkrKyApIHtcblx0XHRcdFx0XHRvcHRpb24gPSBvcHRpb25zWyBpIF07XG5cblx0XHRcdFx0XHQvLyBTdXBwb3J0OiBJRSA8PTkgb25seVxuXHRcdFx0XHRcdC8vIElFOC05IGRvZXNuJ3QgdXBkYXRlIHNlbGVjdGVkIGFmdGVyIGZvcm0gcmVzZXQgKCMyNTUxKVxuXHRcdFx0XHRcdGlmICggKCBvcHRpb24uc2VsZWN0ZWQgfHwgaSA9PT0gaW5kZXggKSAmJlxuXG5cdFx0XHRcdFx0XHRcdC8vIERvbid0IHJldHVybiBvcHRpb25zIHRoYXQgYXJlIGRpc2FibGVkIG9yIGluIGEgZGlzYWJsZWQgb3B0Z3JvdXBcblx0XHRcdFx0XHRcdFx0IW9wdGlvbi5kaXNhYmxlZCAmJlxuXHRcdFx0XHRcdFx0XHQoICFvcHRpb24ucGFyZW50Tm9kZS5kaXNhYmxlZCB8fFxuXHRcdFx0XHRcdFx0XHRcdCFub2RlTmFtZSggb3B0aW9uLnBhcmVudE5vZGUsIFwib3B0Z3JvdXBcIiApICkgKSB7XG5cblx0XHRcdFx0XHRcdC8vIEdldCB0aGUgc3BlY2lmaWMgdmFsdWUgZm9yIHRoZSBvcHRpb25cblx0XHRcdFx0XHRcdHZhbHVlID0galF1ZXJ5KCBvcHRpb24gKS52YWwoKTtcblxuXHRcdFx0XHRcdFx0Ly8gV2UgZG9uJ3QgbmVlZCBhbiBhcnJheSBmb3Igb25lIHNlbGVjdHNcblx0XHRcdFx0XHRcdGlmICggb25lICkge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdmFsdWU7XG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdC8vIE11bHRpLVNlbGVjdHMgcmV0dXJuIGFuIGFycmF5XG5cdFx0XHRcdFx0XHR2YWx1ZXMucHVzaCggdmFsdWUgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXR1cm4gdmFsdWVzO1xuXHRcdFx0fSxcblxuXHRcdFx0c2V0OiBmdW5jdGlvbiggZWxlbSwgdmFsdWUgKSB7XG5cdFx0XHRcdHZhciBvcHRpb25TZXQsIG9wdGlvbixcblx0XHRcdFx0XHRvcHRpb25zID0gZWxlbS5vcHRpb25zLFxuXHRcdFx0XHRcdHZhbHVlcyA9IGpRdWVyeS5tYWtlQXJyYXkoIHZhbHVlICksXG5cdFx0XHRcdFx0aSA9IG9wdGlvbnMubGVuZ3RoO1xuXG5cdFx0XHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0XHRcdG9wdGlvbiA9IG9wdGlvbnNbIGkgXTtcblxuXHRcdFx0XHRcdC8qIGVzbGludC1kaXNhYmxlIG5vLWNvbmQtYXNzaWduICovXG5cblx0XHRcdFx0XHRpZiAoIG9wdGlvbi5zZWxlY3RlZCA9XG5cdFx0XHRcdFx0XHRqUXVlcnkuaW5BcnJheSggalF1ZXJ5LnZhbEhvb2tzLm9wdGlvbi5nZXQoIG9wdGlvbiApLCB2YWx1ZXMgKSA+IC0xXG5cdFx0XHRcdFx0KSB7XG5cdFx0XHRcdFx0XHRvcHRpb25TZXQgPSB0cnVlO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8qIGVzbGludC1lbmFibGUgbm8tY29uZC1hc3NpZ24gKi9cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIEZvcmNlIGJyb3dzZXJzIHRvIGJlaGF2ZSBjb25zaXN0ZW50bHkgd2hlbiBub24tbWF0Y2hpbmcgdmFsdWUgaXMgc2V0XG5cdFx0XHRcdGlmICggIW9wdGlvblNldCApIHtcblx0XHRcdFx0XHRlbGVtLnNlbGVjdGVkSW5kZXggPSAtMTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gdmFsdWVzO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxufSApO1xuXG4vLyBSYWRpb3MgYW5kIGNoZWNrYm94ZXMgZ2V0dGVyL3NldHRlclxualF1ZXJ5LmVhY2goIFsgXCJyYWRpb1wiLCBcImNoZWNrYm94XCIgXSwgZnVuY3Rpb24oKSB7XG5cdGpRdWVyeS52YWxIb29rc1sgdGhpcyBdID0ge1xuXHRcdHNldDogZnVuY3Rpb24oIGVsZW0sIHZhbHVlICkge1xuXHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCB2YWx1ZSApICkge1xuXHRcdFx0XHRyZXR1cm4gKCBlbGVtLmNoZWNrZWQgPSBqUXVlcnkuaW5BcnJheSggalF1ZXJ5KCBlbGVtICkudmFsKCksIHZhbHVlICkgPiAtMSApO1xuXHRcdFx0fVxuXHRcdH1cblx0fTtcblx0aWYgKCAhc3VwcG9ydC5jaGVja09uICkge1xuXHRcdGpRdWVyeS52YWxIb29rc1sgdGhpcyBdLmdldCA9IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0cmV0dXJuIGVsZW0uZ2V0QXR0cmlidXRlKCBcInZhbHVlXCIgKSA9PT0gbnVsbCA/IFwib25cIiA6IGVsZW0udmFsdWU7XG5cdFx0fTtcblx0fVxufSApO1xuXG5cblxuXG4vLyBSZXR1cm4galF1ZXJ5IGZvciBhdHRyaWJ1dGVzLW9ubHkgaW5jbHVzaW9uXG5cblxuc3VwcG9ydC5mb2N1c2luID0gXCJvbmZvY3VzaW5cIiBpbiB3aW5kb3c7XG5cblxudmFyIHJmb2N1c01vcnBoID0gL14oPzpmb2N1c2luZm9jdXN8Zm9jdXNvdXRibHVyKSQvLFxuXHRzdG9wUHJvcGFnYXRpb25DYWxsYmFjayA9IGZ1bmN0aW9uKCBlICkge1xuXHRcdGUuc3RvcFByb3BhZ2F0aW9uKCk7XG5cdH07XG5cbmpRdWVyeS5leHRlbmQoIGpRdWVyeS5ldmVudCwge1xuXG5cdHRyaWdnZXI6IGZ1bmN0aW9uKCBldmVudCwgZGF0YSwgZWxlbSwgb25seUhhbmRsZXJzICkge1xuXG5cdFx0dmFyIGksIGN1ciwgdG1wLCBidWJibGVUeXBlLCBvbnR5cGUsIGhhbmRsZSwgc3BlY2lhbCwgbGFzdEVsZW1lbnQsXG5cdFx0XHRldmVudFBhdGggPSBbIGVsZW0gfHwgZG9jdW1lbnQgXSxcblx0XHRcdHR5cGUgPSBoYXNPd24uY2FsbCggZXZlbnQsIFwidHlwZVwiICkgPyBldmVudC50eXBlIDogZXZlbnQsXG5cdFx0XHRuYW1lc3BhY2VzID0gaGFzT3duLmNhbGwoIGV2ZW50LCBcIm5hbWVzcGFjZVwiICkgPyBldmVudC5uYW1lc3BhY2Uuc3BsaXQoIFwiLlwiICkgOiBbXTtcblxuXHRcdGN1ciA9IGxhc3RFbGVtZW50ID0gdG1wID0gZWxlbSA9IGVsZW0gfHwgZG9jdW1lbnQ7XG5cblx0XHQvLyBEb24ndCBkbyBldmVudHMgb24gdGV4dCBhbmQgY29tbWVudCBub2Rlc1xuXHRcdGlmICggZWxlbS5ub2RlVHlwZSA9PT0gMyB8fCBlbGVtLm5vZGVUeXBlID09PSA4ICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIGZvY3VzL2JsdXIgbW9ycGhzIHRvIGZvY3VzaW4vb3V0OyBlbnN1cmUgd2UncmUgbm90IGZpcmluZyB0aGVtIHJpZ2h0IG5vd1xuXHRcdGlmICggcmZvY3VzTW9ycGgudGVzdCggdHlwZSArIGpRdWVyeS5ldmVudC50cmlnZ2VyZWQgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIHR5cGUuaW5kZXhPZiggXCIuXCIgKSA+IC0xICkge1xuXG5cdFx0XHQvLyBOYW1lc3BhY2VkIHRyaWdnZXI7IGNyZWF0ZSBhIHJlZ2V4cCB0byBtYXRjaCBldmVudCB0eXBlIGluIGhhbmRsZSgpXG5cdFx0XHRuYW1lc3BhY2VzID0gdHlwZS5zcGxpdCggXCIuXCIgKTtcblx0XHRcdHR5cGUgPSBuYW1lc3BhY2VzLnNoaWZ0KCk7XG5cdFx0XHRuYW1lc3BhY2VzLnNvcnQoKTtcblx0XHR9XG5cdFx0b250eXBlID0gdHlwZS5pbmRleE9mKCBcIjpcIiApIDwgMCAmJiBcIm9uXCIgKyB0eXBlO1xuXG5cdFx0Ly8gQ2FsbGVyIGNhbiBwYXNzIGluIGEgalF1ZXJ5LkV2ZW50IG9iamVjdCwgT2JqZWN0LCBvciBqdXN0IGFuIGV2ZW50IHR5cGUgc3RyaW5nXG5cdFx0ZXZlbnQgPSBldmVudFsgalF1ZXJ5LmV4cGFuZG8gXSA/XG5cdFx0XHRldmVudCA6XG5cdFx0XHRuZXcgalF1ZXJ5LkV2ZW50KCB0eXBlLCB0eXBlb2YgZXZlbnQgPT09IFwib2JqZWN0XCIgJiYgZXZlbnQgKTtcblxuXHRcdC8vIFRyaWdnZXIgYml0bWFzazogJiAxIGZvciBuYXRpdmUgaGFuZGxlcnM7ICYgMiBmb3IgalF1ZXJ5IChhbHdheXMgdHJ1ZSlcblx0XHRldmVudC5pc1RyaWdnZXIgPSBvbmx5SGFuZGxlcnMgPyAyIDogMztcblx0XHRldmVudC5uYW1lc3BhY2UgPSBuYW1lc3BhY2VzLmpvaW4oIFwiLlwiICk7XG5cdFx0ZXZlbnQucm5hbWVzcGFjZSA9IGV2ZW50Lm5hbWVzcGFjZSA/XG5cdFx0XHRuZXcgUmVnRXhwKCBcIihefFxcXFwuKVwiICsgbmFtZXNwYWNlcy5qb2luKCBcIlxcXFwuKD86LipcXFxcLnwpXCIgKSArIFwiKFxcXFwufCQpXCIgKSA6XG5cdFx0XHRudWxsO1xuXG5cdFx0Ly8gQ2xlYW4gdXAgdGhlIGV2ZW50IGluIGNhc2UgaXQgaXMgYmVpbmcgcmV1c2VkXG5cdFx0ZXZlbnQucmVzdWx0ID0gdW5kZWZpbmVkO1xuXHRcdGlmICggIWV2ZW50LnRhcmdldCApIHtcblx0XHRcdGV2ZW50LnRhcmdldCA9IGVsZW07XG5cdFx0fVxuXG5cdFx0Ly8gQ2xvbmUgYW55IGluY29taW5nIGRhdGEgYW5kIHByZXBlbmQgdGhlIGV2ZW50LCBjcmVhdGluZyB0aGUgaGFuZGxlciBhcmcgbGlzdFxuXHRcdGRhdGEgPSBkYXRhID09IG51bGwgP1xuXHRcdFx0WyBldmVudCBdIDpcblx0XHRcdGpRdWVyeS5tYWtlQXJyYXkoIGRhdGEsIFsgZXZlbnQgXSApO1xuXG5cdFx0Ly8gQWxsb3cgc3BlY2lhbCBldmVudHMgdG8gZHJhdyBvdXRzaWRlIHRoZSBsaW5lc1xuXHRcdHNwZWNpYWwgPSBqUXVlcnkuZXZlbnQuc3BlY2lhbFsgdHlwZSBdIHx8IHt9O1xuXHRcdGlmICggIW9ubHlIYW5kbGVycyAmJiBzcGVjaWFsLnRyaWdnZXIgJiYgc3BlY2lhbC50cmlnZ2VyLmFwcGx5KCBlbGVtLCBkYXRhICkgPT09IGZhbHNlICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIERldGVybWluZSBldmVudCBwcm9wYWdhdGlvbiBwYXRoIGluIGFkdmFuY2UsIHBlciBXM0MgZXZlbnRzIHNwZWMgKCM5OTUxKVxuXHRcdC8vIEJ1YmJsZSB1cCB0byBkb2N1bWVudCwgdGhlbiB0byB3aW5kb3c7IHdhdGNoIGZvciBhIGdsb2JhbCBvd25lckRvY3VtZW50IHZhciAoIzk3MjQpXG5cdFx0aWYgKCAhb25seUhhbmRsZXJzICYmICFzcGVjaWFsLm5vQnViYmxlICYmICFpc1dpbmRvdyggZWxlbSApICkge1xuXG5cdFx0XHRidWJibGVUeXBlID0gc3BlY2lhbC5kZWxlZ2F0ZVR5cGUgfHwgdHlwZTtcblx0XHRcdGlmICggIXJmb2N1c01vcnBoLnRlc3QoIGJ1YmJsZVR5cGUgKyB0eXBlICkgKSB7XG5cdFx0XHRcdGN1ciA9IGN1ci5wYXJlbnROb2RlO1xuXHRcdFx0fVxuXHRcdFx0Zm9yICggOyBjdXI7IGN1ciA9IGN1ci5wYXJlbnROb2RlICkge1xuXHRcdFx0XHRldmVudFBhdGgucHVzaCggY3VyICk7XG5cdFx0XHRcdHRtcCA9IGN1cjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gT25seSBhZGQgd2luZG93IGlmIHdlIGdvdCB0byBkb2N1bWVudCAoZS5nLiwgbm90IHBsYWluIG9iaiBvciBkZXRhY2hlZCBET00pXG5cdFx0XHRpZiAoIHRtcCA9PT0gKCBlbGVtLm93bmVyRG9jdW1lbnQgfHwgZG9jdW1lbnQgKSApIHtcblx0XHRcdFx0ZXZlbnRQYXRoLnB1c2goIHRtcC5kZWZhdWx0VmlldyB8fCB0bXAucGFyZW50V2luZG93IHx8IHdpbmRvdyApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIEZpcmUgaGFuZGxlcnMgb24gdGhlIGV2ZW50IHBhdGhcblx0XHRpID0gMDtcblx0XHR3aGlsZSAoICggY3VyID0gZXZlbnRQYXRoWyBpKysgXSApICYmICFldmVudC5pc1Byb3BhZ2F0aW9uU3RvcHBlZCgpICkge1xuXHRcdFx0bGFzdEVsZW1lbnQgPSBjdXI7XG5cdFx0XHRldmVudC50eXBlID0gaSA+IDEgP1xuXHRcdFx0XHRidWJibGVUeXBlIDpcblx0XHRcdFx0c3BlY2lhbC5iaW5kVHlwZSB8fCB0eXBlO1xuXG5cdFx0XHQvLyBqUXVlcnkgaGFuZGxlclxuXHRcdFx0aGFuZGxlID0gKCBkYXRhUHJpdi5nZXQoIGN1ciwgXCJldmVudHNcIiApIHx8IE9iamVjdC5jcmVhdGUoIG51bGwgKSApWyBldmVudC50eXBlIF0gJiZcblx0XHRcdFx0ZGF0YVByaXYuZ2V0KCBjdXIsIFwiaGFuZGxlXCIgKTtcblx0XHRcdGlmICggaGFuZGxlICkge1xuXHRcdFx0XHRoYW5kbGUuYXBwbHkoIGN1ciwgZGF0YSApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBOYXRpdmUgaGFuZGxlclxuXHRcdFx0aGFuZGxlID0gb250eXBlICYmIGN1clsgb250eXBlIF07XG5cdFx0XHRpZiAoIGhhbmRsZSAmJiBoYW5kbGUuYXBwbHkgJiYgYWNjZXB0RGF0YSggY3VyICkgKSB7XG5cdFx0XHRcdGV2ZW50LnJlc3VsdCA9IGhhbmRsZS5hcHBseSggY3VyLCBkYXRhICk7XG5cdFx0XHRcdGlmICggZXZlbnQucmVzdWx0ID09PSBmYWxzZSApIHtcblx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGV2ZW50LnR5cGUgPSB0eXBlO1xuXG5cdFx0Ly8gSWYgbm9ib2R5IHByZXZlbnRlZCB0aGUgZGVmYXVsdCBhY3Rpb24sIGRvIGl0IG5vd1xuXHRcdGlmICggIW9ubHlIYW5kbGVycyAmJiAhZXZlbnQuaXNEZWZhdWx0UHJldmVudGVkKCkgKSB7XG5cblx0XHRcdGlmICggKCAhc3BlY2lhbC5fZGVmYXVsdCB8fFxuXHRcdFx0XHRzcGVjaWFsLl9kZWZhdWx0LmFwcGx5KCBldmVudFBhdGgucG9wKCksIGRhdGEgKSA9PT0gZmFsc2UgKSAmJlxuXHRcdFx0XHRhY2NlcHREYXRhKCBlbGVtICkgKSB7XG5cblx0XHRcdFx0Ly8gQ2FsbCBhIG5hdGl2ZSBET00gbWV0aG9kIG9uIHRoZSB0YXJnZXQgd2l0aCB0aGUgc2FtZSBuYW1lIGFzIHRoZSBldmVudC5cblx0XHRcdFx0Ly8gRG9uJ3QgZG8gZGVmYXVsdCBhY3Rpb25zIG9uIHdpbmRvdywgdGhhdCdzIHdoZXJlIGdsb2JhbCB2YXJpYWJsZXMgYmUgKCM2MTcwKVxuXHRcdFx0XHRpZiAoIG9udHlwZSAmJiBpc0Z1bmN0aW9uKCBlbGVtWyB0eXBlIF0gKSAmJiAhaXNXaW5kb3coIGVsZW0gKSApIHtcblxuXHRcdFx0XHRcdC8vIERvbid0IHJlLXRyaWdnZXIgYW4gb25GT08gZXZlbnQgd2hlbiB3ZSBjYWxsIGl0cyBGT08oKSBtZXRob2Rcblx0XHRcdFx0XHR0bXAgPSBlbGVtWyBvbnR5cGUgXTtcblxuXHRcdFx0XHRcdGlmICggdG1wICkge1xuXHRcdFx0XHRcdFx0ZWxlbVsgb250eXBlIF0gPSBudWxsO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIFByZXZlbnQgcmUtdHJpZ2dlcmluZyBvZiB0aGUgc2FtZSBldmVudCwgc2luY2Ugd2UgYWxyZWFkeSBidWJibGVkIGl0IGFib3ZlXG5cdFx0XHRcdFx0alF1ZXJ5LmV2ZW50LnRyaWdnZXJlZCA9IHR5cGU7XG5cblx0XHRcdFx0XHRpZiAoIGV2ZW50LmlzUHJvcGFnYXRpb25TdG9wcGVkKCkgKSB7XG5cdFx0XHRcdFx0XHRsYXN0RWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCB0eXBlLCBzdG9wUHJvcGFnYXRpb25DYWxsYmFjayApO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGVsZW1bIHR5cGUgXSgpO1xuXG5cdFx0XHRcdFx0aWYgKCBldmVudC5pc1Byb3BhZ2F0aW9uU3RvcHBlZCgpICkge1xuXHRcdFx0XHRcdFx0bGFzdEVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lciggdHlwZSwgc3RvcFByb3BhZ2F0aW9uQ2FsbGJhY2sgKTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRqUXVlcnkuZXZlbnQudHJpZ2dlcmVkID0gdW5kZWZpbmVkO1xuXG5cdFx0XHRcdFx0aWYgKCB0bXAgKSB7XG5cdFx0XHRcdFx0XHRlbGVtWyBvbnR5cGUgXSA9IHRtcDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gZXZlbnQucmVzdWx0O1xuXHR9LFxuXG5cdC8vIFBpZ2d5YmFjayBvbiBhIGRvbm9yIGV2ZW50IHRvIHNpbXVsYXRlIGEgZGlmZmVyZW50IG9uZVxuXHQvLyBVc2VkIG9ubHkgZm9yIGBmb2N1cyhpbiB8IG91dClgIGV2ZW50c1xuXHRzaW11bGF0ZTogZnVuY3Rpb24oIHR5cGUsIGVsZW0sIGV2ZW50ICkge1xuXHRcdHZhciBlID0galF1ZXJ5LmV4dGVuZChcblx0XHRcdG5ldyBqUXVlcnkuRXZlbnQoKSxcblx0XHRcdGV2ZW50LFxuXHRcdFx0e1xuXHRcdFx0XHR0eXBlOiB0eXBlLFxuXHRcdFx0XHRpc1NpbXVsYXRlZDogdHJ1ZVxuXHRcdFx0fVxuXHRcdCk7XG5cblx0XHRqUXVlcnkuZXZlbnQudHJpZ2dlciggZSwgbnVsbCwgZWxlbSApO1xuXHR9XG5cbn0gKTtcblxualF1ZXJ5LmZuLmV4dGVuZCgge1xuXG5cdHRyaWdnZXI6IGZ1bmN0aW9uKCB0eXBlLCBkYXRhICkge1xuXHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0alF1ZXJ5LmV2ZW50LnRyaWdnZXIoIHR5cGUsIGRhdGEsIHRoaXMgKTtcblx0XHR9ICk7XG5cdH0sXG5cdHRyaWdnZXJIYW5kbGVyOiBmdW5jdGlvbiggdHlwZSwgZGF0YSApIHtcblx0XHR2YXIgZWxlbSA9IHRoaXNbIDAgXTtcblx0XHRpZiAoIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4galF1ZXJ5LmV2ZW50LnRyaWdnZXIoIHR5cGUsIGRhdGEsIGVsZW0sIHRydWUgKTtcblx0XHR9XG5cdH1cbn0gKTtcblxuXG4vLyBTdXBwb3J0OiBGaXJlZm94IDw9NDRcbi8vIEZpcmVmb3ggZG9lc24ndCBoYXZlIGZvY3VzKGluIHwgb3V0KSBldmVudHNcbi8vIFJlbGF0ZWQgdGlja2V0IC0gaHR0cHM6Ly9idWd6aWxsYS5tb3ppbGxhLm9yZy9zaG93X2J1Zy5jZ2k/aWQ9Njg3Nzg3XG4vL1xuLy8gU3VwcG9ydDogQ2hyb21lIDw9NDggLSA0OSwgU2FmYXJpIDw9OS4wIC0gOS4xXG4vLyBmb2N1cyhpbiB8IG91dCkgZXZlbnRzIGZpcmUgYWZ0ZXIgZm9jdXMgJiBibHVyIGV2ZW50cyxcbi8vIHdoaWNoIGlzIHNwZWMgdmlvbGF0aW9uIC0gaHR0cDovL3d3dy53My5vcmcvVFIvRE9NLUxldmVsLTMtRXZlbnRzLyNldmVudHMtZm9jdXNldmVudC1ldmVudC1vcmRlclxuLy8gUmVsYXRlZCB0aWNrZXQgLSBodHRwczovL2J1Z3MuY2hyb21pdW0ub3JnL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD00NDk4NTdcbmlmICggIXN1cHBvcnQuZm9jdXNpbiApIHtcblx0alF1ZXJ5LmVhY2goIHsgZm9jdXM6IFwiZm9jdXNpblwiLCBibHVyOiBcImZvY3Vzb3V0XCIgfSwgZnVuY3Rpb24oIG9yaWcsIGZpeCApIHtcblxuXHRcdC8vIEF0dGFjaCBhIHNpbmdsZSBjYXB0dXJpbmcgaGFuZGxlciBvbiB0aGUgZG9jdW1lbnQgd2hpbGUgc29tZW9uZSB3YW50cyBmb2N1c2luL2ZvY3Vzb3V0XG5cdFx0dmFyIGhhbmRsZXIgPSBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRqUXVlcnkuZXZlbnQuc2ltdWxhdGUoIGZpeCwgZXZlbnQudGFyZ2V0LCBqUXVlcnkuZXZlbnQuZml4KCBldmVudCApICk7XG5cdFx0fTtcblxuXHRcdGpRdWVyeS5ldmVudC5zcGVjaWFsWyBmaXggXSA9IHtcblx0XHRcdHNldHVwOiBmdW5jdGlvbigpIHtcblxuXHRcdFx0XHQvLyBIYW5kbGU6IHJlZ3VsYXIgbm9kZXMgKHZpYSBgdGhpcy5vd25lckRvY3VtZW50YCksIHdpbmRvd1xuXHRcdFx0XHQvLyAodmlhIGB0aGlzLmRvY3VtZW50YCkgJiBkb2N1bWVudCAodmlhIGB0aGlzYCkuXG5cdFx0XHRcdHZhciBkb2MgPSB0aGlzLm93bmVyRG9jdW1lbnQgfHwgdGhpcy5kb2N1bWVudCB8fCB0aGlzLFxuXHRcdFx0XHRcdGF0dGFjaGVzID0gZGF0YVByaXYuYWNjZXNzKCBkb2MsIGZpeCApO1xuXG5cdFx0XHRcdGlmICggIWF0dGFjaGVzICkge1xuXHRcdFx0XHRcdGRvYy5hZGRFdmVudExpc3RlbmVyKCBvcmlnLCBoYW5kbGVyLCB0cnVlICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZGF0YVByaXYuYWNjZXNzKCBkb2MsIGZpeCwgKCBhdHRhY2hlcyB8fCAwICkgKyAxICk7XG5cdFx0XHR9LFxuXHRcdFx0dGVhcmRvd246IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgZG9jID0gdGhpcy5vd25lckRvY3VtZW50IHx8IHRoaXMuZG9jdW1lbnQgfHwgdGhpcyxcblx0XHRcdFx0XHRhdHRhY2hlcyA9IGRhdGFQcml2LmFjY2VzcyggZG9jLCBmaXggKSAtIDE7XG5cblx0XHRcdFx0aWYgKCAhYXR0YWNoZXMgKSB7XG5cdFx0XHRcdFx0ZG9jLnJlbW92ZUV2ZW50TGlzdGVuZXIoIG9yaWcsIGhhbmRsZXIsIHRydWUgKTtcblx0XHRcdFx0XHRkYXRhUHJpdi5yZW1vdmUoIGRvYywgZml4ICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRkYXRhUHJpdi5hY2Nlc3MoIGRvYywgZml4LCBhdHRhY2hlcyApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fTtcblx0fSApO1xufVxudmFyIGxvY2F0aW9uID0gd2luZG93LmxvY2F0aW9uO1xuXG52YXIgbm9uY2UgPSB7IGd1aWQ6IERhdGUubm93KCkgfTtcblxudmFyIHJxdWVyeSA9ICggL1xcPy8gKTtcblxuXG5cbi8vIENyb3NzLWJyb3dzZXIgeG1sIHBhcnNpbmdcbmpRdWVyeS5wYXJzZVhNTCA9IGZ1bmN0aW9uKCBkYXRhICkge1xuXHR2YXIgeG1sLCBwYXJzZXJFcnJvckVsZW07XG5cdGlmICggIWRhdGEgfHwgdHlwZW9mIGRhdGEgIT09IFwic3RyaW5nXCIgKSB7XG5cdFx0cmV0dXJuIG51bGw7XG5cdH1cblxuXHQvLyBTdXBwb3J0OiBJRSA5IC0gMTEgb25seVxuXHQvLyBJRSB0aHJvd3Mgb24gcGFyc2VGcm9tU3RyaW5nIHdpdGggaW52YWxpZCBpbnB1dC5cblx0dHJ5IHtcblx0XHR4bWwgPSAoIG5ldyB3aW5kb3cuRE9NUGFyc2VyKCkgKS5wYXJzZUZyb21TdHJpbmcoIGRhdGEsIFwidGV4dC94bWxcIiApO1xuXHR9IGNhdGNoICggZSApIHt9XG5cblx0cGFyc2VyRXJyb3JFbGVtID0geG1sICYmIHhtbC5nZXRFbGVtZW50c0J5VGFnTmFtZSggXCJwYXJzZXJlcnJvclwiIClbIDAgXTtcblx0aWYgKCAheG1sIHx8IHBhcnNlckVycm9yRWxlbSApIHtcblx0XHRqUXVlcnkuZXJyb3IoIFwiSW52YWxpZCBYTUw6IFwiICsgKFxuXHRcdFx0cGFyc2VyRXJyb3JFbGVtID9cblx0XHRcdFx0alF1ZXJ5Lm1hcCggcGFyc2VyRXJyb3JFbGVtLmNoaWxkTm9kZXMsIGZ1bmN0aW9uKCBlbCApIHtcblx0XHRcdFx0XHRyZXR1cm4gZWwudGV4dENvbnRlbnQ7XG5cdFx0XHRcdH0gKS5qb2luKCBcIlxcblwiICkgOlxuXHRcdFx0XHRkYXRhXG5cdFx0KSApO1xuXHR9XG5cdHJldHVybiB4bWw7XG59O1xuXG5cbnZhclxuXHRyYnJhY2tldCA9IC9cXFtcXF0kLyxcblx0ckNSTEYgPSAvXFxyP1xcbi9nLFxuXHRyc3VibWl0dGVyVHlwZXMgPSAvXig/OnN1Ym1pdHxidXR0b258aW1hZ2V8cmVzZXR8ZmlsZSkkL2ksXG5cdHJzdWJtaXR0YWJsZSA9IC9eKD86aW5wdXR8c2VsZWN0fHRleHRhcmVhfGtleWdlbikvaTtcblxuZnVuY3Rpb24gYnVpbGRQYXJhbXMoIHByZWZpeCwgb2JqLCB0cmFkaXRpb25hbCwgYWRkICkge1xuXHR2YXIgbmFtZTtcblxuXHRpZiAoIEFycmF5LmlzQXJyYXkoIG9iaiApICkge1xuXG5cdFx0Ly8gU2VyaWFsaXplIGFycmF5IGl0ZW0uXG5cdFx0alF1ZXJ5LmVhY2goIG9iaiwgZnVuY3Rpb24oIGksIHYgKSB7XG5cdFx0XHRpZiAoIHRyYWRpdGlvbmFsIHx8IHJicmFja2V0LnRlc3QoIHByZWZpeCApICkge1xuXG5cdFx0XHRcdC8vIFRyZWF0IGVhY2ggYXJyYXkgaXRlbSBhcyBhIHNjYWxhci5cblx0XHRcdFx0YWRkKCBwcmVmaXgsIHYgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBJdGVtIGlzIG5vbi1zY2FsYXIgKGFycmF5IG9yIG9iamVjdCksIGVuY29kZSBpdHMgbnVtZXJpYyBpbmRleC5cblx0XHRcdFx0YnVpbGRQYXJhbXMoXG5cdFx0XHRcdFx0cHJlZml4ICsgXCJbXCIgKyAoIHR5cGVvZiB2ID09PSBcIm9iamVjdFwiICYmIHYgIT0gbnVsbCA/IGkgOiBcIlwiICkgKyBcIl1cIixcblx0XHRcdFx0XHR2LFxuXHRcdFx0XHRcdHRyYWRpdGlvbmFsLFxuXHRcdFx0XHRcdGFkZFxuXHRcdFx0XHQpO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHR9IGVsc2UgaWYgKCAhdHJhZGl0aW9uYWwgJiYgdG9UeXBlKCBvYmogKSA9PT0gXCJvYmplY3RcIiApIHtcblxuXHRcdC8vIFNlcmlhbGl6ZSBvYmplY3QgaXRlbS5cblx0XHRmb3IgKCBuYW1lIGluIG9iaiApIHtcblx0XHRcdGJ1aWxkUGFyYW1zKCBwcmVmaXggKyBcIltcIiArIG5hbWUgKyBcIl1cIiwgb2JqWyBuYW1lIF0sIHRyYWRpdGlvbmFsLCBhZGQgKTtcblx0XHR9XG5cblx0fSBlbHNlIHtcblxuXHRcdC8vIFNlcmlhbGl6ZSBzY2FsYXIgaXRlbS5cblx0XHRhZGQoIHByZWZpeCwgb2JqICk7XG5cdH1cbn1cblxuLy8gU2VyaWFsaXplIGFuIGFycmF5IG9mIGZvcm0gZWxlbWVudHMgb3IgYSBzZXQgb2Zcbi8vIGtleS92YWx1ZXMgaW50byBhIHF1ZXJ5IHN0cmluZ1xualF1ZXJ5LnBhcmFtID0gZnVuY3Rpb24oIGEsIHRyYWRpdGlvbmFsICkge1xuXHR2YXIgcHJlZml4LFxuXHRcdHMgPSBbXSxcblx0XHRhZGQgPSBmdW5jdGlvbigga2V5LCB2YWx1ZU9yRnVuY3Rpb24gKSB7XG5cblx0XHRcdC8vIElmIHZhbHVlIGlzIGEgZnVuY3Rpb24sIGludm9rZSBpdCBhbmQgdXNlIGl0cyByZXR1cm4gdmFsdWVcblx0XHRcdHZhciB2YWx1ZSA9IGlzRnVuY3Rpb24oIHZhbHVlT3JGdW5jdGlvbiApID9cblx0XHRcdFx0dmFsdWVPckZ1bmN0aW9uKCkgOlxuXHRcdFx0XHR2YWx1ZU9yRnVuY3Rpb247XG5cblx0XHRcdHNbIHMubGVuZ3RoIF0gPSBlbmNvZGVVUklDb21wb25lbnQoIGtleSApICsgXCI9XCIgK1xuXHRcdFx0XHRlbmNvZGVVUklDb21wb25lbnQoIHZhbHVlID09IG51bGwgPyBcIlwiIDogdmFsdWUgKTtcblx0XHR9O1xuXG5cdGlmICggYSA9PSBudWxsICkge1xuXHRcdHJldHVybiBcIlwiO1xuXHR9XG5cblx0Ly8gSWYgYW4gYXJyYXkgd2FzIHBhc3NlZCBpbiwgYXNzdW1lIHRoYXQgaXQgaXMgYW4gYXJyYXkgb2YgZm9ybSBlbGVtZW50cy5cblx0aWYgKCBBcnJheS5pc0FycmF5KCBhICkgfHwgKCBhLmpxdWVyeSAmJiAhalF1ZXJ5LmlzUGxhaW5PYmplY3QoIGEgKSApICkge1xuXG5cdFx0Ly8gU2VyaWFsaXplIHRoZSBmb3JtIGVsZW1lbnRzXG5cdFx0alF1ZXJ5LmVhY2goIGEsIGZ1bmN0aW9uKCkge1xuXHRcdFx0YWRkKCB0aGlzLm5hbWUsIHRoaXMudmFsdWUgKTtcblx0XHR9ICk7XG5cblx0fSBlbHNlIHtcblxuXHRcdC8vIElmIHRyYWRpdGlvbmFsLCBlbmNvZGUgdGhlIFwib2xkXCIgd2F5ICh0aGUgd2F5IDEuMy4yIG9yIG9sZGVyXG5cdFx0Ly8gZGlkIGl0KSwgb3RoZXJ3aXNlIGVuY29kZSBwYXJhbXMgcmVjdXJzaXZlbHkuXG5cdFx0Zm9yICggcHJlZml4IGluIGEgKSB7XG5cdFx0XHRidWlsZFBhcmFtcyggcHJlZml4LCBhWyBwcmVmaXggXSwgdHJhZGl0aW9uYWwsIGFkZCApO1xuXHRcdH1cblx0fVxuXG5cdC8vIFJldHVybiB0aGUgcmVzdWx0aW5nIHNlcmlhbGl6YXRpb25cblx0cmV0dXJuIHMuam9pbiggXCImXCIgKTtcbn07XG5cbmpRdWVyeS5mbi5leHRlbmQoIHtcblx0c2VyaWFsaXplOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4galF1ZXJ5LnBhcmFtKCB0aGlzLnNlcmlhbGl6ZUFycmF5KCkgKTtcblx0fSxcblx0c2VyaWFsaXplQXJyYXk6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLm1hcCggZnVuY3Rpb24oKSB7XG5cblx0XHRcdC8vIENhbiBhZGQgcHJvcEhvb2sgZm9yIFwiZWxlbWVudHNcIiB0byBmaWx0ZXIgb3IgYWRkIGZvcm0gZWxlbWVudHNcblx0XHRcdHZhciBlbGVtZW50cyA9IGpRdWVyeS5wcm9wKCB0aGlzLCBcImVsZW1lbnRzXCIgKTtcblx0XHRcdHJldHVybiBlbGVtZW50cyA/IGpRdWVyeS5tYWtlQXJyYXkoIGVsZW1lbnRzICkgOiB0aGlzO1xuXHRcdH0gKS5maWx0ZXIoIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHR5cGUgPSB0aGlzLnR5cGU7XG5cblx0XHRcdC8vIFVzZSAuaXMoIFwiOmRpc2FibGVkXCIgKSBzbyB0aGF0IGZpZWxkc2V0W2Rpc2FibGVkXSB3b3Jrc1xuXHRcdFx0cmV0dXJuIHRoaXMubmFtZSAmJiAhalF1ZXJ5KCB0aGlzICkuaXMoIFwiOmRpc2FibGVkXCIgKSAmJlxuXHRcdFx0XHRyc3VibWl0dGFibGUudGVzdCggdGhpcy5ub2RlTmFtZSApICYmICFyc3VibWl0dGVyVHlwZXMudGVzdCggdHlwZSApICYmXG5cdFx0XHRcdCggdGhpcy5jaGVja2VkIHx8ICFyY2hlY2thYmxlVHlwZS50ZXN0KCB0eXBlICkgKTtcblx0XHR9ICkubWFwKCBmdW5jdGlvbiggX2ksIGVsZW0gKSB7XG5cdFx0XHR2YXIgdmFsID0galF1ZXJ5KCB0aGlzICkudmFsKCk7XG5cblx0XHRcdGlmICggdmFsID09IG51bGwgKSB7XG5cdFx0XHRcdHJldHVybiBudWxsO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIHZhbCApICkge1xuXHRcdFx0XHRyZXR1cm4galF1ZXJ5Lm1hcCggdmFsLCBmdW5jdGlvbiggdmFsICkge1xuXHRcdFx0XHRcdHJldHVybiB7IG5hbWU6IGVsZW0ubmFtZSwgdmFsdWU6IHZhbC5yZXBsYWNlKCByQ1JMRiwgXCJcXHJcXG5cIiApIH07XG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHsgbmFtZTogZWxlbS5uYW1lLCB2YWx1ZTogdmFsLnJlcGxhY2UoIHJDUkxGLCBcIlxcclxcblwiICkgfTtcblx0XHR9ICkuZ2V0KCk7XG5cdH1cbn0gKTtcblxuXG52YXJcblx0cjIwID0gLyUyMC9nLFxuXHRyaGFzaCA9IC8jLiokLyxcblx0cmFudGlDYWNoZSA9IC8oWz8mXSlfPVteJl0qLyxcblx0cmhlYWRlcnMgPSAvXiguKj8pOlsgXFx0XSooW15cXHJcXG5dKikkL21nLFxuXG5cdC8vICM3NjUzLCAjODEyNSwgIzgxNTI6IGxvY2FsIHByb3RvY29sIGRldGVjdGlvblxuXHRybG9jYWxQcm90b2NvbCA9IC9eKD86YWJvdXR8YXBwfGFwcC1zdG9yYWdlfC4rLWV4dGVuc2lvbnxmaWxlfHJlc3x3aWRnZXQpOiQvLFxuXHRybm9Db250ZW50ID0gL14oPzpHRVR8SEVBRCkkLyxcblx0cnByb3RvY29sID0gL15cXC9cXC8vLFxuXG5cdC8qIFByZWZpbHRlcnNcblx0ICogMSkgVGhleSBhcmUgdXNlZnVsIHRvIGludHJvZHVjZSBjdXN0b20gZGF0YVR5cGVzIChzZWUgYWpheC9qc29ucC5qcyBmb3IgYW4gZXhhbXBsZSlcblx0ICogMikgVGhlc2UgYXJlIGNhbGxlZDpcblx0ICogICAgLSBCRUZPUkUgYXNraW5nIGZvciBhIHRyYW5zcG9ydFxuXHQgKiAgICAtIEFGVEVSIHBhcmFtIHNlcmlhbGl6YXRpb24gKHMuZGF0YSBpcyBhIHN0cmluZyBpZiBzLnByb2Nlc3NEYXRhIGlzIHRydWUpXG5cdCAqIDMpIGtleSBpcyB0aGUgZGF0YVR5cGVcblx0ICogNCkgdGhlIGNhdGNoYWxsIHN5bWJvbCBcIipcIiBjYW4gYmUgdXNlZFxuXHQgKiA1KSBleGVjdXRpb24gd2lsbCBzdGFydCB3aXRoIHRyYW5zcG9ydCBkYXRhVHlwZSBhbmQgVEhFTiBjb250aW51ZSBkb3duIHRvIFwiKlwiIGlmIG5lZWRlZFxuXHQgKi9cblx0cHJlZmlsdGVycyA9IHt9LFxuXG5cdC8qIFRyYW5zcG9ydHMgYmluZGluZ3Ncblx0ICogMSkga2V5IGlzIHRoZSBkYXRhVHlwZVxuXHQgKiAyKSB0aGUgY2F0Y2hhbGwgc3ltYm9sIFwiKlwiIGNhbiBiZSB1c2VkXG5cdCAqIDMpIHNlbGVjdGlvbiB3aWxsIHN0YXJ0IHdpdGggdHJhbnNwb3J0IGRhdGFUeXBlIGFuZCBUSEVOIGdvIHRvIFwiKlwiIGlmIG5lZWRlZFxuXHQgKi9cblx0dHJhbnNwb3J0cyA9IHt9LFxuXG5cdC8vIEF2b2lkIGNvbW1lbnQtcHJvbG9nIGNoYXIgc2VxdWVuY2UgKCMxMDA5OCk7IG11c3QgYXBwZWFzZSBsaW50IGFuZCBldmFkZSBjb21wcmVzc2lvblxuXHRhbGxUeXBlcyA9IFwiKi9cIi5jb25jYXQoIFwiKlwiICksXG5cblx0Ly8gQW5jaG9yIHRhZyBmb3IgcGFyc2luZyB0aGUgZG9jdW1lbnQgb3JpZ2luXG5cdG9yaWdpbkFuY2hvciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwiYVwiICk7XG5cbm9yaWdpbkFuY2hvci5ocmVmID0gbG9jYXRpb24uaHJlZjtcblxuLy8gQmFzZSBcImNvbnN0cnVjdG9yXCIgZm9yIGpRdWVyeS5hamF4UHJlZmlsdGVyIGFuZCBqUXVlcnkuYWpheFRyYW5zcG9ydFxuZnVuY3Rpb24gYWRkVG9QcmVmaWx0ZXJzT3JUcmFuc3BvcnRzKCBzdHJ1Y3R1cmUgKSB7XG5cblx0Ly8gZGF0YVR5cGVFeHByZXNzaW9uIGlzIG9wdGlvbmFsIGFuZCBkZWZhdWx0cyB0byBcIipcIlxuXHRyZXR1cm4gZnVuY3Rpb24oIGRhdGFUeXBlRXhwcmVzc2lvbiwgZnVuYyApIHtcblxuXHRcdGlmICggdHlwZW9mIGRhdGFUeXBlRXhwcmVzc2lvbiAhPT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdGZ1bmMgPSBkYXRhVHlwZUV4cHJlc3Npb247XG5cdFx0XHRkYXRhVHlwZUV4cHJlc3Npb24gPSBcIipcIjtcblx0XHR9XG5cblx0XHR2YXIgZGF0YVR5cGUsXG5cdFx0XHRpID0gMCxcblx0XHRcdGRhdGFUeXBlcyA9IGRhdGFUeXBlRXhwcmVzc2lvbi50b0xvd2VyQ2FzZSgpLm1hdGNoKCBybm90aHRtbHdoaXRlICkgfHwgW107XG5cblx0XHRpZiAoIGlzRnVuY3Rpb24oIGZ1bmMgKSApIHtcblxuXHRcdFx0Ly8gRm9yIGVhY2ggZGF0YVR5cGUgaW4gdGhlIGRhdGFUeXBlRXhwcmVzc2lvblxuXHRcdFx0d2hpbGUgKCAoIGRhdGFUeXBlID0gZGF0YVR5cGVzWyBpKysgXSApICkge1xuXG5cdFx0XHRcdC8vIFByZXBlbmQgaWYgcmVxdWVzdGVkXG5cdFx0XHRcdGlmICggZGF0YVR5cGVbIDAgXSA9PT0gXCIrXCIgKSB7XG5cdFx0XHRcdFx0ZGF0YVR5cGUgPSBkYXRhVHlwZS5zbGljZSggMSApIHx8IFwiKlwiO1xuXHRcdFx0XHRcdCggc3RydWN0dXJlWyBkYXRhVHlwZSBdID0gc3RydWN0dXJlWyBkYXRhVHlwZSBdIHx8IFtdICkudW5zaGlmdCggZnVuYyApO1xuXG5cdFx0XHRcdC8vIE90aGVyd2lzZSBhcHBlbmRcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHQoIHN0cnVjdHVyZVsgZGF0YVR5cGUgXSA9IHN0cnVjdHVyZVsgZGF0YVR5cGUgXSB8fCBbXSApLnB1c2goIGZ1bmMgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fTtcbn1cblxuLy8gQmFzZSBpbnNwZWN0aW9uIGZ1bmN0aW9uIGZvciBwcmVmaWx0ZXJzIGFuZCB0cmFuc3BvcnRzXG5mdW5jdGlvbiBpbnNwZWN0UHJlZmlsdGVyc09yVHJhbnNwb3J0cyggc3RydWN0dXJlLCBvcHRpb25zLCBvcmlnaW5hbE9wdGlvbnMsIGpxWEhSICkge1xuXG5cdHZhciBpbnNwZWN0ZWQgPSB7fSxcblx0XHRzZWVraW5nVHJhbnNwb3J0ID0gKCBzdHJ1Y3R1cmUgPT09IHRyYW5zcG9ydHMgKTtcblxuXHRmdW5jdGlvbiBpbnNwZWN0KCBkYXRhVHlwZSApIHtcblx0XHR2YXIgc2VsZWN0ZWQ7XG5cdFx0aW5zcGVjdGVkWyBkYXRhVHlwZSBdID0gdHJ1ZTtcblx0XHRqUXVlcnkuZWFjaCggc3RydWN0dXJlWyBkYXRhVHlwZSBdIHx8IFtdLCBmdW5jdGlvbiggXywgcHJlZmlsdGVyT3JGYWN0b3J5ICkge1xuXHRcdFx0dmFyIGRhdGFUeXBlT3JUcmFuc3BvcnQgPSBwcmVmaWx0ZXJPckZhY3RvcnkoIG9wdGlvbnMsIG9yaWdpbmFsT3B0aW9ucywganFYSFIgKTtcblx0XHRcdGlmICggdHlwZW9mIGRhdGFUeXBlT3JUcmFuc3BvcnQgPT09IFwic3RyaW5nXCIgJiZcblx0XHRcdFx0IXNlZWtpbmdUcmFuc3BvcnQgJiYgIWluc3BlY3RlZFsgZGF0YVR5cGVPclRyYW5zcG9ydCBdICkge1xuXG5cdFx0XHRcdG9wdGlvbnMuZGF0YVR5cGVzLnVuc2hpZnQoIGRhdGFUeXBlT3JUcmFuc3BvcnQgKTtcblx0XHRcdFx0aW5zcGVjdCggZGF0YVR5cGVPclRyYW5zcG9ydCApO1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9IGVsc2UgaWYgKCBzZWVraW5nVHJhbnNwb3J0ICkge1xuXHRcdFx0XHRyZXR1cm4gISggc2VsZWN0ZWQgPSBkYXRhVHlwZU9yVHJhbnNwb3J0ICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHRcdHJldHVybiBzZWxlY3RlZDtcblx0fVxuXG5cdHJldHVybiBpbnNwZWN0KCBvcHRpb25zLmRhdGFUeXBlc1sgMCBdICkgfHwgIWluc3BlY3RlZFsgXCIqXCIgXSAmJiBpbnNwZWN0KCBcIipcIiApO1xufVxuXG4vLyBBIHNwZWNpYWwgZXh0ZW5kIGZvciBhamF4IG9wdGlvbnNcbi8vIHRoYXQgdGFrZXMgXCJmbGF0XCIgb3B0aW9ucyAobm90IHRvIGJlIGRlZXAgZXh0ZW5kZWQpXG4vLyBGaXhlcyAjOTg4N1xuZnVuY3Rpb24gYWpheEV4dGVuZCggdGFyZ2V0LCBzcmMgKSB7XG5cdHZhciBrZXksIGRlZXAsXG5cdFx0ZmxhdE9wdGlvbnMgPSBqUXVlcnkuYWpheFNldHRpbmdzLmZsYXRPcHRpb25zIHx8IHt9O1xuXG5cdGZvciAoIGtleSBpbiBzcmMgKSB7XG5cdFx0aWYgKCBzcmNbIGtleSBdICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHQoIGZsYXRPcHRpb25zWyBrZXkgXSA/IHRhcmdldCA6ICggZGVlcCB8fCAoIGRlZXAgPSB7fSApICkgKVsga2V5IF0gPSBzcmNbIGtleSBdO1xuXHRcdH1cblx0fVxuXHRpZiAoIGRlZXAgKSB7XG5cdFx0alF1ZXJ5LmV4dGVuZCggdHJ1ZSwgdGFyZ2V0LCBkZWVwICk7XG5cdH1cblxuXHRyZXR1cm4gdGFyZ2V0O1xufVxuXG4vKiBIYW5kbGVzIHJlc3BvbnNlcyB0byBhbiBhamF4IHJlcXVlc3Q6XG4gKiAtIGZpbmRzIHRoZSByaWdodCBkYXRhVHlwZSAobWVkaWF0ZXMgYmV0d2VlbiBjb250ZW50LXR5cGUgYW5kIGV4cGVjdGVkIGRhdGFUeXBlKVxuICogLSByZXR1cm5zIHRoZSBjb3JyZXNwb25kaW5nIHJlc3BvbnNlXG4gKi9cbmZ1bmN0aW9uIGFqYXhIYW5kbGVSZXNwb25zZXMoIHMsIGpxWEhSLCByZXNwb25zZXMgKSB7XG5cblx0dmFyIGN0LCB0eXBlLCBmaW5hbERhdGFUeXBlLCBmaXJzdERhdGFUeXBlLFxuXHRcdGNvbnRlbnRzID0gcy5jb250ZW50cyxcblx0XHRkYXRhVHlwZXMgPSBzLmRhdGFUeXBlcztcblxuXHQvLyBSZW1vdmUgYXV0byBkYXRhVHlwZSBhbmQgZ2V0IGNvbnRlbnQtdHlwZSBpbiB0aGUgcHJvY2Vzc1xuXHR3aGlsZSAoIGRhdGFUeXBlc1sgMCBdID09PSBcIipcIiApIHtcblx0XHRkYXRhVHlwZXMuc2hpZnQoKTtcblx0XHRpZiAoIGN0ID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRjdCA9IHMubWltZVR5cGUgfHwganFYSFIuZ2V0UmVzcG9uc2VIZWFkZXIoIFwiQ29udGVudC1UeXBlXCIgKTtcblx0XHR9XG5cdH1cblxuXHQvLyBDaGVjayBpZiB3ZSdyZSBkZWFsaW5nIHdpdGggYSBrbm93biBjb250ZW50LXR5cGVcblx0aWYgKCBjdCApIHtcblx0XHRmb3IgKCB0eXBlIGluIGNvbnRlbnRzICkge1xuXHRcdFx0aWYgKCBjb250ZW50c1sgdHlwZSBdICYmIGNvbnRlbnRzWyB0eXBlIF0udGVzdCggY3QgKSApIHtcblx0XHRcdFx0ZGF0YVR5cGVzLnVuc2hpZnQoIHR5cGUgKTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0Ly8gQ2hlY2sgdG8gc2VlIGlmIHdlIGhhdmUgYSByZXNwb25zZSBmb3IgdGhlIGV4cGVjdGVkIGRhdGFUeXBlXG5cdGlmICggZGF0YVR5cGVzWyAwIF0gaW4gcmVzcG9uc2VzICkge1xuXHRcdGZpbmFsRGF0YVR5cGUgPSBkYXRhVHlwZXNbIDAgXTtcblx0fSBlbHNlIHtcblxuXHRcdC8vIFRyeSBjb252ZXJ0aWJsZSBkYXRhVHlwZXNcblx0XHRmb3IgKCB0eXBlIGluIHJlc3BvbnNlcyApIHtcblx0XHRcdGlmICggIWRhdGFUeXBlc1sgMCBdIHx8IHMuY29udmVydGVyc1sgdHlwZSArIFwiIFwiICsgZGF0YVR5cGVzWyAwIF0gXSApIHtcblx0XHRcdFx0ZmluYWxEYXRhVHlwZSA9IHR5cGU7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCAhZmlyc3REYXRhVHlwZSApIHtcblx0XHRcdFx0Zmlyc3REYXRhVHlwZSA9IHR5cGU7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gT3IganVzdCB1c2UgZmlyc3Qgb25lXG5cdFx0ZmluYWxEYXRhVHlwZSA9IGZpbmFsRGF0YVR5cGUgfHwgZmlyc3REYXRhVHlwZTtcblx0fVxuXG5cdC8vIElmIHdlIGZvdW5kIGEgZGF0YVR5cGVcblx0Ly8gV2UgYWRkIHRoZSBkYXRhVHlwZSB0byB0aGUgbGlzdCBpZiBuZWVkZWRcblx0Ly8gYW5kIHJldHVybiB0aGUgY29ycmVzcG9uZGluZyByZXNwb25zZVxuXHRpZiAoIGZpbmFsRGF0YVR5cGUgKSB7XG5cdFx0aWYgKCBmaW5hbERhdGFUeXBlICE9PSBkYXRhVHlwZXNbIDAgXSApIHtcblx0XHRcdGRhdGFUeXBlcy51bnNoaWZ0KCBmaW5hbERhdGFUeXBlICk7XG5cdFx0fVxuXHRcdHJldHVybiByZXNwb25zZXNbIGZpbmFsRGF0YVR5cGUgXTtcblx0fVxufVxuXG4vKiBDaGFpbiBjb252ZXJzaW9ucyBnaXZlbiB0aGUgcmVxdWVzdCBhbmQgdGhlIG9yaWdpbmFsIHJlc3BvbnNlXG4gKiBBbHNvIHNldHMgdGhlIHJlc3BvbnNlWFhYIGZpZWxkcyBvbiB0aGUganFYSFIgaW5zdGFuY2VcbiAqL1xuZnVuY3Rpb24gYWpheENvbnZlcnQoIHMsIHJlc3BvbnNlLCBqcVhIUiwgaXNTdWNjZXNzICkge1xuXHR2YXIgY29udjIsIGN1cnJlbnQsIGNvbnYsIHRtcCwgcHJldixcblx0XHRjb252ZXJ0ZXJzID0ge30sXG5cblx0XHQvLyBXb3JrIHdpdGggYSBjb3B5IG9mIGRhdGFUeXBlcyBpbiBjYXNlIHdlIG5lZWQgdG8gbW9kaWZ5IGl0IGZvciBjb252ZXJzaW9uXG5cdFx0ZGF0YVR5cGVzID0gcy5kYXRhVHlwZXMuc2xpY2UoKTtcblxuXHQvLyBDcmVhdGUgY29udmVydGVycyBtYXAgd2l0aCBsb3dlcmNhc2VkIGtleXNcblx0aWYgKCBkYXRhVHlwZXNbIDEgXSApIHtcblx0XHRmb3IgKCBjb252IGluIHMuY29udmVydGVycyApIHtcblx0XHRcdGNvbnZlcnRlcnNbIGNvbnYudG9Mb3dlckNhc2UoKSBdID0gcy5jb252ZXJ0ZXJzWyBjb252IF07XG5cdFx0fVxuXHR9XG5cblx0Y3VycmVudCA9IGRhdGFUeXBlcy5zaGlmdCgpO1xuXG5cdC8vIENvbnZlcnQgdG8gZWFjaCBzZXF1ZW50aWFsIGRhdGFUeXBlXG5cdHdoaWxlICggY3VycmVudCApIHtcblxuXHRcdGlmICggcy5yZXNwb25zZUZpZWxkc1sgY3VycmVudCBdICkge1xuXHRcdFx0anFYSFJbIHMucmVzcG9uc2VGaWVsZHNbIGN1cnJlbnQgXSBdID0gcmVzcG9uc2U7XG5cdFx0fVxuXG5cdFx0Ly8gQXBwbHkgdGhlIGRhdGFGaWx0ZXIgaWYgcHJvdmlkZWRcblx0XHRpZiAoICFwcmV2ICYmIGlzU3VjY2VzcyAmJiBzLmRhdGFGaWx0ZXIgKSB7XG5cdFx0XHRyZXNwb25zZSA9IHMuZGF0YUZpbHRlciggcmVzcG9uc2UsIHMuZGF0YVR5cGUgKTtcblx0XHR9XG5cblx0XHRwcmV2ID0gY3VycmVudDtcblx0XHRjdXJyZW50ID0gZGF0YVR5cGVzLnNoaWZ0KCk7XG5cblx0XHRpZiAoIGN1cnJlbnQgKSB7XG5cblx0XHRcdC8vIFRoZXJlJ3Mgb25seSB3b3JrIHRvIGRvIGlmIGN1cnJlbnQgZGF0YVR5cGUgaXMgbm9uLWF1dG9cblx0XHRcdGlmICggY3VycmVudCA9PT0gXCIqXCIgKSB7XG5cblx0XHRcdFx0Y3VycmVudCA9IHByZXY7XG5cblx0XHRcdC8vIENvbnZlcnQgcmVzcG9uc2UgaWYgcHJldiBkYXRhVHlwZSBpcyBub24tYXV0byBhbmQgZGlmZmVycyBmcm9tIGN1cnJlbnRcblx0XHRcdH0gZWxzZSBpZiAoIHByZXYgIT09IFwiKlwiICYmIHByZXYgIT09IGN1cnJlbnQgKSB7XG5cblx0XHRcdFx0Ly8gU2VlayBhIGRpcmVjdCBjb252ZXJ0ZXJcblx0XHRcdFx0Y29udiA9IGNvbnZlcnRlcnNbIHByZXYgKyBcIiBcIiArIGN1cnJlbnQgXSB8fCBjb252ZXJ0ZXJzWyBcIiogXCIgKyBjdXJyZW50IF07XG5cblx0XHRcdFx0Ly8gSWYgbm9uZSBmb3VuZCwgc2VlayBhIHBhaXJcblx0XHRcdFx0aWYgKCAhY29udiApIHtcblx0XHRcdFx0XHRmb3IgKCBjb252MiBpbiBjb252ZXJ0ZXJzICkge1xuXG5cdFx0XHRcdFx0XHQvLyBJZiBjb252MiBvdXRwdXRzIGN1cnJlbnRcblx0XHRcdFx0XHRcdHRtcCA9IGNvbnYyLnNwbGl0KCBcIiBcIiApO1xuXHRcdFx0XHRcdFx0aWYgKCB0bXBbIDEgXSA9PT0gY3VycmVudCApIHtcblxuXHRcdFx0XHRcdFx0XHQvLyBJZiBwcmV2IGNhbiBiZSBjb252ZXJ0ZWQgdG8gYWNjZXB0ZWQgaW5wdXRcblx0XHRcdFx0XHRcdFx0Y29udiA9IGNvbnZlcnRlcnNbIHByZXYgKyBcIiBcIiArIHRtcFsgMCBdIF0gfHxcblx0XHRcdFx0XHRcdFx0XHRjb252ZXJ0ZXJzWyBcIiogXCIgKyB0bXBbIDAgXSBdO1xuXHRcdFx0XHRcdFx0XHRpZiAoIGNvbnYgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHQvLyBDb25kZW5zZSBlcXVpdmFsZW5jZSBjb252ZXJ0ZXJzXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCBjb252ID09PSB0cnVlICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0Y29udiA9IGNvbnZlcnRlcnNbIGNvbnYyIF07XG5cblx0XHRcdFx0XHRcdFx0XHQvLyBPdGhlcndpc2UsIGluc2VydCB0aGUgaW50ZXJtZWRpYXRlIGRhdGFUeXBlXG5cdFx0XHRcdFx0XHRcdFx0fSBlbHNlIGlmICggY29udmVydGVyc1sgY29udjIgXSAhPT0gdHJ1ZSApIHtcblx0XHRcdFx0XHRcdFx0XHRcdGN1cnJlbnQgPSB0bXBbIDAgXTtcblx0XHRcdFx0XHRcdFx0XHRcdGRhdGFUeXBlcy51bnNoaWZ0KCB0bXBbIDEgXSApO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIEFwcGx5IGNvbnZlcnRlciAoaWYgbm90IGFuIGVxdWl2YWxlbmNlKVxuXHRcdFx0XHRpZiAoIGNvbnYgIT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHQvLyBVbmxlc3MgZXJyb3JzIGFyZSBhbGxvd2VkIHRvIGJ1YmJsZSwgY2F0Y2ggYW5kIHJldHVybiB0aGVtXG5cdFx0XHRcdFx0aWYgKCBjb252ICYmIHMudGhyb3dzICkge1xuXHRcdFx0XHRcdFx0cmVzcG9uc2UgPSBjb252KCByZXNwb25zZSApO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdFx0XHRyZXNwb25zZSA9IGNvbnYoIHJlc3BvbnNlICk7XG5cdFx0XHRcdFx0XHR9IGNhdGNoICggZSApIHtcblx0XHRcdFx0XHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0XHRcdFx0XHRzdGF0ZTogXCJwYXJzZXJlcnJvclwiLFxuXHRcdFx0XHRcdFx0XHRcdGVycm9yOiBjb252ID8gZSA6IFwiTm8gY29udmVyc2lvbiBmcm9tIFwiICsgcHJldiArIFwiIHRvIFwiICsgY3VycmVudFxuXHRcdFx0XHRcdFx0XHR9O1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdHJldHVybiB7IHN0YXRlOiBcInN1Y2Nlc3NcIiwgZGF0YTogcmVzcG9uc2UgfTtcbn1cblxualF1ZXJ5LmV4dGVuZCgge1xuXG5cdC8vIENvdW50ZXIgZm9yIGhvbGRpbmcgdGhlIG51bWJlciBvZiBhY3RpdmUgcXVlcmllc1xuXHRhY3RpdmU6IDAsXG5cblx0Ly8gTGFzdC1Nb2RpZmllZCBoZWFkZXIgY2FjaGUgZm9yIG5leHQgcmVxdWVzdFxuXHRsYXN0TW9kaWZpZWQ6IHt9LFxuXHRldGFnOiB7fSxcblxuXHRhamF4U2V0dGluZ3M6IHtcblx0XHR1cmw6IGxvY2F0aW9uLmhyZWYsXG5cdFx0dHlwZTogXCJHRVRcIixcblx0XHRpc0xvY2FsOiBybG9jYWxQcm90b2NvbC50ZXN0KCBsb2NhdGlvbi5wcm90b2NvbCApLFxuXHRcdGdsb2JhbDogdHJ1ZSxcblx0XHRwcm9jZXNzRGF0YTogdHJ1ZSxcblx0XHRhc3luYzogdHJ1ZSxcblx0XHRjb250ZW50VHlwZTogXCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQ7IGNoYXJzZXQ9VVRGLThcIixcblxuXHRcdC8qXG5cdFx0dGltZW91dDogMCxcblx0XHRkYXRhOiBudWxsLFxuXHRcdGRhdGFUeXBlOiBudWxsLFxuXHRcdHVzZXJuYW1lOiBudWxsLFxuXHRcdHBhc3N3b3JkOiBudWxsLFxuXHRcdGNhY2hlOiBudWxsLFxuXHRcdHRocm93czogZmFsc2UsXG5cdFx0dHJhZGl0aW9uYWw6IGZhbHNlLFxuXHRcdGhlYWRlcnM6IHt9LFxuXHRcdCovXG5cblx0XHRhY2NlcHRzOiB7XG5cdFx0XHRcIipcIjogYWxsVHlwZXMsXG5cdFx0XHR0ZXh0OiBcInRleHQvcGxhaW5cIixcblx0XHRcdGh0bWw6IFwidGV4dC9odG1sXCIsXG5cdFx0XHR4bWw6IFwiYXBwbGljYXRpb24veG1sLCB0ZXh0L3htbFwiLFxuXHRcdFx0anNvbjogXCJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L2phdmFzY3JpcHRcIlxuXHRcdH0sXG5cblx0XHRjb250ZW50czoge1xuXHRcdFx0eG1sOiAvXFxieG1sXFxiLyxcblx0XHRcdGh0bWw6IC9cXGJodG1sLyxcblx0XHRcdGpzb246IC9cXGJqc29uXFxiL1xuXHRcdH0sXG5cblx0XHRyZXNwb25zZUZpZWxkczoge1xuXHRcdFx0eG1sOiBcInJlc3BvbnNlWE1MXCIsXG5cdFx0XHR0ZXh0OiBcInJlc3BvbnNlVGV4dFwiLFxuXHRcdFx0anNvbjogXCJyZXNwb25zZUpTT05cIlxuXHRcdH0sXG5cblx0XHQvLyBEYXRhIGNvbnZlcnRlcnNcblx0XHQvLyBLZXlzIHNlcGFyYXRlIHNvdXJjZSAob3IgY2F0Y2hhbGwgXCIqXCIpIGFuZCBkZXN0aW5hdGlvbiB0eXBlcyB3aXRoIGEgc2luZ2xlIHNwYWNlXG5cdFx0Y29udmVydGVyczoge1xuXG5cdFx0XHQvLyBDb252ZXJ0IGFueXRoaW5nIHRvIHRleHRcblx0XHRcdFwiKiB0ZXh0XCI6IFN0cmluZyxcblxuXHRcdFx0Ly8gVGV4dCB0byBodG1sICh0cnVlID0gbm8gdHJhbnNmb3JtYXRpb24pXG5cdFx0XHRcInRleHQgaHRtbFwiOiB0cnVlLFxuXG5cdFx0XHQvLyBFdmFsdWF0ZSB0ZXh0IGFzIGEganNvbiBleHByZXNzaW9uXG5cdFx0XHRcInRleHQganNvblwiOiBKU09OLnBhcnNlLFxuXG5cdFx0XHQvLyBQYXJzZSB0ZXh0IGFzIHhtbFxuXHRcdFx0XCJ0ZXh0IHhtbFwiOiBqUXVlcnkucGFyc2VYTUxcblx0XHR9LFxuXG5cdFx0Ly8gRm9yIG9wdGlvbnMgdGhhdCBzaG91bGRuJ3QgYmUgZGVlcCBleHRlbmRlZDpcblx0XHQvLyB5b3UgY2FuIGFkZCB5b3VyIG93biBjdXN0b20gb3B0aW9ucyBoZXJlIGlmXG5cdFx0Ly8gYW5kIHdoZW4geW91IGNyZWF0ZSBvbmUgdGhhdCBzaG91bGRuJ3QgYmVcblx0XHQvLyBkZWVwIGV4dGVuZGVkIChzZWUgYWpheEV4dGVuZClcblx0XHRmbGF0T3B0aW9uczoge1xuXHRcdFx0dXJsOiB0cnVlLFxuXHRcdFx0Y29udGV4dDogdHJ1ZVxuXHRcdH1cblx0fSxcblxuXHQvLyBDcmVhdGVzIGEgZnVsbCBmbGVkZ2VkIHNldHRpbmdzIG9iamVjdCBpbnRvIHRhcmdldFxuXHQvLyB3aXRoIGJvdGggYWpheFNldHRpbmdzIGFuZCBzZXR0aW5ncyBmaWVsZHMuXG5cdC8vIElmIHRhcmdldCBpcyBvbWl0dGVkLCB3cml0ZXMgaW50byBhamF4U2V0dGluZ3MuXG5cdGFqYXhTZXR1cDogZnVuY3Rpb24oIHRhcmdldCwgc2V0dGluZ3MgKSB7XG5cdFx0cmV0dXJuIHNldHRpbmdzID9cblxuXHRcdFx0Ly8gQnVpbGRpbmcgYSBzZXR0aW5ncyBvYmplY3Rcblx0XHRcdGFqYXhFeHRlbmQoIGFqYXhFeHRlbmQoIHRhcmdldCwgalF1ZXJ5LmFqYXhTZXR0aW5ncyApLCBzZXR0aW5ncyApIDpcblxuXHRcdFx0Ly8gRXh0ZW5kaW5nIGFqYXhTZXR0aW5nc1xuXHRcdFx0YWpheEV4dGVuZCggalF1ZXJ5LmFqYXhTZXR0aW5ncywgdGFyZ2V0ICk7XG5cdH0sXG5cblx0YWpheFByZWZpbHRlcjogYWRkVG9QcmVmaWx0ZXJzT3JUcmFuc3BvcnRzKCBwcmVmaWx0ZXJzICksXG5cdGFqYXhUcmFuc3BvcnQ6IGFkZFRvUHJlZmlsdGVyc09yVHJhbnNwb3J0cyggdHJhbnNwb3J0cyApLFxuXG5cdC8vIE1haW4gbWV0aG9kXG5cdGFqYXg6IGZ1bmN0aW9uKCB1cmwsIG9wdGlvbnMgKSB7XG5cblx0XHQvLyBJZiB1cmwgaXMgYW4gb2JqZWN0LCBzaW11bGF0ZSBwcmUtMS41IHNpZ25hdHVyZVxuXHRcdGlmICggdHlwZW9mIHVybCA9PT0gXCJvYmplY3RcIiApIHtcblx0XHRcdG9wdGlvbnMgPSB1cmw7XG5cdFx0XHR1cmwgPSB1bmRlZmluZWQ7XG5cdFx0fVxuXG5cdFx0Ly8gRm9yY2Ugb3B0aW9ucyB0byBiZSBhbiBvYmplY3Rcblx0XHRvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuXHRcdHZhciB0cmFuc3BvcnQsXG5cblx0XHRcdC8vIFVSTCB3aXRob3V0IGFudGktY2FjaGUgcGFyYW1cblx0XHRcdGNhY2hlVVJMLFxuXG5cdFx0XHQvLyBSZXNwb25zZSBoZWFkZXJzXG5cdFx0XHRyZXNwb25zZUhlYWRlcnNTdHJpbmcsXG5cdFx0XHRyZXNwb25zZUhlYWRlcnMsXG5cblx0XHRcdC8vIHRpbWVvdXQgaGFuZGxlXG5cdFx0XHR0aW1lb3V0VGltZXIsXG5cblx0XHRcdC8vIFVybCBjbGVhbnVwIHZhclxuXHRcdFx0dXJsQW5jaG9yLFxuXG5cdFx0XHQvLyBSZXF1ZXN0IHN0YXRlIChiZWNvbWVzIGZhbHNlIHVwb24gc2VuZCBhbmQgdHJ1ZSB1cG9uIGNvbXBsZXRpb24pXG5cdFx0XHRjb21wbGV0ZWQsXG5cblx0XHRcdC8vIFRvIGtub3cgaWYgZ2xvYmFsIGV2ZW50cyBhcmUgdG8gYmUgZGlzcGF0Y2hlZFxuXHRcdFx0ZmlyZUdsb2JhbHMsXG5cblx0XHRcdC8vIExvb3AgdmFyaWFibGVcblx0XHRcdGksXG5cblx0XHRcdC8vIHVuY2FjaGVkIHBhcnQgb2YgdGhlIHVybFxuXHRcdFx0dW5jYWNoZWQsXG5cblx0XHRcdC8vIENyZWF0ZSB0aGUgZmluYWwgb3B0aW9ucyBvYmplY3Rcblx0XHRcdHMgPSBqUXVlcnkuYWpheFNldHVwKCB7fSwgb3B0aW9ucyApLFxuXG5cdFx0XHQvLyBDYWxsYmFja3MgY29udGV4dFxuXHRcdFx0Y2FsbGJhY2tDb250ZXh0ID0gcy5jb250ZXh0IHx8IHMsXG5cblx0XHRcdC8vIENvbnRleHQgZm9yIGdsb2JhbCBldmVudHMgaXMgY2FsbGJhY2tDb250ZXh0IGlmIGl0IGlzIGEgRE9NIG5vZGUgb3IgalF1ZXJ5IGNvbGxlY3Rpb25cblx0XHRcdGdsb2JhbEV2ZW50Q29udGV4dCA9IHMuY29udGV4dCAmJlxuXHRcdFx0XHQoIGNhbGxiYWNrQ29udGV4dC5ub2RlVHlwZSB8fCBjYWxsYmFja0NvbnRleHQuanF1ZXJ5ICkgP1xuXHRcdFx0XHRqUXVlcnkoIGNhbGxiYWNrQ29udGV4dCApIDpcblx0XHRcdFx0alF1ZXJ5LmV2ZW50LFxuXG5cdFx0XHQvLyBEZWZlcnJlZHNcblx0XHRcdGRlZmVycmVkID0galF1ZXJ5LkRlZmVycmVkKCksXG5cdFx0XHRjb21wbGV0ZURlZmVycmVkID0galF1ZXJ5LkNhbGxiYWNrcyggXCJvbmNlIG1lbW9yeVwiICksXG5cblx0XHRcdC8vIFN0YXR1cy1kZXBlbmRlbnQgY2FsbGJhY2tzXG5cdFx0XHRzdGF0dXNDb2RlID0gcy5zdGF0dXNDb2RlIHx8IHt9LFxuXG5cdFx0XHQvLyBIZWFkZXJzICh0aGV5IGFyZSBzZW50IGFsbCBhdCBvbmNlKVxuXHRcdFx0cmVxdWVzdEhlYWRlcnMgPSB7fSxcblx0XHRcdHJlcXVlc3RIZWFkZXJzTmFtZXMgPSB7fSxcblxuXHRcdFx0Ly8gRGVmYXVsdCBhYm9ydCBtZXNzYWdlXG5cdFx0XHRzdHJBYm9ydCA9IFwiY2FuY2VsZWRcIixcblxuXHRcdFx0Ly8gRmFrZSB4aHJcblx0XHRcdGpxWEhSID0ge1xuXHRcdFx0XHRyZWFkeVN0YXRlOiAwLFxuXG5cdFx0XHRcdC8vIEJ1aWxkcyBoZWFkZXJzIGhhc2h0YWJsZSBpZiBuZWVkZWRcblx0XHRcdFx0Z2V0UmVzcG9uc2VIZWFkZXI6IGZ1bmN0aW9uKCBrZXkgKSB7XG5cdFx0XHRcdFx0dmFyIG1hdGNoO1xuXHRcdFx0XHRcdGlmICggY29tcGxldGVkICkge1xuXHRcdFx0XHRcdFx0aWYgKCAhcmVzcG9uc2VIZWFkZXJzICkge1xuXHRcdFx0XHRcdFx0XHRyZXNwb25zZUhlYWRlcnMgPSB7fTtcblx0XHRcdFx0XHRcdFx0d2hpbGUgKCAoIG1hdGNoID0gcmhlYWRlcnMuZXhlYyggcmVzcG9uc2VIZWFkZXJzU3RyaW5nICkgKSApIHtcblx0XHRcdFx0XHRcdFx0XHRyZXNwb25zZUhlYWRlcnNbIG1hdGNoWyAxIF0udG9Mb3dlckNhc2UoKSArIFwiIFwiIF0gPVxuXHRcdFx0XHRcdFx0XHRcdFx0KCByZXNwb25zZUhlYWRlcnNbIG1hdGNoWyAxIF0udG9Mb3dlckNhc2UoKSArIFwiIFwiIF0gfHwgW10gKVxuXHRcdFx0XHRcdFx0XHRcdFx0XHQuY29uY2F0KCBtYXRjaFsgMiBdICk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdG1hdGNoID0gcmVzcG9uc2VIZWFkZXJzWyBrZXkudG9Mb3dlckNhc2UoKSArIFwiIFwiIF07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybiBtYXRjaCA9PSBudWxsID8gbnVsbCA6IG1hdGNoLmpvaW4oIFwiLCBcIiApO1xuXHRcdFx0XHR9LFxuXG5cdFx0XHRcdC8vIFJhdyBzdHJpbmdcblx0XHRcdFx0Z2V0QWxsUmVzcG9uc2VIZWFkZXJzOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRyZXR1cm4gY29tcGxldGVkID8gcmVzcG9uc2VIZWFkZXJzU3RyaW5nIDogbnVsbDtcblx0XHRcdFx0fSxcblxuXHRcdFx0XHQvLyBDYWNoZXMgdGhlIGhlYWRlclxuXHRcdFx0XHRzZXRSZXF1ZXN0SGVhZGVyOiBmdW5jdGlvbiggbmFtZSwgdmFsdWUgKSB7XG5cdFx0XHRcdFx0aWYgKCBjb21wbGV0ZWQgPT0gbnVsbCApIHtcblx0XHRcdFx0XHRcdG5hbWUgPSByZXF1ZXN0SGVhZGVyc05hbWVzWyBuYW1lLnRvTG93ZXJDYXNlKCkgXSA9XG5cdFx0XHRcdFx0XHRcdHJlcXVlc3RIZWFkZXJzTmFtZXNbIG5hbWUudG9Mb3dlckNhc2UoKSBdIHx8IG5hbWU7XG5cdFx0XHRcdFx0XHRyZXF1ZXN0SGVhZGVyc1sgbmFtZSBdID0gdmFsdWU7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybiB0aGlzO1xuXHRcdFx0XHR9LFxuXG5cdFx0XHRcdC8vIE92ZXJyaWRlcyByZXNwb25zZSBjb250ZW50LXR5cGUgaGVhZGVyXG5cdFx0XHRcdG92ZXJyaWRlTWltZVR5cGU6IGZ1bmN0aW9uKCB0eXBlICkge1xuXHRcdFx0XHRcdGlmICggY29tcGxldGVkID09IG51bGwgKSB7XG5cdFx0XHRcdFx0XHRzLm1pbWVUeXBlID0gdHlwZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHRcdH0sXG5cblx0XHRcdFx0Ly8gU3RhdHVzLWRlcGVuZGVudCBjYWxsYmFja3Ncblx0XHRcdFx0c3RhdHVzQ29kZTogZnVuY3Rpb24oIG1hcCApIHtcblx0XHRcdFx0XHR2YXIgY29kZTtcblx0XHRcdFx0XHRpZiAoIG1hcCApIHtcblx0XHRcdFx0XHRcdGlmICggY29tcGxldGVkICkge1xuXG5cdFx0XHRcdFx0XHRcdC8vIEV4ZWN1dGUgdGhlIGFwcHJvcHJpYXRlIGNhbGxiYWNrc1xuXHRcdFx0XHRcdFx0XHRqcVhIUi5hbHdheXMoIG1hcFsganFYSFIuc3RhdHVzIF0gKTtcblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0Ly8gTGF6eS1hZGQgdGhlIG5ldyBjYWxsYmFja3MgaW4gYSB3YXkgdGhhdCBwcmVzZXJ2ZXMgb2xkIG9uZXNcblx0XHRcdFx0XHRcdFx0Zm9yICggY29kZSBpbiBtYXAgKSB7XG5cdFx0XHRcdFx0XHRcdFx0c3RhdHVzQ29kZVsgY29kZSBdID0gWyBzdGF0dXNDb2RlWyBjb2RlIF0sIG1hcFsgY29kZSBdIF07XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHRcdH0sXG5cblx0XHRcdFx0Ly8gQ2FuY2VsIHRoZSByZXF1ZXN0XG5cdFx0XHRcdGFib3J0OiBmdW5jdGlvbiggc3RhdHVzVGV4dCApIHtcblx0XHRcdFx0XHR2YXIgZmluYWxUZXh0ID0gc3RhdHVzVGV4dCB8fCBzdHJBYm9ydDtcblx0XHRcdFx0XHRpZiAoIHRyYW5zcG9ydCApIHtcblx0XHRcdFx0XHRcdHRyYW5zcG9ydC5hYm9ydCggZmluYWxUZXh0ICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGRvbmUoIDAsIGZpbmFsVGV4dCApO1xuXHRcdFx0XHRcdHJldHVybiB0aGlzO1xuXHRcdFx0XHR9XG5cdFx0XHR9O1xuXG5cdFx0Ly8gQXR0YWNoIGRlZmVycmVkc1xuXHRcdGRlZmVycmVkLnByb21pc2UoIGpxWEhSICk7XG5cblx0XHQvLyBBZGQgcHJvdG9jb2wgaWYgbm90IHByb3ZpZGVkIChwcmVmaWx0ZXJzIG1pZ2h0IGV4cGVjdCBpdClcblx0XHQvLyBIYW5kbGUgZmFsc3kgdXJsIGluIHRoZSBzZXR0aW5ncyBvYmplY3QgKCMxMDA5MzogY29uc2lzdGVuY3kgd2l0aCBvbGQgc2lnbmF0dXJlKVxuXHRcdC8vIFdlIGFsc28gdXNlIHRoZSB1cmwgcGFyYW1ldGVyIGlmIGF2YWlsYWJsZVxuXHRcdHMudXJsID0gKCAoIHVybCB8fCBzLnVybCB8fCBsb2NhdGlvbi5ocmVmICkgKyBcIlwiIClcblx0XHRcdC5yZXBsYWNlKCBycHJvdG9jb2wsIGxvY2F0aW9uLnByb3RvY29sICsgXCIvL1wiICk7XG5cblx0XHQvLyBBbGlhcyBtZXRob2Qgb3B0aW9uIHRvIHR5cGUgYXMgcGVyIHRpY2tldCAjMTIwMDRcblx0XHRzLnR5cGUgPSBvcHRpb25zLm1ldGhvZCB8fCBvcHRpb25zLnR5cGUgfHwgcy5tZXRob2QgfHwgcy50eXBlO1xuXG5cdFx0Ly8gRXh0cmFjdCBkYXRhVHlwZXMgbGlzdFxuXHRcdHMuZGF0YVR5cGVzID0gKCBzLmRhdGFUeXBlIHx8IFwiKlwiICkudG9Mb3dlckNhc2UoKS5tYXRjaCggcm5vdGh0bWx3aGl0ZSApIHx8IFsgXCJcIiBdO1xuXG5cdFx0Ly8gQSBjcm9zcy1kb21haW4gcmVxdWVzdCBpcyBpbiBvcmRlciB3aGVuIHRoZSBvcmlnaW4gZG9lc24ndCBtYXRjaCB0aGUgY3VycmVudCBvcmlnaW4uXG5cdFx0aWYgKCBzLmNyb3NzRG9tYWluID09IG51bGwgKSB7XG5cdFx0XHR1cmxBbmNob3IgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcImFcIiApO1xuXG5cdFx0XHQvLyBTdXBwb3J0OiBJRSA8PTggLSAxMSwgRWRnZSAxMiAtIDE1XG5cdFx0XHQvLyBJRSB0aHJvd3MgZXhjZXB0aW9uIG9uIGFjY2Vzc2luZyB0aGUgaHJlZiBwcm9wZXJ0eSBpZiB1cmwgaXMgbWFsZm9ybWVkLFxuXHRcdFx0Ly8gZS5nLiBodHRwOi8vZXhhbXBsZS5jb206ODB4L1xuXHRcdFx0dHJ5IHtcblx0XHRcdFx0dXJsQW5jaG9yLmhyZWYgPSBzLnVybDtcblxuXHRcdFx0XHQvLyBTdXBwb3J0OiBJRSA8PTggLSAxMSBvbmx5XG5cdFx0XHRcdC8vIEFuY2hvcidzIGhvc3QgcHJvcGVydHkgaXNuJ3QgY29ycmVjdGx5IHNldCB3aGVuIHMudXJsIGlzIHJlbGF0aXZlXG5cdFx0XHRcdHVybEFuY2hvci5ocmVmID0gdXJsQW5jaG9yLmhyZWY7XG5cdFx0XHRcdHMuY3Jvc3NEb21haW4gPSBvcmlnaW5BbmNob3IucHJvdG9jb2wgKyBcIi8vXCIgKyBvcmlnaW5BbmNob3IuaG9zdCAhPT1cblx0XHRcdFx0XHR1cmxBbmNob3IucHJvdG9jb2wgKyBcIi8vXCIgKyB1cmxBbmNob3IuaG9zdDtcblx0XHRcdH0gY2F0Y2ggKCBlICkge1xuXG5cdFx0XHRcdC8vIElmIHRoZXJlIGlzIGFuIGVycm9yIHBhcnNpbmcgdGhlIFVSTCwgYXNzdW1lIGl0IGlzIGNyb3NzRG9tYWluLFxuXHRcdFx0XHQvLyBpdCBjYW4gYmUgcmVqZWN0ZWQgYnkgdGhlIHRyYW5zcG9ydCBpZiBpdCBpcyBpbnZhbGlkXG5cdFx0XHRcdHMuY3Jvc3NEb21haW4gPSB0cnVlO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIENvbnZlcnQgZGF0YSBpZiBub3QgYWxyZWFkeSBhIHN0cmluZ1xuXHRcdGlmICggcy5kYXRhICYmIHMucHJvY2Vzc0RhdGEgJiYgdHlwZW9mIHMuZGF0YSAhPT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdHMuZGF0YSA9IGpRdWVyeS5wYXJhbSggcy5kYXRhLCBzLnRyYWRpdGlvbmFsICk7XG5cdFx0fVxuXG5cdFx0Ly8gQXBwbHkgcHJlZmlsdGVyc1xuXHRcdGluc3BlY3RQcmVmaWx0ZXJzT3JUcmFuc3BvcnRzKCBwcmVmaWx0ZXJzLCBzLCBvcHRpb25zLCBqcVhIUiApO1xuXG5cdFx0Ly8gSWYgcmVxdWVzdCB3YXMgYWJvcnRlZCBpbnNpZGUgYSBwcmVmaWx0ZXIsIHN0b3AgdGhlcmVcblx0XHRpZiAoIGNvbXBsZXRlZCApIHtcblx0XHRcdHJldHVybiBqcVhIUjtcblx0XHR9XG5cblx0XHQvLyBXZSBjYW4gZmlyZSBnbG9iYWwgZXZlbnRzIGFzIG9mIG5vdyBpZiBhc2tlZCB0b1xuXHRcdC8vIERvbid0IGZpcmUgZXZlbnRzIGlmIGpRdWVyeS5ldmVudCBpcyB1bmRlZmluZWQgaW4gYW4gQU1ELXVzYWdlIHNjZW5hcmlvICgjMTUxMTgpXG5cdFx0ZmlyZUdsb2JhbHMgPSBqUXVlcnkuZXZlbnQgJiYgcy5nbG9iYWw7XG5cblx0XHQvLyBXYXRjaCBmb3IgYSBuZXcgc2V0IG9mIHJlcXVlc3RzXG5cdFx0aWYgKCBmaXJlR2xvYmFscyAmJiBqUXVlcnkuYWN0aXZlKysgPT09IDAgKSB7XG5cdFx0XHRqUXVlcnkuZXZlbnQudHJpZ2dlciggXCJhamF4U3RhcnRcIiApO1xuXHRcdH1cblxuXHRcdC8vIFVwcGVyY2FzZSB0aGUgdHlwZVxuXHRcdHMudHlwZSA9IHMudHlwZS50b1VwcGVyQ2FzZSgpO1xuXG5cdFx0Ly8gRGV0ZXJtaW5lIGlmIHJlcXVlc3QgaGFzIGNvbnRlbnRcblx0XHRzLmhhc0NvbnRlbnQgPSAhcm5vQ29udGVudC50ZXN0KCBzLnR5cGUgKTtcblxuXHRcdC8vIFNhdmUgdGhlIFVSTCBpbiBjYXNlIHdlJ3JlIHRveWluZyB3aXRoIHRoZSBJZi1Nb2RpZmllZC1TaW5jZVxuXHRcdC8vIGFuZC9vciBJZi1Ob25lLU1hdGNoIGhlYWRlciBsYXRlciBvblxuXHRcdC8vIFJlbW92ZSBoYXNoIHRvIHNpbXBsaWZ5IHVybCBtYW5pcHVsYXRpb25cblx0XHRjYWNoZVVSTCA9IHMudXJsLnJlcGxhY2UoIHJoYXNoLCBcIlwiICk7XG5cblx0XHQvLyBNb3JlIG9wdGlvbnMgaGFuZGxpbmcgZm9yIHJlcXVlc3RzIHdpdGggbm8gY29udGVudFxuXHRcdGlmICggIXMuaGFzQ29udGVudCApIHtcblxuXHRcdFx0Ly8gUmVtZW1iZXIgdGhlIGhhc2ggc28gd2UgY2FuIHB1dCBpdCBiYWNrXG5cdFx0XHR1bmNhY2hlZCA9IHMudXJsLnNsaWNlKCBjYWNoZVVSTC5sZW5ndGggKTtcblxuXHRcdFx0Ly8gSWYgZGF0YSBpcyBhdmFpbGFibGUgYW5kIHNob3VsZCBiZSBwcm9jZXNzZWQsIGFwcGVuZCBkYXRhIHRvIHVybFxuXHRcdFx0aWYgKCBzLmRhdGEgJiYgKCBzLnByb2Nlc3NEYXRhIHx8IHR5cGVvZiBzLmRhdGEgPT09IFwic3RyaW5nXCIgKSApIHtcblx0XHRcdFx0Y2FjaGVVUkwgKz0gKCBycXVlcnkudGVzdCggY2FjaGVVUkwgKSA/IFwiJlwiIDogXCI/XCIgKSArIHMuZGF0YTtcblxuXHRcdFx0XHQvLyAjOTY4MjogcmVtb3ZlIGRhdGEgc28gdGhhdCBpdCdzIG5vdCB1c2VkIGluIGFuIGV2ZW50dWFsIHJldHJ5XG5cdFx0XHRcdGRlbGV0ZSBzLmRhdGE7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEFkZCBvciB1cGRhdGUgYW50aS1jYWNoZSBwYXJhbSBpZiBuZWVkZWRcblx0XHRcdGlmICggcy5jYWNoZSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRcdGNhY2hlVVJMID0gY2FjaGVVUkwucmVwbGFjZSggcmFudGlDYWNoZSwgXCIkMVwiICk7XG5cdFx0XHRcdHVuY2FjaGVkID0gKCBycXVlcnkudGVzdCggY2FjaGVVUkwgKSA/IFwiJlwiIDogXCI/XCIgKSArIFwiXz1cIiArICggbm9uY2UuZ3VpZCsrICkgK1xuXHRcdFx0XHRcdHVuY2FjaGVkO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBQdXQgaGFzaCBhbmQgYW50aS1jYWNoZSBvbiB0aGUgVVJMIHRoYXQgd2lsbCBiZSByZXF1ZXN0ZWQgKGdoLTE3MzIpXG5cdFx0XHRzLnVybCA9IGNhY2hlVVJMICsgdW5jYWNoZWQ7XG5cblx0XHQvLyBDaGFuZ2UgJyUyMCcgdG8gJysnIGlmIHRoaXMgaXMgZW5jb2RlZCBmb3JtIGJvZHkgY29udGVudCAoZ2gtMjY1OClcblx0XHR9IGVsc2UgaWYgKCBzLmRhdGEgJiYgcy5wcm9jZXNzRGF0YSAmJlxuXHRcdFx0KCBzLmNvbnRlbnRUeXBlIHx8IFwiXCIgKS5pbmRleE9mKCBcImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZFwiICkgPT09IDAgKSB7XG5cdFx0XHRzLmRhdGEgPSBzLmRhdGEucmVwbGFjZSggcjIwLCBcIitcIiApO1xuXHRcdH1cblxuXHRcdC8vIFNldCB0aGUgSWYtTW9kaWZpZWQtU2luY2UgYW5kL29yIElmLU5vbmUtTWF0Y2ggaGVhZGVyLCBpZiBpbiBpZk1vZGlmaWVkIG1vZGUuXG5cdFx0aWYgKCBzLmlmTW9kaWZpZWQgKSB7XG5cdFx0XHRpZiAoIGpRdWVyeS5sYXN0TW9kaWZpZWRbIGNhY2hlVVJMIF0gKSB7XG5cdFx0XHRcdGpxWEhSLnNldFJlcXVlc3RIZWFkZXIoIFwiSWYtTW9kaWZpZWQtU2luY2VcIiwgalF1ZXJ5Lmxhc3RNb2RpZmllZFsgY2FjaGVVUkwgXSApO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBqUXVlcnkuZXRhZ1sgY2FjaGVVUkwgXSApIHtcblx0XHRcdFx0anFYSFIuc2V0UmVxdWVzdEhlYWRlciggXCJJZi1Ob25lLU1hdGNoXCIsIGpRdWVyeS5ldGFnWyBjYWNoZVVSTCBdICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gU2V0IHRoZSBjb3JyZWN0IGhlYWRlciwgaWYgZGF0YSBpcyBiZWluZyBzZW50XG5cdFx0aWYgKCBzLmRhdGEgJiYgcy5oYXNDb250ZW50ICYmIHMuY29udGVudFR5cGUgIT09IGZhbHNlIHx8IG9wdGlvbnMuY29udGVudFR5cGUgKSB7XG5cdFx0XHRqcVhIUi5zZXRSZXF1ZXN0SGVhZGVyKCBcIkNvbnRlbnQtVHlwZVwiLCBzLmNvbnRlbnRUeXBlICk7XG5cdFx0fVxuXG5cdFx0Ly8gU2V0IHRoZSBBY2NlcHRzIGhlYWRlciBmb3IgdGhlIHNlcnZlciwgZGVwZW5kaW5nIG9uIHRoZSBkYXRhVHlwZVxuXHRcdGpxWEhSLnNldFJlcXVlc3RIZWFkZXIoXG5cdFx0XHRcIkFjY2VwdFwiLFxuXHRcdFx0cy5kYXRhVHlwZXNbIDAgXSAmJiBzLmFjY2VwdHNbIHMuZGF0YVR5cGVzWyAwIF0gXSA/XG5cdFx0XHRcdHMuYWNjZXB0c1sgcy5kYXRhVHlwZXNbIDAgXSBdICtcblx0XHRcdFx0XHQoIHMuZGF0YVR5cGVzWyAwIF0gIT09IFwiKlwiID8gXCIsIFwiICsgYWxsVHlwZXMgKyBcIjsgcT0wLjAxXCIgOiBcIlwiICkgOlxuXHRcdFx0XHRzLmFjY2VwdHNbIFwiKlwiIF1cblx0XHQpO1xuXG5cdFx0Ly8gQ2hlY2sgZm9yIGhlYWRlcnMgb3B0aW9uXG5cdFx0Zm9yICggaSBpbiBzLmhlYWRlcnMgKSB7XG5cdFx0XHRqcVhIUi5zZXRSZXF1ZXN0SGVhZGVyKCBpLCBzLmhlYWRlcnNbIGkgXSApO1xuXHRcdH1cblxuXHRcdC8vIEFsbG93IGN1c3RvbSBoZWFkZXJzL21pbWV0eXBlcyBhbmQgZWFybHkgYWJvcnRcblx0XHRpZiAoIHMuYmVmb3JlU2VuZCAmJlxuXHRcdFx0KCBzLmJlZm9yZVNlbmQuY2FsbCggY2FsbGJhY2tDb250ZXh0LCBqcVhIUiwgcyApID09PSBmYWxzZSB8fCBjb21wbGV0ZWQgKSApIHtcblxuXHRcdFx0Ly8gQWJvcnQgaWYgbm90IGRvbmUgYWxyZWFkeSBhbmQgcmV0dXJuXG5cdFx0XHRyZXR1cm4ganFYSFIuYWJvcnQoKTtcblx0XHR9XG5cblx0XHQvLyBBYm9ydGluZyBpcyBubyBsb25nZXIgYSBjYW5jZWxsYXRpb25cblx0XHRzdHJBYm9ydCA9IFwiYWJvcnRcIjtcblxuXHRcdC8vIEluc3RhbGwgY2FsbGJhY2tzIG9uIGRlZmVycmVkc1xuXHRcdGNvbXBsZXRlRGVmZXJyZWQuYWRkKCBzLmNvbXBsZXRlICk7XG5cdFx0anFYSFIuZG9uZSggcy5zdWNjZXNzICk7XG5cdFx0anFYSFIuZmFpbCggcy5lcnJvciApO1xuXG5cdFx0Ly8gR2V0IHRyYW5zcG9ydFxuXHRcdHRyYW5zcG9ydCA9IGluc3BlY3RQcmVmaWx0ZXJzT3JUcmFuc3BvcnRzKCB0cmFuc3BvcnRzLCBzLCBvcHRpb25zLCBqcVhIUiApO1xuXG5cdFx0Ly8gSWYgbm8gdHJhbnNwb3J0LCB3ZSBhdXRvLWFib3J0XG5cdFx0aWYgKCAhdHJhbnNwb3J0ICkge1xuXHRcdFx0ZG9uZSggLTEsIFwiTm8gVHJhbnNwb3J0XCIgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0anFYSFIucmVhZHlTdGF0ZSA9IDE7XG5cblx0XHRcdC8vIFNlbmQgZ2xvYmFsIGV2ZW50XG5cdFx0XHRpZiAoIGZpcmVHbG9iYWxzICkge1xuXHRcdFx0XHRnbG9iYWxFdmVudENvbnRleHQudHJpZ2dlciggXCJhamF4U2VuZFwiLCBbIGpxWEhSLCBzIF0gKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gSWYgcmVxdWVzdCB3YXMgYWJvcnRlZCBpbnNpZGUgYWpheFNlbmQsIHN0b3AgdGhlcmVcblx0XHRcdGlmICggY29tcGxldGVkICkge1xuXHRcdFx0XHRyZXR1cm4ganFYSFI7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFRpbWVvdXRcblx0XHRcdGlmICggcy5hc3luYyAmJiBzLnRpbWVvdXQgPiAwICkge1xuXHRcdFx0XHR0aW1lb3V0VGltZXIgPSB3aW5kb3cuc2V0VGltZW91dCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0anFYSFIuYWJvcnQoIFwidGltZW91dFwiICk7XG5cdFx0XHRcdH0sIHMudGltZW91dCApO1xuXHRcdFx0fVxuXG5cdFx0XHR0cnkge1xuXHRcdFx0XHRjb21wbGV0ZWQgPSBmYWxzZTtcblx0XHRcdFx0dHJhbnNwb3J0LnNlbmQoIHJlcXVlc3RIZWFkZXJzLCBkb25lICk7XG5cdFx0XHR9IGNhdGNoICggZSApIHtcblxuXHRcdFx0XHQvLyBSZXRocm93IHBvc3QtY29tcGxldGlvbiBleGNlcHRpb25zXG5cdFx0XHRcdGlmICggY29tcGxldGVkICkge1xuXHRcdFx0XHRcdHRocm93IGU7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBQcm9wYWdhdGUgb3RoZXJzIGFzIHJlc3VsdHNcblx0XHRcdFx0ZG9uZSggLTEsIGUgKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBDYWxsYmFjayBmb3Igd2hlbiBldmVyeXRoaW5nIGlzIGRvbmVcblx0XHRmdW5jdGlvbiBkb25lKCBzdGF0dXMsIG5hdGl2ZVN0YXR1c1RleHQsIHJlc3BvbnNlcywgaGVhZGVycyApIHtcblx0XHRcdHZhciBpc1N1Y2Nlc3MsIHN1Y2Nlc3MsIGVycm9yLCByZXNwb25zZSwgbW9kaWZpZWQsXG5cdFx0XHRcdHN0YXR1c1RleHQgPSBuYXRpdmVTdGF0dXNUZXh0O1xuXG5cdFx0XHQvLyBJZ25vcmUgcmVwZWF0IGludm9jYXRpb25zXG5cdFx0XHRpZiAoIGNvbXBsZXRlZCApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRjb21wbGV0ZWQgPSB0cnVlO1xuXG5cdFx0XHQvLyBDbGVhciB0aW1lb3V0IGlmIGl0IGV4aXN0c1xuXHRcdFx0aWYgKCB0aW1lb3V0VGltZXIgKSB7XG5cdFx0XHRcdHdpbmRvdy5jbGVhclRpbWVvdXQoIHRpbWVvdXRUaW1lciApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBEZXJlZmVyZW5jZSB0cmFuc3BvcnQgZm9yIGVhcmx5IGdhcmJhZ2UgY29sbGVjdGlvblxuXHRcdFx0Ly8gKG5vIG1hdHRlciBob3cgbG9uZyB0aGUganFYSFIgb2JqZWN0IHdpbGwgYmUgdXNlZClcblx0XHRcdHRyYW5zcG9ydCA9IHVuZGVmaW5lZDtcblxuXHRcdFx0Ly8gQ2FjaGUgcmVzcG9uc2UgaGVhZGVyc1xuXHRcdFx0cmVzcG9uc2VIZWFkZXJzU3RyaW5nID0gaGVhZGVycyB8fCBcIlwiO1xuXG5cdFx0XHQvLyBTZXQgcmVhZHlTdGF0ZVxuXHRcdFx0anFYSFIucmVhZHlTdGF0ZSA9IHN0YXR1cyA+IDAgPyA0IDogMDtcblxuXHRcdFx0Ly8gRGV0ZXJtaW5lIGlmIHN1Y2Nlc3NmdWxcblx0XHRcdGlzU3VjY2VzcyA9IHN0YXR1cyA+PSAyMDAgJiYgc3RhdHVzIDwgMzAwIHx8IHN0YXR1cyA9PT0gMzA0O1xuXG5cdFx0XHQvLyBHZXQgcmVzcG9uc2UgZGF0YVxuXHRcdFx0aWYgKCByZXNwb25zZXMgKSB7XG5cdFx0XHRcdHJlc3BvbnNlID0gYWpheEhhbmRsZVJlc3BvbnNlcyggcywganFYSFIsIHJlc3BvbnNlcyApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBVc2UgYSBub29wIGNvbnZlcnRlciBmb3IgbWlzc2luZyBzY3JpcHQgYnV0IG5vdCBpZiBqc29ucFxuXHRcdFx0aWYgKCAhaXNTdWNjZXNzICYmXG5cdFx0XHRcdGpRdWVyeS5pbkFycmF5KCBcInNjcmlwdFwiLCBzLmRhdGFUeXBlcyApID4gLTEgJiZcblx0XHRcdFx0alF1ZXJ5LmluQXJyYXkoIFwianNvblwiLCBzLmRhdGFUeXBlcyApIDwgMCApIHtcblx0XHRcdFx0cy5jb252ZXJ0ZXJzWyBcInRleHQgc2NyaXB0XCIgXSA9IGZ1bmN0aW9uKCkge307XG5cdFx0XHR9XG5cblx0XHRcdC8vIENvbnZlcnQgbm8gbWF0dGVyIHdoYXQgKHRoYXQgd2F5IHJlc3BvbnNlWFhYIGZpZWxkcyBhcmUgYWx3YXlzIHNldClcblx0XHRcdHJlc3BvbnNlID0gYWpheENvbnZlcnQoIHMsIHJlc3BvbnNlLCBqcVhIUiwgaXNTdWNjZXNzICk7XG5cblx0XHRcdC8vIElmIHN1Y2Nlc3NmdWwsIGhhbmRsZSB0eXBlIGNoYWluaW5nXG5cdFx0XHRpZiAoIGlzU3VjY2VzcyApIHtcblxuXHRcdFx0XHQvLyBTZXQgdGhlIElmLU1vZGlmaWVkLVNpbmNlIGFuZC9vciBJZi1Ob25lLU1hdGNoIGhlYWRlciwgaWYgaW4gaWZNb2RpZmllZCBtb2RlLlxuXHRcdFx0XHRpZiAoIHMuaWZNb2RpZmllZCApIHtcblx0XHRcdFx0XHRtb2RpZmllZCA9IGpxWEhSLmdldFJlc3BvbnNlSGVhZGVyKCBcIkxhc3QtTW9kaWZpZWRcIiApO1xuXHRcdFx0XHRcdGlmICggbW9kaWZpZWQgKSB7XG5cdFx0XHRcdFx0XHRqUXVlcnkubGFzdE1vZGlmaWVkWyBjYWNoZVVSTCBdID0gbW9kaWZpZWQ7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdG1vZGlmaWVkID0ganFYSFIuZ2V0UmVzcG9uc2VIZWFkZXIoIFwiZXRhZ1wiICk7XG5cdFx0XHRcdFx0aWYgKCBtb2RpZmllZCApIHtcblx0XHRcdFx0XHRcdGpRdWVyeS5ldGFnWyBjYWNoZVVSTCBdID0gbW9kaWZpZWQ7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gaWYgbm8gY29udGVudFxuXHRcdFx0XHRpZiAoIHN0YXR1cyA9PT0gMjA0IHx8IHMudHlwZSA9PT0gXCJIRUFEXCIgKSB7XG5cdFx0XHRcdFx0c3RhdHVzVGV4dCA9IFwibm9jb250ZW50XCI7XG5cblx0XHRcdFx0Ly8gaWYgbm90IG1vZGlmaWVkXG5cdFx0XHRcdH0gZWxzZSBpZiAoIHN0YXR1cyA9PT0gMzA0ICkge1xuXHRcdFx0XHRcdHN0YXR1c1RleHQgPSBcIm5vdG1vZGlmaWVkXCI7XG5cblx0XHRcdFx0Ly8gSWYgd2UgaGF2ZSBkYXRhLCBsZXQncyBjb252ZXJ0IGl0XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0c3RhdHVzVGV4dCA9IHJlc3BvbnNlLnN0YXRlO1xuXHRcdFx0XHRcdHN1Y2Nlc3MgPSByZXNwb25zZS5kYXRhO1xuXHRcdFx0XHRcdGVycm9yID0gcmVzcG9uc2UuZXJyb3I7XG5cdFx0XHRcdFx0aXNTdWNjZXNzID0gIWVycm9yO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIEV4dHJhY3QgZXJyb3IgZnJvbSBzdGF0dXNUZXh0IGFuZCBub3JtYWxpemUgZm9yIG5vbi1hYm9ydHNcblx0XHRcdFx0ZXJyb3IgPSBzdGF0dXNUZXh0O1xuXHRcdFx0XHRpZiAoIHN0YXR1cyB8fCAhc3RhdHVzVGV4dCApIHtcblx0XHRcdFx0XHRzdGF0dXNUZXh0ID0gXCJlcnJvclwiO1xuXHRcdFx0XHRcdGlmICggc3RhdHVzIDwgMCApIHtcblx0XHRcdFx0XHRcdHN0YXR1cyA9IDA7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vIFNldCBkYXRhIGZvciB0aGUgZmFrZSB4aHIgb2JqZWN0XG5cdFx0XHRqcVhIUi5zdGF0dXMgPSBzdGF0dXM7XG5cdFx0XHRqcVhIUi5zdGF0dXNUZXh0ID0gKCBuYXRpdmVTdGF0dXNUZXh0IHx8IHN0YXR1c1RleHQgKSArIFwiXCI7XG5cblx0XHRcdC8vIFN1Y2Nlc3MvRXJyb3Jcblx0XHRcdGlmICggaXNTdWNjZXNzICkge1xuXHRcdFx0XHRkZWZlcnJlZC5yZXNvbHZlV2l0aCggY2FsbGJhY2tDb250ZXh0LCBbIHN1Y2Nlc3MsIHN0YXR1c1RleHQsIGpxWEhSIF0gKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGRlZmVycmVkLnJlamVjdFdpdGgoIGNhbGxiYWNrQ29udGV4dCwgWyBqcVhIUiwgc3RhdHVzVGV4dCwgZXJyb3IgXSApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTdGF0dXMtZGVwZW5kZW50IGNhbGxiYWNrc1xuXHRcdFx0anFYSFIuc3RhdHVzQ29kZSggc3RhdHVzQ29kZSApO1xuXHRcdFx0c3RhdHVzQ29kZSA9IHVuZGVmaW5lZDtcblxuXHRcdFx0aWYgKCBmaXJlR2xvYmFscyApIHtcblx0XHRcdFx0Z2xvYmFsRXZlbnRDb250ZXh0LnRyaWdnZXIoIGlzU3VjY2VzcyA/IFwiYWpheFN1Y2Nlc3NcIiA6IFwiYWpheEVycm9yXCIsXG5cdFx0XHRcdFx0WyBqcVhIUiwgcywgaXNTdWNjZXNzID8gc3VjY2VzcyA6IGVycm9yIF0gKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ29tcGxldGVcblx0XHRcdGNvbXBsZXRlRGVmZXJyZWQuZmlyZVdpdGgoIGNhbGxiYWNrQ29udGV4dCwgWyBqcVhIUiwgc3RhdHVzVGV4dCBdICk7XG5cblx0XHRcdGlmICggZmlyZUdsb2JhbHMgKSB7XG5cdFx0XHRcdGdsb2JhbEV2ZW50Q29udGV4dC50cmlnZ2VyKCBcImFqYXhDb21wbGV0ZVwiLCBbIGpxWEhSLCBzIF0gKTtcblxuXHRcdFx0XHQvLyBIYW5kbGUgdGhlIGdsb2JhbCBBSkFYIGNvdW50ZXJcblx0XHRcdFx0aWYgKCAhKCAtLWpRdWVyeS5hY3RpdmUgKSApIHtcblx0XHRcdFx0XHRqUXVlcnkuZXZlbnQudHJpZ2dlciggXCJhamF4U3RvcFwiICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4ganFYSFI7XG5cdH0sXG5cblx0Z2V0SlNPTjogZnVuY3Rpb24oIHVybCwgZGF0YSwgY2FsbGJhY2sgKSB7XG5cdFx0cmV0dXJuIGpRdWVyeS5nZXQoIHVybCwgZGF0YSwgY2FsbGJhY2ssIFwianNvblwiICk7XG5cdH0sXG5cblx0Z2V0U2NyaXB0OiBmdW5jdGlvbiggdXJsLCBjYWxsYmFjayApIHtcblx0XHRyZXR1cm4galF1ZXJ5LmdldCggdXJsLCB1bmRlZmluZWQsIGNhbGxiYWNrLCBcInNjcmlwdFwiICk7XG5cdH1cbn0gKTtcblxualF1ZXJ5LmVhY2goIFsgXCJnZXRcIiwgXCJwb3N0XCIgXSwgZnVuY3Rpb24oIF9pLCBtZXRob2QgKSB7XG5cdGpRdWVyeVsgbWV0aG9kIF0gPSBmdW5jdGlvbiggdXJsLCBkYXRhLCBjYWxsYmFjaywgdHlwZSApIHtcblxuXHRcdC8vIFNoaWZ0IGFyZ3VtZW50cyBpZiBkYXRhIGFyZ3VtZW50IHdhcyBvbWl0dGVkXG5cdFx0aWYgKCBpc0Z1bmN0aW9uKCBkYXRhICkgKSB7XG5cdFx0XHR0eXBlID0gdHlwZSB8fCBjYWxsYmFjaztcblx0XHRcdGNhbGxiYWNrID0gZGF0YTtcblx0XHRcdGRhdGEgPSB1bmRlZmluZWQ7XG5cdFx0fVxuXG5cdFx0Ly8gVGhlIHVybCBjYW4gYmUgYW4gb3B0aW9ucyBvYmplY3QgKHdoaWNoIHRoZW4gbXVzdCBoYXZlIC51cmwpXG5cdFx0cmV0dXJuIGpRdWVyeS5hamF4KCBqUXVlcnkuZXh0ZW5kKCB7XG5cdFx0XHR1cmw6IHVybCxcblx0XHRcdHR5cGU6IG1ldGhvZCxcblx0XHRcdGRhdGFUeXBlOiB0eXBlLFxuXHRcdFx0ZGF0YTogZGF0YSxcblx0XHRcdHN1Y2Nlc3M6IGNhbGxiYWNrXG5cdFx0fSwgalF1ZXJ5LmlzUGxhaW5PYmplY3QoIHVybCApICYmIHVybCApICk7XG5cdH07XG59ICk7XG5cbmpRdWVyeS5hamF4UHJlZmlsdGVyKCBmdW5jdGlvbiggcyApIHtcblx0dmFyIGk7XG5cdGZvciAoIGkgaW4gcy5oZWFkZXJzICkge1xuXHRcdGlmICggaS50b0xvd2VyQ2FzZSgpID09PSBcImNvbnRlbnQtdHlwZVwiICkge1xuXHRcdFx0cy5jb250ZW50VHlwZSA9IHMuaGVhZGVyc1sgaSBdIHx8IFwiXCI7XG5cdFx0fVxuXHR9XG59ICk7XG5cblxualF1ZXJ5Ll9ldmFsVXJsID0gZnVuY3Rpb24oIHVybCwgb3B0aW9ucywgZG9jICkge1xuXHRyZXR1cm4galF1ZXJ5LmFqYXgoIHtcblx0XHR1cmw6IHVybCxcblxuXHRcdC8vIE1ha2UgdGhpcyBleHBsaWNpdCwgc2luY2UgdXNlciBjYW4gb3ZlcnJpZGUgdGhpcyB0aHJvdWdoIGFqYXhTZXR1cCAoIzExMjY0KVxuXHRcdHR5cGU6IFwiR0VUXCIsXG5cdFx0ZGF0YVR5cGU6IFwic2NyaXB0XCIsXG5cdFx0Y2FjaGU6IHRydWUsXG5cdFx0YXN5bmM6IGZhbHNlLFxuXHRcdGdsb2JhbDogZmFsc2UsXG5cblx0XHQvLyBPbmx5IGV2YWx1YXRlIHRoZSByZXNwb25zZSBpZiBpdCBpcyBzdWNjZXNzZnVsIChnaC00MTI2KVxuXHRcdC8vIGRhdGFGaWx0ZXIgaXMgbm90IGludm9rZWQgZm9yIGZhaWx1cmUgcmVzcG9uc2VzLCBzbyB1c2luZyBpdCBpbnN0ZWFkXG5cdFx0Ly8gb2YgdGhlIGRlZmF1bHQgY29udmVydGVyIGlzIGtsdWRneSBidXQgaXQgd29ya3MuXG5cdFx0Y29udmVydGVyczoge1xuXHRcdFx0XCJ0ZXh0IHNjcmlwdFwiOiBmdW5jdGlvbigpIHt9XG5cdFx0fSxcblx0XHRkYXRhRmlsdGVyOiBmdW5jdGlvbiggcmVzcG9uc2UgKSB7XG5cdFx0XHRqUXVlcnkuZ2xvYmFsRXZhbCggcmVzcG9uc2UsIG9wdGlvbnMsIGRvYyApO1xuXHRcdH1cblx0fSApO1xufTtcblxuXG5qUXVlcnkuZm4uZXh0ZW5kKCB7XG5cdHdyYXBBbGw6IGZ1bmN0aW9uKCBodG1sICkge1xuXHRcdHZhciB3cmFwO1xuXG5cdFx0aWYgKCB0aGlzWyAwIF0gKSB7XG5cdFx0XHRpZiAoIGlzRnVuY3Rpb24oIGh0bWwgKSApIHtcblx0XHRcdFx0aHRtbCA9IGh0bWwuY2FsbCggdGhpc1sgMCBdICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFRoZSBlbGVtZW50cyB0byB3cmFwIHRoZSB0YXJnZXQgYXJvdW5kXG5cdFx0XHR3cmFwID0galF1ZXJ5KCBodG1sLCB0aGlzWyAwIF0ub3duZXJEb2N1bWVudCApLmVxKCAwICkuY2xvbmUoIHRydWUgKTtcblxuXHRcdFx0aWYgKCB0aGlzWyAwIF0ucGFyZW50Tm9kZSApIHtcblx0XHRcdFx0d3JhcC5pbnNlcnRCZWZvcmUoIHRoaXNbIDAgXSApO1xuXHRcdFx0fVxuXG5cdFx0XHR3cmFwLm1hcCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBlbGVtID0gdGhpcztcblxuXHRcdFx0XHR3aGlsZSAoIGVsZW0uZmlyc3RFbGVtZW50Q2hpbGQgKSB7XG5cdFx0XHRcdFx0ZWxlbSA9IGVsZW0uZmlyc3RFbGVtZW50Q2hpbGQ7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXR1cm4gZWxlbTtcblx0XHRcdH0gKS5hcHBlbmQoIHRoaXMgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHR3cmFwSW5uZXI6IGZ1bmN0aW9uKCBodG1sICkge1xuXHRcdGlmICggaXNGdW5jdGlvbiggaHRtbCApICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oIGkgKSB7XG5cdFx0XHRcdGpRdWVyeSggdGhpcyApLndyYXBJbm5lciggaHRtbC5jYWxsKCB0aGlzLCBpICkgKTtcblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBzZWxmID0galF1ZXJ5KCB0aGlzICksXG5cdFx0XHRcdGNvbnRlbnRzID0gc2VsZi5jb250ZW50cygpO1xuXG5cdFx0XHRpZiAoIGNvbnRlbnRzLmxlbmd0aCApIHtcblx0XHRcdFx0Y29udGVudHMud3JhcEFsbCggaHRtbCApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRzZWxmLmFwcGVuZCggaHRtbCApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHR3cmFwOiBmdW5jdGlvbiggaHRtbCApIHtcblx0XHR2YXIgaHRtbElzRnVuY3Rpb24gPSBpc0Z1bmN0aW9uKCBodG1sICk7XG5cblx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbiggaSApIHtcblx0XHRcdGpRdWVyeSggdGhpcyApLndyYXBBbGwoIGh0bWxJc0Z1bmN0aW9uID8gaHRtbC5jYWxsKCB0aGlzLCBpICkgOiBodG1sICk7XG5cdFx0fSApO1xuXHR9LFxuXG5cdHVud3JhcDogZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdHRoaXMucGFyZW50KCBzZWxlY3RvciApLm5vdCggXCJib2R5XCIgKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdGpRdWVyeSggdGhpcyApLnJlcGxhY2VXaXRoKCB0aGlzLmNoaWxkTm9kZXMgKTtcblx0XHR9ICk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cbn0gKTtcblxuXG5qUXVlcnkuZXhwci5wc2V1ZG9zLmhpZGRlbiA9IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRyZXR1cm4gIWpRdWVyeS5leHByLnBzZXVkb3MudmlzaWJsZSggZWxlbSApO1xufTtcbmpRdWVyeS5leHByLnBzZXVkb3MudmlzaWJsZSA9IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRyZXR1cm4gISEoIGVsZW0ub2Zmc2V0V2lkdGggfHwgZWxlbS5vZmZzZXRIZWlnaHQgfHwgZWxlbS5nZXRDbGllbnRSZWN0cygpLmxlbmd0aCApO1xufTtcblxuXG5cblxualF1ZXJ5LmFqYXhTZXR0aW5ncy54aHIgPSBmdW5jdGlvbigpIHtcblx0dHJ5IHtcblx0XHRyZXR1cm4gbmV3IHdpbmRvdy5YTUxIdHRwUmVxdWVzdCgpO1xuXHR9IGNhdGNoICggZSApIHt9XG59O1xuXG52YXIgeGhyU3VjY2Vzc1N0YXR1cyA9IHtcblxuXHRcdC8vIEZpbGUgcHJvdG9jb2wgYWx3YXlzIHlpZWxkcyBzdGF0dXMgY29kZSAwLCBhc3N1bWUgMjAwXG5cdFx0MDogMjAwLFxuXG5cdFx0Ly8gU3VwcG9ydDogSUUgPD05IG9ubHlcblx0XHQvLyAjMTQ1MDogc29tZXRpbWVzIElFIHJldHVybnMgMTIyMyB3aGVuIGl0IHNob3VsZCBiZSAyMDRcblx0XHQxMjIzOiAyMDRcblx0fSxcblx0eGhyU3VwcG9ydGVkID0galF1ZXJ5LmFqYXhTZXR0aW5ncy54aHIoKTtcblxuc3VwcG9ydC5jb3JzID0gISF4aHJTdXBwb3J0ZWQgJiYgKCBcIndpdGhDcmVkZW50aWFsc1wiIGluIHhoclN1cHBvcnRlZCApO1xuc3VwcG9ydC5hamF4ID0geGhyU3VwcG9ydGVkID0gISF4aHJTdXBwb3J0ZWQ7XG5cbmpRdWVyeS5hamF4VHJhbnNwb3J0KCBmdW5jdGlvbiggb3B0aW9ucyApIHtcblx0dmFyIGNhbGxiYWNrLCBlcnJvckNhbGxiYWNrO1xuXG5cdC8vIENyb3NzIGRvbWFpbiBvbmx5IGFsbG93ZWQgaWYgc3VwcG9ydGVkIHRocm91Z2ggWE1MSHR0cFJlcXVlc3Rcblx0aWYgKCBzdXBwb3J0LmNvcnMgfHwgeGhyU3VwcG9ydGVkICYmICFvcHRpb25zLmNyb3NzRG9tYWluICkge1xuXHRcdHJldHVybiB7XG5cdFx0XHRzZW5kOiBmdW5jdGlvbiggaGVhZGVycywgY29tcGxldGUgKSB7XG5cdFx0XHRcdHZhciBpLFxuXHRcdFx0XHRcdHhociA9IG9wdGlvbnMueGhyKCk7XG5cblx0XHRcdFx0eGhyLm9wZW4oXG5cdFx0XHRcdFx0b3B0aW9ucy50eXBlLFxuXHRcdFx0XHRcdG9wdGlvbnMudXJsLFxuXHRcdFx0XHRcdG9wdGlvbnMuYXN5bmMsXG5cdFx0XHRcdFx0b3B0aW9ucy51c2VybmFtZSxcblx0XHRcdFx0XHRvcHRpb25zLnBhc3N3b3JkXG5cdFx0XHRcdCk7XG5cblx0XHRcdFx0Ly8gQXBwbHkgY3VzdG9tIGZpZWxkcyBpZiBwcm92aWRlZFxuXHRcdFx0XHRpZiAoIG9wdGlvbnMueGhyRmllbGRzICkge1xuXHRcdFx0XHRcdGZvciAoIGkgaW4gb3B0aW9ucy54aHJGaWVsZHMgKSB7XG5cdFx0XHRcdFx0XHR4aHJbIGkgXSA9IG9wdGlvbnMueGhyRmllbGRzWyBpIF07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gT3ZlcnJpZGUgbWltZSB0eXBlIGlmIG5lZWRlZFxuXHRcdFx0XHRpZiAoIG9wdGlvbnMubWltZVR5cGUgJiYgeGhyLm92ZXJyaWRlTWltZVR5cGUgKSB7XG5cdFx0XHRcdFx0eGhyLm92ZXJyaWRlTWltZVR5cGUoIG9wdGlvbnMubWltZVR5cGUgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFgtUmVxdWVzdGVkLVdpdGggaGVhZGVyXG5cdFx0XHRcdC8vIEZvciBjcm9zcy1kb21haW4gcmVxdWVzdHMsIHNlZWluZyBhcyBjb25kaXRpb25zIGZvciBhIHByZWZsaWdodCBhcmVcblx0XHRcdFx0Ly8gYWtpbiB0byBhIGppZ3NhdyBwdXp6bGUsIHdlIHNpbXBseSBuZXZlciBzZXQgaXQgdG8gYmUgc3VyZS5cblx0XHRcdFx0Ly8gKGl0IGNhbiBhbHdheXMgYmUgc2V0IG9uIGEgcGVyLXJlcXVlc3QgYmFzaXMgb3IgZXZlbiB1c2luZyBhamF4U2V0dXApXG5cdFx0XHRcdC8vIEZvciBzYW1lLWRvbWFpbiByZXF1ZXN0cywgd29uJ3QgY2hhbmdlIGhlYWRlciBpZiBhbHJlYWR5IHByb3ZpZGVkLlxuXHRcdFx0XHRpZiAoICFvcHRpb25zLmNyb3NzRG9tYWluICYmICFoZWFkZXJzWyBcIlgtUmVxdWVzdGVkLVdpdGhcIiBdICkge1xuXHRcdFx0XHRcdGhlYWRlcnNbIFwiWC1SZXF1ZXN0ZWQtV2l0aFwiIF0gPSBcIlhNTEh0dHBSZXF1ZXN0XCI7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBTZXQgaGVhZGVyc1xuXHRcdFx0XHRmb3IgKCBpIGluIGhlYWRlcnMgKSB7XG5cdFx0XHRcdFx0eGhyLnNldFJlcXVlc3RIZWFkZXIoIGksIGhlYWRlcnNbIGkgXSApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gQ2FsbGJhY2tcblx0XHRcdFx0Y2FsbGJhY2sgPSBmdW5jdGlvbiggdHlwZSApIHtcblx0XHRcdFx0XHRyZXR1cm4gZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRpZiAoIGNhbGxiYWNrICkge1xuXHRcdFx0XHRcdFx0XHRjYWxsYmFjayA9IGVycm9yQ2FsbGJhY2sgPSB4aHIub25sb2FkID1cblx0XHRcdFx0XHRcdFx0XHR4aHIub25lcnJvciA9IHhoci5vbmFib3J0ID0geGhyLm9udGltZW91dCA9XG5cdFx0XHRcdFx0XHRcdFx0XHR4aHIub25yZWFkeXN0YXRlY2hhbmdlID0gbnVsbDtcblxuXHRcdFx0XHRcdFx0XHRpZiAoIHR5cGUgPT09IFwiYWJvcnRcIiApIHtcblx0XHRcdFx0XHRcdFx0XHR4aHIuYWJvcnQoKTtcblx0XHRcdFx0XHRcdFx0fSBlbHNlIGlmICggdHlwZSA9PT0gXCJlcnJvclwiICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0Ly8gU3VwcG9ydDogSUUgPD05IG9ubHlcblx0XHRcdFx0XHRcdFx0XHQvLyBPbiBhIG1hbnVhbCBuYXRpdmUgYWJvcnQsIElFOSB0aHJvd3Ncblx0XHRcdFx0XHRcdFx0XHQvLyBlcnJvcnMgb24gYW55IHByb3BlcnR5IGFjY2VzcyB0aGF0IGlzIG5vdCByZWFkeVN0YXRlXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCB0eXBlb2YgeGhyLnN0YXR1cyAhPT0gXCJudW1iZXJcIiApIHtcblx0XHRcdFx0XHRcdFx0XHRcdGNvbXBsZXRlKCAwLCBcImVycm9yXCIgKTtcblx0XHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdFx0Y29tcGxldGUoXG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gRmlsZTogcHJvdG9jb2wgYWx3YXlzIHlpZWxkcyBzdGF0dXMgMDsgc2VlICM4NjA1LCAjMTQyMDdcblx0XHRcdFx0XHRcdFx0XHRcdFx0eGhyLnN0YXR1cyxcblx0XHRcdFx0XHRcdFx0XHRcdFx0eGhyLnN0YXR1c1RleHRcblx0XHRcdFx0XHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdGNvbXBsZXRlKFxuXHRcdFx0XHRcdFx0XHRcdFx0eGhyU3VjY2Vzc1N0YXR1c1sgeGhyLnN0YXR1cyBdIHx8IHhoci5zdGF0dXMsXG5cdFx0XHRcdFx0XHRcdFx0XHR4aHIuc3RhdHVzVGV4dCxcblxuXHRcdFx0XHRcdFx0XHRcdFx0Ly8gU3VwcG9ydDogSUUgPD05IG9ubHlcblx0XHRcdFx0XHRcdFx0XHRcdC8vIElFOSBoYXMgbm8gWEhSMiBidXQgdGhyb3dzIG9uIGJpbmFyeSAodHJhYy0xMTQyNilcblx0XHRcdFx0XHRcdFx0XHRcdC8vIEZvciBYSFIyIG5vbi10ZXh0LCBsZXQgdGhlIGNhbGxlciBoYW5kbGUgaXQgKGdoLTI0OTgpXG5cdFx0XHRcdFx0XHRcdFx0XHQoIHhoci5yZXNwb25zZVR5cGUgfHwgXCJ0ZXh0XCIgKSAhPT0gXCJ0ZXh0XCIgIHx8XG5cdFx0XHRcdFx0XHRcdFx0XHR0eXBlb2YgeGhyLnJlc3BvbnNlVGV4dCAhPT0gXCJzdHJpbmdcIiA/XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHsgYmluYXJ5OiB4aHIucmVzcG9uc2UgfSA6XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHsgdGV4dDogeGhyLnJlc3BvbnNlVGV4dCB9LFxuXHRcdFx0XHRcdFx0XHRcdFx0eGhyLmdldEFsbFJlc3BvbnNlSGVhZGVycygpXG5cdFx0XHRcdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH07XG5cdFx0XHRcdH07XG5cblx0XHRcdFx0Ly8gTGlzdGVuIHRvIGV2ZW50c1xuXHRcdFx0XHR4aHIub25sb2FkID0gY2FsbGJhY2soKTtcblx0XHRcdFx0ZXJyb3JDYWxsYmFjayA9IHhoci5vbmVycm9yID0geGhyLm9udGltZW91dCA9IGNhbGxiYWNrKCBcImVycm9yXCIgKTtcblxuXHRcdFx0XHQvLyBTdXBwb3J0OiBJRSA5IG9ubHlcblx0XHRcdFx0Ly8gVXNlIG9ucmVhZHlzdGF0ZWNoYW5nZSB0byByZXBsYWNlIG9uYWJvcnRcblx0XHRcdFx0Ly8gdG8gaGFuZGxlIHVuY2F1Z2h0IGFib3J0c1xuXHRcdFx0XHRpZiAoIHhoci5vbmFib3J0ICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0eGhyLm9uYWJvcnQgPSBlcnJvckNhbGxiYWNrO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHhoci5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBmdW5jdGlvbigpIHtcblxuXHRcdFx0XHRcdFx0Ly8gQ2hlY2sgcmVhZHlTdGF0ZSBiZWZvcmUgdGltZW91dCBhcyBpdCBjaGFuZ2VzXG5cdFx0XHRcdFx0XHRpZiAoIHhoci5yZWFkeVN0YXRlID09PSA0ICkge1xuXG5cdFx0XHRcdFx0XHRcdC8vIEFsbG93IG9uZXJyb3IgdG8gYmUgY2FsbGVkIGZpcnN0LFxuXHRcdFx0XHRcdFx0XHQvLyBidXQgdGhhdCB3aWxsIG5vdCBoYW5kbGUgYSBuYXRpdmUgYWJvcnRcblx0XHRcdFx0XHRcdFx0Ly8gQWxzbywgc2F2ZSBlcnJvckNhbGxiYWNrIHRvIGEgdmFyaWFibGVcblx0XHRcdFx0XHRcdFx0Ly8gYXMgeGhyLm9uZXJyb3IgY2Fubm90IGJlIGFjY2Vzc2VkXG5cdFx0XHRcdFx0XHRcdHdpbmRvdy5zZXRUaW1lb3V0KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdFx0XHRpZiAoIGNhbGxiYWNrICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0ZXJyb3JDYWxsYmFjaygpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fSApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH07XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBDcmVhdGUgdGhlIGFib3J0IGNhbGxiYWNrXG5cdFx0XHRcdGNhbGxiYWNrID0gY2FsbGJhY2soIFwiYWJvcnRcIiApO1xuXG5cdFx0XHRcdHRyeSB7XG5cblx0XHRcdFx0XHQvLyBEbyBzZW5kIHRoZSByZXF1ZXN0ICh0aGlzIG1heSByYWlzZSBhbiBleGNlcHRpb24pXG5cdFx0XHRcdFx0eGhyLnNlbmQoIG9wdGlvbnMuaGFzQ29udGVudCAmJiBvcHRpb25zLmRhdGEgfHwgbnVsbCApO1xuXHRcdFx0XHR9IGNhdGNoICggZSApIHtcblxuXHRcdFx0XHRcdC8vICMxNDY4MzogT25seSByZXRocm93IGlmIHRoaXMgaGFzbid0IGJlZW4gbm90aWZpZWQgYXMgYW4gZXJyb3IgeWV0XG5cdFx0XHRcdFx0aWYgKCBjYWxsYmFjayApIHtcblx0XHRcdFx0XHRcdHRocm93IGU7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXG5cdFx0XHRhYm9ydDogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggY2FsbGJhY2sgKSB7XG5cdFx0XHRcdFx0Y2FsbGJhY2soKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH07XG5cdH1cbn0gKTtcblxuXG5cblxuLy8gUHJldmVudCBhdXRvLWV4ZWN1dGlvbiBvZiBzY3JpcHRzIHdoZW4gbm8gZXhwbGljaXQgZGF0YVR5cGUgd2FzIHByb3ZpZGVkIChTZWUgZ2gtMjQzMilcbmpRdWVyeS5hamF4UHJlZmlsdGVyKCBmdW5jdGlvbiggcyApIHtcblx0aWYgKCBzLmNyb3NzRG9tYWluICkge1xuXHRcdHMuY29udGVudHMuc2NyaXB0ID0gZmFsc2U7XG5cdH1cbn0gKTtcblxuLy8gSW5zdGFsbCBzY3JpcHQgZGF0YVR5cGVcbmpRdWVyeS5hamF4U2V0dXAoIHtcblx0YWNjZXB0czoge1xuXHRcdHNjcmlwdDogXCJ0ZXh0L2phdmFzY3JpcHQsIGFwcGxpY2F0aW9uL2phdmFzY3JpcHQsIFwiICtcblx0XHRcdFwiYXBwbGljYXRpb24vZWNtYXNjcmlwdCwgYXBwbGljYXRpb24veC1lY21hc2NyaXB0XCJcblx0fSxcblx0Y29udGVudHM6IHtcblx0XHRzY3JpcHQ6IC9cXGIoPzpqYXZhfGVjbWEpc2NyaXB0XFxiL1xuXHR9LFxuXHRjb252ZXJ0ZXJzOiB7XG5cdFx0XCJ0ZXh0IHNjcmlwdFwiOiBmdW5jdGlvbiggdGV4dCApIHtcblx0XHRcdGpRdWVyeS5nbG9iYWxFdmFsKCB0ZXh0ICk7XG5cdFx0XHRyZXR1cm4gdGV4dDtcblx0XHR9XG5cdH1cbn0gKTtcblxuLy8gSGFuZGxlIGNhY2hlJ3Mgc3BlY2lhbCBjYXNlIGFuZCBjcm9zc0RvbWFpblxualF1ZXJ5LmFqYXhQcmVmaWx0ZXIoIFwic2NyaXB0XCIsIGZ1bmN0aW9uKCBzICkge1xuXHRpZiAoIHMuY2FjaGUgPT09IHVuZGVmaW5lZCApIHtcblx0XHRzLmNhY2hlID0gZmFsc2U7XG5cdH1cblx0aWYgKCBzLmNyb3NzRG9tYWluICkge1xuXHRcdHMudHlwZSA9IFwiR0VUXCI7XG5cdH1cbn0gKTtcblxuLy8gQmluZCBzY3JpcHQgdGFnIGhhY2sgdHJhbnNwb3J0XG5qUXVlcnkuYWpheFRyYW5zcG9ydCggXCJzY3JpcHRcIiwgZnVuY3Rpb24oIHMgKSB7XG5cblx0Ly8gVGhpcyB0cmFuc3BvcnQgb25seSBkZWFscyB3aXRoIGNyb3NzIGRvbWFpbiBvciBmb3JjZWQtYnktYXR0cnMgcmVxdWVzdHNcblx0aWYgKCBzLmNyb3NzRG9tYWluIHx8IHMuc2NyaXB0QXR0cnMgKSB7XG5cdFx0dmFyIHNjcmlwdCwgY2FsbGJhY2s7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHNlbmQ6IGZ1bmN0aW9uKCBfLCBjb21wbGV0ZSApIHtcblx0XHRcdFx0c2NyaXB0ID0galF1ZXJ5KCBcIjxzY3JpcHQ+XCIgKVxuXHRcdFx0XHRcdC5hdHRyKCBzLnNjcmlwdEF0dHJzIHx8IHt9IClcblx0XHRcdFx0XHQucHJvcCggeyBjaGFyc2V0OiBzLnNjcmlwdENoYXJzZXQsIHNyYzogcy51cmwgfSApXG5cdFx0XHRcdFx0Lm9uKCBcImxvYWQgZXJyb3JcIiwgY2FsbGJhY2sgPSBmdW5jdGlvbiggZXZ0ICkge1xuXHRcdFx0XHRcdFx0c2NyaXB0LnJlbW92ZSgpO1xuXHRcdFx0XHRcdFx0Y2FsbGJhY2sgPSBudWxsO1xuXHRcdFx0XHRcdFx0aWYgKCBldnQgKSB7XG5cdFx0XHRcdFx0XHRcdGNvbXBsZXRlKCBldnQudHlwZSA9PT0gXCJlcnJvclwiID8gNDA0IDogMjAwLCBldnQudHlwZSApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0gKTtcblxuXHRcdFx0XHQvLyBVc2UgbmF0aXZlIERPTSBtYW5pcHVsYXRpb24gdG8gYXZvaWQgb3VyIGRvbU1hbmlwIEFKQVggdHJpY2tlcnlcblx0XHRcdFx0ZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZCggc2NyaXB0WyAwIF0gKTtcblx0XHRcdH0sXG5cdFx0XHRhYm9ydDogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggY2FsbGJhY2sgKSB7XG5cdFx0XHRcdFx0Y2FsbGJhY2soKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH07XG5cdH1cbn0gKTtcblxuXG5cblxudmFyIG9sZENhbGxiYWNrcyA9IFtdLFxuXHRyanNvbnAgPSAvKD0pXFw/KD89JnwkKXxcXD9cXD8vO1xuXG4vLyBEZWZhdWx0IGpzb25wIHNldHRpbmdzXG5qUXVlcnkuYWpheFNldHVwKCB7XG5cdGpzb25wOiBcImNhbGxiYWNrXCIsXG5cdGpzb25wQ2FsbGJhY2s6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBjYWxsYmFjayA9IG9sZENhbGxiYWNrcy5wb3AoKSB8fCAoIGpRdWVyeS5leHBhbmRvICsgXCJfXCIgKyAoIG5vbmNlLmd1aWQrKyApICk7XG5cdFx0dGhpc1sgY2FsbGJhY2sgXSA9IHRydWU7XG5cdFx0cmV0dXJuIGNhbGxiYWNrO1xuXHR9XG59ICk7XG5cbi8vIERldGVjdCwgbm9ybWFsaXplIG9wdGlvbnMgYW5kIGluc3RhbGwgY2FsbGJhY2tzIGZvciBqc29ucCByZXF1ZXN0c1xualF1ZXJ5LmFqYXhQcmVmaWx0ZXIoIFwianNvbiBqc29ucFwiLCBmdW5jdGlvbiggcywgb3JpZ2luYWxTZXR0aW5ncywganFYSFIgKSB7XG5cblx0dmFyIGNhbGxiYWNrTmFtZSwgb3ZlcndyaXR0ZW4sIHJlc3BvbnNlQ29udGFpbmVyLFxuXHRcdGpzb25Qcm9wID0gcy5qc29ucCAhPT0gZmFsc2UgJiYgKCByanNvbnAudGVzdCggcy51cmwgKSA/XG5cdFx0XHRcInVybFwiIDpcblx0XHRcdHR5cGVvZiBzLmRhdGEgPT09IFwic3RyaW5nXCIgJiZcblx0XHRcdFx0KCBzLmNvbnRlbnRUeXBlIHx8IFwiXCIgKVxuXHRcdFx0XHRcdC5pbmRleE9mKCBcImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZFwiICkgPT09IDAgJiZcblx0XHRcdFx0cmpzb25wLnRlc3QoIHMuZGF0YSApICYmIFwiZGF0YVwiXG5cdFx0KTtcblxuXHQvLyBIYW5kbGUgaWZmIHRoZSBleHBlY3RlZCBkYXRhIHR5cGUgaXMgXCJqc29ucFwiIG9yIHdlIGhhdmUgYSBwYXJhbWV0ZXIgdG8gc2V0XG5cdGlmICgganNvblByb3AgfHwgcy5kYXRhVHlwZXNbIDAgXSA9PT0gXCJqc29ucFwiICkge1xuXG5cdFx0Ly8gR2V0IGNhbGxiYWNrIG5hbWUsIHJlbWVtYmVyaW5nIHByZWV4aXN0aW5nIHZhbHVlIGFzc29jaWF0ZWQgd2l0aCBpdFxuXHRcdGNhbGxiYWNrTmFtZSA9IHMuanNvbnBDYWxsYmFjayA9IGlzRnVuY3Rpb24oIHMuanNvbnBDYWxsYmFjayApID9cblx0XHRcdHMuanNvbnBDYWxsYmFjaygpIDpcblx0XHRcdHMuanNvbnBDYWxsYmFjaztcblxuXHRcdC8vIEluc2VydCBjYWxsYmFjayBpbnRvIHVybCBvciBmb3JtIGRhdGFcblx0XHRpZiAoIGpzb25Qcm9wICkge1xuXHRcdFx0c1sganNvblByb3AgXSA9IHNbIGpzb25Qcm9wIF0ucmVwbGFjZSggcmpzb25wLCBcIiQxXCIgKyBjYWxsYmFja05hbWUgKTtcblx0XHR9IGVsc2UgaWYgKCBzLmpzb25wICE9PSBmYWxzZSApIHtcblx0XHRcdHMudXJsICs9ICggcnF1ZXJ5LnRlc3QoIHMudXJsICkgPyBcIiZcIiA6IFwiP1wiICkgKyBzLmpzb25wICsgXCI9XCIgKyBjYWxsYmFja05hbWU7XG5cdFx0fVxuXG5cdFx0Ly8gVXNlIGRhdGEgY29udmVydGVyIHRvIHJldHJpZXZlIGpzb24gYWZ0ZXIgc2NyaXB0IGV4ZWN1dGlvblxuXHRcdHMuY29udmVydGVyc1sgXCJzY3JpcHQganNvblwiIF0gPSBmdW5jdGlvbigpIHtcblx0XHRcdGlmICggIXJlc3BvbnNlQ29udGFpbmVyICkge1xuXHRcdFx0XHRqUXVlcnkuZXJyb3IoIGNhbGxiYWNrTmFtZSArIFwiIHdhcyBub3QgY2FsbGVkXCIgKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiByZXNwb25zZUNvbnRhaW5lclsgMCBdO1xuXHRcdH07XG5cblx0XHQvLyBGb3JjZSBqc29uIGRhdGFUeXBlXG5cdFx0cy5kYXRhVHlwZXNbIDAgXSA9IFwianNvblwiO1xuXG5cdFx0Ly8gSW5zdGFsbCBjYWxsYmFja1xuXHRcdG92ZXJ3cml0dGVuID0gd2luZG93WyBjYWxsYmFja05hbWUgXTtcblx0XHR3aW5kb3dbIGNhbGxiYWNrTmFtZSBdID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRyZXNwb25zZUNvbnRhaW5lciA9IGFyZ3VtZW50cztcblx0XHR9O1xuXG5cdFx0Ly8gQ2xlYW4tdXAgZnVuY3Rpb24gKGZpcmVzIGFmdGVyIGNvbnZlcnRlcnMpXG5cdFx0anFYSFIuYWx3YXlzKCBmdW5jdGlvbigpIHtcblxuXHRcdFx0Ly8gSWYgcHJldmlvdXMgdmFsdWUgZGlkbid0IGV4aXN0IC0gcmVtb3ZlIGl0XG5cdFx0XHRpZiAoIG92ZXJ3cml0dGVuID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdGpRdWVyeSggd2luZG93ICkucmVtb3ZlUHJvcCggY2FsbGJhY2tOYW1lICk7XG5cblx0XHRcdC8vIE90aGVyd2lzZSByZXN0b3JlIHByZWV4aXN0aW5nIHZhbHVlXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR3aW5kb3dbIGNhbGxiYWNrTmFtZSBdID0gb3ZlcndyaXR0ZW47XG5cdFx0XHR9XG5cblx0XHRcdC8vIFNhdmUgYmFjayBhcyBmcmVlXG5cdFx0XHRpZiAoIHNbIGNhbGxiYWNrTmFtZSBdICkge1xuXG5cdFx0XHRcdC8vIE1ha2Ugc3VyZSB0aGF0IHJlLXVzaW5nIHRoZSBvcHRpb25zIGRvZXNuJ3Qgc2NyZXcgdGhpbmdzIGFyb3VuZFxuXHRcdFx0XHRzLmpzb25wQ2FsbGJhY2sgPSBvcmlnaW5hbFNldHRpbmdzLmpzb25wQ2FsbGJhY2s7XG5cblx0XHRcdFx0Ly8gU2F2ZSB0aGUgY2FsbGJhY2sgbmFtZSBmb3IgZnV0dXJlIHVzZVxuXHRcdFx0XHRvbGRDYWxsYmFja3MucHVzaCggY2FsbGJhY2tOYW1lICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIENhbGwgaWYgaXQgd2FzIGEgZnVuY3Rpb24gYW5kIHdlIGhhdmUgYSByZXNwb25zZVxuXHRcdFx0aWYgKCByZXNwb25zZUNvbnRhaW5lciAmJiBpc0Z1bmN0aW9uKCBvdmVyd3JpdHRlbiApICkge1xuXHRcdFx0XHRvdmVyd3JpdHRlbiggcmVzcG9uc2VDb250YWluZXJbIDAgXSApO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXNwb25zZUNvbnRhaW5lciA9IG92ZXJ3cml0dGVuID0gdW5kZWZpbmVkO1xuXHRcdH0gKTtcblxuXHRcdC8vIERlbGVnYXRlIHRvIHNjcmlwdFxuXHRcdHJldHVybiBcInNjcmlwdFwiO1xuXHR9XG59ICk7XG5cblxuXG5cbi8vIFN1cHBvcnQ6IFNhZmFyaSA4IG9ubHlcbi8vIEluIFNhZmFyaSA4IGRvY3VtZW50cyBjcmVhdGVkIHZpYSBkb2N1bWVudC5pbXBsZW1lbnRhdGlvbi5jcmVhdGVIVE1MRG9jdW1lbnRcbi8vIGNvbGxhcHNlIHNpYmxpbmcgZm9ybXM6IHRoZSBzZWNvbmQgb25lIGJlY29tZXMgYSBjaGlsZCBvZiB0aGUgZmlyc3Qgb25lLlxuLy8gQmVjYXVzZSBvZiB0aGF0LCB0aGlzIHNlY3VyaXR5IG1lYXN1cmUgaGFzIHRvIGJlIGRpc2FibGVkIGluIFNhZmFyaSA4LlxuLy8gaHR0cHM6Ly9idWdzLndlYmtpdC5vcmcvc2hvd19idWcuY2dpP2lkPTEzNzMzN1xuc3VwcG9ydC5jcmVhdGVIVE1MRG9jdW1lbnQgPSAoIGZ1bmN0aW9uKCkge1xuXHR2YXIgYm9keSA9IGRvY3VtZW50LmltcGxlbWVudGF0aW9uLmNyZWF0ZUhUTUxEb2N1bWVudCggXCJcIiApLmJvZHk7XG5cdGJvZHkuaW5uZXJIVE1MID0gXCI8Zm9ybT48L2Zvcm0+PGZvcm0+PC9mb3JtPlwiO1xuXHRyZXR1cm4gYm9keS5jaGlsZE5vZGVzLmxlbmd0aCA9PT0gMjtcbn0gKSgpO1xuXG5cbi8vIEFyZ3VtZW50IFwiZGF0YVwiIHNob3VsZCBiZSBzdHJpbmcgb2YgaHRtbFxuLy8gY29udGV4dCAob3B0aW9uYWwpOiBJZiBzcGVjaWZpZWQsIHRoZSBmcmFnbWVudCB3aWxsIGJlIGNyZWF0ZWQgaW4gdGhpcyBjb250ZXh0LFxuLy8gZGVmYXVsdHMgdG8gZG9jdW1lbnRcbi8vIGtlZXBTY3JpcHRzIChvcHRpb25hbCk6IElmIHRydWUsIHdpbGwgaW5jbHVkZSBzY3JpcHRzIHBhc3NlZCBpbiB0aGUgaHRtbCBzdHJpbmdcbmpRdWVyeS5wYXJzZUhUTUwgPSBmdW5jdGlvbiggZGF0YSwgY29udGV4dCwga2VlcFNjcmlwdHMgKSB7XG5cdGlmICggdHlwZW9mIGRhdGEgIT09IFwic3RyaW5nXCIgKSB7XG5cdFx0cmV0dXJuIFtdO1xuXHR9XG5cdGlmICggdHlwZW9mIGNvbnRleHQgPT09IFwiYm9vbGVhblwiICkge1xuXHRcdGtlZXBTY3JpcHRzID0gY29udGV4dDtcblx0XHRjb250ZXh0ID0gZmFsc2U7XG5cdH1cblxuXHR2YXIgYmFzZSwgcGFyc2VkLCBzY3JpcHRzO1xuXG5cdGlmICggIWNvbnRleHQgKSB7XG5cblx0XHQvLyBTdG9wIHNjcmlwdHMgb3IgaW5saW5lIGV2ZW50IGhhbmRsZXJzIGZyb20gYmVpbmcgZXhlY3V0ZWQgaW1tZWRpYXRlbHlcblx0XHQvLyBieSB1c2luZyBkb2N1bWVudC5pbXBsZW1lbnRhdGlvblxuXHRcdGlmICggc3VwcG9ydC5jcmVhdGVIVE1MRG9jdW1lbnQgKSB7XG5cdFx0XHRjb250ZXh0ID0gZG9jdW1lbnQuaW1wbGVtZW50YXRpb24uY3JlYXRlSFRNTERvY3VtZW50KCBcIlwiICk7XG5cblx0XHRcdC8vIFNldCB0aGUgYmFzZSBocmVmIGZvciB0aGUgY3JlYXRlZCBkb2N1bWVudFxuXHRcdFx0Ly8gc28gYW55IHBhcnNlZCBlbGVtZW50cyB3aXRoIFVSTHNcblx0XHRcdC8vIGFyZSBiYXNlZCBvbiB0aGUgZG9jdW1lbnQncyBVUkwgKGdoLTI5NjUpXG5cdFx0XHRiYXNlID0gY29udGV4dC5jcmVhdGVFbGVtZW50KCBcImJhc2VcIiApO1xuXHRcdFx0YmFzZS5ocmVmID0gZG9jdW1lbnQubG9jYXRpb24uaHJlZjtcblx0XHRcdGNvbnRleHQuaGVhZC5hcHBlbmRDaGlsZCggYmFzZSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRjb250ZXh0ID0gZG9jdW1lbnQ7XG5cdFx0fVxuXHR9XG5cblx0cGFyc2VkID0gcnNpbmdsZVRhZy5leGVjKCBkYXRhICk7XG5cdHNjcmlwdHMgPSAha2VlcFNjcmlwdHMgJiYgW107XG5cblx0Ly8gU2luZ2xlIHRhZ1xuXHRpZiAoIHBhcnNlZCApIHtcblx0XHRyZXR1cm4gWyBjb250ZXh0LmNyZWF0ZUVsZW1lbnQoIHBhcnNlZFsgMSBdICkgXTtcblx0fVxuXG5cdHBhcnNlZCA9IGJ1aWxkRnJhZ21lbnQoIFsgZGF0YSBdLCBjb250ZXh0LCBzY3JpcHRzICk7XG5cblx0aWYgKCBzY3JpcHRzICYmIHNjcmlwdHMubGVuZ3RoICkge1xuXHRcdGpRdWVyeSggc2NyaXB0cyApLnJlbW92ZSgpO1xuXHR9XG5cblx0cmV0dXJuIGpRdWVyeS5tZXJnZSggW10sIHBhcnNlZC5jaGlsZE5vZGVzICk7XG59O1xuXG5cbi8qKlxuICogTG9hZCBhIHVybCBpbnRvIGEgcGFnZVxuICovXG5qUXVlcnkuZm4ubG9hZCA9IGZ1bmN0aW9uKCB1cmwsIHBhcmFtcywgY2FsbGJhY2sgKSB7XG5cdHZhciBzZWxlY3RvciwgdHlwZSwgcmVzcG9uc2UsXG5cdFx0c2VsZiA9IHRoaXMsXG5cdFx0b2ZmID0gdXJsLmluZGV4T2YoIFwiIFwiICk7XG5cblx0aWYgKCBvZmYgPiAtMSApIHtcblx0XHRzZWxlY3RvciA9IHN0cmlwQW5kQ29sbGFwc2UoIHVybC5zbGljZSggb2ZmICkgKTtcblx0XHR1cmwgPSB1cmwuc2xpY2UoIDAsIG9mZiApO1xuXHR9XG5cblx0Ly8gSWYgaXQncyBhIGZ1bmN0aW9uXG5cdGlmICggaXNGdW5jdGlvbiggcGFyYW1zICkgKSB7XG5cblx0XHQvLyBXZSBhc3N1bWUgdGhhdCBpdCdzIHRoZSBjYWxsYmFja1xuXHRcdGNhbGxiYWNrID0gcGFyYW1zO1xuXHRcdHBhcmFtcyA9IHVuZGVmaW5lZDtcblxuXHQvLyBPdGhlcndpc2UsIGJ1aWxkIGEgcGFyYW0gc3RyaW5nXG5cdH0gZWxzZSBpZiAoIHBhcmFtcyAmJiB0eXBlb2YgcGFyYW1zID09PSBcIm9iamVjdFwiICkge1xuXHRcdHR5cGUgPSBcIlBPU1RcIjtcblx0fVxuXG5cdC8vIElmIHdlIGhhdmUgZWxlbWVudHMgdG8gbW9kaWZ5LCBtYWtlIHRoZSByZXF1ZXN0XG5cdGlmICggc2VsZi5sZW5ndGggPiAwICkge1xuXHRcdGpRdWVyeS5hamF4KCB7XG5cdFx0XHR1cmw6IHVybCxcblxuXHRcdFx0Ly8gSWYgXCJ0eXBlXCIgdmFyaWFibGUgaXMgdW5kZWZpbmVkLCB0aGVuIFwiR0VUXCIgbWV0aG9kIHdpbGwgYmUgdXNlZC5cblx0XHRcdC8vIE1ha2UgdmFsdWUgb2YgdGhpcyBmaWVsZCBleHBsaWNpdCBzaW5jZVxuXHRcdFx0Ly8gdXNlciBjYW4gb3ZlcnJpZGUgaXQgdGhyb3VnaCBhamF4U2V0dXAgbWV0aG9kXG5cdFx0XHR0eXBlOiB0eXBlIHx8IFwiR0VUXCIsXG5cdFx0XHRkYXRhVHlwZTogXCJodG1sXCIsXG5cdFx0XHRkYXRhOiBwYXJhbXNcblx0XHR9ICkuZG9uZSggZnVuY3Rpb24oIHJlc3BvbnNlVGV4dCApIHtcblxuXHRcdFx0Ly8gU2F2ZSByZXNwb25zZSBmb3IgdXNlIGluIGNvbXBsZXRlIGNhbGxiYWNrXG5cdFx0XHRyZXNwb25zZSA9IGFyZ3VtZW50cztcblxuXHRcdFx0c2VsZi5odG1sKCBzZWxlY3RvciA/XG5cblx0XHRcdFx0Ly8gSWYgYSBzZWxlY3RvciB3YXMgc3BlY2lmaWVkLCBsb2NhdGUgdGhlIHJpZ2h0IGVsZW1lbnRzIGluIGEgZHVtbXkgZGl2XG5cdFx0XHRcdC8vIEV4Y2x1ZGUgc2NyaXB0cyB0byBhdm9pZCBJRSAnUGVybWlzc2lvbiBEZW5pZWQnIGVycm9yc1xuXHRcdFx0XHRqUXVlcnkoIFwiPGRpdj5cIiApLmFwcGVuZCggalF1ZXJ5LnBhcnNlSFRNTCggcmVzcG9uc2VUZXh0ICkgKS5maW5kKCBzZWxlY3RvciApIDpcblxuXHRcdFx0XHQvLyBPdGhlcndpc2UgdXNlIHRoZSBmdWxsIHJlc3VsdFxuXHRcdFx0XHRyZXNwb25zZVRleHQgKTtcblxuXHRcdC8vIElmIHRoZSByZXF1ZXN0IHN1Y2NlZWRzLCB0aGlzIGZ1bmN0aW9uIGdldHMgXCJkYXRhXCIsIFwic3RhdHVzXCIsIFwianFYSFJcIlxuXHRcdC8vIGJ1dCB0aGV5IGFyZSBpZ25vcmVkIGJlY2F1c2UgcmVzcG9uc2Ugd2FzIHNldCBhYm92ZS5cblx0XHQvLyBJZiBpdCBmYWlscywgdGhpcyBmdW5jdGlvbiBnZXRzIFwianFYSFJcIiwgXCJzdGF0dXNcIiwgXCJlcnJvclwiXG5cdFx0fSApLmFsd2F5cyggY2FsbGJhY2sgJiYgZnVuY3Rpb24oIGpxWEhSLCBzdGF0dXMgKSB7XG5cdFx0XHRzZWxmLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRjYWxsYmFjay5hcHBseSggdGhpcywgcmVzcG9uc2UgfHwgWyBqcVhIUi5yZXNwb25zZVRleHQsIHN0YXR1cywganFYSFIgXSApO1xuXHRcdFx0fSApO1xuXHRcdH0gKTtcblx0fVxuXG5cdHJldHVybiB0aGlzO1xufTtcblxuXG5cblxualF1ZXJ5LmV4cHIucHNldWRvcy5hbmltYXRlZCA9IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRyZXR1cm4galF1ZXJ5LmdyZXAoIGpRdWVyeS50aW1lcnMsIGZ1bmN0aW9uKCBmbiApIHtcblx0XHRyZXR1cm4gZWxlbSA9PT0gZm4uZWxlbTtcblx0fSApLmxlbmd0aDtcbn07XG5cblxuXG5cbmpRdWVyeS5vZmZzZXQgPSB7XG5cdHNldE9mZnNldDogZnVuY3Rpb24oIGVsZW0sIG9wdGlvbnMsIGkgKSB7XG5cdFx0dmFyIGN1clBvc2l0aW9uLCBjdXJMZWZ0LCBjdXJDU1NUb3AsIGN1clRvcCwgY3VyT2Zmc2V0LCBjdXJDU1NMZWZ0LCBjYWxjdWxhdGVQb3NpdGlvbixcblx0XHRcdHBvc2l0aW9uID0galF1ZXJ5LmNzcyggZWxlbSwgXCJwb3NpdGlvblwiICksXG5cdFx0XHRjdXJFbGVtID0galF1ZXJ5KCBlbGVtICksXG5cdFx0XHRwcm9wcyA9IHt9O1xuXG5cdFx0Ly8gU2V0IHBvc2l0aW9uIGZpcnN0LCBpbi1jYXNlIHRvcC9sZWZ0IGFyZSBzZXQgZXZlbiBvbiBzdGF0aWMgZWxlbVxuXHRcdGlmICggcG9zaXRpb24gPT09IFwic3RhdGljXCIgKSB7XG5cdFx0XHRlbGVtLnN0eWxlLnBvc2l0aW9uID0gXCJyZWxhdGl2ZVwiO1xuXHRcdH1cblxuXHRcdGN1ck9mZnNldCA9IGN1ckVsZW0ub2Zmc2V0KCk7XG5cdFx0Y3VyQ1NTVG9wID0galF1ZXJ5LmNzcyggZWxlbSwgXCJ0b3BcIiApO1xuXHRcdGN1ckNTU0xlZnQgPSBqUXVlcnkuY3NzKCBlbGVtLCBcImxlZnRcIiApO1xuXHRcdGNhbGN1bGF0ZVBvc2l0aW9uID0gKCBwb3NpdGlvbiA9PT0gXCJhYnNvbHV0ZVwiIHx8IHBvc2l0aW9uID09PSBcImZpeGVkXCIgKSAmJlxuXHRcdFx0KCBjdXJDU1NUb3AgKyBjdXJDU1NMZWZ0ICkuaW5kZXhPZiggXCJhdXRvXCIgKSA+IC0xO1xuXG5cdFx0Ly8gTmVlZCB0byBiZSBhYmxlIHRvIGNhbGN1bGF0ZSBwb3NpdGlvbiBpZiBlaXRoZXJcblx0XHQvLyB0b3Agb3IgbGVmdCBpcyBhdXRvIGFuZCBwb3NpdGlvbiBpcyBlaXRoZXIgYWJzb2x1dGUgb3IgZml4ZWRcblx0XHRpZiAoIGNhbGN1bGF0ZVBvc2l0aW9uICkge1xuXHRcdFx0Y3VyUG9zaXRpb24gPSBjdXJFbGVtLnBvc2l0aW9uKCk7XG5cdFx0XHRjdXJUb3AgPSBjdXJQb3NpdGlvbi50b3A7XG5cdFx0XHRjdXJMZWZ0ID0gY3VyUG9zaXRpb24ubGVmdDtcblxuXHRcdH0gZWxzZSB7XG5cdFx0XHRjdXJUb3AgPSBwYXJzZUZsb2F0KCBjdXJDU1NUb3AgKSB8fCAwO1xuXHRcdFx0Y3VyTGVmdCA9IHBhcnNlRmxvYXQoIGN1ckNTU0xlZnQgKSB8fCAwO1xuXHRcdH1cblxuXHRcdGlmICggaXNGdW5jdGlvbiggb3B0aW9ucyApICkge1xuXG5cdFx0XHQvLyBVc2UgalF1ZXJ5LmV4dGVuZCBoZXJlIHRvIGFsbG93IG1vZGlmaWNhdGlvbiBvZiBjb29yZGluYXRlcyBhcmd1bWVudCAoZ2gtMTg0OClcblx0XHRcdG9wdGlvbnMgPSBvcHRpb25zLmNhbGwoIGVsZW0sIGksIGpRdWVyeS5leHRlbmQoIHt9LCBjdXJPZmZzZXQgKSApO1xuXHRcdH1cblxuXHRcdGlmICggb3B0aW9ucy50b3AgIT0gbnVsbCApIHtcblx0XHRcdHByb3BzLnRvcCA9ICggb3B0aW9ucy50b3AgLSBjdXJPZmZzZXQudG9wICkgKyBjdXJUb3A7XG5cdFx0fVxuXHRcdGlmICggb3B0aW9ucy5sZWZ0ICE9IG51bGwgKSB7XG5cdFx0XHRwcm9wcy5sZWZ0ID0gKCBvcHRpb25zLmxlZnQgLSBjdXJPZmZzZXQubGVmdCApICsgY3VyTGVmdDtcblx0XHR9XG5cblx0XHRpZiAoIFwidXNpbmdcIiBpbiBvcHRpb25zICkge1xuXHRcdFx0b3B0aW9ucy51c2luZy5jYWxsKCBlbGVtLCBwcm9wcyApO1xuXG5cdFx0fSBlbHNlIHtcblx0XHRcdGN1ckVsZW0uY3NzKCBwcm9wcyApO1xuXHRcdH1cblx0fVxufTtcblxualF1ZXJ5LmZuLmV4dGVuZCgge1xuXG5cdC8vIG9mZnNldCgpIHJlbGF0ZXMgYW4gZWxlbWVudCdzIGJvcmRlciBib3ggdG8gdGhlIGRvY3VtZW50IG9yaWdpblxuXHRvZmZzZXQ6IGZ1bmN0aW9uKCBvcHRpb25zICkge1xuXG5cdFx0Ly8gUHJlc2VydmUgY2hhaW5pbmcgZm9yIHNldHRlclxuXHRcdGlmICggYXJndW1lbnRzLmxlbmd0aCApIHtcblx0XHRcdHJldHVybiBvcHRpb25zID09PSB1bmRlZmluZWQgP1xuXHRcdFx0XHR0aGlzIDpcblx0XHRcdFx0dGhpcy5lYWNoKCBmdW5jdGlvbiggaSApIHtcblx0XHRcdFx0XHRqUXVlcnkub2Zmc2V0LnNldE9mZnNldCggdGhpcywgb3B0aW9ucywgaSApO1xuXHRcdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0dmFyIHJlY3QsIHdpbixcblx0XHRcdGVsZW0gPSB0aGlzWyAwIF07XG5cblx0XHRpZiAoICFlbGVtICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIFJldHVybiB6ZXJvcyBmb3IgZGlzY29ubmVjdGVkIGFuZCBoaWRkZW4gKGRpc3BsYXk6IG5vbmUpIGVsZW1lbnRzIChnaC0yMzEwKVxuXHRcdC8vIFN1cHBvcnQ6IElFIDw9MTEgb25seVxuXHRcdC8vIFJ1bm5pbmcgZ2V0Qm91bmRpbmdDbGllbnRSZWN0IG9uIGFcblx0XHQvLyBkaXNjb25uZWN0ZWQgbm9kZSBpbiBJRSB0aHJvd3MgYW4gZXJyb3Jcblx0XHRpZiAoICFlbGVtLmdldENsaWVudFJlY3RzKCkubGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuIHsgdG9wOiAwLCBsZWZ0OiAwIH07XG5cdFx0fVxuXG5cdFx0Ly8gR2V0IGRvY3VtZW50LXJlbGF0aXZlIHBvc2l0aW9uIGJ5IGFkZGluZyB2aWV3cG9ydCBzY3JvbGwgdG8gdmlld3BvcnQtcmVsYXRpdmUgZ0JDUlxuXHRcdHJlY3QgPSBlbGVtLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXHRcdHdpbiA9IGVsZW0ub3duZXJEb2N1bWVudC5kZWZhdWx0Vmlldztcblx0XHRyZXR1cm4ge1xuXHRcdFx0dG9wOiByZWN0LnRvcCArIHdpbi5wYWdlWU9mZnNldCxcblx0XHRcdGxlZnQ6IHJlY3QubGVmdCArIHdpbi5wYWdlWE9mZnNldFxuXHRcdH07XG5cdH0sXG5cblx0Ly8gcG9zaXRpb24oKSByZWxhdGVzIGFuIGVsZW1lbnQncyBtYXJnaW4gYm94IHRvIGl0cyBvZmZzZXQgcGFyZW50J3MgcGFkZGluZyBib3hcblx0Ly8gVGhpcyBjb3JyZXNwb25kcyB0byB0aGUgYmVoYXZpb3Igb2YgQ1NTIGFic29sdXRlIHBvc2l0aW9uaW5nXG5cdHBvc2l0aW9uOiBmdW5jdGlvbigpIHtcblx0XHRpZiAoICF0aGlzWyAwIF0gKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dmFyIG9mZnNldFBhcmVudCwgb2Zmc2V0LCBkb2MsXG5cdFx0XHRlbGVtID0gdGhpc1sgMCBdLFxuXHRcdFx0cGFyZW50T2Zmc2V0ID0geyB0b3A6IDAsIGxlZnQ6IDAgfTtcblxuXHRcdC8vIHBvc2l0aW9uOmZpeGVkIGVsZW1lbnRzIGFyZSBvZmZzZXQgZnJvbSB0aGUgdmlld3BvcnQsIHdoaWNoIGl0c2VsZiBhbHdheXMgaGFzIHplcm8gb2Zmc2V0XG5cdFx0aWYgKCBqUXVlcnkuY3NzKCBlbGVtLCBcInBvc2l0aW9uXCIgKSA9PT0gXCJmaXhlZFwiICkge1xuXG5cdFx0XHQvLyBBc3N1bWUgcG9zaXRpb246Zml4ZWQgaW1wbGllcyBhdmFpbGFiaWxpdHkgb2YgZ2V0Qm91bmRpbmdDbGllbnRSZWN0XG5cdFx0XHRvZmZzZXQgPSBlbGVtLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXG5cdFx0fSBlbHNlIHtcblx0XHRcdG9mZnNldCA9IHRoaXMub2Zmc2V0KCk7XG5cblx0XHRcdC8vIEFjY291bnQgZm9yIHRoZSAqcmVhbCogb2Zmc2V0IHBhcmVudCwgd2hpY2ggY2FuIGJlIHRoZSBkb2N1bWVudCBvciBpdHMgcm9vdCBlbGVtZW50XG5cdFx0XHQvLyB3aGVuIGEgc3RhdGljYWxseSBwb3NpdGlvbmVkIGVsZW1lbnQgaXMgaWRlbnRpZmllZFxuXHRcdFx0ZG9jID0gZWxlbS5vd25lckRvY3VtZW50O1xuXHRcdFx0b2Zmc2V0UGFyZW50ID0gZWxlbS5vZmZzZXRQYXJlbnQgfHwgZG9jLmRvY3VtZW50RWxlbWVudDtcblx0XHRcdHdoaWxlICggb2Zmc2V0UGFyZW50ICYmXG5cdFx0XHRcdCggb2Zmc2V0UGFyZW50ID09PSBkb2MuYm9keSB8fCBvZmZzZXRQYXJlbnQgPT09IGRvYy5kb2N1bWVudEVsZW1lbnQgKSAmJlxuXHRcdFx0XHRqUXVlcnkuY3NzKCBvZmZzZXRQYXJlbnQsIFwicG9zaXRpb25cIiApID09PSBcInN0YXRpY1wiICkge1xuXG5cdFx0XHRcdG9mZnNldFBhcmVudCA9IG9mZnNldFBhcmVudC5wYXJlbnROb2RlO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBvZmZzZXRQYXJlbnQgJiYgb2Zmc2V0UGFyZW50ICE9PSBlbGVtICYmIG9mZnNldFBhcmVudC5ub2RlVHlwZSA9PT0gMSApIHtcblxuXHRcdFx0XHQvLyBJbmNvcnBvcmF0ZSBib3JkZXJzIGludG8gaXRzIG9mZnNldCwgc2luY2UgdGhleSBhcmUgb3V0c2lkZSBpdHMgY29udGVudCBvcmlnaW5cblx0XHRcdFx0cGFyZW50T2Zmc2V0ID0galF1ZXJ5KCBvZmZzZXRQYXJlbnQgKS5vZmZzZXQoKTtcblx0XHRcdFx0cGFyZW50T2Zmc2V0LnRvcCArPSBqUXVlcnkuY3NzKCBvZmZzZXRQYXJlbnQsIFwiYm9yZGVyVG9wV2lkdGhcIiwgdHJ1ZSApO1xuXHRcdFx0XHRwYXJlbnRPZmZzZXQubGVmdCArPSBqUXVlcnkuY3NzKCBvZmZzZXRQYXJlbnQsIFwiYm9yZGVyTGVmdFdpZHRoXCIsIHRydWUgKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBTdWJ0cmFjdCBwYXJlbnQgb2Zmc2V0cyBhbmQgZWxlbWVudCBtYXJnaW5zXG5cdFx0cmV0dXJuIHtcblx0XHRcdHRvcDogb2Zmc2V0LnRvcCAtIHBhcmVudE9mZnNldC50b3AgLSBqUXVlcnkuY3NzKCBlbGVtLCBcIm1hcmdpblRvcFwiLCB0cnVlICksXG5cdFx0XHRsZWZ0OiBvZmZzZXQubGVmdCAtIHBhcmVudE9mZnNldC5sZWZ0IC0galF1ZXJ5LmNzcyggZWxlbSwgXCJtYXJnaW5MZWZ0XCIsIHRydWUgKVxuXHRcdH07XG5cdH0sXG5cblx0Ly8gVGhpcyBtZXRob2Qgd2lsbCByZXR1cm4gZG9jdW1lbnRFbGVtZW50IGluIHRoZSBmb2xsb3dpbmcgY2FzZXM6XG5cdC8vIDEpIEZvciB0aGUgZWxlbWVudCBpbnNpZGUgdGhlIGlmcmFtZSB3aXRob3V0IG9mZnNldFBhcmVudCwgdGhpcyBtZXRob2Qgd2lsbCByZXR1cm5cblx0Ly8gICAgZG9jdW1lbnRFbGVtZW50IG9mIHRoZSBwYXJlbnQgd2luZG93XG5cdC8vIDIpIEZvciB0aGUgaGlkZGVuIG9yIGRldGFjaGVkIGVsZW1lbnRcblx0Ly8gMykgRm9yIGJvZHkgb3IgaHRtbCBlbGVtZW50LCBpLmUuIGluIGNhc2Ugb2YgdGhlIGh0bWwgbm9kZSAtIGl0IHdpbGwgcmV0dXJuIGl0c2VsZlxuXHQvL1xuXHQvLyBidXQgdGhvc2UgZXhjZXB0aW9ucyB3ZXJlIG5ldmVyIHByZXNlbnRlZCBhcyBhIHJlYWwgbGlmZSB1c2UtY2FzZXNcblx0Ly8gYW5kIG1pZ2h0IGJlIGNvbnNpZGVyZWQgYXMgbW9yZSBwcmVmZXJhYmxlIHJlc3VsdHMuXG5cdC8vXG5cdC8vIFRoaXMgbG9naWMsIGhvd2V2ZXIsIGlzIG5vdCBndWFyYW50ZWVkIGFuZCBjYW4gY2hhbmdlIGF0IGFueSBwb2ludCBpbiB0aGUgZnV0dXJlXG5cdG9mZnNldFBhcmVudDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMubWFwKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBvZmZzZXRQYXJlbnQgPSB0aGlzLm9mZnNldFBhcmVudDtcblxuXHRcdFx0d2hpbGUgKCBvZmZzZXRQYXJlbnQgJiYgalF1ZXJ5LmNzcyggb2Zmc2V0UGFyZW50LCBcInBvc2l0aW9uXCIgKSA9PT0gXCJzdGF0aWNcIiApIHtcblx0XHRcdFx0b2Zmc2V0UGFyZW50ID0gb2Zmc2V0UGFyZW50Lm9mZnNldFBhcmVudDtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIG9mZnNldFBhcmVudCB8fCBkb2N1bWVudEVsZW1lbnQ7XG5cdFx0fSApO1xuXHR9XG59ICk7XG5cbi8vIENyZWF0ZSBzY3JvbGxMZWZ0IGFuZCBzY3JvbGxUb3AgbWV0aG9kc1xualF1ZXJ5LmVhY2goIHsgc2Nyb2xsTGVmdDogXCJwYWdlWE9mZnNldFwiLCBzY3JvbGxUb3A6IFwicGFnZVlPZmZzZXRcIiB9LCBmdW5jdGlvbiggbWV0aG9kLCBwcm9wICkge1xuXHR2YXIgdG9wID0gXCJwYWdlWU9mZnNldFwiID09PSBwcm9wO1xuXG5cdGpRdWVyeS5mblsgbWV0aG9kIF0gPSBmdW5jdGlvbiggdmFsICkge1xuXHRcdHJldHVybiBhY2Nlc3MoIHRoaXMsIGZ1bmN0aW9uKCBlbGVtLCBtZXRob2QsIHZhbCApIHtcblxuXHRcdFx0Ly8gQ29hbGVzY2UgZG9jdW1lbnRzIGFuZCB3aW5kb3dzXG5cdFx0XHR2YXIgd2luO1xuXHRcdFx0aWYgKCBpc1dpbmRvdyggZWxlbSApICkge1xuXHRcdFx0XHR3aW4gPSBlbGVtO1xuXHRcdFx0fSBlbHNlIGlmICggZWxlbS5ub2RlVHlwZSA9PT0gOSApIHtcblx0XHRcdFx0d2luID0gZWxlbS5kZWZhdWx0Vmlldztcblx0XHRcdH1cblxuXHRcdFx0aWYgKCB2YWwgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0cmV0dXJuIHdpbiA/IHdpblsgcHJvcCBdIDogZWxlbVsgbWV0aG9kIF07XG5cdFx0XHR9XG5cblx0XHRcdGlmICggd2luICkge1xuXHRcdFx0XHR3aW4uc2Nyb2xsVG8oXG5cdFx0XHRcdFx0IXRvcCA/IHZhbCA6IHdpbi5wYWdlWE9mZnNldCxcblx0XHRcdFx0XHR0b3AgPyB2YWwgOiB3aW4ucGFnZVlPZmZzZXRcblx0XHRcdFx0KTtcblxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0ZWxlbVsgbWV0aG9kIF0gPSB2YWw7XG5cdFx0XHR9XG5cdFx0fSwgbWV0aG9kLCB2YWwsIGFyZ3VtZW50cy5sZW5ndGggKTtcblx0fTtcbn0gKTtcblxuLy8gU3VwcG9ydDogU2FmYXJpIDw9NyAtIDkuMSwgQ2hyb21lIDw9MzcgLSA0OVxuLy8gQWRkIHRoZSB0b3AvbGVmdCBjc3NIb29rcyB1c2luZyBqUXVlcnkuZm4ucG9zaXRpb25cbi8vIFdlYmtpdCBidWc6IGh0dHBzOi8vYnVncy53ZWJraXQub3JnL3Nob3dfYnVnLmNnaT9pZD0yOTA4NFxuLy8gQmxpbmsgYnVnOiBodHRwczovL2J1Z3MuY2hyb21pdW0ub3JnL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD01ODkzNDdcbi8vIGdldENvbXB1dGVkU3R5bGUgcmV0dXJucyBwZXJjZW50IHdoZW4gc3BlY2lmaWVkIGZvciB0b3AvbGVmdC9ib3R0b20vcmlnaHQ7XG4vLyByYXRoZXIgdGhhbiBtYWtlIHRoZSBjc3MgbW9kdWxlIGRlcGVuZCBvbiB0aGUgb2Zmc2V0IG1vZHVsZSwganVzdCBjaGVjayBmb3IgaXQgaGVyZVxualF1ZXJ5LmVhY2goIFsgXCJ0b3BcIiwgXCJsZWZ0XCIgXSwgZnVuY3Rpb24oIF9pLCBwcm9wICkge1xuXHRqUXVlcnkuY3NzSG9va3NbIHByb3AgXSA9IGFkZEdldEhvb2tJZiggc3VwcG9ydC5waXhlbFBvc2l0aW9uLFxuXHRcdGZ1bmN0aW9uKCBlbGVtLCBjb21wdXRlZCApIHtcblx0XHRcdGlmICggY29tcHV0ZWQgKSB7XG5cdFx0XHRcdGNvbXB1dGVkID0gY3VyQ1NTKCBlbGVtLCBwcm9wICk7XG5cblx0XHRcdFx0Ly8gSWYgY3VyQ1NTIHJldHVybnMgcGVyY2VudGFnZSwgZmFsbGJhY2sgdG8gb2Zmc2V0XG5cdFx0XHRcdHJldHVybiBybnVtbm9ucHgudGVzdCggY29tcHV0ZWQgKSA/XG5cdFx0XHRcdFx0alF1ZXJ5KCBlbGVtICkucG9zaXRpb24oKVsgcHJvcCBdICsgXCJweFwiIDpcblx0XHRcdFx0XHRjb21wdXRlZDtcblx0XHRcdH1cblx0XHR9XG5cdCk7XG59ICk7XG5cblxuLy8gQ3JlYXRlIGlubmVySGVpZ2h0LCBpbm5lcldpZHRoLCBoZWlnaHQsIHdpZHRoLCBvdXRlckhlaWdodCBhbmQgb3V0ZXJXaWR0aCBtZXRob2RzXG5qUXVlcnkuZWFjaCggeyBIZWlnaHQ6IFwiaGVpZ2h0XCIsIFdpZHRoOiBcIndpZHRoXCIgfSwgZnVuY3Rpb24oIG5hbWUsIHR5cGUgKSB7XG5cdGpRdWVyeS5lYWNoKCB7XG5cdFx0cGFkZGluZzogXCJpbm5lclwiICsgbmFtZSxcblx0XHRjb250ZW50OiB0eXBlLFxuXHRcdFwiXCI6IFwib3V0ZXJcIiArIG5hbWVcblx0fSwgZnVuY3Rpb24oIGRlZmF1bHRFeHRyYSwgZnVuY05hbWUgKSB7XG5cblx0XHQvLyBNYXJnaW4gaXMgb25seSBmb3Igb3V0ZXJIZWlnaHQsIG91dGVyV2lkdGhcblx0XHRqUXVlcnkuZm5bIGZ1bmNOYW1lIF0gPSBmdW5jdGlvbiggbWFyZ2luLCB2YWx1ZSApIHtcblx0XHRcdHZhciBjaGFpbmFibGUgPSBhcmd1bWVudHMubGVuZ3RoICYmICggZGVmYXVsdEV4dHJhIHx8IHR5cGVvZiBtYXJnaW4gIT09IFwiYm9vbGVhblwiICksXG5cdFx0XHRcdGV4dHJhID0gZGVmYXVsdEV4dHJhIHx8ICggbWFyZ2luID09PSB0cnVlIHx8IHZhbHVlID09PSB0cnVlID8gXCJtYXJnaW5cIiA6IFwiYm9yZGVyXCIgKTtcblxuXHRcdFx0cmV0dXJuIGFjY2VzcyggdGhpcywgZnVuY3Rpb24oIGVsZW0sIHR5cGUsIHZhbHVlICkge1xuXHRcdFx0XHR2YXIgZG9jO1xuXG5cdFx0XHRcdGlmICggaXNXaW5kb3coIGVsZW0gKSApIHtcblxuXHRcdFx0XHRcdC8vICQoIHdpbmRvdyApLm91dGVyV2lkdGgvSGVpZ2h0IHJldHVybiB3L2ggaW5jbHVkaW5nIHNjcm9sbGJhcnMgKGdoLTE3MjkpXG5cdFx0XHRcdFx0cmV0dXJuIGZ1bmNOYW1lLmluZGV4T2YoIFwib3V0ZXJcIiApID09PSAwID9cblx0XHRcdFx0XHRcdGVsZW1bIFwiaW5uZXJcIiArIG5hbWUgXSA6XG5cdFx0XHRcdFx0XHRlbGVtLmRvY3VtZW50LmRvY3VtZW50RWxlbWVudFsgXCJjbGllbnRcIiArIG5hbWUgXTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIEdldCBkb2N1bWVudCB3aWR0aCBvciBoZWlnaHRcblx0XHRcdFx0aWYgKCBlbGVtLm5vZGVUeXBlID09PSA5ICkge1xuXHRcdFx0XHRcdGRvYyA9IGVsZW0uZG9jdW1lbnRFbGVtZW50O1xuXG5cdFx0XHRcdFx0Ly8gRWl0aGVyIHNjcm9sbFtXaWR0aC9IZWlnaHRdIG9yIG9mZnNldFtXaWR0aC9IZWlnaHRdIG9yIGNsaWVudFtXaWR0aC9IZWlnaHRdLFxuXHRcdFx0XHRcdC8vIHdoaWNoZXZlciBpcyBncmVhdGVzdFxuXHRcdFx0XHRcdHJldHVybiBNYXRoLm1heChcblx0XHRcdFx0XHRcdGVsZW0uYm9keVsgXCJzY3JvbGxcIiArIG5hbWUgXSwgZG9jWyBcInNjcm9sbFwiICsgbmFtZSBdLFxuXHRcdFx0XHRcdFx0ZWxlbS5ib2R5WyBcIm9mZnNldFwiICsgbmFtZSBdLCBkb2NbIFwib2Zmc2V0XCIgKyBuYW1lIF0sXG5cdFx0XHRcdFx0XHRkb2NbIFwiY2xpZW50XCIgKyBuYW1lIF1cblx0XHRcdFx0XHQpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0cmV0dXJuIHZhbHVlID09PSB1bmRlZmluZWQgP1xuXG5cdFx0XHRcdFx0Ly8gR2V0IHdpZHRoIG9yIGhlaWdodCBvbiB0aGUgZWxlbWVudCwgcmVxdWVzdGluZyBidXQgbm90IGZvcmNpbmcgcGFyc2VGbG9hdFxuXHRcdFx0XHRcdGpRdWVyeS5jc3MoIGVsZW0sIHR5cGUsIGV4dHJhICkgOlxuXG5cdFx0XHRcdFx0Ly8gU2V0IHdpZHRoIG9yIGhlaWdodCBvbiB0aGUgZWxlbWVudFxuXHRcdFx0XHRcdGpRdWVyeS5zdHlsZSggZWxlbSwgdHlwZSwgdmFsdWUsIGV4dHJhICk7XG5cdFx0XHR9LCB0eXBlLCBjaGFpbmFibGUgPyBtYXJnaW4gOiB1bmRlZmluZWQsIGNoYWluYWJsZSApO1xuXHRcdH07XG5cdH0gKTtcbn0gKTtcblxuXG5qUXVlcnkuZWFjaCggW1xuXHRcImFqYXhTdGFydFwiLFxuXHRcImFqYXhTdG9wXCIsXG5cdFwiYWpheENvbXBsZXRlXCIsXG5cdFwiYWpheEVycm9yXCIsXG5cdFwiYWpheFN1Y2Nlc3NcIixcblx0XCJhamF4U2VuZFwiXG5dLCBmdW5jdGlvbiggX2ksIHR5cGUgKSB7XG5cdGpRdWVyeS5mblsgdHlwZSBdID0gZnVuY3Rpb24oIGZuICkge1xuXHRcdHJldHVybiB0aGlzLm9uKCB0eXBlLCBmbiApO1xuXHR9O1xufSApO1xuXG5cblxuXG5qUXVlcnkuZm4uZXh0ZW5kKCB7XG5cblx0YmluZDogZnVuY3Rpb24oIHR5cGVzLCBkYXRhLCBmbiApIHtcblx0XHRyZXR1cm4gdGhpcy5vbiggdHlwZXMsIG51bGwsIGRhdGEsIGZuICk7XG5cdH0sXG5cdHVuYmluZDogZnVuY3Rpb24oIHR5cGVzLCBmbiApIHtcblx0XHRyZXR1cm4gdGhpcy5vZmYoIHR5cGVzLCBudWxsLCBmbiApO1xuXHR9LFxuXG5cdGRlbGVnYXRlOiBmdW5jdGlvbiggc2VsZWN0b3IsIHR5cGVzLCBkYXRhLCBmbiApIHtcblx0XHRyZXR1cm4gdGhpcy5vbiggdHlwZXMsIHNlbGVjdG9yLCBkYXRhLCBmbiApO1xuXHR9LFxuXHR1bmRlbGVnYXRlOiBmdW5jdGlvbiggc2VsZWN0b3IsIHR5cGVzLCBmbiApIHtcblxuXHRcdC8vICggbmFtZXNwYWNlICkgb3IgKCBzZWxlY3RvciwgdHlwZXMgWywgZm5dIClcblx0XHRyZXR1cm4gYXJndW1lbnRzLmxlbmd0aCA9PT0gMSA/XG5cdFx0XHR0aGlzLm9mZiggc2VsZWN0b3IsIFwiKipcIiApIDpcblx0XHRcdHRoaXMub2ZmKCB0eXBlcywgc2VsZWN0b3IgfHwgXCIqKlwiLCBmbiApO1xuXHR9LFxuXG5cdGhvdmVyOiBmdW5jdGlvbiggZm5PdmVyLCBmbk91dCApIHtcblx0XHRyZXR1cm4gdGhpcy5tb3VzZWVudGVyKCBmbk92ZXIgKS5tb3VzZWxlYXZlKCBmbk91dCB8fCBmbk92ZXIgKTtcblx0fVxufSApO1xuXG5qUXVlcnkuZWFjaChcblx0KCBcImJsdXIgZm9jdXMgZm9jdXNpbiBmb2N1c291dCByZXNpemUgc2Nyb2xsIGNsaWNrIGRibGNsaWNrIFwiICtcblx0XCJtb3VzZWRvd24gbW91c2V1cCBtb3VzZW1vdmUgbW91c2VvdmVyIG1vdXNlb3V0IG1vdXNlZW50ZXIgbW91c2VsZWF2ZSBcIiArXG5cdFwiY2hhbmdlIHNlbGVjdCBzdWJtaXQga2V5ZG93biBrZXlwcmVzcyBrZXl1cCBjb250ZXh0bWVudVwiICkuc3BsaXQoIFwiIFwiICksXG5cdGZ1bmN0aW9uKCBfaSwgbmFtZSApIHtcblxuXHRcdC8vIEhhbmRsZSBldmVudCBiaW5kaW5nXG5cdFx0alF1ZXJ5LmZuWyBuYW1lIF0gPSBmdW5jdGlvbiggZGF0YSwgZm4gKSB7XG5cdFx0XHRyZXR1cm4gYXJndW1lbnRzLmxlbmd0aCA+IDAgP1xuXHRcdFx0XHR0aGlzLm9uKCBuYW1lLCBudWxsLCBkYXRhLCBmbiApIDpcblx0XHRcdFx0dGhpcy50cmlnZ2VyKCBuYW1lICk7XG5cdFx0fTtcblx0fVxuKTtcblxuXG5cblxuLy8gU3VwcG9ydDogQW5kcm9pZCA8PTQuMCBvbmx5XG4vLyBNYWtlIHN1cmUgd2UgdHJpbSBCT00gYW5kIE5CU1BcbnZhciBydHJpbSA9IC9eW1xcc1xcdUZFRkZcXHhBMF0rfFtcXHNcXHVGRUZGXFx4QTBdKyQvZztcblxuLy8gQmluZCBhIGZ1bmN0aW9uIHRvIGEgY29udGV4dCwgb3B0aW9uYWxseSBwYXJ0aWFsbHkgYXBwbHlpbmcgYW55XG4vLyBhcmd1bWVudHMuXG4vLyBqUXVlcnkucHJveHkgaXMgZGVwcmVjYXRlZCB0byBwcm9tb3RlIHN0YW5kYXJkcyAoc3BlY2lmaWNhbGx5IEZ1bmN0aW9uI2JpbmQpXG4vLyBIb3dldmVyLCBpdCBpcyBub3Qgc2xhdGVkIGZvciByZW1vdmFsIGFueSB0aW1lIHNvb25cbmpRdWVyeS5wcm94eSA9IGZ1bmN0aW9uKCBmbiwgY29udGV4dCApIHtcblx0dmFyIHRtcCwgYXJncywgcHJveHk7XG5cblx0aWYgKCB0eXBlb2YgY29udGV4dCA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHR0bXAgPSBmblsgY29udGV4dCBdO1xuXHRcdGNvbnRleHQgPSBmbjtcblx0XHRmbiA9IHRtcDtcblx0fVxuXG5cdC8vIFF1aWNrIGNoZWNrIHRvIGRldGVybWluZSBpZiB0YXJnZXQgaXMgY2FsbGFibGUsIGluIHRoZSBzcGVjXG5cdC8vIHRoaXMgdGhyb3dzIGEgVHlwZUVycm9yLCBidXQgd2Ugd2lsbCBqdXN0IHJldHVybiB1bmRlZmluZWQuXG5cdGlmICggIWlzRnVuY3Rpb24oIGZuICkgKSB7XG5cdFx0cmV0dXJuIHVuZGVmaW5lZDtcblx0fVxuXG5cdC8vIFNpbXVsYXRlZCBiaW5kXG5cdGFyZ3MgPSBzbGljZS5jYWxsKCBhcmd1bWVudHMsIDIgKTtcblx0cHJveHkgPSBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gZm4uYXBwbHkoIGNvbnRleHQgfHwgdGhpcywgYXJncy5jb25jYXQoIHNsaWNlLmNhbGwoIGFyZ3VtZW50cyApICkgKTtcblx0fTtcblxuXHQvLyBTZXQgdGhlIGd1aWQgb2YgdW5pcXVlIGhhbmRsZXIgdG8gdGhlIHNhbWUgb2Ygb3JpZ2luYWwgaGFuZGxlciwgc28gaXQgY2FuIGJlIHJlbW92ZWRcblx0cHJveHkuZ3VpZCA9IGZuLmd1aWQgPSBmbi5ndWlkIHx8IGpRdWVyeS5ndWlkKys7XG5cblx0cmV0dXJuIHByb3h5O1xufTtcblxualF1ZXJ5LmhvbGRSZWFkeSA9IGZ1bmN0aW9uKCBob2xkICkge1xuXHRpZiAoIGhvbGQgKSB7XG5cdFx0alF1ZXJ5LnJlYWR5V2FpdCsrO1xuXHR9IGVsc2Uge1xuXHRcdGpRdWVyeS5yZWFkeSggdHJ1ZSApO1xuXHR9XG59O1xualF1ZXJ5LmlzQXJyYXkgPSBBcnJheS5pc0FycmF5O1xualF1ZXJ5LnBhcnNlSlNPTiA9IEpTT04ucGFyc2U7XG5qUXVlcnkubm9kZU5hbWUgPSBub2RlTmFtZTtcbmpRdWVyeS5pc0Z1bmN0aW9uID0gaXNGdW5jdGlvbjtcbmpRdWVyeS5pc1dpbmRvdyA9IGlzV2luZG93O1xualF1ZXJ5LmNhbWVsQ2FzZSA9IGNhbWVsQ2FzZTtcbmpRdWVyeS50eXBlID0gdG9UeXBlO1xuXG5qUXVlcnkubm93ID0gRGF0ZS5ub3c7XG5cbmpRdWVyeS5pc051bWVyaWMgPSBmdW5jdGlvbiggb2JqICkge1xuXG5cdC8vIEFzIG9mIGpRdWVyeSAzLjAsIGlzTnVtZXJpYyBpcyBsaW1pdGVkIHRvXG5cdC8vIHN0cmluZ3MgYW5kIG51bWJlcnMgKHByaW1pdGl2ZXMgb3Igb2JqZWN0cylcblx0Ly8gdGhhdCBjYW4gYmUgY29lcmNlZCB0byBmaW5pdGUgbnVtYmVycyAoZ2gtMjY2Milcblx0dmFyIHR5cGUgPSBqUXVlcnkudHlwZSggb2JqICk7XG5cdHJldHVybiAoIHR5cGUgPT09IFwibnVtYmVyXCIgfHwgdHlwZSA9PT0gXCJzdHJpbmdcIiApICYmXG5cblx0XHQvLyBwYXJzZUZsb2F0IE5hTnMgbnVtZXJpYy1jYXN0IGZhbHNlIHBvc2l0aXZlcyAoXCJcIilcblx0XHQvLyAuLi5idXQgbWlzaW50ZXJwcmV0cyBsZWFkaW5nLW51bWJlciBzdHJpbmdzLCBwYXJ0aWN1bGFybHkgaGV4IGxpdGVyYWxzIChcIjB4Li4uXCIpXG5cdFx0Ly8gc3VidHJhY3Rpb24gZm9yY2VzIGluZmluaXRpZXMgdG8gTmFOXG5cdFx0IWlzTmFOKCBvYmogLSBwYXJzZUZsb2F0KCBvYmogKSApO1xufTtcblxualF1ZXJ5LnRyaW0gPSBmdW5jdGlvbiggdGV4dCApIHtcblx0cmV0dXJuIHRleHQgPT0gbnVsbCA/XG5cdFx0XCJcIiA6XG5cdFx0KCB0ZXh0ICsgXCJcIiApLnJlcGxhY2UoIHJ0cmltLCBcIlwiICk7XG59O1xuXG5cblxuLy8gUmVnaXN0ZXIgYXMgYSBuYW1lZCBBTUQgbW9kdWxlLCBzaW5jZSBqUXVlcnkgY2FuIGJlIGNvbmNhdGVuYXRlZCB3aXRoIG90aGVyXG4vLyBmaWxlcyB0aGF0IG1heSB1c2UgZGVmaW5lLCBidXQgbm90IHZpYSBhIHByb3BlciBjb25jYXRlbmF0aW9uIHNjcmlwdCB0aGF0XG4vLyB1bmRlcnN0YW5kcyBhbm9ueW1vdXMgQU1EIG1vZHVsZXMuIEEgbmFtZWQgQU1EIGlzIHNhZmVzdCBhbmQgbW9zdCByb2J1c3Rcbi8vIHdheSB0byByZWdpc3Rlci4gTG93ZXJjYXNlIGpxdWVyeSBpcyB1c2VkIGJlY2F1c2UgQU1EIG1vZHVsZSBuYW1lcyBhcmVcbi8vIGRlcml2ZWQgZnJvbSBmaWxlIG5hbWVzLCBhbmQgalF1ZXJ5IGlzIG5vcm1hbGx5IGRlbGl2ZXJlZCBpbiBhIGxvd2VyY2FzZVxuLy8gZmlsZSBuYW1lLiBEbyB0aGlzIGFmdGVyIGNyZWF0aW5nIHRoZSBnbG9iYWwgc28gdGhhdCBpZiBhbiBBTUQgbW9kdWxlIHdhbnRzXG4vLyB0byBjYWxsIG5vQ29uZmxpY3QgdG8gaGlkZSB0aGlzIHZlcnNpb24gb2YgalF1ZXJ5LCBpdCB3aWxsIHdvcmsuXG5cbi8vIE5vdGUgdGhhdCBmb3IgbWF4aW11bSBwb3J0YWJpbGl0eSwgbGlicmFyaWVzIHRoYXQgYXJlIG5vdCBqUXVlcnkgc2hvdWxkXG4vLyBkZWNsYXJlIHRoZW1zZWx2ZXMgYXMgYW5vbnltb3VzIG1vZHVsZXMsIGFuZCBhdm9pZCBzZXR0aW5nIGEgZ2xvYmFsIGlmIGFuXG4vLyBBTUQgbG9hZGVyIGlzIHByZXNlbnQuIGpRdWVyeSBpcyBhIHNwZWNpYWwgY2FzZS4gRm9yIG1vcmUgaW5mb3JtYXRpb24sIHNlZVxuLy8gaHR0cHM6Ly9naXRodWIuY29tL2pyYnVya2UvcmVxdWlyZWpzL3dpa2kvVXBkYXRpbmctZXhpc3RpbmctbGlicmFyaWVzI3dpa2ktYW5vblxuXG5pZiAoIHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiBkZWZpbmUuYW1kICkge1xuXHRkZWZpbmUoIFwianF1ZXJ5XCIsIFtdLCBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4galF1ZXJ5O1xuXHR9ICk7XG59XG5cblxuXG5cbnZhclxuXG5cdC8vIE1hcCBvdmVyIGpRdWVyeSBpbiBjYXNlIG9mIG92ZXJ3cml0ZVxuXHRfalF1ZXJ5ID0gd2luZG93LmpRdWVyeSxcblxuXHQvLyBNYXAgb3ZlciB0aGUgJCBpbiBjYXNlIG9mIG92ZXJ3cml0ZVxuXHRfJCA9IHdpbmRvdy4kO1xuXG5qUXVlcnkubm9Db25mbGljdCA9IGZ1bmN0aW9uKCBkZWVwICkge1xuXHRpZiAoIHdpbmRvdy4kID09PSBqUXVlcnkgKSB7XG5cdFx0d2luZG93LiQgPSBfJDtcblx0fVxuXG5cdGlmICggZGVlcCAmJiB3aW5kb3cualF1ZXJ5ID09PSBqUXVlcnkgKSB7XG5cdFx0d2luZG93LmpRdWVyeSA9IF9qUXVlcnk7XG5cdH1cblxuXHRyZXR1cm4galF1ZXJ5O1xufTtcblxuLy8gRXhwb3NlIGpRdWVyeSBhbmQgJCBpZGVudGlmaWVycywgZXZlbiBpbiBBTURcbi8vICgjNzEwMiNjb21tZW50OjEwLCBodHRwczovL2dpdGh1Yi5jb20vanF1ZXJ5L2pxdWVyeS9wdWxsLzU1Nylcbi8vIGFuZCBDb21tb25KUyBmb3IgYnJvd3NlciBlbXVsYXRvcnMgKCMxMzU2NilcbmlmICggdHlwZW9mIG5vR2xvYmFsID09PSBcInVuZGVmaW5lZFwiICkge1xuXHR3aW5kb3cualF1ZXJ5ID0gd2luZG93LiQgPSBqUXVlcnk7XG59XG5cblxuXG5cbnJldHVybiBqUXVlcnk7XG59ICk7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/jquery/dist/jquery.js\n");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./resources/sass/app.scss":
|
|
/*!*********************************!*\
|
|
!*** ./resources/sass/app.scss ***!
|
|
\*********************************/
|
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
|
|
"use strict";
|
|
eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9yZXNvdXJjZXMvc2Fzcy9hcHAuc2Nzcy5qcyIsIm1hcHBpbmdzIjoiO0FBQUEiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9yZXNvdXJjZXMvc2Fzcy9hcHAuc2Nzcz9hODBiIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIGV4dHJhY3RlZCBieSBtaW5pLWNzcy1leHRyYWN0LXBsdWdpblxuZXhwb3J0IHt9OyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./resources/sass/app.scss\n");
|
|
|
|
/***/ }),
|
|
|
|
/***/ "./node_modules/popper.js/dist/esm/popper.js":
|
|
/*!***************************************************!*\
|
|
!*** ./node_modules/popper.js/dist/esm/popper.js ***!
|
|
\***************************************************/
|
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
|
|
"use strict";
|
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/**!\n * @fileOverview Kickass library to create and place poppers near their reference elements.\n * @version 1.16.1\n * @license\n * Copyright (c) 2016 Federico Zivolo and contributors\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\nvar isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && typeof navigator !== 'undefined';\n\nvar timeoutDuration = function () {\n var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];\n for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) {\n if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {\n return 1;\n }\n }\n return 0;\n}();\n\nfunction microtaskDebounce(fn) {\n var called = false;\n return function () {\n if (called) {\n return;\n }\n called = true;\n window.Promise.resolve().then(function () {\n called = false;\n fn();\n });\n };\n}\n\nfunction taskDebounce(fn) {\n var scheduled = false;\n return function () {\n if (!scheduled) {\n scheduled = true;\n setTimeout(function () {\n scheduled = false;\n fn();\n }, timeoutDuration);\n }\n };\n}\n\nvar supportsMicroTasks = isBrowser && window.Promise;\n\n/**\n* Create a debounced version of a method, that's asynchronously deferred\n* but called in the minimum time possible.\n*\n* @method\n* @memberof Popper.Utils\n* @argument {Function} fn\n* @returns {Function}\n*/\nvar debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce;\n\n/**\n * Check if the given variable is a function\n * @method\n * @memberof Popper.Utils\n * @argument {Any} functionToCheck - variable to check\n * @returns {Boolean} answer to: is a function?\n */\nfunction isFunction(functionToCheck) {\n var getType = {};\n return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';\n}\n\n/**\n * Get CSS computed property of the given element\n * @method\n * @memberof Popper.Utils\n * @argument {Eement} element\n * @argument {String} property\n */\nfunction getStyleComputedProperty(element, property) {\n if (element.nodeType !== 1) {\n return [];\n }\n // NOTE: 1 DOM access here\n var window = element.ownerDocument.defaultView;\n var css = window.getComputedStyle(element, null);\n return property ? css[property] : css;\n}\n\n/**\n * Returns the parentNode or the host of the element\n * @method\n * @memberof Popper.Utils\n * @argument {Element} element\n * @returns {Element} parent\n */\nfunction getParentNode(element) {\n if (element.nodeName === 'HTML') {\n return element;\n }\n return element.parentNode || element.host;\n}\n\n/**\n * Returns the scrolling parent of the given element\n * @method\n * @memberof Popper.Utils\n * @argument {Element} element\n * @returns {Element} scroll parent\n */\nfunction getScrollParent(element) {\n // Return body, `getScroll` will take care to get the correct `scrollTop` from it\n if (!element) {\n return document.body;\n }\n\n switch (element.nodeName) {\n case 'HTML':\n case 'BODY':\n return element.ownerDocument.body;\n case '#document':\n return element.body;\n }\n\n // Firefox want us to check `-x` and `-y` variations as well\n\n var _getStyleComputedProp = getStyleComputedProperty(element),\n overflow = _getStyleComputedProp.overflow,\n overflowX = _getStyleComputedProp.overflowX,\n overflowY = _getStyleComputedProp.overflowY;\n\n if (/(auto|scroll|overlay)/.test(overflow + overflowY + overflowX)) {\n return element;\n }\n\n return getScrollParent(getParentNode(element));\n}\n\n/**\n * Returns the reference node of the reference object, or the reference object itself.\n * @method\n * @memberof Popper.Utils\n * @param {Element|Object} reference - the reference element (the popper will be relative to this)\n * @returns {Element} parent\n */\nfunction getReferenceNode(reference) {\n return reference && reference.referenceNode ? reference.referenceNode : reference;\n}\n\nvar isIE11 = isBrowser && !!(window.MSInputMethodContext && document.documentMode);\nvar isIE10 = isBrowser && /MSIE 10/.test(navigator.userAgent);\n\n/**\n * Determines if the browser is Internet Explorer\n * @method\n * @memberof Popper.Utils\n * @param {Number} version to check\n * @returns {Boolean} isIE\n */\nfunction isIE(version) {\n if (version === 11) {\n return isIE11;\n }\n if (version === 10) {\n return isIE10;\n }\n return isIE11 || isIE10;\n}\n\n/**\n * Returns the offset parent of the given element\n * @method\n * @memberof Popper.Utils\n * @argument {Element} element\n * @returns {Element} offset parent\n */\nfunction getOffsetParent(element) {\n if (!element) {\n return document.documentElement;\n }\n\n var noOffsetParent = isIE(10) ? document.body : null;\n\n // NOTE: 1 DOM access here\n var offsetParent = element.offsetParent || null;\n // Skip hidden elements which don't have an offsetParent\n while (offsetParent === noOffsetParent && element.nextElementSibling) {\n offsetParent = (element = element.nextElementSibling).offsetParent;\n }\n\n var nodeName = offsetParent && offsetParent.nodeName;\n\n if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {\n return element ? element.ownerDocument.documentElement : document.documentElement;\n }\n\n // .offsetParent will return the closest TH, TD or TABLE in case\n // no offsetParent is present, I hate this job...\n if (['TH', 'TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') {\n return getOffsetParent(offsetParent);\n }\n\n return offsetParent;\n}\n\nfunction isOffsetContainer(element) {\n var nodeName = element.nodeName;\n\n if (nodeName === 'BODY') {\n return false;\n }\n return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element;\n}\n\n/**\n * Finds the root node (document, shadowDOM root) of the given element\n * @method\n * @memberof Popper.Utils\n * @argument {Element} node\n * @returns {Element} root node\n */\nfunction getRoot(node) {\n if (node.parentNode !== null) {\n return getRoot(node.parentNode);\n }\n\n return node;\n}\n\n/**\n * Finds the offset parent common to the two provided nodes\n * @method\n * @memberof Popper.Utils\n * @argument {Element} element1\n * @argument {Element} element2\n * @returns {Element} common offset parent\n */\nfunction findCommonOffsetParent(element1, element2) {\n // This check is needed to avoid errors in case one of the elements isn't defined for any reason\n if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) {\n return document.documentElement;\n }\n\n // Here we make sure to give as \"start\" the element that comes first in the DOM\n var order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING;\n var start = order ? element1 : element2;\n var end = order ? element2 : element1;\n\n // Get common ancestor container\n var range = document.createRange();\n range.setStart(start, 0);\n range.setEnd(end, 0);\n var commonAncestorContainer = range.commonAncestorContainer;\n\n // Both nodes are inside #document\n\n if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) {\n if (isOffsetContainer(commonAncestorContainer)) {\n return commonAncestorContainer;\n }\n\n return getOffsetParent(commonAncestorContainer);\n }\n\n // one of the nodes is inside shadowDOM, find which one\n var element1root = getRoot(element1);\n if (element1root.host) {\n return findCommonOffsetParent(element1root.host, element2);\n } else {\n return findCommonOffsetParent(element1, getRoot(element2).host);\n }\n}\n\n/**\n * Gets the scroll value of the given element in the given side (top and left)\n * @method\n * @memberof Popper.Utils\n * @argument {Element} element\n * @argument {String} side `top` or `left`\n * @returns {number} amount of scrolled pixels\n */\nfunction getScroll(element) {\n var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top';\n\n var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft';\n var nodeName = element.nodeName;\n\n if (nodeName === 'BODY' || nodeName === 'HTML') {\n var html = element.ownerDocument.documentElement;\n var scrollingElement = element.ownerDocument.scrollingElement || html;\n return scrollingElement[upperSide];\n }\n\n return element[upperSide];\n}\n\n/*\n * Sum or subtract the element scroll values (left and top) from a given rect object\n * @method\n * @memberof Popper.Utils\n * @param {Object} rect - Rect object you want to change\n * @param {HTMLElement} element - The element from the function reads the scroll values\n * @param {Boolean} subtract - set to true if you want to subtract the scroll values\n * @return {Object} rect - The modifier rect object\n */\nfunction includeScroll(rect, element) {\n var subtract = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n\n var scrollTop = getScroll(element, 'top');\n var scrollLeft = getScroll(element, 'left');\n var modifier = subtract ? -1 : 1;\n rect.top += scrollTop * modifier;\n rect.bottom += scrollTop * modifier;\n rect.left += scrollLeft * modifier;\n rect.right += scrollLeft * modifier;\n return rect;\n}\n\n/*\n * Helper to detect borders of a given element\n * @method\n * @memberof Popper.Utils\n * @param {CSSStyleDeclaration} styles\n * Result of `getStyleComputedProperty` on the given element\n * @param {String} axis - `x` or `y`\n * @return {number} borders - The borders size of the given axis\n */\n\nfunction getBordersSize(styles, axis) {\n var sideA = axis === 'x' ? 'Left' : 'Top';\n var sideB = sideA === 'Left' ? 'Right' : 'Bottom';\n\n return parseFloat(styles['border' + sideA + 'Width']) + parseFloat(styles['border' + sideB + 'Width']);\n}\n\nfunction getSize(axis, body, html, computedStyle) {\n return Math.max(body['offset' + axis], body['scroll' + axis], html['client' + axis], html['offset' + axis], html['scroll' + axis], isIE(10) ? parseInt(html['offset' + axis]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')]) : 0);\n}\n\nfunction getWindowSizes(document) {\n var body = document.body;\n var html = document.documentElement;\n var computedStyle = isIE(10) && getComputedStyle(html);\n\n return {\n height: getSize('Height', body, html, computedStyle),\n width: getSize('Width', body, html, computedStyle)\n };\n}\n\nvar classCallCheck = function (instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n};\n\nvar createClass = function () {\n function defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n }\n\n return function (Constructor, protoProps, staticProps) {\n if (protoProps) defineProperties(Constructor.prototype, protoProps);\n if (staticProps) defineProperties(Constructor, staticProps);\n return Constructor;\n };\n}();\n\n\n\n\n\nvar defineProperty = function (obj, key, value) {\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n\n return obj;\n};\n\nvar _extends = Object.assign || function (target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i];\n\n for (var key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n }\n }\n\n return target;\n};\n\n/**\n * Given element offsets, generate an output similar to getBoundingClientRect\n * @method\n * @memberof Popper.Utils\n * @argument {Object} offsets\n * @returns {Object} ClientRect like output\n */\nfunction getClientRect(offsets) {\n return _extends({}, offsets, {\n right: offsets.left + offsets.width,\n bottom: offsets.top + offsets.height\n });\n}\n\n/**\n * Get bounding client rect of given element\n * @method\n * @memberof Popper.Utils\n * @param {HTMLElement} element\n * @return {Object} client rect\n */\nfunction getBoundingClientRect(element) {\n var rect = {};\n\n // IE10 10 FIX: Please, don't ask, the element isn't\n // considered in DOM in some circumstances...\n // This isn't reproducible in IE10 compatibility mode of IE11\n try {\n if (isIE(10)) {\n rect = element.getBoundingClientRect();\n var scrollTop = getScroll(element, 'top');\n var scrollLeft = getScroll(element, 'left');\n rect.top += scrollTop;\n rect.left += scrollLeft;\n rect.bottom += scrollTop;\n rect.right += scrollLeft;\n } else {\n rect = element.getBoundingClientRect();\n }\n } catch (e) {}\n\n var result = {\n left: rect.left,\n top: rect.top,\n width: rect.right - rect.left,\n height: rect.bottom - rect.top\n };\n\n // subtract scrollbar size from sizes\n var sizes = element.nodeName === 'HTML' ? getWindowSizes(element.ownerDocument) : {};\n var width = sizes.width || element.clientWidth || result.width;\n var height = sizes.height || element.clientHeight || result.height;\n\n var horizScrollbar = element.offsetWidth - width;\n var vertScrollbar = element.offsetHeight - height;\n\n // if an hypothetical scrollbar is detected, we must be sure it's not a `border`\n // we make this check conditional for performance reasons\n if (horizScrollbar || vertScrollbar) {\n var styles = getStyleComputedProperty(element);\n horizScrollbar -= getBordersSize(styles, 'x');\n vertScrollbar -= getBordersSize(styles, 'y');\n\n result.width -= horizScrollbar;\n result.height -= vertScrollbar;\n }\n\n return getClientRect(result);\n}\n\nfunction getOffsetRectRelativeToArbitraryNode(children, parent) {\n var fixedPosition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n\n var isIE10 = isIE(10);\n var isHTML = parent.nodeName === 'HTML';\n var childrenRect = getBoundingClientRect(children);\n var parentRect = getBoundingClientRect(parent);\n var scrollParent = getScrollParent(children);\n\n var styles = getStyleComputedProperty(parent);\n var borderTopWidth = parseFloat(styles.borderTopWidth);\n var borderLeftWidth = parseFloat(styles.borderLeftWidth);\n\n // In cases where the parent is fixed, we must ignore negative scroll in offset calc\n if (fixedPosition && isHTML) {\n parentRect.top = Math.max(parentRect.top, 0);\n parentRect.left = Math.max(parentRect.left, 0);\n }\n var offsets = getClientRect({\n top: childrenRect.top - parentRect.top - borderTopWidth,\n left: childrenRect.left - parentRect.left - borderLeftWidth,\n width: childrenRect.width,\n height: childrenRect.height\n });\n offsets.marginTop = 0;\n offsets.marginLeft = 0;\n\n // Subtract margins of documentElement in case it's being used as parent\n // we do this only on HTML because it's the only element that behaves\n // differently when margins are applied to it. The margins are included in\n // the box of the documentElement, in the other cases not.\n if (!isIE10 && isHTML) {\n var marginTop = parseFloat(styles.marginTop);\n var marginLeft = parseFloat(styles.marginLeft);\n\n offsets.top -= borderTopWidth - marginTop;\n offsets.bottom -= borderTopWidth - marginTop;\n offsets.left -= borderLeftWidth - marginLeft;\n offsets.right -= borderLeftWidth - marginLeft;\n\n // Attach marginTop and marginLeft because in some circumstances we may need them\n offsets.marginTop = marginTop;\n offsets.marginLeft = marginLeft;\n }\n\n if (isIE10 && !fixedPosition ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') {\n offsets = includeScroll(offsets, parent);\n }\n\n return offsets;\n}\n\nfunction getViewportOffsetRectRelativeToArtbitraryNode(element) {\n var excludeScroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n var html = element.ownerDocument.documentElement;\n var relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html);\n var width = Math.max(html.clientWidth, window.innerWidth || 0);\n var height = Math.max(html.clientHeight, window.innerHeight || 0);\n\n var scrollTop = !excludeScroll ? getScroll(html) : 0;\n var scrollLeft = !excludeScroll ? getScroll(html, 'left') : 0;\n\n var offset = {\n top: scrollTop - relativeOffset.top + relativeOffset.marginTop,\n left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft,\n width: width,\n height: height\n };\n\n return getClientRect(offset);\n}\n\n/**\n * Check if the given element is fixed or is inside a fixed parent\n * @method\n * @memberof Popper.Utils\n * @argument {Element} element\n * @argument {Element} customContainer\n * @returns {Boolean} answer to \"isFixed?\"\n */\nfunction isFixed(element) {\n var nodeName = element.nodeName;\n if (nodeName === 'BODY' || nodeName === 'HTML') {\n return false;\n }\n if (getStyleComputedProperty(element, 'position') === 'fixed') {\n return true;\n }\n var parentNode = getParentNode(element);\n if (!parentNode) {\n return false;\n }\n return isFixed(parentNode);\n}\n\n/**\n * Finds the first parent of an element that has a transformed property defined\n * @method\n * @memberof Popper.Utils\n * @argument {Element} element\n * @returns {Element} first transformed parent or documentElement\n */\n\nfunction getFixedPositionOffsetParent(element) {\n // This check is needed to avoid errors in case one of the elements isn't defined for any reason\n if (!element || !element.parentElement || isIE()) {\n return document.documentElement;\n }\n var el = element.parentElement;\n while (el && getStyleComputedProperty(el, 'transform') === 'none') {\n el = el.parentElement;\n }\n return el || document.documentElement;\n}\n\n/**\n * Computed the boundaries limits and return them\n * @method\n * @memberof Popper.Utils\n * @param {HTMLElement} popper\n * @param {HTMLElement} reference\n * @param {number} padding\n * @param {HTMLElement} boundariesElement - Element used to define the boundaries\n * @param {Boolean} fixedPosition - Is in fixed position mode\n * @returns {Object} Coordinates of the boundaries\n */\nfunction getBoundaries(popper, reference, padding, boundariesElement) {\n var fixedPosition = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;\n\n // NOTE: 1 DOM access here\n\n var boundaries = { top: 0, left: 0 };\n var offsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, getReferenceNode(reference));\n\n // Handle viewport case\n if (boundariesElement === 'viewport') {\n boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent, fixedPosition);\n } else {\n // Handle other cases based on DOM element used as boundaries\n var boundariesNode = void 0;\n if (boundariesElement === 'scrollParent') {\n boundariesNode = getScrollParent(getParentNode(reference));\n if (boundariesNode.nodeName === 'BODY') {\n boundariesNode = popper.ownerDocument.documentElement;\n }\n } else if (boundariesElement === 'window') {\n boundariesNode = popper.ownerDocument.documentElement;\n } else {\n boundariesNode = boundariesElement;\n }\n\n var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent, fixedPosition);\n\n // In case of HTML, we need a different computation\n if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) {\n var _getWindowSizes = getWindowSizes(popper.ownerDocument),\n height = _getWindowSizes.height,\n width = _getWindowSizes.width;\n\n boundaries.top += offsets.top - offsets.marginTop;\n boundaries.bottom = height + offsets.top;\n boundaries.left += offsets.left - offsets.marginLeft;\n boundaries.right = width + offsets.left;\n } else {\n // for all the other DOM elements, this one is good\n boundaries = offsets;\n }\n }\n\n // Add paddings\n padding = padding || 0;\n var isPaddingNumber = typeof padding === 'number';\n boundaries.left += isPaddingNumber ? padding : padding.left || 0;\n boundaries.top += isPaddingNumber ? padding : padding.top || 0;\n boundaries.right -= isPaddingNumber ? padding : padding.right || 0;\n boundaries.bottom -= isPaddingNumber ? padding : padding.bottom || 0;\n\n return boundaries;\n}\n\nfunction getArea(_ref) {\n var width = _ref.width,\n height = _ref.height;\n\n return width * height;\n}\n\n/**\n * Utility used to transform the `auto` placement to the placement with more\n * available space.\n * @method\n * @memberof Popper.Utils\n * @argument {Object} data - The data object generated by update method\n * @argument {Object} options - Modifiers configuration and options\n * @returns {Object} The data object, properly modified\n */\nfunction computeAutoPlacement(placement, refRect, popper, reference, boundariesElement) {\n var padding = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;\n\n if (placement.indexOf('auto') === -1) {\n return placement;\n }\n\n var boundaries = getBoundaries(popper, reference, padding, boundariesElement);\n\n var rects = {\n top: {\n width: boundaries.width,\n height: refRect.top - boundaries.top\n },\n right: {\n width: boundaries.right - refRect.right,\n height: boundaries.height\n },\n bottom: {\n width: boundaries.width,\n height: boundaries.bottom - refRect.bottom\n },\n left: {\n width: refRect.left - boundaries.left,\n height: boundaries.height\n }\n };\n\n var sortedAreas = Object.keys(rects).map(function (key) {\n return _extends({\n key: key\n }, rects[key], {\n area: getArea(rects[key])\n });\n }).sort(function (a, b) {\n return b.area - a.area;\n });\n\n var filteredAreas = sortedAreas.filter(function (_ref2) {\n var width = _ref2.width,\n height = _ref2.height;\n return width >= popper.clientWidth && height >= popper.clientHeight;\n });\n\n var computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key;\n\n var variation = placement.split('-')[1];\n\n return computedPlacement + (variation ? '-' + variation : '');\n}\n\n/**\n * Get offsets to the reference element\n * @method\n * @memberof Popper.Utils\n * @param {Object} state\n * @param {Element} popper - the popper element\n * @param {Element} reference - the reference element (the popper will be relative to this)\n * @param {Element} fixedPosition - is in fixed position mode\n * @returns {Object} An object containing the offsets which will be applied to the popper\n */\nfunction getReferenceOffsets(state, popper, reference) {\n var fixedPosition = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;\n\n var commonOffsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, getReferenceNode(reference));\n return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent, fixedPosition);\n}\n\n/**\n * Get the outer sizes of the given element (offset size + margins)\n * @method\n * @memberof Popper.Utils\n * @argument {Element} element\n * @returns {Object} object containing width and height properties\n */\nfunction getOuterSizes(element) {\n var window = element.ownerDocument.defaultView;\n var styles = window.getComputedStyle(element);\n var x = parseFloat(styles.marginTop || 0) + parseFloat(styles.marginBottom || 0);\n var y = parseFloat(styles.marginLeft || 0) + parseFloat(styles.marginRight || 0);\n var result = {\n width: element.offsetWidth + y,\n height: element.offsetHeight + x\n };\n return result;\n}\n\n/**\n * Get the opposite placement of the given one\n * @method\n * @memberof Popper.Utils\n * @argument {String} placement\n * @returns {String} flipped placement\n */\nfunction getOppositePlacement(placement) {\n var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' };\n return placement.replace(/left|right|bottom|top/g, function (matched) {\n return hash[matched];\n });\n}\n\n/**\n * Get offsets to the popper\n * @method\n * @memberof Popper.Utils\n * @param {Object} position - CSS position the Popper will get applied\n * @param {HTMLElement} popper - the popper element\n * @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this)\n * @param {String} placement - one of the valid placement options\n * @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper\n */\nfunction getPopperOffsets(popper, referenceOffsets, placement) {\n placement = placement.split('-')[0];\n\n // Get popper node sizes\n var popperRect = getOuterSizes(popper);\n\n // Add position, width and height to our offsets object\n var popperOffsets = {\n width: popperRect.width,\n height: popperRect.height\n };\n\n // depending by the popper placement we have to compute its offsets slightly differently\n var isHoriz = ['right', 'left'].indexOf(placement) !== -1;\n var mainSide = isHoriz ? 'top' : 'left';\n var secondarySide = isHoriz ? 'left' : 'top';\n var measurement = isHoriz ? 'height' : 'width';\n var secondaryMeasurement = !isHoriz ? 'height' : 'width';\n\n popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2;\n if (placement === secondarySide) {\n popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement];\n } else {\n popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)];\n }\n\n return popperOffsets;\n}\n\n/**\n * Mimics the `find` method of Array\n * @method\n * @memberof Popper.Utils\n * @argument {Array} arr\n * @argument prop\n * @argument value\n * @returns index or -1\n */\nfunction find(arr, check) {\n // use native find if supported\n if (Array.prototype.find) {\n return arr.find(check);\n }\n\n // use `filter` to obtain the same behavior of `find`\n return arr.filter(check)[0];\n}\n\n/**\n * Return the index of the matching object\n * @method\n * @memberof Popper.Utils\n * @argument {Array} arr\n * @argument prop\n * @argument value\n * @returns index or -1\n */\nfunction findIndex(arr, prop, value) {\n // use native findIndex if supported\n if (Array.prototype.findIndex) {\n return arr.findIndex(function (cur) {\n return cur[prop] === value;\n });\n }\n\n // use `find` + `indexOf` if `findIndex` isn't supported\n var match = find(arr, function (obj) {\n return obj[prop] === value;\n });\n return arr.indexOf(match);\n}\n\n/**\n * Loop trough the list of modifiers and run them in order,\n * each of them will then edit the data object.\n * @method\n * @memberof Popper.Utils\n * @param {dataObject} data\n * @param {Array} modifiers\n * @param {String} ends - Optional modifier name used as stopper\n * @returns {dataObject}\n */\nfunction runModifiers(modifiers, data, ends) {\n var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends));\n\n modifiersToRun.forEach(function (modifier) {\n if (modifier['function']) {\n // eslint-disable-line dot-notation\n console.warn('`modifier.function` is deprecated, use `modifier.fn`!');\n }\n var fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation\n if (modifier.enabled && isFunction(fn)) {\n // Add properties to offsets to make them a complete clientRect object\n // we do this before each modifier to make sure the previous one doesn't\n // mess with these values\n data.offsets.popper = getClientRect(data.offsets.popper);\n data.offsets.reference = getClientRect(data.offsets.reference);\n\n data = fn(data, modifier);\n }\n });\n\n return data;\n}\n\n/**\n * Updates the position of the popper, computing the new offsets and applying\n * the new style.<br />\n * Prefer `scheduleUpdate` over `update` because of performance reasons.\n * @method\n * @memberof Popper\n */\nfunction update() {\n // if popper is destroyed, don't perform any further update\n if (this.state.isDestroyed) {\n return;\n }\n\n var data = {\n instance: this,\n styles: {},\n arrowStyles: {},\n attributes: {},\n flipped: false,\n offsets: {}\n };\n\n // compute reference element offsets\n data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference, this.options.positionFixed);\n\n // compute auto placement, store placement inside the data object,\n // modifiers will be able to edit `placement` if needed\n // and refer to originalPlacement to know the original value\n data.placement = computeAutoPlacement(this.options.placement, data.offsets.reference, this.popper, this.reference, this.options.modifiers.flip.boundariesElement, this.options.modifiers.flip.padding);\n\n // store the computed placement inside `originalPlacement`\n data.originalPlacement = data.placement;\n\n data.positionFixed = this.options.positionFixed;\n\n // compute the popper offsets\n data.offsets.popper = getPopperOffsets(this.popper, data.offsets.reference, data.placement);\n\n data.offsets.popper.position = this.options.positionFixed ? 'fixed' : 'absolute';\n\n // run the modifiers\n data = runModifiers(this.modifiers, data);\n\n // the first `update` will call `onCreate` callback\n // the other ones will call `onUpdate` callback\n if (!this.state.isCreated) {\n this.state.isCreated = true;\n this.options.onCreate(data);\n } else {\n this.options.onUpdate(data);\n }\n}\n\n/**\n * Helper used to know if the given modifier is enabled.\n * @method\n * @memberof Popper.Utils\n * @returns {Boolean}\n */\nfunction isModifierEnabled(modifiers, modifierName) {\n return modifiers.some(function (_ref) {\n var name = _ref.name,\n enabled = _ref.enabled;\n return enabled && name === modifierName;\n });\n}\n\n/**\n * Get the prefixed supported property name\n * @method\n * @memberof Popper.Utils\n * @argument {String} property (camelCase)\n * @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix)\n */\nfunction getSupportedPropertyName(property) {\n var prefixes = [false, 'ms', 'Webkit', 'Moz', 'O'];\n var upperProp = property.charAt(0).toUpperCase() + property.slice(1);\n\n for (var i = 0; i < prefixes.length; i++) {\n var prefix = prefixes[i];\n var toCheck = prefix ? '' + prefix + upperProp : property;\n if (typeof document.body.style[toCheck] !== 'undefined') {\n return toCheck;\n }\n }\n return null;\n}\n\n/**\n * Destroys the popper.\n * @method\n * @memberof Popper\n */\nfunction destroy() {\n this.state.isDestroyed = true;\n\n // touch DOM only if `applyStyle` modifier is enabled\n if (isModifierEnabled(this.modifiers, 'applyStyle')) {\n this.popper.removeAttribute('x-placement');\n this.popper.style.position = '';\n this.popper.style.top = '';\n this.popper.style.left = '';\n this.popper.style.right = '';\n this.popper.style.bottom = '';\n this.popper.style.willChange = '';\n this.popper.style[getSupportedPropertyName('transform')] = '';\n }\n\n this.disableEventListeners();\n\n // remove the popper if user explicitly asked for the deletion on destroy\n // do not use `remove` because IE11 doesn't support it\n if (this.options.removeOnDestroy) {\n this.popper.parentNode.removeChild(this.popper);\n }\n return this;\n}\n\n/**\n * Get the window associated with the element\n * @argument {Element} element\n * @returns {Window}\n */\nfunction getWindow(element) {\n var ownerDocument = element.ownerDocument;\n return ownerDocument ? ownerDocument.defaultView : window;\n}\n\nfunction attachToScrollParents(scrollParent, event, callback, scrollParents) {\n var isBody = scrollParent.nodeName === 'BODY';\n var target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent;\n target.addEventListener(event, callback, { passive: true });\n\n if (!isBody) {\n attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents);\n }\n scrollParents.push(target);\n}\n\n/**\n * Setup needed event listeners used to update the popper position\n * @method\n * @memberof Popper.Utils\n * @private\n */\nfunction setupEventListeners(reference, options, state, updateBound) {\n // Resize event listener on window\n state.updateBound = updateBound;\n getWindow(reference).addEventListener('resize', state.updateBound, { passive: true });\n\n // Scroll event listener on scroll parents\n var scrollElement = getScrollParent(reference);\n attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents);\n state.scrollElement = scrollElement;\n state.eventsEnabled = true;\n\n return state;\n}\n\n/**\n * It will add resize/scroll events and start recalculating\n * position of the popper element when they are triggered.\n * @method\n * @memberof Popper\n */\nfunction enableEventListeners() {\n if (!this.state.eventsEnabled) {\n this.state = setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate);\n }\n}\n\n/**\n * Remove event listeners used to update the popper position\n * @method\n * @memberof Popper.Utils\n * @private\n */\nfunction removeEventListeners(reference, state) {\n // Remove resize event listener on window\n getWindow(reference).removeEventListener('resize', state.updateBound);\n\n // Remove scroll event listener on scroll parents\n state.scrollParents.forEach(function (target) {\n target.removeEventListener('scroll', state.updateBound);\n });\n\n // Reset state\n state.updateBound = null;\n state.scrollParents = [];\n state.scrollElement = null;\n state.eventsEnabled = false;\n return state;\n}\n\n/**\n * It will remove resize/scroll events and won't recalculate popper position\n * when they are triggered. It also won't trigger `onUpdate` callback anymore,\n * unless you call `update` method manually.\n * @method\n * @memberof Popper\n */\nfunction disableEventListeners() {\n if (this.state.eventsEnabled) {\n cancelAnimationFrame(this.scheduleUpdate);\n this.state = removeEventListeners(this.reference, this.state);\n }\n}\n\n/**\n * Tells if a given input is a number\n * @method\n * @memberof Popper.Utils\n * @param {*} input to check\n * @return {Boolean}\n */\nfunction isNumeric(n) {\n return n !== '' && !isNaN(parseFloat(n)) && isFinite(n);\n}\n\n/**\n * Set the style to the given popper\n * @method\n * @memberof Popper.Utils\n * @argument {Element} element - Element to apply the style to\n * @argument {Object} styles\n * Object with a list of properties and values which will be applied to the element\n */\nfunction setStyles(element, styles) {\n Object.keys(styles).forEach(function (prop) {\n var unit = '';\n // add unit if the value is numeric and is one of the following\n if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) {\n unit = 'px';\n }\n element.style[prop] = styles[prop] + unit;\n });\n}\n\n/**\n * Set the attributes to the given popper\n * @method\n * @memberof Popper.Utils\n * @argument {Element} element - Element to apply the attributes to\n * @argument {Object} styles\n * Object with a list of properties and values which will be applied to the element\n */\nfunction setAttributes(element, attributes) {\n Object.keys(attributes).forEach(function (prop) {\n var value = attributes[prop];\n if (value !== false) {\n element.setAttribute(prop, attributes[prop]);\n } else {\n element.removeAttribute(prop);\n }\n });\n}\n\n/**\n * @function\n * @memberof Modifiers\n * @argument {Object} data - The data object generated by `update` method\n * @argument {Object} data.styles - List of style properties - values to apply to popper element\n * @argument {Object} data.attributes - List of attribute properties - values to apply to popper element\n * @argument {Object} options - Modifiers configuration and options\n * @returns {Object} The same data object\n */\nfunction applyStyle(data) {\n // any property present in `data.styles` will be applied to the popper,\n // in this way we can make the 3rd party modifiers add custom styles to it\n // Be aware, modifiers could override the properties defined in the previous\n // lines of this modifier!\n setStyles(data.instance.popper, data.styles);\n\n // any property present in `data.attributes` will be applied to the popper,\n // they will be set as HTML attributes of the element\n setAttributes(data.instance.popper, data.attributes);\n\n // if arrowElement is defined and arrowStyles has some properties\n if (data.arrowElement && Object.keys(data.arrowStyles).length) {\n setStyles(data.arrowElement, data.arrowStyles);\n }\n\n return data;\n}\n\n/**\n * Set the x-placement attribute before everything else because it could be used\n * to add margins to the popper margins needs to be calculated to get the\n * correct popper offsets.\n * @method\n * @memberof Popper.modifiers\n * @param {HTMLElement} reference - The reference element used to position the popper\n * @param {HTMLElement} popper - The HTML element used as popper\n * @param {Object} options - Popper.js options\n */\nfunction applyStyleOnLoad(reference, popper, options, modifierOptions, state) {\n // compute reference element offsets\n var referenceOffsets = getReferenceOffsets(state, popper, reference, options.positionFixed);\n\n // compute auto placement, store placement inside the data object,\n // modifiers will be able to edit `placement` if needed\n // and refer to originalPlacement to know the original value\n var placement = computeAutoPlacement(options.placement, referenceOffsets, popper, reference, options.modifiers.flip.boundariesElement, options.modifiers.flip.padding);\n\n popper.setAttribute('x-placement', placement);\n\n // Apply `position` to popper before anything else because\n // without the position applied we can't guarantee correct computations\n setStyles(popper, { position: options.positionFixed ? 'fixed' : 'absolute' });\n\n return options;\n}\n\n/**\n * @function\n * @memberof Popper.Utils\n * @argument {Object} data - The data object generated by `update` method\n * @argument {Boolean} shouldRound - If the offsets should be rounded at all\n * @returns {Object} The popper's position offsets rounded\n *\n * The tale of pixel-perfect positioning. It's still not 100% perfect, but as\n * good as it can be within reason.\n * Discussion here: https://github.com/FezVrasta/popper.js/pull/715\n *\n * Low DPI screens cause a popper to be blurry if not using full pixels (Safari\n * as well on High DPI screens).\n *\n * Firefox prefers no rounding for positioning and does not have blurriness on\n * high DPI screens.\n *\n * Only horizontal placement and left/right values need to be considered.\n */\nfunction getRoundedOffsets(data, shouldRound) {\n var _data$offsets = data.offsets,\n popper = _data$offsets.popper,\n reference = _data$offsets.reference;\n var round = Math.round,\n floor = Math.floor;\n\n var noRound = function noRound(v) {\n return v;\n };\n\n var referenceWidth = round(reference.width);\n var popperWidth = round(popper.width);\n\n var isVertical = ['left', 'right'].indexOf(data.placement) !== -1;\n var isVariation = data.placement.indexOf('-') !== -1;\n var sameWidthParity = referenceWidth % 2 === popperWidth % 2;\n var bothOddWidth = referenceWidth % 2 === 1 && popperWidth % 2 === 1;\n\n var horizontalToInteger = !shouldRound ? noRound : isVertical || isVariation || sameWidthParity ? round : floor;\n var verticalToInteger = !shouldRound ? noRound : round;\n\n return {\n left: horizontalToInteger(bothOddWidth && !isVariation && shouldRound ? popper.left - 1 : popper.left),\n top: verticalToInteger(popper.top),\n bottom: verticalToInteger(popper.bottom),\n right: horizontalToInteger(popper.right)\n };\n}\n\nvar isFirefox = isBrowser && /Firefox/i.test(navigator.userAgent);\n\n/**\n * @function\n * @memberof Modifiers\n * @argument {Object} data - The data object generated by `update` method\n * @argument {Object} options - Modifiers configuration and options\n * @returns {Object} The data object, properly modified\n */\nfunction computeStyle(data, options) {\n var x = options.x,\n y = options.y;\n var popper = data.offsets.popper;\n\n // Remove this legacy support in Popper.js v2\n\n var legacyGpuAccelerationOption = find(data.instance.modifiers, function (modifier) {\n return modifier.name === 'applyStyle';\n }).gpuAcceleration;\n if (legacyGpuAccelerationOption !== undefined) {\n console.warn('WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!');\n }\n var gpuAcceleration = legacyGpuAccelerationOption !== undefined ? legacyGpuAccelerationOption : options.gpuAcceleration;\n\n var offsetParent = getOffsetParent(data.instance.popper);\n var offsetParentRect = getBoundingClientRect(offsetParent);\n\n // Styles\n var styles = {\n position: popper.position\n };\n\n var offsets = getRoundedOffsets(data, window.devicePixelRatio < 2 || !isFirefox);\n\n var sideA = x === 'bottom' ? 'top' : 'bottom';\n var sideB = y === 'right' ? 'left' : 'right';\n\n // if gpuAcceleration is set to `true` and transform is supported,\n // we use `translate3d` to apply the position to the popper we\n // automatically use the supported prefixed version if needed\n var prefixedProperty = getSupportedPropertyName('transform');\n\n // now, let's make a step back and look at this code closely (wtf?)\n // If the content of the popper grows once it's been positioned, it\n // may happen that the popper gets misplaced because of the new content\n // overflowing its reference element\n // To avoid this problem, we provide two options (x and y), which allow\n // the consumer to define the offset origin.\n // If we position a popper on top of a reference element, we can set\n // `x` to `top` to make the popper grow towards its top instead of\n // its bottom.\n var left = void 0,\n top = void 0;\n if (sideA === 'bottom') {\n // when offsetParent is <html> the positioning is relative to the bottom of the screen (excluding the scrollbar)\n // and not the bottom of the html element\n if (offsetParent.nodeName === 'HTML') {\n top = -offsetParent.clientHeight + offsets.bottom;\n } else {\n top = -offsetParentRect.height + offsets.bottom;\n }\n } else {\n top = offsets.top;\n }\n if (sideB === 'right') {\n if (offsetParent.nodeName === 'HTML') {\n left = -offsetParent.clientWidth + offsets.right;\n } else {\n left = -offsetParentRect.width + offsets.right;\n }\n } else {\n left = offsets.left;\n }\n if (gpuAcceleration && prefixedProperty) {\n styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)';\n styles[sideA] = 0;\n styles[sideB] = 0;\n styles.willChange = 'transform';\n } else {\n // othwerise, we use the standard `top`, `left`, `bottom` and `right` properties\n var invertTop = sideA === 'bottom' ? -1 : 1;\n var invertLeft = sideB === 'right' ? -1 : 1;\n styles[sideA] = top * invertTop;\n styles[sideB] = left * invertLeft;\n styles.willChange = sideA + ', ' + sideB;\n }\n\n // Attributes\n var attributes = {\n 'x-placement': data.placement\n };\n\n // Update `data` attributes, styles and arrowStyles\n data.attributes = _extends({}, attributes, data.attributes);\n data.styles = _extends({}, styles, data.styles);\n data.arrowStyles = _extends({}, data.offsets.arrow, data.arrowStyles);\n\n return data;\n}\n\n/**\n * Helper used to know if the given modifier depends from another one.<br />\n * It checks if the needed modifier is listed and enabled.\n * @method\n * @memberof Popper.Utils\n * @param {Array} modifiers - list of modifiers\n * @param {String} requestingName - name of requesting modifier\n * @param {String} requestedName - name of requested modifier\n * @returns {Boolean}\n */\nfunction isModifierRequired(modifiers, requestingName, requestedName) {\n var requesting = find(modifiers, function (_ref) {\n var name = _ref.name;\n return name === requestingName;\n });\n\n var isRequired = !!requesting && modifiers.some(function (modifier) {\n return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order;\n });\n\n if (!isRequired) {\n var _requesting = '`' + requestingName + '`';\n var requested = '`' + requestedName + '`';\n console.warn(requested + ' modifier is required by ' + _requesting + ' modifier in order to work, be sure to include it before ' + _requesting + '!');\n }\n return isRequired;\n}\n\n/**\n * @function\n * @memberof Modifiers\n * @argument {Object} data - The data object generated by update method\n * @argument {Object} options - Modifiers configuration and options\n * @returns {Object} The data object, properly modified\n */\nfunction arrow(data, options) {\n var _data$offsets$arrow;\n\n // arrow depends on keepTogether in order to work\n if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) {\n return data;\n }\n\n var arrowElement = options.element;\n\n // if arrowElement is a string, suppose it's a CSS selector\n if (typeof arrowElement === 'string') {\n arrowElement = data.instance.popper.querySelector(arrowElement);\n\n // if arrowElement is not found, don't run the modifier\n if (!arrowElement) {\n return data;\n }\n } else {\n // if the arrowElement isn't a query selector we must check that the\n // provided DOM node is child of its popper node\n if (!data.instance.popper.contains(arrowElement)) {\n console.warn('WARNING: `arrow.element` must be child of its popper element!');\n return data;\n }\n }\n\n var placement = data.placement.split('-')[0];\n var _data$offsets = data.offsets,\n popper = _data$offsets.popper,\n reference = _data$offsets.reference;\n\n var isVertical = ['left', 'right'].indexOf(placement) !== -1;\n\n var len = isVertical ? 'height' : 'width';\n var sideCapitalized = isVertical ? 'Top' : 'Left';\n var side = sideCapitalized.toLowerCase();\n var altSide = isVertical ? 'left' : 'top';\n var opSide = isVertical ? 'bottom' : 'right';\n var arrowElementSize = getOuterSizes(arrowElement)[len];\n\n //\n // extends keepTogether behavior making sure the popper and its\n // reference have enough pixels in conjunction\n //\n\n // top/left side\n if (reference[opSide] - arrowElementSize < popper[side]) {\n data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowElementSize);\n }\n // bottom/right side\n if (reference[side] + arrowElementSize > popper[opSide]) {\n data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide];\n }\n data.offsets.popper = getClientRect(data.offsets.popper);\n\n // compute center of the popper\n var center = reference[side] + reference[len] / 2 - arrowElementSize / 2;\n\n // Compute the sideValue using the updated popper offsets\n // take popper margin in account because we don't have this info available\n var css = getStyleComputedProperty(data.instance.popper);\n var popperMarginSide = parseFloat(css['margin' + sideCapitalized]);\n var popperBorderSide = parseFloat(css['border' + sideCapitalized + 'Width']);\n var sideValue = center - data.offsets.popper[side] - popperMarginSide - popperBorderSide;\n\n // prevent arrowElement from being placed not contiguously to its popper\n sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0);\n\n data.arrowElement = arrowElement;\n data.offsets.arrow = (_data$offsets$arrow = {}, defineProperty(_data$offsets$arrow, side, Math.round(sideValue)), defineProperty(_data$offsets$arrow, altSide, ''), _data$offsets$arrow);\n\n return data;\n}\n\n/**\n * Get the opposite placement variation of the given one\n * @method\n * @memberof Popper.Utils\n * @argument {String} placement variation\n * @returns {String} flipped placement variation\n */\nfunction getOppositeVariation(variation) {\n if (variation === 'end') {\n return 'start';\n } else if (variation === 'start') {\n return 'end';\n }\n return variation;\n}\n\n/**\n * List of accepted placements to use as values of the `placement` option.<br />\n * Valid placements are:\n * - `auto`\n * - `top`\n * - `right`\n * - `bottom`\n * - `left`\n *\n * Each placement can have a variation from this list:\n * - `-start`\n * - `-end`\n *\n * Variations are interpreted easily if you think of them as the left to right\n * written languages. Horizontally (`top` and `bottom`), `start` is left and `end`\n * is right.<br />\n * Vertically (`left` and `right`), `start` is top and `end` is bottom.\n *\n * Some valid examples are:\n * - `top-end` (on top of reference, right aligned)\n * - `right-start` (on right of reference, top aligned)\n * - `bottom` (on bottom, centered)\n * - `auto-end` (on the side with more space available, alignment depends by placement)\n *\n * @static\n * @type {Array}\n * @enum {String}\n * @readonly\n * @method placements\n * @memberof Popper\n */\nvar placements = ['auto-start', 'auto', 'auto-end', 'top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start'];\n\n// Get rid of `auto` `auto-start` and `auto-end`\nvar validPlacements = placements.slice(3);\n\n/**\n * Given an initial placement, returns all the subsequent placements\n * clockwise (or counter-clockwise).\n *\n * @method\n * @memberof Popper.Utils\n * @argument {String} placement - A valid placement (it accepts variations)\n * @argument {Boolean} counter - Set to true to walk the placements counterclockwise\n * @returns {Array} placements including their variations\n */\nfunction clockwise(placement) {\n var counter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n var index = validPlacements.indexOf(placement);\n var arr = validPlacements.slice(index + 1).concat(validPlacements.slice(0, index));\n return counter ? arr.reverse() : arr;\n}\n\nvar BEHAVIORS = {\n FLIP: 'flip',\n CLOCKWISE: 'clockwise',\n COUNTERCLOCKWISE: 'counterclockwise'\n};\n\n/**\n * @function\n * @memberof Modifiers\n * @argument {Object} data - The data object generated by update method\n * @argument {Object} options - Modifiers configuration and options\n * @returns {Object} The data object, properly modified\n */\nfunction flip(data, options) {\n // if `inner` modifier is enabled, we can't use the `flip` modifier\n if (isModifierEnabled(data.instance.modifiers, 'inner')) {\n return data;\n }\n\n if (data.flipped && data.placement === data.originalPlacement) {\n // seems like flip is trying to loop, probably there's not enough space on any of the flippable sides\n return data;\n }\n\n var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, options.boundariesElement, data.positionFixed);\n\n var placement = data.placement.split('-')[0];\n var placementOpposite = getOppositePlacement(placement);\n var variation = data.placement.split('-')[1] || '';\n\n var flipOrder = [];\n\n switch (options.behavior) {\n case BEHAVIORS.FLIP:\n flipOrder = [placement, placementOpposite];\n break;\n case BEHAVIORS.CLOCKWISE:\n flipOrder = clockwise(placement);\n break;\n case BEHAVIORS.COUNTERCLOCKWISE:\n flipOrder = clockwise(placement, true);\n break;\n default:\n flipOrder = options.behavior;\n }\n\n flipOrder.forEach(function (step, index) {\n if (placement !== step || flipOrder.length === index + 1) {\n return data;\n }\n\n placement = data.placement.split('-')[0];\n placementOpposite = getOppositePlacement(placement);\n\n var popperOffsets = data.offsets.popper;\n var refOffsets = data.offsets.reference;\n\n // using floor because the reference offsets may contain decimals we are not going to consider here\n var floor = Math.floor;\n var overlapsRef = placement === 'left' && floor(popperOffsets.right) > floor(refOffsets.left) || placement === 'right' && floor(popperOffsets.left) < floor(refOffsets.right) || placement === 'top' && floor(popperOffsets.bottom) > floor(refOffsets.top) || placement === 'bottom' && floor(popperOffsets.top) < floor(refOffsets.bottom);\n\n var overflowsLeft = floor(popperOffsets.left) < floor(boundaries.left);\n var overflowsRight = floor(popperOffsets.right) > floor(boundaries.right);\n var overflowsTop = floor(popperOffsets.top) < floor(boundaries.top);\n var overflowsBottom = floor(popperOffsets.bottom) > floor(boundaries.bottom);\n\n var overflowsBoundaries = placement === 'left' && overflowsLeft || placement === 'right' && overflowsRight || placement === 'top' && overflowsTop || placement === 'bottom' && overflowsBottom;\n\n // flip the variation if required\n var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;\n\n // flips variation if reference element overflows boundaries\n var flippedVariationByRef = !!options.flipVariations && (isVertical && variation === 'start' && overflowsLeft || isVertical && variation === 'end' && overflowsRight || !isVertical && variation === 'start' && overflowsTop || !isVertical && variation === 'end' && overflowsBottom);\n\n // flips variation if popper content overflows boundaries\n var flippedVariationByContent = !!options.flipVariationsByContent && (isVertical && variation === 'start' && overflowsRight || isVertical && variation === 'end' && overflowsLeft || !isVertical && variation === 'start' && overflowsBottom || !isVertical && variation === 'end' && overflowsTop);\n\n var flippedVariation = flippedVariationByRef || flippedVariationByContent;\n\n if (overlapsRef || overflowsBoundaries || flippedVariation) {\n // this boolean to detect any flip loop\n data.flipped = true;\n\n if (overlapsRef || overflowsBoundaries) {\n placement = flipOrder[index + 1];\n }\n\n if (flippedVariation) {\n variation = getOppositeVariation(variation);\n }\n\n data.placement = placement + (variation ? '-' + variation : '');\n\n // this object contains `position`, we want to preserve it along with\n // any additional property we may add in the future\n data.offsets.popper = _extends({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement));\n\n data = runModifiers(data.instance.modifiers, data, 'flip');\n }\n });\n return data;\n}\n\n/**\n * @function\n * @memberof Modifiers\n * @argument {Object} data - The data object generated by update method\n * @argument {Object} options - Modifiers configuration and options\n * @returns {Object} The data object, properly modified\n */\nfunction keepTogether(data) {\n var _data$offsets = data.offsets,\n popper = _data$offsets.popper,\n reference = _data$offsets.reference;\n\n var placement = data.placement.split('-')[0];\n var floor = Math.floor;\n var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;\n var side = isVertical ? 'right' : 'bottom';\n var opSide = isVertical ? 'left' : 'top';\n var measurement = isVertical ? 'width' : 'height';\n\n if (popper[side] < floor(reference[opSide])) {\n data.offsets.popper[opSide] = floor(reference[opSide]) - popper[measurement];\n }\n if (popper[opSide] > floor(reference[side])) {\n data.offsets.popper[opSide] = floor(reference[side]);\n }\n\n return data;\n}\n\n/**\n * Converts a string containing value + unit into a px value number\n * @function\n * @memberof {modifiers~offset}\n * @private\n * @argument {String} str - Value + unit string\n * @argument {String} measurement - `height` or `width`\n * @argument {Object} popperOffsets\n * @argument {Object} referenceOffsets\n * @returns {Number|String}\n * Value in pixels, or original string if no values were extracted\n */\nfunction toValue(str, measurement, popperOffsets, referenceOffsets) {\n // separate value from unit\n var split = str.match(/((?:\\-|\\+)?\\d*\\.?\\d*)(.*)/);\n var value = +split[1];\n var unit = split[2];\n\n // If it's not a number it's an operator, I guess\n if (!value) {\n return str;\n }\n\n if (unit.indexOf('%') === 0) {\n var element = void 0;\n switch (unit) {\n case '%p':\n element = popperOffsets;\n break;\n case '%':\n case '%r':\n default:\n element = referenceOffsets;\n }\n\n var rect = getClientRect(element);\n return rect[measurement] / 100 * value;\n } else if (unit === 'vh' || unit === 'vw') {\n // if is a vh or vw, we calculate the size based on the viewport\n var size = void 0;\n if (unit === 'vh') {\n size = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);\n } else {\n size = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);\n }\n return size / 100 * value;\n } else {\n // if is an explicit pixel unit, we get rid of the unit and keep the value\n // if is an implicit unit, it's px, and we return just the value\n return value;\n }\n}\n\n/**\n * Parse an `offset` string to extrapolate `x` and `y` numeric offsets.\n * @function\n * @memberof {modifiers~offset}\n * @private\n * @argument {String} offset\n * @argument {Object} popperOffsets\n * @argument {Object} referenceOffsets\n * @argument {String} basePlacement\n * @returns {Array} a two cells array with x and y offsets in numbers\n */\nfunction parseOffset(offset, popperOffsets, referenceOffsets, basePlacement) {\n var offsets = [0, 0];\n\n // Use height if placement is left or right and index is 0 otherwise use width\n // in this way the first offset will use an axis and the second one\n // will use the other one\n var useHeight = ['right', 'left'].indexOf(basePlacement) !== -1;\n\n // Split the offset string to obtain a list of values and operands\n // The regex addresses values with the plus or minus sign in front (+10, -20, etc)\n var fragments = offset.split(/(\\+|\\-)/).map(function (frag) {\n return frag.trim();\n });\n\n // Detect if the offset string contains a pair of values or a single one\n // they could be separated by comma or space\n var divider = fragments.indexOf(find(fragments, function (frag) {\n return frag.search(/,|\\s/) !== -1;\n }));\n\n if (fragments[divider] && fragments[divider].indexOf(',') === -1) {\n console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.');\n }\n\n // If divider is found, we divide the list of values and operands to divide\n // them by ofset X and Y.\n var splitRegex = /\\s*,\\s*|\\s+/;\n var ops = divider !== -1 ? [fragments.slice(0, divider).concat([fragments[divider].split(splitRegex)[0]]), [fragments[divider].split(splitRegex)[1]].concat(fragments.slice(divider + 1))] : [fragments];\n\n // Convert the values with units to absolute pixels to allow our computations\n ops = ops.map(function (op, index) {\n // Most of the units rely on the orientation of the popper\n var measurement = (index === 1 ? !useHeight : useHeight) ? 'height' : 'width';\n var mergeWithPrevious = false;\n return op\n // This aggregates any `+` or `-` sign that aren't considered operators\n // e.g.: 10 + +5 => [10, +, +5]\n .reduce(function (a, b) {\n if (a[a.length - 1] === '' && ['+', '-'].indexOf(b) !== -1) {\n a[a.length - 1] = b;\n mergeWithPrevious = true;\n return a;\n } else if (mergeWithPrevious) {\n a[a.length - 1] += b;\n mergeWithPrevious = false;\n return a;\n } else {\n return a.concat(b);\n }\n }, [])\n // Here we convert the string values into number values (in px)\n .map(function (str) {\n return toValue(str, measurement, popperOffsets, referenceOffsets);\n });\n });\n\n // Loop trough the offsets arrays and execute the operations\n ops.forEach(function (op, index) {\n op.forEach(function (frag, index2) {\n if (isNumeric(frag)) {\n offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1);\n }\n });\n });\n return offsets;\n}\n\n/**\n * @function\n * @memberof Modifiers\n * @argument {Object} data - The data object generated by update method\n * @argument {Object} options - Modifiers configuration and options\n * @argument {Number|String} options.offset=0\n * The offset value as described in the modifier description\n * @returns {Object} The data object, properly modified\n */\nfunction offset(data, _ref) {\n var offset = _ref.offset;\n var placement = data.placement,\n _data$offsets = data.offsets,\n popper = _data$offsets.popper,\n reference = _data$offsets.reference;\n\n var basePlacement = placement.split('-')[0];\n\n var offsets = void 0;\n if (isNumeric(+offset)) {\n offsets = [+offset, 0];\n } else {\n offsets = parseOffset(offset, popper, reference, basePlacement);\n }\n\n if (basePlacement === 'left') {\n popper.top += offsets[0];\n popper.left -= offsets[1];\n } else if (basePlacement === 'right') {\n popper.top += offsets[0];\n popper.left += offsets[1];\n } else if (basePlacement === 'top') {\n popper.left += offsets[0];\n popper.top -= offsets[1];\n } else if (basePlacement === 'bottom') {\n popper.left += offsets[0];\n popper.top += offsets[1];\n }\n\n data.popper = popper;\n return data;\n}\n\n/**\n * @function\n * @memberof Modifiers\n * @argument {Object} data - The data object generated by `update` method\n * @argument {Object} options - Modifiers configuration and options\n * @returns {Object} The data object, properly modified\n */\nfunction preventOverflow(data, options) {\n var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper);\n\n // If offsetParent is the reference element, we really want to\n // go one step up and use the next offsetParent as reference to\n // avoid to make this modifier completely useless and look like broken\n if (data.instance.reference === boundariesElement) {\n boundariesElement = getOffsetParent(boundariesElement);\n }\n\n // NOTE: DOM access here\n // resets the popper's position so that the document size can be calculated excluding\n // the size of the popper element itself\n var transformProp = getSupportedPropertyName('transform');\n var popperStyles = data.instance.popper.style; // assignment to help minification\n var top = popperStyles.top,\n left = popperStyles.left,\n transform = popperStyles[transformProp];\n\n popperStyles.top = '';\n popperStyles.left = '';\n popperStyles[transformProp] = '';\n\n var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement, data.positionFixed);\n\n // NOTE: DOM access here\n // restores the original style properties after the offsets have been computed\n popperStyles.top = top;\n popperStyles.left = left;\n popperStyles[transformProp] = transform;\n\n options.boundaries = boundaries;\n\n var order = options.priority;\n var popper = data.offsets.popper;\n\n var check = {\n primary: function primary(placement) {\n var value = popper[placement];\n if (popper[placement] < boundaries[placement] && !options.escapeWithReference) {\n value = Math.max(popper[placement], boundaries[placement]);\n }\n return defineProperty({}, placement, value);\n },\n secondary: function secondary(placement) {\n var mainSide = placement === 'right' ? 'left' : 'top';\n var value = popper[mainSide];\n if (popper[placement] > boundaries[placement] && !options.escapeWithReference) {\n value = Math.min(popper[mainSide], boundaries[placement] - (placement === 'right' ? popper.width : popper.height));\n }\n return defineProperty({}, mainSide, value);\n }\n };\n\n order.forEach(function (placement) {\n var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary';\n popper = _extends({}, popper, check[side](placement));\n });\n\n data.offsets.popper = popper;\n\n return data;\n}\n\n/**\n * @function\n * @memberof Modifiers\n * @argument {Object} data - The data object generated by `update` method\n * @argument {Object} options - Modifiers configuration and options\n * @returns {Object} The data object, properly modified\n */\nfunction shift(data) {\n var placement = data.placement;\n var basePlacement = placement.split('-')[0];\n var shiftvariation = placement.split('-')[1];\n\n // if shift shiftvariation is specified, run the modifier\n if (shiftvariation) {\n var _data$offsets = data.offsets,\n reference = _data$offsets.reference,\n popper = _data$offsets.popper;\n\n var isVertical = ['bottom', 'top'].indexOf(basePlacement) !== -1;\n var side = isVertical ? 'left' : 'top';\n var measurement = isVertical ? 'width' : 'height';\n\n var shiftOffsets = {\n start: defineProperty({}, side, reference[side]),\n end: defineProperty({}, side, reference[side] + reference[measurement] - popper[measurement])\n };\n\n data.offsets.popper = _extends({}, popper, shiftOffsets[shiftvariation]);\n }\n\n return data;\n}\n\n/**\n * @function\n * @memberof Modifiers\n * @argument {Object} data - The data object generated by update method\n * @argument {Object} options - Modifiers configuration and options\n * @returns {Object} The data object, properly modified\n */\nfunction hide(data) {\n if (!isModifierRequired(data.instance.modifiers, 'hide', 'preventOverflow')) {\n return data;\n }\n\n var refRect = data.offsets.reference;\n var bound = find(data.instance.modifiers, function (modifier) {\n return modifier.name === 'preventOverflow';\n }).boundaries;\n\n if (refRect.bottom < bound.top || refRect.left > bound.right || refRect.top > bound.bottom || refRect.right < bound.left) {\n // Avoid unnecessary DOM access if visibility hasn't changed\n if (data.hide === true) {\n return data;\n }\n\n data.hide = true;\n data.attributes['x-out-of-boundaries'] = '';\n } else {\n // Avoid unnecessary DOM access if visibility hasn't changed\n if (data.hide === false) {\n return data;\n }\n\n data.hide = false;\n data.attributes['x-out-of-boundaries'] = false;\n }\n\n return data;\n}\n\n/**\n * @function\n * @memberof Modifiers\n * @argument {Object} data - The data object generated by `update` method\n * @argument {Object} options - Modifiers configuration and options\n * @returns {Object} The data object, properly modified\n */\nfunction inner(data) {\n var placement = data.placement;\n var basePlacement = placement.split('-')[0];\n var _data$offsets = data.offsets,\n popper = _data$offsets.popper,\n reference = _data$offsets.reference;\n\n var isHoriz = ['left', 'right'].indexOf(basePlacement) !== -1;\n\n var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1;\n\n popper[isHoriz ? 'left' : 'top'] = reference[basePlacement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0);\n\n data.placement = getOppositePlacement(placement);\n data.offsets.popper = getClientRect(popper);\n\n return data;\n}\n\n/**\n * Modifier function, each modifier can have a function of this type assigned\n * to its `fn` property.<br />\n * These functions will be called on each update, this means that you must\n * make sure they are performant enough to avoid performance bottlenecks.\n *\n * @function ModifierFn\n * @argument {dataObject} data - The data object generated by `update` method\n * @argument {Object} options - Modifiers configuration and options\n * @returns {dataObject} The data object, properly modified\n */\n\n/**\n * Modifiers are plugins used to alter the behavior of your poppers.<br />\n * Popper.js uses a set of 9 modifiers to provide all the basic functionalities\n * needed by the library.\n *\n * Usually you don't want to override the `order`, `fn` and `onLoad` props.\n * All the other properties are configurations that could be tweaked.\n * @namespace modifiers\n */\nvar modifiers = {\n /**\n * Modifier used to shift the popper on the start or end of its reference\n * element.<br />\n * It will read the variation of the `placement` property.<br />\n * It can be one either `-end` or `-start`.\n * @memberof modifiers\n * @inner\n */\n shift: {\n /** @prop {number} order=100 - Index used to define the order of execution */\n order: 100,\n /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n enabled: true,\n /** @prop {ModifierFn} */\n fn: shift\n },\n\n /**\n * The `offset` modifier can shift your popper on both its axis.\n *\n * It accepts the following units:\n * - `px` or unit-less, interpreted as pixels\n * - `%` or `%r`, percentage relative to the length of the reference element\n * - `%p`, percentage relative to the length of the popper element\n * - `vw`, CSS viewport width unit\n * - `vh`, CSS viewport height unit\n *\n * For length is intended the main axis relative to the placement of the popper.<br />\n * This means that if the placement is `top` or `bottom`, the length will be the\n * `width`. In case of `left` or `right`, it will be the `height`.\n *\n * You can provide a single value (as `Number` or `String`), or a pair of values\n * as `String` divided by a comma or one (or more) white spaces.<br />\n * The latter is a deprecated method because it leads to confusion and will be\n * removed in v2.<br />\n * Additionally, it accepts additions and subtractions between different units.\n * Note that multiplications and divisions aren't supported.\n *\n * Valid examples are:\n * ```\n * 10\n * '10%'\n * '10, 10'\n * '10%, 10'\n * '10 + 10%'\n * '10 - 5vh + 3%'\n * '-10px + 5vh, 5px - 6%'\n * ```\n * > **NB**: If you desire to apply offsets to your poppers in a way that may make them overlap\n * > with their reference element, unfortunately, you will have to disable the `flip` modifier.\n * > You can read more on this at this [issue](https://github.com/FezVrasta/popper.js/issues/373).\n *\n * @memberof modifiers\n * @inner\n */\n offset: {\n /** @prop {number} order=200 - Index used to define the order of execution */\n order: 200,\n /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n enabled: true,\n /** @prop {ModifierFn} */\n fn: offset,\n /** @prop {Number|String} offset=0\n * The offset value as described in the modifier description\n */\n offset: 0\n },\n\n /**\n * Modifier used to prevent the popper from being positioned outside the boundary.\n *\n * A scenario exists where the reference itself is not within the boundaries.<br />\n * We can say it has \"escaped the boundaries\" — or just \"escaped\".<br />\n * In this case we need to decide whether the popper should either:\n *\n * - detach from the reference and remain \"trapped\" in the boundaries, or\n * - if it should ignore the boundary and \"escape with its reference\"\n *\n * When `escapeWithReference` is set to`true` and reference is completely\n * outside its boundaries, the popper will overflow (or completely leave)\n * the boundaries in order to remain attached to the edge of the reference.\n *\n * @memberof modifiers\n * @inner\n */\n preventOverflow: {\n /** @prop {number} order=300 - Index used to define the order of execution */\n order: 300,\n /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n enabled: true,\n /** @prop {ModifierFn} */\n fn: preventOverflow,\n /**\n * @prop {Array} [priority=['left','right','top','bottom']]\n * Popper will try to prevent overflow following these priorities by default,\n * then, it could overflow on the left and on top of the `boundariesElement`\n */\n priority: ['left', 'right', 'top', 'bottom'],\n /**\n * @prop {number} padding=5\n * Amount of pixel used to define a minimum distance between the boundaries\n * and the popper. This makes sure the popper always has a little padding\n * between the edges of its container\n */\n padding: 5,\n /**\n * @prop {String|HTMLElement} boundariesElement='scrollParent'\n * Boundaries used by the modifier. Can be `scrollParent`, `window`,\n * `viewport` or any DOM element.\n */\n boundariesElement: 'scrollParent'\n },\n\n /**\n * Modifier used to make sure the reference and its popper stay near each other\n * without leaving any gap between the two. Especially useful when the arrow is\n * enabled and you want to ensure that it points to its reference element.\n * It cares only about the first axis. You can still have poppers with margin\n * between the popper and its reference element.\n * @memberof modifiers\n * @inner\n */\n keepTogether: {\n /** @prop {number} order=400 - Index used to define the order of execution */\n order: 400,\n /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n enabled: true,\n /** @prop {ModifierFn} */\n fn: keepTogether\n },\n\n /**\n * This modifier is used to move the `arrowElement` of the popper to make\n * sure it is positioned between the reference element and its popper element.\n * It will read the outer size of the `arrowElement` node to detect how many\n * pixels of conjunction are needed.\n *\n * It has no effect if no `arrowElement` is provided.\n * @memberof modifiers\n * @inner\n */\n arrow: {\n /** @prop {number} order=500 - Index used to define the order of execution */\n order: 500,\n /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n enabled: true,\n /** @prop {ModifierFn} */\n fn: arrow,\n /** @prop {String|HTMLElement} element='[x-arrow]' - Selector or node used as arrow */\n element: '[x-arrow]'\n },\n\n /**\n * Modifier used to flip the popper's placement when it starts to overlap its\n * reference element.\n *\n * Requires the `preventOverflow` modifier before it in order to work.\n *\n * **NOTE:** this modifier will interrupt the current update cycle and will\n * restart it if it detects the need to flip the placement.\n * @memberof modifiers\n * @inner\n */\n flip: {\n /** @prop {number} order=600 - Index used to define the order of execution */\n order: 600,\n /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n enabled: true,\n /** @prop {ModifierFn} */\n fn: flip,\n /**\n * @prop {String|Array} behavior='flip'\n * The behavior used to change the popper's placement. It can be one of\n * `flip`, `clockwise`, `counterclockwise` or an array with a list of valid\n * placements (with optional variations)\n */\n behavior: 'flip',\n /**\n * @prop {number} padding=5\n * The popper will flip if it hits the edges of the `boundariesElement`\n */\n padding: 5,\n /**\n * @prop {String|HTMLElement} boundariesElement='viewport'\n * The element which will define the boundaries of the popper position.\n * The popper will never be placed outside of the defined boundaries\n * (except if `keepTogether` is enabled)\n */\n boundariesElement: 'viewport',\n /**\n * @prop {Boolean} flipVariations=false\n * The popper will switch placement variation between `-start` and `-end` when\n * the reference element overlaps its boundaries.\n *\n * The original placement should have a set variation.\n */\n flipVariations: false,\n /**\n * @prop {Boolean} flipVariationsByContent=false\n * The popper will switch placement variation between `-start` and `-end` when\n * the popper element overlaps its reference boundaries.\n *\n * The original placement should have a set variation.\n */\n flipVariationsByContent: false\n },\n\n /**\n * Modifier used to make the popper flow toward the inner of the reference element.\n * By default, when this modifier is disabled, the popper will be placed outside\n * the reference element.\n * @memberof modifiers\n * @inner\n */\n inner: {\n /** @prop {number} order=700 - Index used to define the order of execution */\n order: 700,\n /** @prop {Boolean} enabled=false - Whether the modifier is enabled or not */\n enabled: false,\n /** @prop {ModifierFn} */\n fn: inner\n },\n\n /**\n * Modifier used to hide the popper when its reference element is outside of the\n * popper boundaries. It will set a `x-out-of-boundaries` attribute which can\n * be used to hide with a CSS selector the popper when its reference is\n * out of boundaries.\n *\n * Requires the `preventOverflow` modifier before it in order to work.\n * @memberof modifiers\n * @inner\n */\n hide: {\n /** @prop {number} order=800 - Index used to define the order of execution */\n order: 800,\n /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n enabled: true,\n /** @prop {ModifierFn} */\n fn: hide\n },\n\n /**\n * Computes the style that will be applied to the popper element to gets\n * properly positioned.\n *\n * Note that this modifier will not touch the DOM, it just prepares the styles\n * so that `applyStyle` modifier can apply it. This separation is useful\n * in case you need to replace `applyStyle` with a custom implementation.\n *\n * This modifier has `850` as `order` value to maintain backward compatibility\n * with previous versions of Popper.js. Expect the modifiers ordering method\n * to change in future major versions of the library.\n *\n * @memberof modifiers\n * @inner\n */\n computeStyle: {\n /** @prop {number} order=850 - Index used to define the order of execution */\n order: 850,\n /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n enabled: true,\n /** @prop {ModifierFn} */\n fn: computeStyle,\n /**\n * @prop {Boolean} gpuAcceleration=true\n * If true, it uses the CSS 3D transformation to position the popper.\n * Otherwise, it will use the `top` and `left` properties\n */\n gpuAcceleration: true,\n /**\n * @prop {string} [x='bottom']\n * Where to anchor the X axis (`bottom` or `top`). AKA X offset origin.\n * Change this if your popper should grow in a direction different from `bottom`\n */\n x: 'bottom',\n /**\n * @prop {string} [x='left']\n * Where to anchor the Y axis (`left` or `right`). AKA Y offset origin.\n * Change this if your popper should grow in a direction different from `right`\n */\n y: 'right'\n },\n\n /**\n * Applies the computed styles to the popper element.\n *\n * All the DOM manipulations are limited to this modifier. This is useful in case\n * you want to integrate Popper.js inside a framework or view library and you\n * want to delegate all the DOM manipulations to it.\n *\n * Note that if you disable this modifier, you must make sure the popper element\n * has its position set to `absolute` before Popper.js can do its work!\n *\n * Just disable this modifier and define your own to achieve the desired effect.\n *\n * @memberof modifiers\n * @inner\n */\n applyStyle: {\n /** @prop {number} order=900 - Index used to define the order of execution */\n order: 900,\n /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n enabled: true,\n /** @prop {ModifierFn} */\n fn: applyStyle,\n /** @prop {Function} */\n onLoad: applyStyleOnLoad,\n /**\n * @deprecated since version 1.10.0, the property moved to `computeStyle` modifier\n * @prop {Boolean} gpuAcceleration=true\n * If true, it uses the CSS 3D transformation to position the popper.\n * Otherwise, it will use the `top` and `left` properties\n */\n gpuAcceleration: undefined\n }\n};\n\n/**\n * The `dataObject` is an object containing all the information used by Popper.js.\n * This object is passed to modifiers and to the `onCreate` and `onUpdate` callbacks.\n * @name dataObject\n * @property {Object} data.instance The Popper.js instance\n * @property {String} data.placement Placement applied to popper\n * @property {String} data.originalPlacement Placement originally defined on init\n * @property {Boolean} data.flipped True if popper has been flipped by flip modifier\n * @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper\n * @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier\n * @property {Object} data.styles Any CSS property defined here will be applied to the popper. It expects the JavaScript nomenclature (eg. `marginBottom`)\n * @property {Object} data.arrowStyles Any CSS property defined here will be applied to the popper arrow. It expects the JavaScript nomenclature (eg. `marginBottom`)\n * @property {Object} data.boundaries Offsets of the popper boundaries\n * @property {Object} data.offsets The measurements of popper, reference and arrow elements\n * @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values\n * @property {Object} data.offsets.reference `top`, `left`, `width`, `height` values\n * @property {Object} data.offsets.arrow] `top` and `left` offsets, only one of them will be different from 0\n */\n\n/**\n * Default options provided to Popper.js constructor.<br />\n * These can be overridden using the `options` argument of Popper.js.<br />\n * To override an option, simply pass an object with the same\n * structure of the `options` object, as the 3rd argument. For example:\n * ```\n * new Popper(ref, pop, {\n * modifiers: {\n * preventOverflow: { enabled: false }\n * }\n * })\n * ```\n * @type {Object}\n * @static\n * @memberof Popper\n */\nvar Defaults = {\n /**\n * Popper's placement.\n * @prop {Popper.placements} placement='bottom'\n */\n placement: 'bottom',\n\n /**\n * Set this to true if you want popper to position it self in 'fixed' mode\n * @prop {Boolean} positionFixed=false\n */\n positionFixed: false,\n\n /**\n * Whether events (resize, scroll) are initially enabled.\n * @prop {Boolean} eventsEnabled=true\n */\n eventsEnabled: true,\n\n /**\n * Set to true if you want to automatically remove the popper when\n * you call the `destroy` method.\n * @prop {Boolean} removeOnDestroy=false\n */\n removeOnDestroy: false,\n\n /**\n * Callback called when the popper is created.<br />\n * By default, it is set to no-op.<br />\n * Access Popper.js instance with `data.instance`.\n * @prop {onCreate}\n */\n onCreate: function onCreate() {},\n\n /**\n * Callback called when the popper is updated. This callback is not called\n * on the initialization/creation of the popper, but only on subsequent\n * updates.<br />\n * By default, it is set to no-op.<br />\n * Access Popper.js instance with `data.instance`.\n * @prop {onUpdate}\n */\n onUpdate: function onUpdate() {},\n\n /**\n * List of modifiers used to modify the offsets before they are applied to the popper.\n * They provide most of the functionalities of Popper.js.\n * @prop {modifiers}\n */\n modifiers: modifiers\n};\n\n/**\n * @callback onCreate\n * @param {dataObject} data\n */\n\n/**\n * @callback onUpdate\n * @param {dataObject} data\n */\n\n// Utils\n// Methods\nvar Popper = function () {\n /**\n * Creates a new Popper.js instance.\n * @class Popper\n * @param {Element|referenceObject} reference - The reference element used to position the popper\n * @param {Element} popper - The HTML / XML element used as the popper\n * @param {Object} options - Your custom options to override the ones defined in [Defaults](#defaults)\n * @return {Object} instance - The generated Popper.js instance\n */\n function Popper(reference, popper) {\n var _this = this;\n\n var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n classCallCheck(this, Popper);\n\n this.scheduleUpdate = function () {\n return requestAnimationFrame(_this.update);\n };\n\n // make update() debounced, so that it only runs at most once-per-tick\n this.update = debounce(this.update.bind(this));\n\n // with {} we create a new object with the options inside it\n this.options = _extends({}, Popper.Defaults, options);\n\n // init state\n this.state = {\n isDestroyed: false,\n isCreated: false,\n scrollParents: []\n };\n\n // get reference and popper elements (allow jQuery wrappers)\n this.reference = reference && reference.jquery ? reference[0] : reference;\n this.popper = popper && popper.jquery ? popper[0] : popper;\n\n // Deep merge modifiers options\n this.options.modifiers = {};\n Object.keys(_extends({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) {\n _this.options.modifiers[name] = _extends({}, Popper.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {});\n });\n\n // Refactoring modifiers' list (Object => Array)\n this.modifiers = Object.keys(this.options.modifiers).map(function (name) {\n return _extends({\n name: name\n }, _this.options.modifiers[name]);\n })\n // sort the modifiers by order\n .sort(function (a, b) {\n return a.order - b.order;\n });\n\n // modifiers have the ability to execute arbitrary code when Popper.js get inited\n // such code is executed in the same order of its modifier\n // they could add new properties to their options configuration\n // BE AWARE: don't add options to `options.modifiers.name` but to `modifierOptions`!\n this.modifiers.forEach(function (modifierOptions) {\n if (modifierOptions.enabled && isFunction(modifierOptions.onLoad)) {\n modifierOptions.onLoad(_this.reference, _this.popper, _this.options, modifierOptions, _this.state);\n }\n });\n\n // fire the first update to position the popper in the right place\n this.update();\n\n var eventsEnabled = this.options.eventsEnabled;\n if (eventsEnabled) {\n // setup event listeners, they will take care of update the position in specific situations\n this.enableEventListeners();\n }\n\n this.state.eventsEnabled = eventsEnabled;\n }\n\n // We can't use class properties because they don't get listed in the\n // class prototype and break stuff like Sinon stubs\n\n\n createClass(Popper, [{\n key: 'update',\n value: function update$$1() {\n return update.call(this);\n }\n }, {\n key: 'destroy',\n value: function destroy$$1() {\n return destroy.call(this);\n }\n }, {\n key: 'enableEventListeners',\n value: function enableEventListeners$$1() {\n return enableEventListeners.call(this);\n }\n }, {\n key: 'disableEventListeners',\n value: function disableEventListeners$$1() {\n return disableEventListeners.call(this);\n }\n\n /**\n * Schedules an update. It will run on the next UI update available.\n * @method scheduleUpdate\n * @memberof Popper\n */\n\n\n /**\n * Collection of utilities useful when writing custom modifiers.\n * Starting from version 1.7, this method is available only if you\n * include `popper-utils.js` before `popper.js`.\n *\n * **DEPRECATION**: This way to access PopperUtils is deprecated\n * and will be removed in v2! Use the PopperUtils module directly instead.\n * Due to the high instability of the methods contained in Utils, we can't\n * guarantee them to follow semver. Use them at your own risk!\n * @static\n * @private\n * @type {Object}\n * @deprecated since version 1.8\n * @member Utils\n * @memberof Popper\n */\n\n }]);\n return Popper;\n}();\n\n/**\n * The `referenceObject` is an object that provides an interface compatible with Popper.js\n * and lets you use it as replacement of a real DOM node.<br />\n * You can use this method to position a popper relatively to a set of coordinates\n * in case you don't have a DOM node to use as reference.\n *\n * ```\n * new Popper(referenceObject, popperNode);\n * ```\n *\n * NB: This feature isn't supported in Internet Explorer 10.\n * @name referenceObject\n * @property {Function} data.getBoundingClientRect\n * A function that returns a set of coordinates compatible with the native `getBoundingClientRect` method.\n * @property {number} data.clientWidth\n * An ES6 getter that will return the width of the virtual reference element.\n * @property {number} data.clientHeight\n * An ES6 getter that will return the height of the virtual reference element.\n */\n\n\nPopper.Utils = (typeof window !== 'undefined' ? window : __webpack_require__.g).PopperUtils;\nPopper.placements = placements;\nPopper.Defaults = Defaults;\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Popper);\n//# sourceMappingURL=popper.js.map\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvcG9wcGVyLmpzL2Rpc3QvZXNtL3BvcHBlci5qcy5qcyIsIm1hcHBpbmdzIjoiOzs7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGtCQUFrQixrQ0FBa0M7QUFDcEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFVBQVU7QUFDdkIsWUFBWTtBQUNaO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLEtBQUs7QUFDbkIsYUFBYSxTQUFTO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEIsY0FBYyxRQUFRO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QixhQUFhLFNBQVM7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxnQkFBZ0I7QUFDM0IsYUFBYSxTQUFTO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFFBQVE7QUFDbkIsYUFBYSxTQUFTO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QixhQUFhLFNBQVM7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCLGNBQWMsU0FBUztBQUN2QixhQUFhLFNBQVM7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkIsY0FBYyxRQUFRO0FBQ3RCLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFFBQVE7QUFDbkIsV0FBVyxhQUFhO0FBQ3hCLFdBQVcsU0FBUztBQUNwQixZQUFZLFFBQVE7QUFDcEI7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVcscUJBQXFCO0FBQ2hDO0FBQ0EsV0FBVyxRQUFRO0FBQ25CLFlBQVksUUFBUTtBQUNwQjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxvQkFBb0Isa0JBQWtCO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOzs7Ozs7QUFNRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0Esa0JBQWtCLHNCQUFzQjtBQUN4Qzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBLG9CQUFvQjtBQUNwQjtBQUNBO0FBQ0EsR0FBRztBQUNIOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxhQUFhO0FBQ3hCLFlBQVksUUFBUTtBQUNwQjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCLGNBQWMsU0FBUztBQUN2QixhQUFhLFNBQVM7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCLGFBQWEsU0FBUztBQUN0Qjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxhQUFhO0FBQ3hCLFdBQVcsYUFBYTtBQUN4QixXQUFXLFFBQVE7QUFDbkIsV0FBVyxhQUFhO0FBQ3hCLFdBQVcsU0FBUztBQUNwQixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBOztBQUVBOztBQUVBLHFCQUFxQjtBQUNyQjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQSxNQUFNO0FBQ047QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixjQUFjLFFBQVE7QUFDdEIsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBLEtBQUs7QUFDTCxHQUFHO0FBQ0g7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxRQUFRO0FBQ25CLFdBQVcsU0FBUztBQUNwQixXQUFXLFNBQVM7QUFDcEIsV0FBVyxTQUFTO0FBQ3BCLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEIsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQSxlQUFlO0FBQ2Y7QUFDQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsUUFBUTtBQUNuQixXQUFXLGFBQWE7QUFDeEIsV0FBVyxRQUFRO0FBQ25CLFdBQVcsUUFBUTtBQUNuQixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsT0FBTztBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxPQUFPO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxZQUFZO0FBQ3ZCLFdBQVcsT0FBTztBQUNsQixXQUFXLFFBQVE7QUFDbkIsYUFBYTtBQUNiO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0RBQWtEO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsY0FBYztBQUNkLG1CQUFtQjtBQUNuQixrQkFBa0I7QUFDbEI7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxrQkFBa0IscUJBQXFCO0FBQ3ZDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLDZDQUE2QyxlQUFlOztBQUU1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVFQUF1RSxlQUFlOztBQUV0RjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsR0FBRztBQUNkLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QixjQUFjLFFBQVE7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkIsY0FBYyxRQUFRO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCLGNBQWMsUUFBUTtBQUN0QixjQUFjLFFBQVE7QUFDdEIsY0FBYyxRQUFRO0FBQ3RCLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLGFBQWE7QUFDeEIsV0FBVyxhQUFhO0FBQ3hCLFdBQVcsUUFBUTtBQUNuQjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0Esc0JBQXNCLHdEQUF3RDs7QUFFOUU7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEIsY0FBYyxTQUFTO0FBQ3ZCLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixjQUFjLFFBQVE7QUFDdEIsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSwrQkFBK0I7QUFDL0IsMkJBQTJCO0FBQzNCLGdDQUFnQzs7QUFFaEM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxPQUFPO0FBQ2xCLFdBQVcsUUFBUTtBQUNuQixXQUFXLFFBQVE7QUFDbkIsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixjQUFjLFFBQVE7QUFDdEIsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsZ0RBQWdEOztBQUVoRDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVixVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixjQUFjLFNBQVM7QUFDdkIsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixjQUFjLFFBQVE7QUFDdEIsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsdUNBQXVDOztBQUV2QztBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCLGNBQWMsUUFBUTtBQUN0QixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCLGNBQWMsUUFBUTtBQUN0QixjQUFjLFFBQVE7QUFDdEIsY0FBYyxRQUFRO0FBQ3RCLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCLGNBQWMsUUFBUTtBQUN0QixjQUFjLFFBQVE7QUFDdEIsY0FBYyxRQUFRO0FBQ3RCLGFBQWEsT0FBTztBQUNwQjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixjQUFjLFFBQVE7QUFDdEIsY0FBYyxlQUFlO0FBQzdCO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEIsY0FBYyxRQUFRO0FBQ3RCLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaURBQWlEO0FBQ2pEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhCQUE4QjtBQUM5QixLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOEJBQThCO0FBQzlCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLHdCQUF3QjtBQUN4QixHQUFHOztBQUVIOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCLGNBQWMsUUFBUTtBQUN0QixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDhCQUE4QjtBQUM5Qiw0QkFBNEI7QUFDNUI7O0FBRUEscUNBQXFDO0FBQ3JDOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCLGNBQWMsUUFBUTtBQUN0QixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEIsY0FBYyxRQUFRO0FBQ3RCLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFlBQVk7QUFDMUIsY0FBYyxRQUFRO0FBQ3RCLGFBQWEsWUFBWTtBQUN6Qjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWUsUUFBUTtBQUN2QjtBQUNBLGVBQWUsU0FBUztBQUN4QjtBQUNBLGVBQWUsWUFBWTtBQUMzQjtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZSxRQUFRO0FBQ3ZCO0FBQ0EsZUFBZSxTQUFTO0FBQ3hCO0FBQ0EsZUFBZSxZQUFZO0FBQzNCO0FBQ0EsZUFBZSxlQUFlO0FBQzlCO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZSxRQUFRO0FBQ3ZCO0FBQ0EsZUFBZSxTQUFTO0FBQ3hCO0FBQ0EsZUFBZSxZQUFZO0FBQzNCO0FBQ0E7QUFDQSxjQUFjLE9BQU87QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLG9CQUFvQjtBQUNsQztBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLFFBQVE7QUFDdkI7QUFDQSxlQUFlLFNBQVM7QUFDeEI7QUFDQSxlQUFlLFlBQVk7QUFDM0I7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLFFBQVE7QUFDdkI7QUFDQSxlQUFlLFNBQVM7QUFDeEI7QUFDQSxlQUFlLFlBQVk7QUFDM0I7QUFDQSxlQUFlLG9CQUFvQjtBQUNuQztBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZSxRQUFRO0FBQ3ZCO0FBQ0EsZUFBZSxTQUFTO0FBQ3hCO0FBQ0EsZUFBZSxZQUFZO0FBQzNCO0FBQ0E7QUFDQSxjQUFjLGNBQWM7QUFDNUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxvQkFBb0I7QUFDbEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWUsUUFBUTtBQUN2QjtBQUNBLGVBQWUsU0FBUztBQUN4QjtBQUNBLGVBQWUsWUFBWTtBQUMzQjtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWUsUUFBUTtBQUN2QjtBQUNBLGVBQWUsU0FBUztBQUN4QjtBQUNBLGVBQWUsWUFBWTtBQUMzQjtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLFFBQVE7QUFDdkI7QUFDQSxlQUFlLFNBQVM7QUFDeEI7QUFDQSxlQUFlLFlBQVk7QUFDM0I7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZSxRQUFRO0FBQ3ZCO0FBQ0EsZUFBZSxTQUFTO0FBQ3hCO0FBQ0EsZUFBZSxZQUFZO0FBQzNCO0FBQ0EsZUFBZSxVQUFVO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEIsY0FBYyxRQUFRO0FBQ3RCLGNBQWMsUUFBUTtBQUN0QixjQUFjLFNBQVM7QUFDdkIsY0FBYyxTQUFTO0FBQ3ZCLGNBQWMsYUFBYTtBQUMzQixjQUFjLFFBQVE7QUFDdEIsY0FBYyxRQUFRO0FBQ3RCLGNBQWMsUUFBUTtBQUN0QixjQUFjLFFBQVE7QUFDdEIsY0FBYyxRQUFRO0FBQ3RCLGNBQWMsUUFBUTtBQUN0QixjQUFjLFFBQVE7QUFDdEI7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQjtBQUMxQjtBQUNBLElBQUk7QUFDSjtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLG1CQUFtQjtBQUMvQjtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZLFNBQVM7QUFDckI7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWSxTQUFTO0FBQ3JCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsWUFBWSxTQUFTO0FBQ3JCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQSxrQ0FBa0M7O0FBRWxDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBLGtDQUFrQzs7QUFFbEM7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVyxZQUFZO0FBQ3ZCOztBQUVBO0FBQ0E7QUFDQSxXQUFXLFlBQVk7QUFDdkI7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSx5QkFBeUI7QUFDdEMsYUFBYSxTQUFTO0FBQ3RCLGFBQWEsUUFBUTtBQUNyQixjQUFjLFFBQVE7QUFDdEI7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsZUFBZTtBQUNmLDhCQUE4Qjs7QUFFOUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsMkJBQTJCO0FBQzNCLGlEQUFpRCx1Q0FBdUMsa0RBQWtEO0FBQzFJLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEdBQUc7QUFDSDtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxVQUFVO0FBQ3hCO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCO0FBQ0E7OztBQUdBLHlEQUF5RCxxQkFBTTtBQUMvRDtBQUNBOztBQUVBLGlFQUFlLE1BQU0sRUFBQztBQUN0QiIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9wb3BwZXIuanMvZGlzdC9lc20vcG9wcGVyLmpzP2VhMjYiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqIVxuICogQGZpbGVPdmVydmlldyBLaWNrYXNzIGxpYnJhcnkgdG8gY3JlYXRlIGFuZCBwbGFjZSBwb3BwZXJzIG5lYXIgdGhlaXIgcmVmZXJlbmNlIGVsZW1lbnRzLlxuICogQHZlcnNpb24gMS4xNi4xXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IChjKSAyMDE2IEZlZGVyaWNvIFppdm9sbyBhbmQgY29udHJpYnV0b3JzXG4gKlxuICogUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuICogb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbFxuICogaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0c1xuICogdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbFxuICogY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzXG4gKiBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuICpcbiAqIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbFxuICogY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbiAqXG4gKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4gKiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbiAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuICogQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuICogTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbiAqIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFXG4gKiBTT0ZUV0FSRS5cbiAqL1xudmFyIGlzQnJvd3NlciA9IHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiBkb2N1bWVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCc7XG5cbnZhciB0aW1lb3V0RHVyYXRpb24gPSBmdW5jdGlvbiAoKSB7XG4gIHZhciBsb25nZXJUaW1lb3V0QnJvd3NlcnMgPSBbJ0VkZ2UnLCAnVHJpZGVudCcsICdGaXJlZm94J107XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbG9uZ2VyVGltZW91dEJyb3dzZXJzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgaWYgKGlzQnJvd3NlciAmJiBuYXZpZ2F0b3IudXNlckFnZW50LmluZGV4T2YobG9uZ2VyVGltZW91dEJyb3dzZXJzW2ldKSA+PSAwKSB7XG4gICAgICByZXR1cm4gMTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIDA7XG59KCk7XG5cbmZ1bmN0aW9uIG1pY3JvdGFza0RlYm91bmNlKGZuKSB7XG4gIHZhciBjYWxsZWQgPSBmYWxzZTtcbiAgcmV0dXJuIGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoY2FsbGVkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNhbGxlZCA9IHRydWU7XG4gICAgd2luZG93LlByb21pc2UucmVzb2x2ZSgpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgY2FsbGVkID0gZmFsc2U7XG4gICAgICBmbigpO1xuICAgIH0pO1xuICB9O1xufVxuXG5mdW5jdGlvbiB0YXNrRGVib3VuY2UoZm4pIHtcbiAgdmFyIHNjaGVkdWxlZCA9IGZhbHNlO1xuICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgIGlmICghc2NoZWR1bGVkKSB7XG4gICAgICBzY2hlZHVsZWQgPSB0cnVlO1xuICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgIHNjaGVkdWxlZCA9IGZhbHNlO1xuICAgICAgICBmbigpO1xuICAgICAgfSwgdGltZW91dER1cmF0aW9uKTtcbiAgICB9XG4gIH07XG59XG5cbnZhciBzdXBwb3J0c01pY3JvVGFza3MgPSBpc0Jyb3dzZXIgJiYgd2luZG93LlByb21pc2U7XG5cbi8qKlxuKiBDcmVhdGUgYSBkZWJvdW5jZWQgdmVyc2lvbiBvZiBhIG1ldGhvZCwgdGhhdCdzIGFzeW5jaHJvbm91c2x5IGRlZmVycmVkXG4qIGJ1dCBjYWxsZWQgaW4gdGhlIG1pbmltdW0gdGltZSBwb3NzaWJsZS5cbipcbiogQG1ldGhvZFxuKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4qIEBhcmd1bWVudCB7RnVuY3Rpb259IGZuXG4qIEByZXR1cm5zIHtGdW5jdGlvbn1cbiovXG52YXIgZGVib3VuY2UgPSBzdXBwb3J0c01pY3JvVGFza3MgPyBtaWNyb3Rhc2tEZWJvdW5jZSA6IHRhc2tEZWJvdW5jZTtcblxuLyoqXG4gKiBDaGVjayBpZiB0aGUgZ2l2ZW4gdmFyaWFibGUgaXMgYSBmdW5jdGlvblxuICogQG1ldGhvZFxuICogQG1lbWJlcm9mIFBvcHBlci5VdGlsc1xuICogQGFyZ3VtZW50IHtBbnl9IGZ1bmN0aW9uVG9DaGVjayAtIHZhcmlhYmxlIHRvIGNoZWNrXG4gKiBAcmV0dXJucyB7Qm9vbGVhbn0gYW5zd2VyIHRvOiBpcyBhIGZ1bmN0aW9uP1xuICovXG5mdW5jdGlvbiBpc0Z1bmN0aW9uKGZ1bmN0aW9uVG9DaGVjaykge1xuICB2YXIgZ2V0VHlwZSA9IHt9O1xuICByZXR1cm4gZnVuY3Rpb25Ub0NoZWNrICYmIGdldFR5cGUudG9TdHJpbmcuY2FsbChmdW5jdGlvblRvQ2hlY2spID09PSAnW29iamVjdCBGdW5jdGlvbl0nO1xufVxuXG4vKipcbiAqIEdldCBDU1MgY29tcHV0ZWQgcHJvcGVydHkgb2YgdGhlIGdpdmVuIGVsZW1lbnRcbiAqIEBtZXRob2RcbiAqIEBtZW1iZXJvZiBQb3BwZXIuVXRpbHNcbiAqIEBhcmd1bWVudCB7RWVtZW50fSBlbGVtZW50XG4gKiBAYXJndW1lbnQge1N0cmluZ30gcHJvcGVydHlcbiAqL1xuZnVuY3Rpb24gZ2V0U3R5bGVDb21wdXRlZFByb3BlcnR5KGVsZW1lbnQsIHByb3BlcnR5KSB7XG4gIGlmIChlbGVtZW50Lm5vZGVUeXBlICE9PSAxKSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG4gIC8vIE5PVEU6IDEgRE9NIGFjY2VzcyBoZXJlXG4gIHZhciB3aW5kb3cgPSBlbGVtZW50Lm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXc7XG4gIHZhciBjc3MgPSB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShlbGVtZW50LCBudWxsKTtcbiAgcmV0dXJuIHByb3BlcnR5ID8gY3NzW3Byb3BlcnR5XSA6IGNzcztcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBwYXJlbnROb2RlIG9yIHRoZSBob3N0IG9mIHRoZSBlbGVtZW50XG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAYXJndW1lbnQge0VsZW1lbnR9IGVsZW1lbnRcbiAqIEByZXR1cm5zIHtFbGVtZW50fSBwYXJlbnRcbiAqL1xuZnVuY3Rpb24gZ2V0UGFyZW50Tm9kZShlbGVtZW50KSB7XG4gIGlmIChlbGVtZW50Lm5vZGVOYW1lID09PSAnSFRNTCcpIHtcbiAgICByZXR1cm4gZWxlbWVudDtcbiAgfVxuICByZXR1cm4gZWxlbWVudC5wYXJlbnROb2RlIHx8IGVsZW1lbnQuaG9zdDtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBzY3JvbGxpbmcgcGFyZW50IG9mIHRoZSBnaXZlbiBlbGVtZW50XG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAYXJndW1lbnQge0VsZW1lbnR9IGVsZW1lbnRcbiAqIEByZXR1cm5zIHtFbGVtZW50fSBzY3JvbGwgcGFyZW50XG4gKi9cbmZ1bmN0aW9uIGdldFNjcm9sbFBhcmVudChlbGVtZW50KSB7XG4gIC8vIFJldHVybiBib2R5LCBgZ2V0U2Nyb2xsYCB3aWxsIHRha2UgY2FyZSB0byBnZXQgdGhlIGNvcnJlY3QgYHNjcm9sbFRvcGAgZnJvbSBpdFxuICBpZiAoIWVsZW1lbnQpIHtcbiAgICByZXR1cm4gZG9jdW1lbnQuYm9keTtcbiAgfVxuXG4gIHN3aXRjaCAoZWxlbWVudC5ub2RlTmFtZSkge1xuICAgIGNhc2UgJ0hUTUwnOlxuICAgIGNhc2UgJ0JPRFknOlxuICAgICAgcmV0dXJuIGVsZW1lbnQub3duZXJEb2N1bWVudC5ib2R5O1xuICAgIGNhc2UgJyNkb2N1bWVudCc6XG4gICAgICByZXR1cm4gZWxlbWVudC5ib2R5O1xuICB9XG5cbiAgLy8gRmlyZWZveCB3YW50IHVzIHRvIGNoZWNrIGAteGAgYW5kIGAteWAgdmFyaWF0aW9ucyBhcyB3ZWxsXG5cbiAgdmFyIF9nZXRTdHlsZUNvbXB1dGVkUHJvcCA9IGdldFN0eWxlQ29tcHV0ZWRQcm9wZXJ0eShlbGVtZW50KSxcbiAgICAgIG92ZXJmbG93ID0gX2dldFN0eWxlQ29tcHV0ZWRQcm9wLm92ZXJmbG93LFxuICAgICAgb3ZlcmZsb3dYID0gX2dldFN0eWxlQ29tcHV0ZWRQcm9wLm92ZXJmbG93WCxcbiAgICAgIG92ZXJmbG93WSA9IF9nZXRTdHlsZUNvbXB1dGVkUHJvcC5vdmVyZmxvd1k7XG5cbiAgaWYgKC8oYXV0b3xzY3JvbGx8b3ZlcmxheSkvLnRlc3Qob3ZlcmZsb3cgKyBvdmVyZmxvd1kgKyBvdmVyZmxvd1gpKSB7XG4gICAgcmV0dXJuIGVsZW1lbnQ7XG4gIH1cblxuICByZXR1cm4gZ2V0U2Nyb2xsUGFyZW50KGdldFBhcmVudE5vZGUoZWxlbWVudCkpO1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIHJlZmVyZW5jZSBub2RlIG9mIHRoZSByZWZlcmVuY2Ugb2JqZWN0LCBvciB0aGUgcmVmZXJlbmNlIG9iamVjdCBpdHNlbGYuXG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAcGFyYW0ge0VsZW1lbnR8T2JqZWN0fSByZWZlcmVuY2UgLSB0aGUgcmVmZXJlbmNlIGVsZW1lbnQgKHRoZSBwb3BwZXIgd2lsbCBiZSByZWxhdGl2ZSB0byB0aGlzKVxuICogQHJldHVybnMge0VsZW1lbnR9IHBhcmVudFxuICovXG5mdW5jdGlvbiBnZXRSZWZlcmVuY2VOb2RlKHJlZmVyZW5jZSkge1xuICByZXR1cm4gcmVmZXJlbmNlICYmIHJlZmVyZW5jZS5yZWZlcmVuY2VOb2RlID8gcmVmZXJlbmNlLnJlZmVyZW5jZU5vZGUgOiByZWZlcmVuY2U7XG59XG5cbnZhciBpc0lFMTEgPSBpc0Jyb3dzZXIgJiYgISEod2luZG93Lk1TSW5wdXRNZXRob2RDb250ZXh0ICYmIGRvY3VtZW50LmRvY3VtZW50TW9kZSk7XG52YXIgaXNJRTEwID0gaXNCcm93c2VyICYmIC9NU0lFIDEwLy50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpO1xuXG4vKipcbiAqIERldGVybWluZXMgaWYgdGhlIGJyb3dzZXIgaXMgSW50ZXJuZXQgRXhwbG9yZXJcbiAqIEBtZXRob2RcbiAqIEBtZW1iZXJvZiBQb3BwZXIuVXRpbHNcbiAqIEBwYXJhbSB7TnVtYmVyfSB2ZXJzaW9uIHRvIGNoZWNrXG4gKiBAcmV0dXJucyB7Qm9vbGVhbn0gaXNJRVxuICovXG5mdW5jdGlvbiBpc0lFKHZlcnNpb24pIHtcbiAgaWYgKHZlcnNpb24gPT09IDExKSB7XG4gICAgcmV0dXJuIGlzSUUxMTtcbiAgfVxuICBpZiAodmVyc2lvbiA9PT0gMTApIHtcbiAgICByZXR1cm4gaXNJRTEwO1xuICB9XG4gIHJldHVybiBpc0lFMTEgfHwgaXNJRTEwO1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIG9mZnNldCBwYXJlbnQgb2YgdGhlIGdpdmVuIGVsZW1lbnRcbiAqIEBtZXRob2RcbiAqIEBtZW1iZXJvZiBQb3BwZXIuVXRpbHNcbiAqIEBhcmd1bWVudCB7RWxlbWVudH0gZWxlbWVudFxuICogQHJldHVybnMge0VsZW1lbnR9IG9mZnNldCBwYXJlbnRcbiAqL1xuZnVuY3Rpb24gZ2V0T2Zmc2V0UGFyZW50KGVsZW1lbnQpIHtcbiAgaWYgKCFlbGVtZW50KSB7XG4gICAgcmV0dXJuIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudDtcbiAgfVxuXG4gIHZhciBub09mZnNldFBhcmVudCA9IGlzSUUoMTApID8gZG9jdW1lbnQuYm9keSA6IG51bGw7XG5cbiAgLy8gTk9URTogMSBET00gYWNjZXNzIGhlcmVcbiAgdmFyIG9mZnNldFBhcmVudCA9IGVsZW1lbnQub2Zmc2V0UGFyZW50IHx8IG51bGw7XG4gIC8vIFNraXAgaGlkZGVuIGVsZW1lbnRzIHdoaWNoIGRvbid0IGhhdmUgYW4gb2Zmc2V0UGFyZW50XG4gIHdoaWxlIChvZmZzZXRQYXJlbnQgPT09IG5vT2Zmc2V0UGFyZW50ICYmIGVsZW1lbnQubmV4dEVsZW1lbnRTaWJsaW5nKSB7XG4gICAgb2Zmc2V0UGFyZW50ID0gKGVsZW1lbnQgPSBlbGVtZW50Lm5leHRFbGVtZW50U2libGluZykub2Zmc2V0UGFyZW50O1xuICB9XG5cbiAgdmFyIG5vZGVOYW1lID0gb2Zmc2V0UGFyZW50ICYmIG9mZnNldFBhcmVudC5ub2RlTmFtZTtcblxuICBpZiAoIW5vZGVOYW1lIHx8IG5vZGVOYW1lID09PSAnQk9EWScgfHwgbm9kZU5hbWUgPT09ICdIVE1MJykge1xuICAgIHJldHVybiBlbGVtZW50ID8gZWxlbWVudC5vd25lckRvY3VtZW50LmRvY3VtZW50RWxlbWVudCA6IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudDtcbiAgfVxuXG4gIC8vIC5vZmZzZXRQYXJlbnQgd2lsbCByZXR1cm4gdGhlIGNsb3Nlc3QgVEgsIFREIG9yIFRBQkxFIGluIGNhc2VcbiAgLy8gbm8gb2Zmc2V0UGFyZW50IGlzIHByZXNlbnQsIEkgaGF0ZSB0aGlzIGpvYi4uLlxuICBpZiAoWydUSCcsICdURCcsICdUQUJMRSddLmluZGV4T2Yob2Zmc2V0UGFyZW50Lm5vZGVOYW1lKSAhPT0gLTEgJiYgZ2V0U3R5bGVDb21wdXRlZFByb3BlcnR5KG9mZnNldFBhcmVudCwgJ3Bvc2l0aW9uJykgPT09ICdzdGF0aWMnKSB7XG4gICAgcmV0dXJuIGdldE9mZnNldFBhcmVudChvZmZzZXRQYXJlbnQpO1xuICB9XG5cbiAgcmV0dXJuIG9mZnNldFBhcmVudDtcbn1cblxuZnVuY3Rpb24gaXNPZmZzZXRDb250YWluZXIoZWxlbWVudCkge1xuICB2YXIgbm9kZU5hbWUgPSBlbGVtZW50Lm5vZGVOYW1lO1xuXG4gIGlmIChub2RlTmFtZSA9PT0gJ0JPRFknKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiBub2RlTmFtZSA9PT0gJ0hUTUwnIHx8IGdldE9mZnNldFBhcmVudChlbGVtZW50LmZpcnN0RWxlbWVudENoaWxkKSA9PT0gZWxlbWVudDtcbn1cblxuLyoqXG4gKiBGaW5kcyB0aGUgcm9vdCBub2RlIChkb2N1bWVudCwgc2hhZG93RE9NIHJvb3QpIG9mIHRoZSBnaXZlbiBlbGVtZW50XG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAYXJndW1lbnQge0VsZW1lbnR9IG5vZGVcbiAqIEByZXR1cm5zIHtFbGVtZW50fSByb290IG5vZGVcbiAqL1xuZnVuY3Rpb24gZ2V0Um9vdChub2RlKSB7XG4gIGlmIChub2RlLnBhcmVudE5vZGUgIT09IG51bGwpIHtcbiAgICByZXR1cm4gZ2V0Um9vdChub2RlLnBhcmVudE5vZGUpO1xuICB9XG5cbiAgcmV0dXJuIG5vZGU7XG59XG5cbi8qKlxuICogRmluZHMgdGhlIG9mZnNldCBwYXJlbnQgY29tbW9uIHRvIHRoZSB0d28gcHJvdmlkZWQgbm9kZXNcbiAqIEBtZXRob2RcbiAqIEBtZW1iZXJvZiBQb3BwZXIuVXRpbHNcbiAqIEBhcmd1bWVudCB7RWxlbWVudH0gZWxlbWVudDFcbiAqIEBhcmd1bWVudCB7RWxlbWVudH0gZWxlbWVudDJcbiAqIEByZXR1cm5zIHtFbGVtZW50fSBjb21tb24gb2Zmc2V0IHBhcmVudFxuICovXG5mdW5jdGlvbiBmaW5kQ29tbW9uT2Zmc2V0UGFyZW50KGVsZW1lbnQxLCBlbGVtZW50Mikge1xuICAvLyBUaGlzIGNoZWNrIGlzIG5lZWRlZCB0byBhdm9pZCBlcnJvcnMgaW4gY2FzZSBvbmUgb2YgdGhlIGVsZW1lbnRzIGlzbid0IGRlZmluZWQgZm9yIGFueSByZWFzb25cbiAgaWYgKCFlbGVtZW50MSB8fCAhZWxlbWVudDEubm9kZVR5cGUgfHwgIWVsZW1lbnQyIHx8ICFlbGVtZW50Mi5ub2RlVHlwZSkge1xuICAgIHJldHVybiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQ7XG4gIH1cblxuICAvLyBIZXJlIHdlIG1ha2Ugc3VyZSB0byBnaXZlIGFzIFwic3RhcnRcIiB0aGUgZWxlbWVudCB0aGF0IGNvbWVzIGZpcnN0IGluIHRoZSBET01cbiAgdmFyIG9yZGVyID0gZWxlbWVudDEuY29tcGFyZURvY3VtZW50UG9zaXRpb24oZWxlbWVudDIpICYgTm9kZS5ET0NVTUVOVF9QT1NJVElPTl9GT0xMT1dJTkc7XG4gIHZhciBzdGFydCA9IG9yZGVyID8gZWxlbWVudDEgOiBlbGVtZW50MjtcbiAgdmFyIGVuZCA9IG9yZGVyID8gZWxlbWVudDIgOiBlbGVtZW50MTtcblxuICAvLyBHZXQgY29tbW9uIGFuY2VzdG9yIGNvbnRhaW5lclxuICB2YXIgcmFuZ2UgPSBkb2N1bWVudC5jcmVhdGVSYW5nZSgpO1xuICByYW5nZS5zZXRTdGFydChzdGFydCwgMCk7XG4gIHJhbmdlLnNldEVuZChlbmQsIDApO1xuICB2YXIgY29tbW9uQW5jZXN0b3JDb250YWluZXIgPSByYW5nZS5jb21tb25BbmNlc3RvckNvbnRhaW5lcjtcblxuICAvLyBCb3RoIG5vZGVzIGFyZSBpbnNpZGUgI2RvY3VtZW50XG5cbiAgaWYgKGVsZW1lbnQxICE9PSBjb21tb25BbmNlc3RvckNvbnRhaW5lciAmJiBlbGVtZW50MiAhPT0gY29tbW9uQW5jZXN0b3JDb250YWluZXIgfHwgc3RhcnQuY29udGFpbnMoZW5kKSkge1xuICAgIGlmIChpc09mZnNldENvbnRhaW5lcihjb21tb25BbmNlc3RvckNvbnRhaW5lcikpIHtcbiAgICAgIHJldHVybiBjb21tb25BbmNlc3RvckNvbnRhaW5lcjtcbiAgICB9XG5cbiAgICByZXR1cm4gZ2V0T2Zmc2V0UGFyZW50KGNvbW1vbkFuY2VzdG9yQ29udGFpbmVyKTtcbiAgfVxuXG4gIC8vIG9uZSBvZiB0aGUgbm9kZXMgaXMgaW5zaWRlIHNoYWRvd0RPTSwgZmluZCB3aGljaCBvbmVcbiAgdmFyIGVsZW1lbnQxcm9vdCA9IGdldFJvb3QoZWxlbWVudDEpO1xuICBpZiAoZWxlbWVudDFyb290Lmhvc3QpIHtcbiAgICByZXR1cm4gZmluZENvbW1vbk9mZnNldFBhcmVudChlbGVtZW50MXJvb3QuaG9zdCwgZWxlbWVudDIpO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBmaW5kQ29tbW9uT2Zmc2V0UGFyZW50KGVsZW1lbnQxLCBnZXRSb290KGVsZW1lbnQyKS5ob3N0KTtcbiAgfVxufVxuXG4vKipcbiAqIEdldHMgdGhlIHNjcm9sbCB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudCBpbiB0aGUgZ2l2ZW4gc2lkZSAodG9wIGFuZCBsZWZ0KVxuICogQG1ldGhvZFxuICogQG1lbWJlcm9mIFBvcHBlci5VdGlsc1xuICogQGFyZ3VtZW50IHtFbGVtZW50fSBlbGVtZW50XG4gKiBAYXJndW1lbnQge1N0cmluZ30gc2lkZSBgdG9wYCBvciBgbGVmdGBcbiAqIEByZXR1cm5zIHtudW1iZXJ9IGFtb3VudCBvZiBzY3JvbGxlZCBwaXhlbHNcbiAqL1xuZnVuY3Rpb24gZ2V0U2Nyb2xsKGVsZW1lbnQpIHtcbiAgdmFyIHNpZGUgPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiBhcmd1bWVudHNbMV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1sxXSA6ICd0b3AnO1xuXG4gIHZhciB1cHBlclNpZGUgPSBzaWRlID09PSAndG9wJyA/ICdzY3JvbGxUb3AnIDogJ3Njcm9sbExlZnQnO1xuICB2YXIgbm9kZU5hbWUgPSBlbGVtZW50Lm5vZGVOYW1lO1xuXG4gIGlmIChub2RlTmFtZSA9PT0gJ0JPRFknIHx8IG5vZGVOYW1lID09PSAnSFRNTCcpIHtcbiAgICB2YXIgaHRtbCA9IGVsZW1lbnQub3duZXJEb2N1bWVudC5kb2N1bWVudEVsZW1lbnQ7XG4gICAgdmFyIHNjcm9sbGluZ0VsZW1lbnQgPSBlbGVtZW50Lm93bmVyRG9jdW1lbnQuc2Nyb2xsaW5nRWxlbWVudCB8fCBodG1sO1xuICAgIHJldHVybiBzY3JvbGxpbmdFbGVtZW50W3VwcGVyU2lkZV07XG4gIH1cblxuICByZXR1cm4gZWxlbWVudFt1cHBlclNpZGVdO1xufVxuXG4vKlxuICogU3VtIG9yIHN1YnRyYWN0IHRoZSBlbGVtZW50IHNjcm9sbCB2YWx1ZXMgKGxlZnQgYW5kIHRvcCkgZnJvbSBhIGdpdmVuIHJlY3Qgb2JqZWN0XG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAcGFyYW0ge09iamVjdH0gcmVjdCAtIFJlY3Qgb2JqZWN0IHlvdSB3YW50IHRvIGNoYW5nZVxuICogQHBhcmFtIHtIVE1MRWxlbWVudH0gZWxlbWVudCAtIFRoZSBlbGVtZW50IGZyb20gdGhlIGZ1bmN0aW9uIHJlYWRzIHRoZSBzY3JvbGwgdmFsdWVzXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHN1YnRyYWN0IC0gc2V0IHRvIHRydWUgaWYgeW91IHdhbnQgdG8gc3VidHJhY3QgdGhlIHNjcm9sbCB2YWx1ZXNcbiAqIEByZXR1cm4ge09iamVjdH0gcmVjdCAtIFRoZSBtb2RpZmllciByZWN0IG9iamVjdFxuICovXG5mdW5jdGlvbiBpbmNsdWRlU2Nyb2xsKHJlY3QsIGVsZW1lbnQpIHtcbiAgdmFyIHN1YnRyYWN0ID0gYXJndW1lbnRzLmxlbmd0aCA+IDIgJiYgYXJndW1lbnRzWzJdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMl0gOiBmYWxzZTtcblxuICB2YXIgc2Nyb2xsVG9wID0gZ2V0U2Nyb2xsKGVsZW1lbnQsICd0b3AnKTtcbiAgdmFyIHNjcm9sbExlZnQgPSBnZXRTY3JvbGwoZWxlbWVudCwgJ2xlZnQnKTtcbiAgdmFyIG1vZGlmaWVyID0gc3VidHJhY3QgPyAtMSA6IDE7XG4gIHJlY3QudG9wICs9IHNjcm9sbFRvcCAqIG1vZGlmaWVyO1xuICByZWN0LmJvdHRvbSArPSBzY3JvbGxUb3AgKiBtb2RpZmllcjtcbiAgcmVjdC5sZWZ0ICs9IHNjcm9sbExlZnQgKiBtb2RpZmllcjtcbiAgcmVjdC5yaWdodCArPSBzY3JvbGxMZWZ0ICogbW9kaWZpZXI7XG4gIHJldHVybiByZWN0O1xufVxuXG4vKlxuICogSGVscGVyIHRvIGRldGVjdCBib3JkZXJzIG9mIGEgZ2l2ZW4gZWxlbWVudFxuICogQG1ldGhvZFxuICogQG1lbWJlcm9mIFBvcHBlci5VdGlsc1xuICogQHBhcmFtIHtDU1NTdHlsZURlY2xhcmF0aW9ufSBzdHlsZXNcbiAqIFJlc3VsdCBvZiBgZ2V0U3R5bGVDb21wdXRlZFByb3BlcnR5YCBvbiB0aGUgZ2l2ZW4gZWxlbWVudFxuICogQHBhcmFtIHtTdHJpbmd9IGF4aXMgLSBgeGAgb3IgYHlgXG4gKiBAcmV0dXJuIHtudW1iZXJ9IGJvcmRlcnMgLSBUaGUgYm9yZGVycyBzaXplIG9mIHRoZSBnaXZlbiBheGlzXG4gKi9cblxuZnVuY3Rpb24gZ2V0Qm9yZGVyc1NpemUoc3R5bGVzLCBheGlzKSB7XG4gIHZhciBzaWRlQSA9IGF4aXMgPT09ICd4JyA/ICdMZWZ0JyA6ICdUb3AnO1xuICB2YXIgc2lkZUIgPSBzaWRlQSA9PT0gJ0xlZnQnID8gJ1JpZ2h0JyA6ICdCb3R0b20nO1xuXG4gIHJldHVybiBwYXJzZUZsb2F0KHN0eWxlc1snYm9yZGVyJyArIHNpZGVBICsgJ1dpZHRoJ10pICsgcGFyc2VGbG9hdChzdHlsZXNbJ2JvcmRlcicgKyBzaWRlQiArICdXaWR0aCddKTtcbn1cblxuZnVuY3Rpb24gZ2V0U2l6ZShheGlzLCBib2R5LCBodG1sLCBjb21wdXRlZFN0eWxlKSB7XG4gIHJldHVybiBNYXRoLm1heChib2R5WydvZmZzZXQnICsgYXhpc10sIGJvZHlbJ3Njcm9sbCcgKyBheGlzXSwgaHRtbFsnY2xpZW50JyArIGF4aXNdLCBodG1sWydvZmZzZXQnICsgYXhpc10sIGh0bWxbJ3Njcm9sbCcgKyBheGlzXSwgaXNJRSgxMCkgPyBwYXJzZUludChodG1sWydvZmZzZXQnICsgYXhpc10pICsgcGFyc2VJbnQoY29tcHV0ZWRTdHlsZVsnbWFyZ2luJyArIChheGlzID09PSAnSGVpZ2h0JyA/ICdUb3AnIDogJ0xlZnQnKV0pICsgcGFyc2VJbnQoY29tcHV0ZWRTdHlsZVsnbWFyZ2luJyArIChheGlzID09PSAnSGVpZ2h0JyA/ICdCb3R0b20nIDogJ1JpZ2h0JyldKSA6IDApO1xufVxuXG5mdW5jdGlvbiBnZXRXaW5kb3dTaXplcyhkb2N1bWVudCkge1xuICB2YXIgYm9keSA9IGRvY3VtZW50LmJvZHk7XG4gIHZhciBodG1sID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50O1xuICB2YXIgY29tcHV0ZWRTdHlsZSA9IGlzSUUoMTApICYmIGdldENvbXB1dGVkU3R5bGUoaHRtbCk7XG5cbiAgcmV0dXJuIHtcbiAgICBoZWlnaHQ6IGdldFNpemUoJ0hlaWdodCcsIGJvZHksIGh0bWwsIGNvbXB1dGVkU3R5bGUpLFxuICAgIHdpZHRoOiBnZXRTaXplKCdXaWR0aCcsIGJvZHksIGh0bWwsIGNvbXB1dGVkU3R5bGUpXG4gIH07XG59XG5cbnZhciBjbGFzc0NhbGxDaGVjayA9IGZ1bmN0aW9uIChpbnN0YW5jZSwgQ29uc3RydWN0b3IpIHtcbiAgaWYgKCEoaW5zdGFuY2UgaW5zdGFuY2VvZiBDb25zdHJ1Y3RvcikpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uXCIpO1xuICB9XG59O1xuXG52YXIgY3JlYXRlQ2xhc3MgPSBmdW5jdGlvbiAoKSB7XG4gIGZ1bmN0aW9uIGRlZmluZVByb3BlcnRpZXModGFyZ2V0LCBwcm9wcykge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcHJvcHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBkZXNjcmlwdG9yID0gcHJvcHNbaV07XG4gICAgICBkZXNjcmlwdG9yLmVudW1lcmFibGUgPSBkZXNjcmlwdG9yLmVudW1lcmFibGUgfHwgZmFsc2U7XG4gICAgICBkZXNjcmlwdG9yLmNvbmZpZ3VyYWJsZSA9IHRydWU7XG4gICAgICBpZiAoXCJ2YWx1ZVwiIGluIGRlc2NyaXB0b3IpIGRlc2NyaXB0b3Iud3JpdGFibGUgPSB0cnVlO1xuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRhcmdldCwgZGVzY3JpcHRvci5rZXksIGRlc2NyaXB0b3IpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBmdW5jdGlvbiAoQ29uc3RydWN0b3IsIHByb3RvUHJvcHMsIHN0YXRpY1Byb3BzKSB7XG4gICAgaWYgKHByb3RvUHJvcHMpIGRlZmluZVByb3BlcnRpZXMoQ29uc3RydWN0b3IucHJvdG90eXBlLCBwcm90b1Byb3BzKTtcbiAgICBpZiAoc3RhdGljUHJvcHMpIGRlZmluZVByb3BlcnRpZXMoQ29uc3RydWN0b3IsIHN0YXRpY1Byb3BzKTtcbiAgICByZXR1cm4gQ29uc3RydWN0b3I7XG4gIH07XG59KCk7XG5cblxuXG5cblxudmFyIGRlZmluZVByb3BlcnR5ID0gZnVuY3Rpb24gKG9iaiwga2V5LCB2YWx1ZSkge1xuICBpZiAoa2V5IGluIG9iaikge1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShvYmosIGtleSwge1xuICAgICAgdmFsdWU6IHZhbHVlLFxuICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgIHdyaXRhYmxlOiB0cnVlXG4gICAgfSk7XG4gIH0gZWxzZSB7XG4gICAgb2JqW2tleV0gPSB2YWx1ZTtcbiAgfVxuXG4gIHJldHVybiBvYmo7XG59O1xuXG52YXIgX2V4dGVuZHMgPSBPYmplY3QuYXNzaWduIHx8IGZ1bmN0aW9uICh0YXJnZXQpIHtcbiAgZm9yICh2YXIgaSA9IDE7IGkgPCBhcmd1bWVudHMubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgc291cmNlID0gYXJndW1lbnRzW2ldO1xuXG4gICAgZm9yICh2YXIga2V5IGluIHNvdXJjZSkge1xuICAgICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzb3VyY2UsIGtleSkpIHtcbiAgICAgICAgdGFyZ2V0W2tleV0gPSBzb3VyY2Vba2V5XTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gdGFyZ2V0O1xufTtcblxuLyoqXG4gKiBHaXZlbiBlbGVtZW50IG9mZnNldHMsIGdlbmVyYXRlIGFuIG91dHB1dCBzaW1pbGFyIHRvIGdldEJvdW5kaW5nQ2xpZW50UmVjdFxuICogQG1ldGhvZFxuICogQG1lbWJlcm9mIFBvcHBlci5VdGlsc1xuICogQGFyZ3VtZW50IHtPYmplY3R9IG9mZnNldHNcbiAqIEByZXR1cm5zIHtPYmplY3R9IENsaWVudFJlY3QgbGlrZSBvdXRwdXRcbiAqL1xuZnVuY3Rpb24gZ2V0Q2xpZW50UmVjdChvZmZzZXRzKSB7XG4gIHJldHVybiBfZXh0ZW5kcyh7fSwgb2Zmc2V0cywge1xuICAgIHJpZ2h0OiBvZmZzZXRzLmxlZnQgKyBvZmZzZXRzLndpZHRoLFxuICAgIGJvdHRvbTogb2Zmc2V0cy50b3AgKyBvZmZzZXRzLmhlaWdodFxuICB9KTtcbn1cblxuLyoqXG4gKiBHZXQgYm91bmRpbmcgY2xpZW50IHJlY3Qgb2YgZ2l2ZW4gZWxlbWVudFxuICogQG1ldGhvZFxuICogQG1lbWJlcm9mIFBvcHBlci5VdGlsc1xuICogQHBhcmFtIHtIVE1MRWxlbWVudH0gZWxlbWVudFxuICogQHJldHVybiB7T2JqZWN0fSBjbGllbnQgcmVjdFxuICovXG5mdW5jdGlvbiBnZXRCb3VuZGluZ0NsaWVudFJlY3QoZWxlbWVudCkge1xuICB2YXIgcmVjdCA9IHt9O1xuXG4gIC8vIElFMTAgMTAgRklYOiBQbGVhc2UsIGRvbid0IGFzaywgdGhlIGVsZW1lbnQgaXNuJ3RcbiAgLy8gY29uc2lkZXJlZCBpbiBET00gaW4gc29tZSBjaXJjdW1zdGFuY2VzLi4uXG4gIC8vIFRoaXMgaXNuJ3QgcmVwcm9kdWNpYmxlIGluIElFMTAgY29tcGF0aWJpbGl0eSBtb2RlIG9mIElFMTFcbiAgdHJ5IHtcbiAgICBpZiAoaXNJRSgxMCkpIHtcbiAgICAgIHJlY3QgPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgdmFyIHNjcm9sbFRvcCA9IGdldFNjcm9sbChlbGVtZW50LCAndG9wJyk7XG4gICAgICB2YXIgc2Nyb2xsTGVmdCA9IGdldFNjcm9sbChlbGVtZW50LCAnbGVmdCcpO1xuICAgICAgcmVjdC50b3AgKz0gc2Nyb2xsVG9wO1xuICAgICAgcmVjdC5sZWZ0ICs9IHNjcm9sbExlZnQ7XG4gICAgICByZWN0LmJvdHRvbSArPSBzY3JvbGxUb3A7XG4gICAgICByZWN0LnJpZ2h0ICs9IHNjcm9sbExlZnQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJlY3QgPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIH1cbiAgfSBjYXRjaCAoZSkge31cblxuICB2YXIgcmVzdWx0ID0ge1xuICAgIGxlZnQ6IHJlY3QubGVmdCxcbiAgICB0b3A6IHJlY3QudG9wLFxuICAgIHdpZHRoOiByZWN0LnJpZ2h0IC0gcmVjdC5sZWZ0LFxuICAgIGhlaWdodDogcmVjdC5ib3R0b20gLSByZWN0LnRvcFxuICB9O1xuXG4gIC8vIHN1YnRyYWN0IHNjcm9sbGJhciBzaXplIGZyb20gc2l6ZXNcbiAgdmFyIHNpemVzID0gZWxlbWVudC5ub2RlTmFtZSA9PT0gJ0hUTUwnID8gZ2V0V2luZG93U2l6ZXMoZWxlbWVudC5vd25lckRvY3VtZW50KSA6IHt9O1xuICB2YXIgd2lkdGggPSBzaXplcy53aWR0aCB8fCBlbGVtZW50LmNsaWVudFdpZHRoIHx8IHJlc3VsdC53aWR0aDtcbiAgdmFyIGhlaWdodCA9IHNpemVzLmhlaWdodCB8fCBlbGVtZW50LmNsaWVudEhlaWdodCB8fCByZXN1bHQuaGVpZ2h0O1xuXG4gIHZhciBob3JpelNjcm9sbGJhciA9IGVsZW1lbnQub2Zmc2V0V2lkdGggLSB3aWR0aDtcbiAgdmFyIHZlcnRTY3JvbGxiYXIgPSBlbGVtZW50Lm9mZnNldEhlaWdodCAtIGhlaWdodDtcblxuICAvLyBpZiBhbiBoeXBvdGhldGljYWwgc2Nyb2xsYmFyIGlzIGRldGVjdGVkLCB3ZSBtdXN0IGJlIHN1cmUgaXQncyBub3QgYSBgYm9yZGVyYFxuICAvLyB3ZSBtYWtlIHRoaXMgY2hlY2sgY29uZGl0aW9uYWwgZm9yIHBlcmZvcm1hbmNlIHJlYXNvbnNcbiAgaWYgKGhvcml6U2Nyb2xsYmFyIHx8IHZlcnRTY3JvbGxiYXIpIHtcbiAgICB2YXIgc3R5bGVzID0gZ2V0U3R5bGVDb21wdXRlZFByb3BlcnR5KGVsZW1lbnQpO1xuICAgIGhvcml6U2Nyb2xsYmFyIC09IGdldEJvcmRlcnNTaXplKHN0eWxlcywgJ3gnKTtcbiAgICB2ZXJ0U2Nyb2xsYmFyIC09IGdldEJvcmRlcnNTaXplKHN0eWxlcywgJ3knKTtcblxuICAgIHJlc3VsdC53aWR0aCAtPSBob3JpelNjcm9sbGJhcjtcbiAgICByZXN1bHQuaGVpZ2h0IC09IHZlcnRTY3JvbGxiYXI7XG4gIH1cblxuICByZXR1cm4gZ2V0Q2xpZW50UmVjdChyZXN1bHQpO1xufVxuXG5mdW5jdGlvbiBnZXRPZmZzZXRSZWN0UmVsYXRpdmVUb0FyYml0cmFyeU5vZGUoY2hpbGRyZW4sIHBhcmVudCkge1xuICB2YXIgZml4ZWRQb3NpdGlvbiA9IGFyZ3VtZW50cy5sZW5ndGggPiAyICYmIGFyZ3VtZW50c1syXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzJdIDogZmFsc2U7XG5cbiAgdmFyIGlzSUUxMCA9IGlzSUUoMTApO1xuICB2YXIgaXNIVE1MID0gcGFyZW50Lm5vZGVOYW1lID09PSAnSFRNTCc7XG4gIHZhciBjaGlsZHJlblJlY3QgPSBnZXRCb3VuZGluZ0NsaWVudFJlY3QoY2hpbGRyZW4pO1xuICB2YXIgcGFyZW50UmVjdCA9IGdldEJvdW5kaW5nQ2xpZW50UmVjdChwYXJlbnQpO1xuICB2YXIgc2Nyb2xsUGFyZW50ID0gZ2V0U2Nyb2xsUGFyZW50KGNoaWxkcmVuKTtcblxuICB2YXIgc3R5bGVzID0gZ2V0U3R5bGVDb21wdXRlZFByb3BlcnR5KHBhcmVudCk7XG4gIHZhciBib3JkZXJUb3BXaWR0aCA9IHBhcnNlRmxvYXQoc3R5bGVzLmJvcmRlclRvcFdpZHRoKTtcbiAgdmFyIGJvcmRlckxlZnRXaWR0aCA9IHBhcnNlRmxvYXQoc3R5bGVzLmJvcmRlckxlZnRXaWR0aCk7XG5cbiAgLy8gSW4gY2FzZXMgd2hlcmUgdGhlIHBhcmVudCBpcyBmaXhlZCwgd2UgbXVzdCBpZ25vcmUgbmVnYXRpdmUgc2Nyb2xsIGluIG9mZnNldCBjYWxjXG4gIGlmIChmaXhlZFBvc2l0aW9uICYmIGlzSFRNTCkge1xuICAgIHBhcmVudFJlY3QudG9wID0gTWF0aC5tYXgocGFyZW50UmVjdC50b3AsIDApO1xuICAgIHBhcmVudFJlY3QubGVmdCA9IE1hdGgubWF4KHBhcmVudFJlY3QubGVmdCwgMCk7XG4gIH1cbiAgdmFyIG9mZnNldHMgPSBnZXRDbGllbnRSZWN0KHtcbiAgICB0b3A6IGNoaWxkcmVuUmVjdC50b3AgLSBwYXJlbnRSZWN0LnRvcCAtIGJvcmRlclRvcFdpZHRoLFxuICAgIGxlZnQ6IGNoaWxkcmVuUmVjdC5sZWZ0IC0gcGFyZW50UmVjdC5sZWZ0IC0gYm9yZGVyTGVmdFdpZHRoLFxuICAgIHdpZHRoOiBjaGlsZHJlblJlY3Qud2lkdGgsXG4gICAgaGVpZ2h0OiBjaGlsZHJlblJlY3QuaGVpZ2h0XG4gIH0pO1xuICBvZmZzZXRzLm1hcmdpblRvcCA9IDA7XG4gIG9mZnNldHMubWFyZ2luTGVmdCA9IDA7XG5cbiAgLy8gU3VidHJhY3QgbWFyZ2lucyBvZiBkb2N1bWVudEVsZW1lbnQgaW4gY2FzZSBpdCdzIGJlaW5nIHVzZWQgYXMgcGFyZW50XG4gIC8vIHdlIGRvIHRoaXMgb25seSBvbiBIVE1MIGJlY2F1c2UgaXQncyB0aGUgb25seSBlbGVtZW50IHRoYXQgYmVoYXZlc1xuICAvLyBkaWZmZXJlbnRseSB3aGVuIG1hcmdpbnMgYXJlIGFwcGxpZWQgdG8gaXQuIFRoZSBtYXJnaW5zIGFyZSBpbmNsdWRlZCBpblxuICAvLyB0aGUgYm94IG9mIHRoZSBkb2N1bWVudEVsZW1lbnQsIGluIHRoZSBvdGhlciBjYXNlcyBub3QuXG4gIGlmICghaXNJRTEwICYmIGlzSFRNTCkge1xuICAgIHZhciBtYXJnaW5Ub3AgPSBwYXJzZUZsb2F0KHN0eWxlcy5tYXJnaW5Ub3ApO1xuICAgIHZhciBtYXJnaW5MZWZ0ID0gcGFyc2VGbG9hdChzdHlsZXMubWFyZ2luTGVmdCk7XG5cbiAgICBvZmZzZXRzLnRvcCAtPSBib3JkZXJUb3BXaWR0aCAtIG1hcmdpblRvcDtcbiAgICBvZmZzZXRzLmJvdHRvbSAtPSBib3JkZXJUb3BXaWR0aCAtIG1hcmdpblRvcDtcbiAgICBvZmZzZXRzLmxlZnQgLT0gYm9yZGVyTGVmdFdpZHRoIC0gbWFyZ2luTGVmdDtcbiAgICBvZmZzZXRzLnJpZ2h0IC09IGJvcmRlckxlZnRXaWR0aCAtIG1hcmdpbkxlZnQ7XG5cbiAgICAvLyBBdHRhY2ggbWFyZ2luVG9wIGFuZCBtYXJnaW5MZWZ0IGJlY2F1c2UgaW4gc29tZSBjaXJjdW1zdGFuY2VzIHdlIG1heSBuZWVkIHRoZW1cbiAgICBvZmZzZXRzLm1hcmdpblRvcCA9IG1hcmdpblRvcDtcbiAgICBvZmZzZXRzLm1hcmdpbkxlZnQgPSBtYXJnaW5MZWZ0O1xuICB9XG5cbiAgaWYgKGlzSUUxMCAmJiAhZml4ZWRQb3NpdGlvbiA/IHBhcmVudC5jb250YWlucyhzY3JvbGxQYXJlbnQpIDogcGFyZW50ID09PSBzY3JvbGxQYXJlbnQgJiYgc2Nyb2xsUGFyZW50Lm5vZGVOYW1lICE9PSAnQk9EWScpIHtcbiAgICBvZmZzZXRzID0gaW5jbHVkZVNjcm9sbChvZmZzZXRzLCBwYXJlbnQpO1xuICB9XG5cbiAgcmV0dXJuIG9mZnNldHM7XG59XG5cbmZ1bmN0aW9uIGdldFZpZXdwb3J0T2Zmc2V0UmVjdFJlbGF0aXZlVG9BcnRiaXRyYXJ5Tm9kZShlbGVtZW50KSB7XG4gIHZhciBleGNsdWRlU2Nyb2xsID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgYXJndW1lbnRzWzFdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMV0gOiBmYWxzZTtcblxuICB2YXIgaHRtbCA9IGVsZW1lbnQub3duZXJEb2N1bWVudC5kb2N1bWVudEVsZW1lbnQ7XG4gIHZhciByZWxhdGl2ZU9mZnNldCA9IGdldE9mZnNldFJlY3RSZWxhdGl2ZVRvQXJiaXRyYXJ5Tm9kZShlbGVtZW50LCBodG1sKTtcbiAgdmFyIHdpZHRoID0gTWF0aC5tYXgoaHRtbC5jbGllbnRXaWR0aCwgd2luZG93LmlubmVyV2lkdGggfHwgMCk7XG4gIHZhciBoZWlnaHQgPSBNYXRoLm1heChodG1sLmNsaWVudEhlaWdodCwgd2luZG93LmlubmVySGVpZ2h0IHx8IDApO1xuXG4gIHZhciBzY3JvbGxUb3AgPSAhZXhjbHVkZVNjcm9sbCA/IGdldFNjcm9sbChodG1sKSA6IDA7XG4gIHZhciBzY3JvbGxMZWZ0ID0gIWV4Y2x1ZGVTY3JvbGwgPyBnZXRTY3JvbGwoaHRtbCwgJ2xlZnQnKSA6IDA7XG5cbiAgdmFyIG9mZnNldCA9IHtcbiAgICB0b3A6IHNjcm9sbFRvcCAtIHJlbGF0aXZlT2Zmc2V0LnRvcCArIHJlbGF0aXZlT2Zmc2V0Lm1hcmdpblRvcCxcbiAgICBsZWZ0OiBzY3JvbGxMZWZ0IC0gcmVsYXRpdmVPZmZzZXQubGVmdCArIHJlbGF0aXZlT2Zmc2V0Lm1hcmdpbkxlZnQsXG4gICAgd2lkdGg6IHdpZHRoLFxuICAgIGhlaWdodDogaGVpZ2h0XG4gIH07XG5cbiAgcmV0dXJuIGdldENsaWVudFJlY3Qob2Zmc2V0KTtcbn1cblxuLyoqXG4gKiBDaGVjayBpZiB0aGUgZ2l2ZW4gZWxlbWVudCBpcyBmaXhlZCBvciBpcyBpbnNpZGUgYSBmaXhlZCBwYXJlbnRcbiAqIEBtZXRob2RcbiAqIEBtZW1iZXJvZiBQb3BwZXIuVXRpbHNcbiAqIEBhcmd1bWVudCB7RWxlbWVudH0gZWxlbWVudFxuICogQGFyZ3VtZW50IHtFbGVtZW50fSBjdXN0b21Db250YWluZXJcbiAqIEByZXR1cm5zIHtCb29sZWFufSBhbnN3ZXIgdG8gXCJpc0ZpeGVkP1wiXG4gKi9cbmZ1bmN0aW9uIGlzRml4ZWQoZWxlbWVudCkge1xuICB2YXIgbm9kZU5hbWUgPSBlbGVtZW50Lm5vZGVOYW1lO1xuICBpZiAobm9kZU5hbWUgPT09ICdCT0RZJyB8fCBub2RlTmFtZSA9PT0gJ0hUTUwnKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGlmIChnZXRTdHlsZUNvbXB1dGVkUHJvcGVydHkoZWxlbWVudCwgJ3Bvc2l0aW9uJykgPT09ICdmaXhlZCcpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuICB2YXIgcGFyZW50Tm9kZSA9IGdldFBhcmVudE5vZGUoZWxlbWVudCk7XG4gIGlmICghcGFyZW50Tm9kZSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICByZXR1cm4gaXNGaXhlZChwYXJlbnROb2RlKTtcbn1cblxuLyoqXG4gKiBGaW5kcyB0aGUgZmlyc3QgcGFyZW50IG9mIGFuIGVsZW1lbnQgdGhhdCBoYXMgYSB0cmFuc2Zvcm1lZCBwcm9wZXJ0eSBkZWZpbmVkXG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAYXJndW1lbnQge0VsZW1lbnR9IGVsZW1lbnRcbiAqIEByZXR1cm5zIHtFbGVtZW50fSBmaXJzdCB0cmFuc2Zvcm1lZCBwYXJlbnQgb3IgZG9jdW1lbnRFbGVtZW50XG4gKi9cblxuZnVuY3Rpb24gZ2V0Rml4ZWRQb3NpdGlvbk9mZnNldFBhcmVudChlbGVtZW50KSB7XG4gIC8vIFRoaXMgY2hlY2sgaXMgbmVlZGVkIHRvIGF2b2lkIGVycm9ycyBpbiBjYXNlIG9uZSBvZiB0aGUgZWxlbWVudHMgaXNuJ3QgZGVmaW5lZCBmb3IgYW55IHJlYXNvblxuICBpZiAoIWVsZW1lbnQgfHwgIWVsZW1lbnQucGFyZW50RWxlbWVudCB8fCBpc0lFKCkpIHtcbiAgICByZXR1cm4gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50O1xuICB9XG4gIHZhciBlbCA9IGVsZW1lbnQucGFyZW50RWxlbWVudDtcbiAgd2hpbGUgKGVsICYmIGdldFN0eWxlQ29tcHV0ZWRQcm9wZXJ0eShlbCwgJ3RyYW5zZm9ybScpID09PSAnbm9uZScpIHtcbiAgICBlbCA9IGVsLnBhcmVudEVsZW1lbnQ7XG4gIH1cbiAgcmV0dXJuIGVsIHx8IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudDtcbn1cblxuLyoqXG4gKiBDb21wdXRlZCB0aGUgYm91bmRhcmllcyBsaW1pdHMgYW5kIHJldHVybiB0aGVtXG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBwb3BwZXJcbiAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IHJlZmVyZW5jZVxuICogQHBhcmFtIHtudW1iZXJ9IHBhZGRpbmdcbiAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGJvdW5kYXJpZXNFbGVtZW50IC0gRWxlbWVudCB1c2VkIHRvIGRlZmluZSB0aGUgYm91bmRhcmllc1xuICogQHBhcmFtIHtCb29sZWFufSBmaXhlZFBvc2l0aW9uIC0gSXMgaW4gZml4ZWQgcG9zaXRpb24gbW9kZVxuICogQHJldHVybnMge09iamVjdH0gQ29vcmRpbmF0ZXMgb2YgdGhlIGJvdW5kYXJpZXNcbiAqL1xuZnVuY3Rpb24gZ2V0Qm91bmRhcmllcyhwb3BwZXIsIHJlZmVyZW5jZSwgcGFkZGluZywgYm91bmRhcmllc0VsZW1lbnQpIHtcbiAgdmFyIGZpeGVkUG9zaXRpb24gPSBhcmd1bWVudHMubGVuZ3RoID4gNCAmJiBhcmd1bWVudHNbNF0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1s0XSA6IGZhbHNlO1xuXG4gIC8vIE5PVEU6IDEgRE9NIGFjY2VzcyBoZXJlXG5cbiAgdmFyIGJvdW5kYXJpZXMgPSB7IHRvcDogMCwgbGVmdDogMCB9O1xuICB2YXIgb2Zmc2V0UGFyZW50ID0gZml4ZWRQb3NpdGlvbiA/IGdldEZpeGVkUG9zaXRpb25PZmZzZXRQYXJlbnQocG9wcGVyKSA6IGZpbmRDb21tb25PZmZzZXRQYXJlbnQocG9wcGVyLCBnZXRSZWZlcmVuY2VOb2RlKHJlZmVyZW5jZSkpO1xuXG4gIC8vIEhhbmRsZSB2aWV3cG9ydCBjYXNlXG4gIGlmIChib3VuZGFyaWVzRWxlbWVudCA9PT0gJ3ZpZXdwb3J0Jykge1xuICAgIGJvdW5kYXJpZXMgPSBnZXRWaWV3cG9ydE9mZnNldFJlY3RSZWxhdGl2ZVRvQXJ0Yml0cmFyeU5vZGUob2Zmc2V0UGFyZW50LCBmaXhlZFBvc2l0aW9uKTtcbiAgfSBlbHNlIHtcbiAgICAvLyBIYW5kbGUgb3RoZXIgY2FzZXMgYmFzZWQgb24gRE9NIGVsZW1lbnQgdXNlZCBhcyBib3VuZGFyaWVzXG4gICAgdmFyIGJvdW5kYXJpZXNOb2RlID0gdm9pZCAwO1xuICAgIGlmIChib3VuZGFyaWVzRWxlbWVudCA9PT0gJ3Njcm9sbFBhcmVudCcpIHtcbiAgICAgIGJvdW5kYXJpZXNOb2RlID0gZ2V0U2Nyb2xsUGFyZW50KGdldFBhcmVudE5vZGUocmVmZXJlbmNlKSk7XG4gICAgICBpZiAoYm91bmRhcmllc05vZGUubm9kZU5hbWUgPT09ICdCT0RZJykge1xuICAgICAgICBib3VuZGFyaWVzTm9kZSA9IHBvcHBlci5vd25lckRvY3VtZW50LmRvY3VtZW50RWxlbWVudDtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGJvdW5kYXJpZXNFbGVtZW50ID09PSAnd2luZG93Jykge1xuICAgICAgYm91bmRhcmllc05vZGUgPSBwb3BwZXIub3duZXJEb2N1bWVudC5kb2N1bWVudEVsZW1lbnQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIGJvdW5kYXJpZXNOb2RlID0gYm91bmRhcmllc0VsZW1lbnQ7XG4gICAgfVxuXG4gICAgdmFyIG9mZnNldHMgPSBnZXRPZmZzZXRSZWN0UmVsYXRpdmVUb0FyYml0cmFyeU5vZGUoYm91bmRhcmllc05vZGUsIG9mZnNldFBhcmVudCwgZml4ZWRQb3NpdGlvbik7XG5cbiAgICAvLyBJbiBjYXNlIG9mIEhUTUwsIHdlIG5lZWQgYSBkaWZmZXJlbnQgY29tcHV0YXRpb25cbiAgICBpZiAoYm91bmRhcmllc05vZGUubm9kZU5hbWUgPT09ICdIVE1MJyAmJiAhaXNGaXhlZChvZmZzZXRQYXJlbnQpKSB7XG4gICAgICB2YXIgX2dldFdpbmRvd1NpemVzID0gZ2V0V2luZG93U2l6ZXMocG9wcGVyLm93bmVyRG9jdW1lbnQpLFxuICAgICAgICAgIGhlaWdodCA9IF9nZXRXaW5kb3dTaXplcy5oZWlnaHQsXG4gICAgICAgICAgd2lkdGggPSBfZ2V0V2luZG93U2l6ZXMud2lkdGg7XG5cbiAgICAgIGJvdW5kYXJpZXMudG9wICs9IG9mZnNldHMudG9wIC0gb2Zmc2V0cy5tYXJnaW5Ub3A7XG4gICAgICBib3VuZGFyaWVzLmJvdHRvbSA9IGhlaWdodCArIG9mZnNldHMudG9wO1xuICAgICAgYm91bmRhcmllcy5sZWZ0ICs9IG9mZnNldHMubGVmdCAtIG9mZnNldHMubWFyZ2luTGVmdDtcbiAgICAgIGJvdW5kYXJpZXMucmlnaHQgPSB3aWR0aCArIG9mZnNldHMubGVmdDtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gZm9yIGFsbCB0aGUgb3RoZXIgRE9NIGVsZW1lbnRzLCB0aGlzIG9uZSBpcyBnb29kXG4gICAgICBib3VuZGFyaWVzID0gb2Zmc2V0cztcbiAgICB9XG4gIH1cblxuICAvLyBBZGQgcGFkZGluZ3NcbiAgcGFkZGluZyA9IHBhZGRpbmcgfHwgMDtcbiAgdmFyIGlzUGFkZGluZ051bWJlciA9IHR5cGVvZiBwYWRkaW5nID09PSAnbnVtYmVyJztcbiAgYm91bmRhcmllcy5sZWZ0ICs9IGlzUGFkZGluZ051bWJlciA/IHBhZGRpbmcgOiBwYWRkaW5nLmxlZnQgfHwgMDtcbiAgYm91bmRhcmllcy50b3AgKz0gaXNQYWRkaW5nTnVtYmVyID8gcGFkZGluZyA6IHBhZGRpbmcudG9wIHx8IDA7XG4gIGJvdW5kYXJpZXMucmlnaHQgLT0gaXNQYWRkaW5nTnVtYmVyID8gcGFkZGluZyA6IHBhZGRpbmcucmlnaHQgfHwgMDtcbiAgYm91bmRhcmllcy5ib3R0b20gLT0gaXNQYWRkaW5nTnVtYmVyID8gcGFkZGluZyA6IHBhZGRpbmcuYm90dG9tIHx8IDA7XG5cbiAgcmV0dXJuIGJvdW5kYXJpZXM7XG59XG5cbmZ1bmN0aW9uIGdldEFyZWEoX3JlZikge1xuICB2YXIgd2lkdGggPSBfcmVmLndpZHRoLFxuICAgICAgaGVpZ2h0ID0gX3JlZi5oZWlnaHQ7XG5cbiAgcmV0dXJuIHdpZHRoICogaGVpZ2h0O1xufVxuXG4vKipcbiAqIFV0aWxpdHkgdXNlZCB0byB0cmFuc2Zvcm0gdGhlIGBhdXRvYCBwbGFjZW1lbnQgdG8gdGhlIHBsYWNlbWVudCB3aXRoIG1vcmVcbiAqIGF2YWlsYWJsZSBzcGFjZS5cbiAqIEBtZXRob2RcbiAqIEBtZW1iZXJvZiBQb3BwZXIuVXRpbHNcbiAqIEBhcmd1bWVudCB7T2JqZWN0fSBkYXRhIC0gVGhlIGRhdGEgb2JqZWN0IGdlbmVyYXRlZCBieSB1cGRhdGUgbWV0aG9kXG4gKiBAYXJndW1lbnQge09iamVjdH0gb3B0aW9ucyAtIE1vZGlmaWVycyBjb25maWd1cmF0aW9uIGFuZCBvcHRpb25zXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgZGF0YSBvYmplY3QsIHByb3Blcmx5IG1vZGlmaWVkXG4gKi9cbmZ1bmN0aW9uIGNvbXB1dGVBdXRvUGxhY2VtZW50KHBsYWNlbWVudCwgcmVmUmVjdCwgcG9wcGVyLCByZWZlcmVuY2UsIGJvdW5kYXJpZXNFbGVtZW50KSB7XG4gIHZhciBwYWRkaW5nID0gYXJndW1lbnRzLmxlbmd0aCA+IDUgJiYgYXJndW1lbnRzWzVdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbNV0gOiAwO1xuXG4gIGlmIChwbGFjZW1lbnQuaW5kZXhPZignYXV0bycpID09PSAtMSkge1xuICAgIHJldHVybiBwbGFjZW1lbnQ7XG4gIH1cblxuICB2YXIgYm91bmRhcmllcyA9IGdldEJvdW5kYXJpZXMocG9wcGVyLCByZWZlcmVuY2UsIHBhZGRpbmcsIGJvdW5kYXJpZXNFbGVtZW50KTtcblxuICB2YXIgcmVjdHMgPSB7XG4gICAgdG9wOiB7XG4gICAgICB3aWR0aDogYm91bmRhcmllcy53aWR0aCxcbiAgICAgIGhlaWdodDogcmVmUmVjdC50b3AgLSBib3VuZGFyaWVzLnRvcFxuICAgIH0sXG4gICAgcmlnaHQ6IHtcbiAgICAgIHdpZHRoOiBib3VuZGFyaWVzLnJpZ2h0IC0gcmVmUmVjdC5yaWdodCxcbiAgICAgIGhlaWdodDogYm91bmRhcmllcy5oZWlnaHRcbiAgICB9LFxuICAgIGJvdHRvbToge1xuICAgICAgd2lkdGg6IGJvdW5kYXJpZXMud2lkdGgsXG4gICAgICBoZWlnaHQ6IGJvdW5kYXJpZXMuYm90dG9tIC0gcmVmUmVjdC5ib3R0b21cbiAgICB9LFxuICAgIGxlZnQ6IHtcbiAgICAgIHdpZHRoOiByZWZSZWN0LmxlZnQgLSBib3VuZGFyaWVzLmxlZnQsXG4gICAgICBoZWlnaHQ6IGJvdW5kYXJpZXMuaGVpZ2h0XG4gICAgfVxuICB9O1xuXG4gIHZhciBzb3J0ZWRBcmVhcyA9IE9iamVjdC5rZXlzKHJlY3RzKS5tYXAoZnVuY3Rpb24gKGtleSkge1xuICAgIHJldHVybiBfZXh0ZW5kcyh7XG4gICAgICBrZXk6IGtleVxuICAgIH0sIHJlY3RzW2tleV0sIHtcbiAgICAgIGFyZWE6IGdldEFyZWEocmVjdHNba2V5XSlcbiAgICB9KTtcbiAgfSkuc29ydChmdW5jdGlvbiAoYSwgYikge1xuICAgIHJldHVybiBiLmFyZWEgLSBhLmFyZWE7XG4gIH0pO1xuXG4gIHZhciBmaWx0ZXJlZEFyZWFzID0gc29ydGVkQXJlYXMuZmlsdGVyKGZ1bmN0aW9uIChfcmVmMikge1xuICAgIHZhciB3aWR0aCA9IF9yZWYyLndpZHRoLFxuICAgICAgICBoZWlnaHQgPSBfcmVmMi5oZWlnaHQ7XG4gICAgcmV0dXJuIHdpZHRoID49IHBvcHBlci5jbGllbnRXaWR0aCAmJiBoZWlnaHQgPj0gcG9wcGVyLmNsaWVudEhlaWdodDtcbiAgfSk7XG5cbiAgdmFyIGNvbXB1dGVkUGxhY2VtZW50ID0gZmlsdGVyZWRBcmVhcy5sZW5ndGggPiAwID8gZmlsdGVyZWRBcmVhc1swXS5rZXkgOiBzb3J0ZWRBcmVhc1swXS5rZXk7XG5cbiAgdmFyIHZhcmlhdGlvbiA9IHBsYWNlbWVudC5zcGxpdCgnLScpWzFdO1xuXG4gIHJldHVybiBjb21wdXRlZFBsYWNlbWVudCArICh2YXJpYXRpb24gPyAnLScgKyB2YXJpYXRpb24gOiAnJyk7XG59XG5cbi8qKlxuICogR2V0IG9mZnNldHMgdG8gdGhlIHJlZmVyZW5jZSBlbGVtZW50XG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAcGFyYW0ge09iamVjdH0gc3RhdGVcbiAqIEBwYXJhbSB7RWxlbWVudH0gcG9wcGVyIC0gdGhlIHBvcHBlciBlbGVtZW50XG4gKiBAcGFyYW0ge0VsZW1lbnR9IHJlZmVyZW5jZSAtIHRoZSByZWZlcmVuY2UgZWxlbWVudCAodGhlIHBvcHBlciB3aWxsIGJlIHJlbGF0aXZlIHRvIHRoaXMpXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGZpeGVkUG9zaXRpb24gLSBpcyBpbiBmaXhlZCBwb3NpdGlvbiBtb2RlXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgb2Zmc2V0cyB3aGljaCB3aWxsIGJlIGFwcGxpZWQgdG8gdGhlIHBvcHBlclxuICovXG5mdW5jdGlvbiBnZXRSZWZlcmVuY2VPZmZzZXRzKHN0YXRlLCBwb3BwZXIsIHJlZmVyZW5jZSkge1xuICB2YXIgZml4ZWRQb3NpdGlvbiA9IGFyZ3VtZW50cy5sZW5ndGggPiAzICYmIGFyZ3VtZW50c1szXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzNdIDogbnVsbDtcblxuICB2YXIgY29tbW9uT2Zmc2V0UGFyZW50ID0gZml4ZWRQb3NpdGlvbiA/IGdldEZpeGVkUG9zaXRpb25PZmZzZXRQYXJlbnQocG9wcGVyKSA6IGZpbmRDb21tb25PZmZzZXRQYXJlbnQocG9wcGVyLCBnZXRSZWZlcmVuY2VOb2RlKHJlZmVyZW5jZSkpO1xuICByZXR1cm4gZ2V0T2Zmc2V0UmVjdFJlbGF0aXZlVG9BcmJpdHJhcnlOb2RlKHJlZmVyZW5jZSwgY29tbW9uT2Zmc2V0UGFyZW50LCBmaXhlZFBvc2l0aW9uKTtcbn1cblxuLyoqXG4gKiBHZXQgdGhlIG91dGVyIHNpemVzIG9mIHRoZSBnaXZlbiBlbGVtZW50IChvZmZzZXQgc2l6ZSArIG1hcmdpbnMpXG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAYXJndW1lbnQge0VsZW1lbnR9IGVsZW1lbnRcbiAqIEByZXR1cm5zIHtPYmplY3R9IG9iamVjdCBjb250YWluaW5nIHdpZHRoIGFuZCBoZWlnaHQgcHJvcGVydGllc1xuICovXG5mdW5jdGlvbiBnZXRPdXRlclNpemVzKGVsZW1lbnQpIHtcbiAgdmFyIHdpbmRvdyA9IGVsZW1lbnQub3duZXJEb2N1bWVudC5kZWZhdWx0VmlldztcbiAgdmFyIHN0eWxlcyA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGVsZW1lbnQpO1xuICB2YXIgeCA9IHBhcnNlRmxvYXQoc3R5bGVzLm1hcmdpblRvcCB8fCAwKSArIHBhcnNlRmxvYXQoc3R5bGVzLm1hcmdpbkJvdHRvbSB8fCAwKTtcbiAgdmFyIHkgPSBwYXJzZUZsb2F0KHN0eWxlcy5tYXJnaW5MZWZ0IHx8IDApICsgcGFyc2VGbG9hdChzdHlsZXMubWFyZ2luUmlnaHQgfHwgMCk7XG4gIHZhciByZXN1bHQgPSB7XG4gICAgd2lkdGg6IGVsZW1lbnQub2Zmc2V0V2lkdGggKyB5LFxuICAgIGhlaWdodDogZWxlbWVudC5vZmZzZXRIZWlnaHQgKyB4XG4gIH07XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKlxuICogR2V0IHRoZSBvcHBvc2l0ZSBwbGFjZW1lbnQgb2YgdGhlIGdpdmVuIG9uZVxuICogQG1ldGhvZFxuICogQG1lbWJlcm9mIFBvcHBlci5VdGlsc1xuICogQGFyZ3VtZW50IHtTdHJpbmd9IHBsYWNlbWVudFxuICogQHJldHVybnMge1N0cmluZ30gZmxpcHBlZCBwbGFjZW1lbnRcbiAqL1xuZnVuY3Rpb24gZ2V0T3Bwb3NpdGVQbGFjZW1lbnQocGxhY2VtZW50KSB7XG4gIHZhciBoYXNoID0geyBsZWZ0OiAncmlnaHQnLCByaWdodDogJ2xlZnQnLCBib3R0b206ICd0b3AnLCB0b3A6ICdib3R0b20nIH07XG4gIHJldHVybiBwbGFjZW1lbnQucmVwbGFjZSgvbGVmdHxyaWdodHxib3R0b218dG9wL2csIGZ1bmN0aW9uIChtYXRjaGVkKSB7XG4gICAgcmV0dXJuIGhhc2hbbWF0Y2hlZF07XG4gIH0pO1xufVxuXG4vKipcbiAqIEdldCBvZmZzZXRzIHRvIHRoZSBwb3BwZXJcbiAqIEBtZXRob2RcbiAqIEBtZW1iZXJvZiBQb3BwZXIuVXRpbHNcbiAqIEBwYXJhbSB7T2JqZWN0fSBwb3NpdGlvbiAtIENTUyBwb3NpdGlvbiB0aGUgUG9wcGVyIHdpbGwgZ2V0IGFwcGxpZWRcbiAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IHBvcHBlciAtIHRoZSBwb3BwZXIgZWxlbWVudFxuICogQHBhcmFtIHtPYmplY3R9IHJlZmVyZW5jZU9mZnNldHMgLSB0aGUgcmVmZXJlbmNlIG9mZnNldHMgKHRoZSBwb3BwZXIgd2lsbCBiZSByZWxhdGl2ZSB0byB0aGlzKVxuICogQHBhcmFtIHtTdHJpbmd9IHBsYWNlbWVudCAtIG9uZSBvZiB0aGUgdmFsaWQgcGxhY2VtZW50IG9wdGlvbnNcbiAqIEByZXR1cm5zIHtPYmplY3R9IHBvcHBlck9mZnNldHMgLSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgb2Zmc2V0cyB3aGljaCB3aWxsIGJlIGFwcGxpZWQgdG8gdGhlIHBvcHBlclxuICovXG5mdW5jdGlvbiBnZXRQb3BwZXJPZmZzZXRzKHBvcHBlciwgcmVmZXJlbmNlT2Zmc2V0cywgcGxhY2VtZW50KSB7XG4gIHBsYWNlbWVudCA9IHBsYWNlbWVudC5zcGxpdCgnLScpWzBdO1xuXG4gIC8vIEdldCBwb3BwZXIgbm9kZSBzaXplc1xuICB2YXIgcG9wcGVyUmVjdCA9IGdldE91dGVyU2l6ZXMocG9wcGVyKTtcblxuICAvLyBBZGQgcG9zaXRpb24sIHdpZHRoIGFuZCBoZWlnaHQgdG8gb3VyIG9mZnNldHMgb2JqZWN0XG4gIHZhciBwb3BwZXJPZmZzZXRzID0ge1xuICAgIHdpZHRoOiBwb3BwZXJSZWN0LndpZHRoLFxuICAgIGhlaWdodDogcG9wcGVyUmVjdC5oZWlnaHRcbiAgfTtcblxuICAvLyBkZXBlbmRpbmcgYnkgdGhlIHBvcHBlciBwbGFjZW1lbnQgd2UgaGF2ZSB0byBjb21wdXRlIGl0cyBvZmZzZXRzIHNsaWdodGx5IGRpZmZlcmVudGx5XG4gIHZhciBpc0hvcml6ID0gWydyaWdodCcsICdsZWZ0J10uaW5kZXhPZihwbGFjZW1lbnQpICE9PSAtMTtcbiAgdmFyIG1haW5TaWRlID0gaXNIb3JpeiA/ICd0b3AnIDogJ2xlZnQnO1xuICB2YXIgc2Vjb25kYXJ5U2lkZSA9IGlzSG9yaXogPyAnbGVmdCcgOiAndG9wJztcbiAgdmFyIG1lYXN1cmVtZW50ID0gaXNIb3JpeiA/ICdoZWlnaHQnIDogJ3dpZHRoJztcbiAgdmFyIHNlY29uZGFyeU1lYXN1cmVtZW50ID0gIWlzSG9yaXogPyAnaGVpZ2h0JyA6ICd3aWR0aCc7XG5cbiAgcG9wcGVyT2Zmc2V0c1ttYWluU2lkZV0gPSByZWZlcmVuY2VPZmZzZXRzW21haW5TaWRlXSArIHJlZmVyZW5jZU9mZnNldHNbbWVhc3VyZW1lbnRdIC8gMiAtIHBvcHBlclJlY3RbbWVhc3VyZW1lbnRdIC8gMjtcbiAgaWYgKHBsYWNlbWVudCA9PT0gc2Vjb25kYXJ5U2lkZSkge1xuICAgIHBvcHBlck9mZnNldHNbc2Vjb25kYXJ5U2lkZV0gPSByZWZlcmVuY2VPZmZzZXRzW3NlY29uZGFyeVNpZGVdIC0gcG9wcGVyUmVjdFtzZWNvbmRhcnlNZWFzdXJlbWVudF07XG4gIH0gZWxzZSB7XG4gICAgcG9wcGVyT2Zmc2V0c1tzZWNvbmRhcnlTaWRlXSA9IHJlZmVyZW5jZU9mZnNldHNbZ2V0T3Bwb3NpdGVQbGFjZW1lbnQoc2Vjb25kYXJ5U2lkZSldO1xuICB9XG5cbiAgcmV0dXJuIHBvcHBlck9mZnNldHM7XG59XG5cbi8qKlxuICogTWltaWNzIHRoZSBgZmluZGAgbWV0aG9kIG9mIEFycmF5XG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAYXJndW1lbnQge0FycmF5fSBhcnJcbiAqIEBhcmd1bWVudCBwcm9wXG4gKiBAYXJndW1lbnQgdmFsdWVcbiAqIEByZXR1cm5zIGluZGV4IG9yIC0xXG4gKi9cbmZ1bmN0aW9uIGZpbmQoYXJyLCBjaGVjaykge1xuICAvLyB1c2UgbmF0aXZlIGZpbmQgaWYgc3VwcG9ydGVkXG4gIGlmIChBcnJheS5wcm90b3R5cGUuZmluZCkge1xuICAgIHJldHVybiBhcnIuZmluZChjaGVjayk7XG4gIH1cblxuICAvLyB1c2UgYGZpbHRlcmAgdG8gb2J0YWluIHRoZSBzYW1lIGJlaGF2aW9yIG9mIGBmaW5kYFxuICByZXR1cm4gYXJyLmZpbHRlcihjaGVjaylbMF07XG59XG5cbi8qKlxuICogUmV0dXJuIHRoZSBpbmRleCBvZiB0aGUgbWF0Y2hpbmcgb2JqZWN0XG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAYXJndW1lbnQge0FycmF5fSBhcnJcbiAqIEBhcmd1bWVudCBwcm9wXG4gKiBAYXJndW1lbnQgdmFsdWVcbiAqIEByZXR1cm5zIGluZGV4IG9yIC0xXG4gKi9cbmZ1bmN0aW9uIGZpbmRJbmRleChhcnIsIHByb3AsIHZhbHVlKSB7XG4gIC8vIHVzZSBuYXRpdmUgZmluZEluZGV4IGlmIHN1cHBvcnRlZFxuICBpZiAoQXJyYXkucHJvdG90eXBlLmZpbmRJbmRleCkge1xuICAgIHJldHVybiBhcnIuZmluZEluZGV4KGZ1bmN0aW9uIChjdXIpIHtcbiAgICAgIHJldHVybiBjdXJbcHJvcF0gPT09IHZhbHVlO1xuICAgIH0pO1xuICB9XG5cbiAgLy8gdXNlIGBmaW5kYCArIGBpbmRleE9mYCBpZiBgZmluZEluZGV4YCBpc24ndCBzdXBwb3J0ZWRcbiAgdmFyIG1hdGNoID0gZmluZChhcnIsIGZ1bmN0aW9uIChvYmopIHtcbiAgICByZXR1cm4gb2JqW3Byb3BdID09PSB2YWx1ZTtcbiAgfSk7XG4gIHJldHVybiBhcnIuaW5kZXhPZihtYXRjaCk7XG59XG5cbi8qKlxuICogTG9vcCB0cm91Z2ggdGhlIGxpc3Qgb2YgbW9kaWZpZXJzIGFuZCBydW4gdGhlbSBpbiBvcmRlcixcbiAqIGVhY2ggb2YgdGhlbSB3aWxsIHRoZW4gZWRpdCB0aGUgZGF0YSBvYmplY3QuXG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAcGFyYW0ge2RhdGFPYmplY3R9IGRhdGFcbiAqIEBwYXJhbSB7QXJyYXl9IG1vZGlmaWVyc1xuICogQHBhcmFtIHtTdHJpbmd9IGVuZHMgLSBPcHRpb25hbCBtb2RpZmllciBuYW1lIHVzZWQgYXMgc3RvcHBlclxuICogQHJldHVybnMge2RhdGFPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIHJ1bk1vZGlmaWVycyhtb2RpZmllcnMsIGRhdGEsIGVuZHMpIHtcbiAgdmFyIG1vZGlmaWVyc1RvUnVuID0gZW5kcyA9PT0gdW5kZWZpbmVkID8gbW9kaWZpZXJzIDogbW9kaWZpZXJzLnNsaWNlKDAsIGZpbmRJbmRleChtb2RpZmllcnMsICduYW1lJywgZW5kcykpO1xuXG4gIG1vZGlmaWVyc1RvUnVuLmZvckVhY2goZnVuY3Rpb24gKG1vZGlmaWVyKSB7XG4gICAgaWYgKG1vZGlmaWVyWydmdW5jdGlvbiddKSB7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIGRvdC1ub3RhdGlvblxuICAgICAgY29uc29sZS53YXJuKCdgbW9kaWZpZXIuZnVuY3Rpb25gIGlzIGRlcHJlY2F0ZWQsIHVzZSBgbW9kaWZpZXIuZm5gIScpO1xuICAgIH1cbiAgICB2YXIgZm4gPSBtb2RpZmllclsnZnVuY3Rpb24nXSB8fCBtb2RpZmllci5mbjsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBkb3Qtbm90YXRpb25cbiAgICBpZiAobW9kaWZpZXIuZW5hYmxlZCAmJiBpc0Z1bmN0aW9uKGZuKSkge1xuICAgICAgLy8gQWRkIHByb3BlcnRpZXMgdG8gb2Zmc2V0cyB0byBtYWtlIHRoZW0gYSBjb21wbGV0ZSBjbGllbnRSZWN0IG9iamVjdFxuICAgICAgLy8gd2UgZG8gdGhpcyBiZWZvcmUgZWFjaCBtb2RpZmllciB0byBtYWtlIHN1cmUgdGhlIHByZXZpb3VzIG9uZSBkb2Vzbid0XG4gICAgICAvLyBtZXNzIHdpdGggdGhlc2UgdmFsdWVzXG4gICAgICBkYXRhLm9mZnNldHMucG9wcGVyID0gZ2V0Q2xpZW50UmVjdChkYXRhLm9mZnNldHMucG9wcGVyKTtcbiAgICAgIGRhdGEub2Zmc2V0cy5yZWZlcmVuY2UgPSBnZXRDbGllbnRSZWN0KGRhdGEub2Zmc2V0cy5yZWZlcmVuY2UpO1xuXG4gICAgICBkYXRhID0gZm4oZGF0YSwgbW9kaWZpZXIpO1xuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIGRhdGE7XG59XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgcG9zaXRpb24gb2YgdGhlIHBvcHBlciwgY29tcHV0aW5nIHRoZSBuZXcgb2Zmc2V0cyBhbmQgYXBwbHlpbmdcbiAqIHRoZSBuZXcgc3R5bGUuPGJyIC8+XG4gKiBQcmVmZXIgYHNjaGVkdWxlVXBkYXRlYCBvdmVyIGB1cGRhdGVgIGJlY2F1c2Ugb2YgcGVyZm9ybWFuY2UgcmVhc29ucy5cbiAqIEBtZXRob2RcbiAqIEBtZW1iZXJvZiBQb3BwZXJcbiAqL1xuZnVuY3Rpb24gdXBkYXRlKCkge1xuICAvLyBpZiBwb3BwZXIgaXMgZGVzdHJveWVkLCBkb24ndCBwZXJmb3JtIGFueSBmdXJ0aGVyIHVwZGF0ZVxuICBpZiAodGhpcy5zdGF0ZS5pc0Rlc3Ryb3llZCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIHZhciBkYXRhID0ge1xuICAgIGluc3RhbmNlOiB0aGlzLFxuICAgIHN0eWxlczoge30sXG4gICAgYXJyb3dTdHlsZXM6IHt9LFxuICAgIGF0dHJpYnV0ZXM6IHt9LFxuICAgIGZsaXBwZWQ6IGZhbHNlLFxuICAgIG9mZnNldHM6IHt9XG4gIH07XG5cbiAgLy8gY29tcHV0ZSByZWZlcmVuY2UgZWxlbWVudCBvZmZzZXRzXG4gIGRhdGEub2Zmc2V0cy5yZWZlcmVuY2UgPSBnZXRSZWZlcmVuY2VPZmZzZXRzKHRoaXMuc3RhdGUsIHRoaXMucG9wcGVyLCB0aGlzLnJlZmVyZW5jZSwgdGhpcy5vcHRpb25zLnBvc2l0aW9uRml4ZWQpO1xuXG4gIC8vIGNvbXB1dGUgYXV0byBwbGFjZW1lbnQsIHN0b3JlIHBsYWNlbWVudCBpbnNpZGUgdGhlIGRhdGEgb2JqZWN0LFxuICAvLyBtb2RpZmllcnMgd2lsbCBiZSBhYmxlIHRvIGVkaXQgYHBsYWNlbWVudGAgaWYgbmVlZGVkXG4gIC8vIGFuZCByZWZlciB0byBvcmlnaW5hbFBsYWNlbWVudCB0byBrbm93IHRoZSBvcmlnaW5hbCB2YWx1ZVxuICBkYXRhLnBsYWNlbWVudCA9IGNvbXB1dGVBdXRvUGxhY2VtZW50KHRoaXMub3B0aW9ucy5wbGFjZW1lbnQsIGRhdGEub2Zmc2V0cy5yZWZlcmVuY2UsIHRoaXMucG9wcGVyLCB0aGlzLnJlZmVyZW5jZSwgdGhpcy5vcHRpb25zLm1vZGlmaWVycy5mbGlwLmJvdW5kYXJpZXNFbGVtZW50LCB0aGlzLm9wdGlvbnMubW9kaWZpZXJzLmZsaXAucGFkZGluZyk7XG5cbiAgLy8gc3RvcmUgdGhlIGNvbXB1dGVkIHBsYWNlbWVudCBpbnNpZGUgYG9yaWdpbmFsUGxhY2VtZW50YFxuICBkYXRhLm9yaWdpbmFsUGxhY2VtZW50ID0gZGF0YS5wbGFjZW1lbnQ7XG5cbiAgZGF0YS5wb3NpdGlvbkZpeGVkID0gdGhpcy5vcHRpb25zLnBvc2l0aW9uRml4ZWQ7XG5cbiAgLy8gY29tcHV0ZSB0aGUgcG9wcGVyIG9mZnNldHNcbiAgZGF0YS5vZmZzZXRzLnBvcHBlciA9IGdldFBvcHBlck9mZnNldHModGhpcy5wb3BwZXIsIGRhdGEub2Zmc2V0cy5yZWZlcmVuY2UsIGRhdGEucGxhY2VtZW50KTtcblxuICBkYXRhLm9mZnNldHMucG9wcGVyLnBvc2l0aW9uID0gdGhpcy5vcHRpb25zLnBvc2l0aW9uRml4ZWQgPyAnZml4ZWQnIDogJ2Fic29sdXRlJztcblxuICAvLyBydW4gdGhlIG1vZGlmaWVyc1xuICBkYXRhID0gcnVuTW9kaWZpZXJzKHRoaXMubW9kaWZpZXJzLCBkYXRhKTtcblxuICAvLyB0aGUgZmlyc3QgYHVwZGF0ZWAgd2lsbCBjYWxsIGBvbkNyZWF0ZWAgY2FsbGJhY2tcbiAgLy8gdGhlIG90aGVyIG9uZXMgd2lsbCBjYWxsIGBvblVwZGF0ZWAgY2FsbGJhY2tcbiAgaWYgKCF0aGlzLnN0YXRlLmlzQ3JlYXRlZCkge1xuICAgIHRoaXMuc3RhdGUuaXNDcmVhdGVkID0gdHJ1ZTtcbiAgICB0aGlzLm9wdGlvbnMub25DcmVhdGUoZGF0YSk7XG4gIH0gZWxzZSB7XG4gICAgdGhpcy5vcHRpb25zLm9uVXBkYXRlKGRhdGEpO1xuICB9XG59XG5cbi8qKlxuICogSGVscGVyIHVzZWQgdG8ga25vdyBpZiB0aGUgZ2l2ZW4gbW9kaWZpZXIgaXMgZW5hYmxlZC5cbiAqIEBtZXRob2RcbiAqIEBtZW1iZXJvZiBQb3BwZXIuVXRpbHNcbiAqIEByZXR1cm5zIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBpc01vZGlmaWVyRW5hYmxlZChtb2RpZmllcnMsIG1vZGlmaWVyTmFtZSkge1xuICByZXR1cm4gbW9kaWZpZXJzLnNvbWUoZnVuY3Rpb24gKF9yZWYpIHtcbiAgICB2YXIgbmFtZSA9IF9yZWYubmFtZSxcbiAgICAgICAgZW5hYmxlZCA9IF9yZWYuZW5hYmxlZDtcbiAgICByZXR1cm4gZW5hYmxlZCAmJiBuYW1lID09PSBtb2RpZmllck5hbWU7XG4gIH0pO1xufVxuXG4vKipcbiAqIEdldCB0aGUgcHJlZml4ZWQgc3VwcG9ydGVkIHByb3BlcnR5IG5hbWVcbiAqIEBtZXRob2RcbiAqIEBtZW1iZXJvZiBQb3BwZXIuVXRpbHNcbiAqIEBhcmd1bWVudCB7U3RyaW5nfSBwcm9wZXJ0eSAoY2FtZWxDYXNlKVxuICogQHJldHVybnMge1N0cmluZ30gcHJlZml4ZWQgcHJvcGVydHkgKGNhbWVsQ2FzZSBvciBQYXNjYWxDYXNlLCBkZXBlbmRpbmcgb24gdGhlIHZlbmRvciBwcmVmaXgpXG4gKi9cbmZ1bmN0aW9uIGdldFN1cHBvcnRlZFByb3BlcnR5TmFtZShwcm9wZXJ0eSkge1xuICB2YXIgcHJlZml4ZXMgPSBbZmFsc2UsICdtcycsICdXZWJraXQnLCAnTW96JywgJ08nXTtcbiAgdmFyIHVwcGVyUHJvcCA9IHByb3BlcnR5LmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgcHJvcGVydHkuc2xpY2UoMSk7XG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBwcmVmaXhlcy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBwcmVmaXggPSBwcmVmaXhlc1tpXTtcbiAgICB2YXIgdG9DaGVjayA9IHByZWZpeCA/ICcnICsgcHJlZml4ICsgdXBwZXJQcm9wIDogcHJvcGVydHk7XG4gICAgaWYgKHR5cGVvZiBkb2N1bWVudC5ib2R5LnN0eWxlW3RvQ2hlY2tdICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgcmV0dXJuIHRvQ2hlY2s7XG4gICAgfVxuICB9XG4gIHJldHVybiBudWxsO1xufVxuXG4vKipcbiAqIERlc3Ryb3lzIHRoZSBwb3BwZXIuXG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyXG4gKi9cbmZ1bmN0aW9uIGRlc3Ryb3koKSB7XG4gIHRoaXMuc3RhdGUuaXNEZXN0cm95ZWQgPSB0cnVlO1xuXG4gIC8vIHRvdWNoIERPTSBvbmx5IGlmIGBhcHBseVN0eWxlYCBtb2RpZmllciBpcyBlbmFibGVkXG4gIGlmIChpc01vZGlmaWVyRW5hYmxlZCh0aGlzLm1vZGlmaWVycywgJ2FwcGx5U3R5bGUnKSkge1xuICAgIHRoaXMucG9wcGVyLnJlbW92ZUF0dHJpYnV0ZSgneC1wbGFjZW1lbnQnKTtcbiAgICB0aGlzLnBvcHBlci5zdHlsZS5wb3NpdGlvbiA9ICcnO1xuICAgIHRoaXMucG9wcGVyLnN0eWxlLnRvcCA9ICcnO1xuICAgIHRoaXMucG9wcGVyLnN0eWxlLmxlZnQgPSAnJztcbiAgICB0aGlzLnBvcHBlci5zdHlsZS5yaWdodCA9ICcnO1xuICAgIHRoaXMucG9wcGVyLnN0eWxlLmJvdHRvbSA9ICcnO1xuICAgIHRoaXMucG9wcGVyLnN0eWxlLndpbGxDaGFuZ2UgPSAnJztcbiAgICB0aGlzLnBvcHBlci5zdHlsZVtnZXRTdXBwb3J0ZWRQcm9wZXJ0eU5hbWUoJ3RyYW5zZm9ybScpXSA9ICcnO1xuICB9XG5cbiAgdGhpcy5kaXNhYmxlRXZlbnRMaXN0ZW5lcnMoKTtcblxuICAvLyByZW1vdmUgdGhlIHBvcHBlciBpZiB1c2VyIGV4cGxpY2l0bHkgYXNrZWQgZm9yIHRoZSBkZWxldGlvbiBvbiBkZXN0cm95XG4gIC8vIGRvIG5vdCB1c2UgYHJlbW92ZWAgYmVjYXVzZSBJRTExIGRvZXNuJ3Qgc3VwcG9ydCBpdFxuICBpZiAodGhpcy5vcHRpb25zLnJlbW92ZU9uRGVzdHJveSkge1xuICAgIHRoaXMucG9wcGVyLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQodGhpcy5wb3BwZXIpO1xuICB9XG4gIHJldHVybiB0aGlzO1xufVxuXG4vKipcbiAqIEdldCB0aGUgd2luZG93IGFzc29jaWF0ZWQgd2l0aCB0aGUgZWxlbWVudFxuICogQGFyZ3VtZW50IHtFbGVtZW50fSBlbGVtZW50XG4gKiBAcmV0dXJucyB7V2luZG93fVxuICovXG5mdW5jdGlvbiBnZXRXaW5kb3coZWxlbWVudCkge1xuICB2YXIgb3duZXJEb2N1bWVudCA9IGVsZW1lbnQub3duZXJEb2N1bWVudDtcbiAgcmV0dXJuIG93bmVyRG9jdW1lbnQgPyBvd25lckRvY3VtZW50LmRlZmF1bHRWaWV3IDogd2luZG93O1xufVxuXG5mdW5jdGlvbiBhdHRhY2hUb1Njcm9sbFBhcmVudHMoc2Nyb2xsUGFyZW50LCBldmVudCwgY2FsbGJhY2ssIHNjcm9sbFBhcmVudHMpIHtcbiAgdmFyIGlzQm9keSA9IHNjcm9sbFBhcmVudC5ub2RlTmFtZSA9PT0gJ0JPRFknO1xuICB2YXIgdGFyZ2V0ID0gaXNCb2R5ID8gc2Nyb2xsUGFyZW50Lm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXcgOiBzY3JvbGxQYXJlbnQ7XG4gIHRhcmdldC5hZGRFdmVudExpc3RlbmVyKGV2ZW50LCBjYWxsYmFjaywgeyBwYXNzaXZlOiB0cnVlIH0pO1xuXG4gIGlmICghaXNCb2R5KSB7XG4gICAgYXR0YWNoVG9TY3JvbGxQYXJlbnRzKGdldFNjcm9sbFBhcmVudCh0YXJnZXQucGFyZW50Tm9kZSksIGV2ZW50LCBjYWxsYmFjaywgc2Nyb2xsUGFyZW50cyk7XG4gIH1cbiAgc2Nyb2xsUGFyZW50cy5wdXNoKHRhcmdldCk7XG59XG5cbi8qKlxuICogU2V0dXAgbmVlZGVkIGV2ZW50IGxpc3RlbmVycyB1c2VkIHRvIHVwZGF0ZSB0aGUgcG9wcGVyIHBvc2l0aW9uXG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBzZXR1cEV2ZW50TGlzdGVuZXJzKHJlZmVyZW5jZSwgb3B0aW9ucywgc3RhdGUsIHVwZGF0ZUJvdW5kKSB7XG4gIC8vIFJlc2l6ZSBldmVudCBsaXN0ZW5lciBvbiB3aW5kb3dcbiAgc3RhdGUudXBkYXRlQm91bmQgPSB1cGRhdGVCb3VuZDtcbiAgZ2V0V2luZG93KHJlZmVyZW5jZSkuYWRkRXZlbnRMaXN0ZW5lcigncmVzaXplJywgc3RhdGUudXBkYXRlQm91bmQsIHsgcGFzc2l2ZTogdHJ1ZSB9KTtcblxuICAvLyBTY3JvbGwgZXZlbnQgbGlzdGVuZXIgb24gc2Nyb2xsIHBhcmVudHNcbiAgdmFyIHNjcm9sbEVsZW1lbnQgPSBnZXRTY3JvbGxQYXJlbnQocmVmZXJlbmNlKTtcbiAgYXR0YWNoVG9TY3JvbGxQYXJlbnRzKHNjcm9sbEVsZW1lbnQsICdzY3JvbGwnLCBzdGF0ZS51cGRhdGVCb3VuZCwgc3RhdGUuc2Nyb2xsUGFyZW50cyk7XG4gIHN0YXRlLnNjcm9sbEVsZW1lbnQgPSBzY3JvbGxFbGVtZW50O1xuICBzdGF0ZS5ldmVudHNFbmFibGVkID0gdHJ1ZTtcblxuICByZXR1cm4gc3RhdGU7XG59XG5cbi8qKlxuICogSXQgd2lsbCBhZGQgcmVzaXplL3Njcm9sbCBldmVudHMgYW5kIHN0YXJ0IHJlY2FsY3VsYXRpbmdcbiAqIHBvc2l0aW9uIG9mIHRoZSBwb3BwZXIgZWxlbWVudCB3aGVuIHRoZXkgYXJlIHRyaWdnZXJlZC5cbiAqIEBtZXRob2RcbiAqIEBtZW1iZXJvZiBQb3BwZXJcbiAqL1xuZnVuY3Rpb24gZW5hYmxlRXZlbnRMaXN0ZW5lcnMoKSB7XG4gIGlmICghdGhpcy5zdGF0ZS5ldmVudHNFbmFibGVkKSB7XG4gICAgdGhpcy5zdGF0ZSA9IHNldHVwRXZlbnRMaXN0ZW5lcnModGhpcy5yZWZlcmVuY2UsIHRoaXMub3B0aW9ucywgdGhpcy5zdGF0ZSwgdGhpcy5zY2hlZHVsZVVwZGF0ZSk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZW1vdmUgZXZlbnQgbGlzdGVuZXJzIHVzZWQgdG8gdXBkYXRlIHRoZSBwb3BwZXIgcG9zaXRpb25cbiAqIEBtZXRob2RcbiAqIEBtZW1iZXJvZiBQb3BwZXIuVXRpbHNcbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIHJlbW92ZUV2ZW50TGlzdGVuZXJzKHJlZmVyZW5jZSwgc3RhdGUpIHtcbiAgLy8gUmVtb3ZlIHJlc2l6ZSBldmVudCBsaXN0ZW5lciBvbiB3aW5kb3dcbiAgZ2V0V2luZG93KHJlZmVyZW5jZSkucmVtb3ZlRXZlbnRMaXN0ZW5lcigncmVzaXplJywgc3RhdGUudXBkYXRlQm91bmQpO1xuXG4gIC8vIFJlbW92ZSBzY3JvbGwgZXZlbnQgbGlzdGVuZXIgb24gc2Nyb2xsIHBhcmVudHNcbiAgc3RhdGUuc2Nyb2xsUGFyZW50cy5mb3JFYWNoKGZ1bmN0aW9uICh0YXJnZXQpIHtcbiAgICB0YXJnZXQucmVtb3ZlRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgc3RhdGUudXBkYXRlQm91bmQpO1xuICB9KTtcblxuICAvLyBSZXNldCBzdGF0ZVxuICBzdGF0ZS51cGRhdGVCb3VuZCA9IG51bGw7XG4gIHN0YXRlLnNjcm9sbFBhcmVudHMgPSBbXTtcbiAgc3RhdGUuc2Nyb2xsRWxlbWVudCA9IG51bGw7XG4gIHN0YXRlLmV2ZW50c0VuYWJsZWQgPSBmYWxzZTtcbiAgcmV0dXJuIHN0YXRlO1xufVxuXG4vKipcbiAqIEl0IHdpbGwgcmVtb3ZlIHJlc2l6ZS9zY3JvbGwgZXZlbnRzIGFuZCB3b24ndCByZWNhbGN1bGF0ZSBwb3BwZXIgcG9zaXRpb25cbiAqIHdoZW4gdGhleSBhcmUgdHJpZ2dlcmVkLiBJdCBhbHNvIHdvbid0IHRyaWdnZXIgYG9uVXBkYXRlYCBjYWxsYmFjayBhbnltb3JlLFxuICogdW5sZXNzIHlvdSBjYWxsIGB1cGRhdGVgIG1ldGhvZCBtYW51YWxseS5cbiAqIEBtZXRob2RcbiAqIEBtZW1iZXJvZiBQb3BwZXJcbiAqL1xuZnVuY3Rpb24gZGlzYWJsZUV2ZW50TGlzdGVuZXJzKCkge1xuICBpZiAodGhpcy5zdGF0ZS5ldmVudHNFbmFibGVkKSB7XG4gICAgY2FuY2VsQW5pbWF0aW9uRnJhbWUodGhpcy5zY2hlZHVsZVVwZGF0ZSk7XG4gICAgdGhpcy5zdGF0ZSA9IHJlbW92ZUV2ZW50TGlzdGVuZXJzKHRoaXMucmVmZXJlbmNlLCB0aGlzLnN0YXRlKTtcbiAgfVxufVxuXG4vKipcbiAqIFRlbGxzIGlmIGEgZ2l2ZW4gaW5wdXQgaXMgYSBudW1iZXJcbiAqIEBtZXRob2RcbiAqIEBtZW1iZXJvZiBQb3BwZXIuVXRpbHNcbiAqIEBwYXJhbSB7Kn0gaW5wdXQgdG8gY2hlY2tcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIGlzTnVtZXJpYyhuKSB7XG4gIHJldHVybiBuICE9PSAnJyAmJiAhaXNOYU4ocGFyc2VGbG9hdChuKSkgJiYgaXNGaW5pdGUobik7XG59XG5cbi8qKlxuICogU2V0IHRoZSBzdHlsZSB0byB0aGUgZ2l2ZW4gcG9wcGVyXG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAYXJndW1lbnQge0VsZW1lbnR9IGVsZW1lbnQgLSBFbGVtZW50IHRvIGFwcGx5IHRoZSBzdHlsZSB0b1xuICogQGFyZ3VtZW50IHtPYmplY3R9IHN0eWxlc1xuICogT2JqZWN0IHdpdGggYSBsaXN0IG9mIHByb3BlcnRpZXMgYW5kIHZhbHVlcyB3aGljaCB3aWxsIGJlIGFwcGxpZWQgdG8gdGhlIGVsZW1lbnRcbiAqL1xuZnVuY3Rpb24gc2V0U3R5bGVzKGVsZW1lbnQsIHN0eWxlcykge1xuICBPYmplY3Qua2V5cyhzdHlsZXMpLmZvckVhY2goZnVuY3Rpb24gKHByb3ApIHtcbiAgICB2YXIgdW5pdCA9ICcnO1xuICAgIC8vIGFkZCB1bml0IGlmIHRoZSB2YWx1ZSBpcyBudW1lcmljIGFuZCBpcyBvbmUgb2YgdGhlIGZvbGxvd2luZ1xuICAgIGlmIChbJ3dpZHRoJywgJ2hlaWdodCcsICd0b3AnLCAncmlnaHQnLCAnYm90dG9tJywgJ2xlZnQnXS5pbmRleE9mKHByb3ApICE9PSAtMSAmJiBpc051bWVyaWMoc3R5bGVzW3Byb3BdKSkge1xuICAgICAgdW5pdCA9ICdweCc7XG4gICAgfVxuICAgIGVsZW1lbnQuc3R5bGVbcHJvcF0gPSBzdHlsZXNbcHJvcF0gKyB1bml0O1xuICB9KTtcbn1cblxuLyoqXG4gKiBTZXQgdGhlIGF0dHJpYnV0ZXMgdG8gdGhlIGdpdmVuIHBvcHBlclxuICogQG1ldGhvZFxuICogQG1lbWJlcm9mIFBvcHBlci5VdGlsc1xuICogQGFyZ3VtZW50IHtFbGVtZW50fSBlbGVtZW50IC0gRWxlbWVudCB0byBhcHBseSB0aGUgYXR0cmlidXRlcyB0b1xuICogQGFyZ3VtZW50IHtPYmplY3R9IHN0eWxlc1xuICogT2JqZWN0IHdpdGggYSBsaXN0IG9mIHByb3BlcnRpZXMgYW5kIHZhbHVlcyB3aGljaCB3aWxsIGJlIGFwcGxpZWQgdG8gdGhlIGVsZW1lbnRcbiAqL1xuZnVuY3Rpb24gc2V0QXR0cmlidXRlcyhlbGVtZW50LCBhdHRyaWJ1dGVzKSB7XG4gIE9iamVjdC5rZXlzKGF0dHJpYnV0ZXMpLmZvckVhY2goZnVuY3Rpb24gKHByb3ApIHtcbiAgICB2YXIgdmFsdWUgPSBhdHRyaWJ1dGVzW3Byb3BdO1xuICAgIGlmICh2YWx1ZSAhPT0gZmFsc2UpIHtcbiAgICAgIGVsZW1lbnQuc2V0QXR0cmlidXRlKHByb3AsIGF0dHJpYnV0ZXNbcHJvcF0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBlbGVtZW50LnJlbW92ZUF0dHJpYnV0ZShwcm9wKTtcbiAgICB9XG4gIH0pO1xufVxuXG4vKipcbiAqIEBmdW5jdGlvblxuICogQG1lbWJlcm9mIE1vZGlmaWVyc1xuICogQGFyZ3VtZW50IHtPYmplY3R9IGRhdGEgLSBUaGUgZGF0YSBvYmplY3QgZ2VuZXJhdGVkIGJ5IGB1cGRhdGVgIG1ldGhvZFxuICogQGFyZ3VtZW50IHtPYmplY3R9IGRhdGEuc3R5bGVzIC0gTGlzdCBvZiBzdHlsZSBwcm9wZXJ0aWVzIC0gdmFsdWVzIHRvIGFwcGx5IHRvIHBvcHBlciBlbGVtZW50XG4gKiBAYXJndW1lbnQge09iamVjdH0gZGF0YS5hdHRyaWJ1dGVzIC0gTGlzdCBvZiBhdHRyaWJ1dGUgcHJvcGVydGllcyAtIHZhbHVlcyB0byBhcHBseSB0byBwb3BwZXIgZWxlbWVudFxuICogQGFyZ3VtZW50IHtPYmplY3R9IG9wdGlvbnMgLSBNb2RpZmllcnMgY29uZmlndXJhdGlvbiBhbmQgb3B0aW9uc1xuICogQHJldHVybnMge09iamVjdH0gVGhlIHNhbWUgZGF0YSBvYmplY3RcbiAqL1xuZnVuY3Rpb24gYXBwbHlTdHlsZShkYXRhKSB7XG4gIC8vIGFueSBwcm9wZXJ0eSBwcmVzZW50IGluIGBkYXRhLnN0eWxlc2Agd2lsbCBiZSBhcHBsaWVkIHRvIHRoZSBwb3BwZXIsXG4gIC8vIGluIHRoaXMgd2F5IHdlIGNhbiBtYWtlIHRoZSAzcmQgcGFydHkgbW9kaWZpZXJzIGFkZCBjdXN0b20gc3R5bGVzIHRvIGl0XG4gIC8vIEJlIGF3YXJlLCBtb2RpZmllcnMgY291bGQgb3ZlcnJpZGUgdGhlIHByb3BlcnRpZXMgZGVmaW5lZCBpbiB0aGUgcHJldmlvdXNcbiAgLy8gbGluZXMgb2YgdGhpcyBtb2RpZmllciFcbiAgc2V0U3R5bGVzKGRhdGEuaW5zdGFuY2UucG9wcGVyLCBkYXRhLnN0eWxlcyk7XG5cbiAgLy8gYW55IHByb3BlcnR5IHByZXNlbnQgaW4gYGRhdGEuYXR0cmlidXRlc2Agd2lsbCBiZSBhcHBsaWVkIHRvIHRoZSBwb3BwZXIsXG4gIC8vIHRoZXkgd2lsbCBiZSBzZXQgYXMgSFRNTCBhdHRyaWJ1dGVzIG9mIHRoZSBlbGVtZW50XG4gIHNldEF0dHJpYnV0ZXMoZGF0YS5pbnN0YW5jZS5wb3BwZXIsIGRhdGEuYXR0cmlidXRlcyk7XG5cbiAgLy8gaWYgYXJyb3dFbGVtZW50IGlzIGRlZmluZWQgYW5kIGFycm93U3R5bGVzIGhhcyBzb21lIHByb3BlcnRpZXNcbiAgaWYgKGRhdGEuYXJyb3dFbGVtZW50ICYmIE9iamVjdC5rZXlzKGRhdGEuYXJyb3dTdHlsZXMpLmxlbmd0aCkge1xuICAgIHNldFN0eWxlcyhkYXRhLmFycm93RWxlbWVudCwgZGF0YS5hcnJvd1N0eWxlcyk7XG4gIH1cblxuICByZXR1cm4gZGF0YTtcbn1cblxuLyoqXG4gKiBTZXQgdGhlIHgtcGxhY2VtZW50IGF0dHJpYnV0ZSBiZWZvcmUgZXZlcnl0aGluZyBlbHNlIGJlY2F1c2UgaXQgY291bGQgYmUgdXNlZFxuICogdG8gYWRkIG1hcmdpbnMgdG8gdGhlIHBvcHBlciBtYXJnaW5zIG5lZWRzIHRvIGJlIGNhbGN1bGF0ZWQgdG8gZ2V0IHRoZVxuICogY29ycmVjdCBwb3BwZXIgb2Zmc2V0cy5cbiAqIEBtZXRob2RcbiAqIEBtZW1iZXJvZiBQb3BwZXIubW9kaWZpZXJzXG4gKiBAcGFyYW0ge0hUTUxFbGVtZW50fSByZWZlcmVuY2UgLSBUaGUgcmVmZXJlbmNlIGVsZW1lbnQgdXNlZCB0byBwb3NpdGlvbiB0aGUgcG9wcGVyXG4gKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBwb3BwZXIgLSBUaGUgSFRNTCBlbGVtZW50IHVzZWQgYXMgcG9wcGVyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFBvcHBlci5qcyBvcHRpb25zXG4gKi9cbmZ1bmN0aW9uIGFwcGx5U3R5bGVPbkxvYWQocmVmZXJlbmNlLCBwb3BwZXIsIG9wdGlvbnMsIG1vZGlmaWVyT3B0aW9ucywgc3RhdGUpIHtcbiAgLy8gY29tcHV0ZSByZWZlcmVuY2UgZWxlbWVudCBvZmZzZXRzXG4gIHZhciByZWZlcmVuY2VPZmZzZXRzID0gZ2V0UmVmZXJlbmNlT2Zmc2V0cyhzdGF0ZSwgcG9wcGVyLCByZWZlcmVuY2UsIG9wdGlvbnMucG9zaXRpb25GaXhlZCk7XG5cbiAgLy8gY29tcHV0ZSBhdXRvIHBsYWNlbWVudCwgc3RvcmUgcGxhY2VtZW50IGluc2lkZSB0aGUgZGF0YSBvYmplY3QsXG4gIC8vIG1vZGlmaWVycyB3aWxsIGJlIGFibGUgdG8gZWRpdCBgcGxhY2VtZW50YCBpZiBuZWVkZWRcbiAgLy8gYW5kIHJlZmVyIHRvIG9yaWdpbmFsUGxhY2VtZW50IHRvIGtub3cgdGhlIG9yaWdpbmFsIHZhbHVlXG4gIHZhciBwbGFjZW1lbnQgPSBjb21wdXRlQXV0b1BsYWNlbWVudChvcHRpb25zLnBsYWNlbWVudCwgcmVmZXJlbmNlT2Zmc2V0cywgcG9wcGVyLCByZWZlcmVuY2UsIG9wdGlvbnMubW9kaWZpZXJzLmZsaXAuYm91bmRhcmllc0VsZW1lbnQsIG9wdGlvbnMubW9kaWZpZXJzLmZsaXAucGFkZGluZyk7XG5cbiAgcG9wcGVyLnNldEF0dHJpYnV0ZSgneC1wbGFjZW1lbnQnLCBwbGFjZW1lbnQpO1xuXG4gIC8vIEFwcGx5IGBwb3NpdGlvbmAgdG8gcG9wcGVyIGJlZm9yZSBhbnl0aGluZyBlbHNlIGJlY2F1c2VcbiAgLy8gd2l0aG91dCB0aGUgcG9zaXRpb24gYXBwbGllZCB3ZSBjYW4ndCBndWFyYW50ZWUgY29ycmVjdCBjb21wdXRhdGlvbnNcbiAgc2V0U3R5bGVzKHBvcHBlciwgeyBwb3NpdGlvbjogb3B0aW9ucy5wb3NpdGlvbkZpeGVkID8gJ2ZpeGVkJyA6ICdhYnNvbHV0ZScgfSk7XG5cbiAgcmV0dXJuIG9wdGlvbnM7XG59XG5cbi8qKlxuICogQGZ1bmN0aW9uXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAYXJndW1lbnQge09iamVjdH0gZGF0YSAtIFRoZSBkYXRhIG9iamVjdCBnZW5lcmF0ZWQgYnkgYHVwZGF0ZWAgbWV0aG9kXG4gKiBAYXJndW1lbnQge0Jvb2xlYW59IHNob3VsZFJvdW5kIC0gSWYgdGhlIG9mZnNldHMgc2hvdWxkIGJlIHJvdW5kZWQgYXQgYWxsXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgcG9wcGVyJ3MgcG9zaXRpb24gb2Zmc2V0cyByb3VuZGVkXG4gKlxuICogVGhlIHRhbGUgb2YgcGl4ZWwtcGVyZmVjdCBwb3NpdGlvbmluZy4gSXQncyBzdGlsbCBub3QgMTAwJSBwZXJmZWN0LCBidXQgYXNcbiAqIGdvb2QgYXMgaXQgY2FuIGJlIHdpdGhpbiByZWFzb24uXG4gKiBEaXNjdXNzaW9uIGhlcmU6IGh0dHBzOi8vZ2l0aHViLmNvbS9GZXpWcmFzdGEvcG9wcGVyLmpzL3B1bGwvNzE1XG4gKlxuICogTG93IERQSSBzY3JlZW5zIGNhdXNlIGEgcG9wcGVyIHRvIGJlIGJsdXJyeSBpZiBub3QgdXNpbmcgZnVsbCBwaXhlbHMgKFNhZmFyaVxuICogYXMgd2VsbCBvbiBIaWdoIERQSSBzY3JlZW5zKS5cbiAqXG4gKiBGaXJlZm94IHByZWZlcnMgbm8gcm91bmRpbmcgZm9yIHBvc2l0aW9uaW5nIGFuZCBkb2VzIG5vdCBoYXZlIGJsdXJyaW5lc3Mgb25cbiAqIGhpZ2ggRFBJIHNjcmVlbnMuXG4gKlxuICogT25seSBob3Jpem9udGFsIHBsYWNlbWVudCBhbmQgbGVmdC9yaWdodCB2YWx1ZXMgbmVlZCB0byBiZSBjb25zaWRlcmVkLlxuICovXG5mdW5jdGlvbiBnZXRSb3VuZGVkT2Zmc2V0cyhkYXRhLCBzaG91bGRSb3VuZCkge1xuICB2YXIgX2RhdGEkb2Zmc2V0cyA9IGRhdGEub2Zmc2V0cyxcbiAgICAgIHBvcHBlciA9IF9kYXRhJG9mZnNldHMucG9wcGVyLFxuICAgICAgcmVmZXJlbmNlID0gX2RhdGEkb2Zmc2V0cy5yZWZlcmVuY2U7XG4gIHZhciByb3VuZCA9IE1hdGgucm91bmQsXG4gICAgICBmbG9vciA9IE1hdGguZmxvb3I7XG5cbiAgdmFyIG5vUm91bmQgPSBmdW5jdGlvbiBub1JvdW5kKHYpIHtcbiAgICByZXR1cm4gdjtcbiAgfTtcblxuICB2YXIgcmVmZXJlbmNlV2lkdGggPSByb3VuZChyZWZlcmVuY2Uud2lkdGgpO1xuICB2YXIgcG9wcGVyV2lkdGggPSByb3VuZChwb3BwZXIud2lkdGgpO1xuXG4gIHZhciBpc1ZlcnRpY2FsID0gWydsZWZ0JywgJ3JpZ2h0J10uaW5kZXhPZihkYXRhLnBsYWNlbWVudCkgIT09IC0xO1xuICB2YXIgaXNWYXJpYXRpb24gPSBkYXRhLnBsYWNlbWVudC5pbmRleE9mKCctJykgIT09IC0xO1xuICB2YXIgc2FtZVdpZHRoUGFyaXR5ID0gcmVmZXJlbmNlV2lkdGggJSAyID09PSBwb3BwZXJXaWR0aCAlIDI7XG4gIHZhciBib3RoT2RkV2lkdGggPSByZWZlcmVuY2VXaWR0aCAlIDIgPT09IDEgJiYgcG9wcGVyV2lkdGggJSAyID09PSAxO1xuXG4gIHZhciBob3Jpem9udGFsVG9JbnRlZ2VyID0gIXNob3VsZFJvdW5kID8gbm9Sb3VuZCA6IGlzVmVydGljYWwgfHwgaXNWYXJpYXRpb24gfHwgc2FtZVdpZHRoUGFyaXR5ID8gcm91bmQgOiBmbG9vcjtcbiAgdmFyIHZlcnRpY2FsVG9JbnRlZ2VyID0gIXNob3VsZFJvdW5kID8gbm9Sb3VuZCA6IHJvdW5kO1xuXG4gIHJldHVybiB7XG4gICAgbGVmdDogaG9yaXpvbnRhbFRvSW50ZWdlcihib3RoT2RkV2lkdGggJiYgIWlzVmFyaWF0aW9uICYmIHNob3VsZFJvdW5kID8gcG9wcGVyLmxlZnQgLSAxIDogcG9wcGVyLmxlZnQpLFxuICAgIHRvcDogdmVydGljYWxUb0ludGVnZXIocG9wcGVyLnRvcCksXG4gICAgYm90dG9tOiB2ZXJ0aWNhbFRvSW50ZWdlcihwb3BwZXIuYm90dG9tKSxcbiAgICByaWdodDogaG9yaXpvbnRhbFRvSW50ZWdlcihwb3BwZXIucmlnaHQpXG4gIH07XG59XG5cbnZhciBpc0ZpcmVmb3ggPSBpc0Jyb3dzZXIgJiYgL0ZpcmVmb3gvaS50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpO1xuXG4vKipcbiAqIEBmdW5jdGlvblxuICogQG1lbWJlcm9mIE1vZGlmaWVyc1xuICogQGFyZ3VtZW50IHtPYmplY3R9IGRhdGEgLSBUaGUgZGF0YSBvYmplY3QgZ2VuZXJhdGVkIGJ5IGB1cGRhdGVgIG1ldGhvZFxuICogQGFyZ3VtZW50IHtPYmplY3R9IG9wdGlvbnMgLSBNb2RpZmllcnMgY29uZmlndXJhdGlvbiBhbmQgb3B0aW9uc1xuICogQHJldHVybnMge09iamVjdH0gVGhlIGRhdGEgb2JqZWN0LCBwcm9wZXJseSBtb2RpZmllZFxuICovXG5mdW5jdGlvbiBjb21wdXRlU3R5bGUoZGF0YSwgb3B0aW9ucykge1xuICB2YXIgeCA9IG9wdGlvbnMueCxcbiAgICAgIHkgPSBvcHRpb25zLnk7XG4gIHZhciBwb3BwZXIgPSBkYXRhLm9mZnNldHMucG9wcGVyO1xuXG4gIC8vIFJlbW92ZSB0aGlzIGxlZ2FjeSBzdXBwb3J0IGluIFBvcHBlci5qcyB2MlxuXG4gIHZhciBsZWdhY3lHcHVBY2NlbGVyYXRpb25PcHRpb24gPSBmaW5kKGRhdGEuaW5zdGFuY2UubW9kaWZpZXJzLCBmdW5jdGlvbiAobW9kaWZpZXIpIHtcbiAgICByZXR1cm4gbW9kaWZpZXIubmFtZSA9PT0gJ2FwcGx5U3R5bGUnO1xuICB9KS5ncHVBY2NlbGVyYXRpb247XG4gIGlmIChsZWdhY3lHcHVBY2NlbGVyYXRpb25PcHRpb24gIT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnNvbGUud2FybignV0FSTklORzogYGdwdUFjY2VsZXJhdGlvbmAgb3B0aW9uIG1vdmVkIHRvIGBjb21wdXRlU3R5bGVgIG1vZGlmaWVyIGFuZCB3aWxsIG5vdCBiZSBzdXBwb3J0ZWQgaW4gZnV0dXJlIHZlcnNpb25zIG9mIFBvcHBlci5qcyEnKTtcbiAgfVxuICB2YXIgZ3B1QWNjZWxlcmF0aW9uID0gbGVnYWN5R3B1QWNjZWxlcmF0aW9uT3B0aW9uICE9PSB1bmRlZmluZWQgPyBsZWdhY3lHcHVBY2NlbGVyYXRpb25PcHRpb24gOiBvcHRpb25zLmdwdUFjY2VsZXJhdGlvbjtcblxuICB2YXIgb2Zmc2V0UGFyZW50ID0gZ2V0T2Zmc2V0UGFyZW50KGRhdGEuaW5zdGFuY2UucG9wcGVyKTtcbiAgdmFyIG9mZnNldFBhcmVudFJlY3QgPSBnZXRCb3VuZGluZ0NsaWVudFJlY3Qob2Zmc2V0UGFyZW50KTtcblxuICAvLyBTdHlsZXNcbiAgdmFyIHN0eWxlcyA9IHtcbiAgICBwb3NpdGlvbjogcG9wcGVyLnBvc2l0aW9uXG4gIH07XG5cbiAgdmFyIG9mZnNldHMgPSBnZXRSb3VuZGVkT2Zmc2V0cyhkYXRhLCB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyA8IDIgfHwgIWlzRmlyZWZveCk7XG5cbiAgdmFyIHNpZGVBID0geCA9PT0gJ2JvdHRvbScgPyAndG9wJyA6ICdib3R0b20nO1xuICB2YXIgc2lkZUIgPSB5ID09PSAncmlnaHQnID8gJ2xlZnQnIDogJ3JpZ2h0JztcblxuICAvLyBpZiBncHVBY2NlbGVyYXRpb24gaXMgc2V0IHRvIGB0cnVlYCBhbmQgdHJhbnNmb3JtIGlzIHN1cHBvcnRlZCxcbiAgLy8gIHdlIHVzZSBgdHJhbnNsYXRlM2RgIHRvIGFwcGx5IHRoZSBwb3NpdGlvbiB0byB0aGUgcG9wcGVyIHdlXG4gIC8vIGF1dG9tYXRpY2FsbHkgdXNlIHRoZSBzdXBwb3J0ZWQgcHJlZml4ZWQgdmVyc2lvbiBpZiBuZWVkZWRcbiAgdmFyIHByZWZpeGVkUHJvcGVydHkgPSBnZXRTdXBwb3J0ZWRQcm9wZXJ0eU5hbWUoJ3RyYW5zZm9ybScpO1xuXG4gIC8vIG5vdywgbGV0J3MgbWFrZSBhIHN0ZXAgYmFjayBhbmQgbG9vayBhdCB0aGlzIGNvZGUgY2xvc2VseSAod3RmPylcbiAgLy8gSWYgdGhlIGNvbnRlbnQgb2YgdGhlIHBvcHBlciBncm93cyBvbmNlIGl0J3MgYmVlbiBwb3NpdGlvbmVkLCBpdFxuICAvLyBtYXkgaGFwcGVuIHRoYXQgdGhlIHBvcHBlciBnZXRzIG1pc3BsYWNlZCBiZWNhdXNlIG9mIHRoZSBuZXcgY29udGVudFxuICAvLyBvdmVyZmxvd2luZyBpdHMgcmVmZXJlbmNlIGVsZW1lbnRcbiAgLy8gVG8gYXZvaWQgdGhpcyBwcm9ibGVtLCB3ZSBwcm92aWRlIHR3byBvcHRpb25zICh4IGFuZCB5KSwgd2hpY2ggYWxsb3dcbiAgLy8gdGhlIGNvbnN1bWVyIHRvIGRlZmluZSB0aGUgb2Zmc2V0IG9yaWdpbi5cbiAgLy8gSWYgd2UgcG9zaXRpb24gYSBwb3BwZXIgb24gdG9wIG9mIGEgcmVmZXJlbmNlIGVsZW1lbnQsIHdlIGNhbiBzZXRcbiAgLy8gYHhgIHRvIGB0b3BgIHRvIG1ha2UgdGhlIHBvcHBlciBncm93IHRvd2FyZHMgaXRzIHRvcCBpbnN0ZWFkIG9mXG4gIC8vIGl0cyBib3R0b20uXG4gIHZhciBsZWZ0ID0gdm9pZCAwLFxuICAgICAgdG9wID0gdm9pZCAwO1xuICBpZiAoc2lkZUEgPT09ICdib3R0b20nKSB7XG4gICAgLy8gd2hlbiBvZmZzZXRQYXJlbnQgaXMgPGh0bWw+IHRoZSBwb3NpdGlvbmluZyBpcyByZWxhdGl2ZSB0byB0aGUgYm90dG9tIG9mIHRoZSBzY3JlZW4gKGV4Y2x1ZGluZyB0aGUgc2Nyb2xsYmFyKVxuICAgIC8vIGFuZCBub3QgdGhlIGJvdHRvbSBvZiB0aGUgaHRtbCBlbGVtZW50XG4gICAgaWYgKG9mZnNldFBhcmVudC5ub2RlTmFtZSA9PT0gJ0hUTUwnKSB7XG4gICAgICB0b3AgPSAtb2Zmc2V0UGFyZW50LmNsaWVudEhlaWdodCArIG9mZnNldHMuYm90dG9tO1xuICAgIH0gZWxzZSB7XG4gICAgICB0b3AgPSAtb2Zmc2V0UGFyZW50UmVjdC5oZWlnaHQgKyBvZmZzZXRzLmJvdHRvbTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdG9wID0gb2Zmc2V0cy50b3A7XG4gIH1cbiAgaWYgKHNpZGVCID09PSAncmlnaHQnKSB7XG4gICAgaWYgKG9mZnNldFBhcmVudC5ub2RlTmFtZSA9PT0gJ0hUTUwnKSB7XG4gICAgICBsZWZ0ID0gLW9mZnNldFBhcmVudC5jbGllbnRXaWR0aCArIG9mZnNldHMucmlnaHQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxlZnQgPSAtb2Zmc2V0UGFyZW50UmVjdC53aWR0aCArIG9mZnNldHMucmlnaHQ7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGxlZnQgPSBvZmZzZXRzLmxlZnQ7XG4gIH1cbiAgaWYgKGdwdUFjY2VsZXJhdGlvbiAmJiBwcmVmaXhlZFByb3BlcnR5KSB7XG4gICAgc3R5bGVzW3ByZWZpeGVkUHJvcGVydHldID0gJ3RyYW5zbGF0ZTNkKCcgKyBsZWZ0ICsgJ3B4LCAnICsgdG9wICsgJ3B4LCAwKSc7XG4gICAgc3R5bGVzW3NpZGVBXSA9IDA7XG4gICAgc3R5bGVzW3NpZGVCXSA9IDA7XG4gICAgc3R5bGVzLndpbGxDaGFuZ2UgPSAndHJhbnNmb3JtJztcbiAgfSBlbHNlIHtcbiAgICAvLyBvdGh3ZXJpc2UsIHdlIHVzZSB0aGUgc3RhbmRhcmQgYHRvcGAsIGBsZWZ0YCwgYGJvdHRvbWAgYW5kIGByaWdodGAgcHJvcGVydGllc1xuICAgIHZhciBpbnZlcnRUb3AgPSBzaWRlQSA9PT0gJ2JvdHRvbScgPyAtMSA6IDE7XG4gICAgdmFyIGludmVydExlZnQgPSBzaWRlQiA9PT0gJ3JpZ2h0JyA/IC0xIDogMTtcbiAgICBzdHlsZXNbc2lkZUFdID0gdG9wICogaW52ZXJ0VG9wO1xuICAgIHN0eWxlc1tzaWRlQl0gPSBsZWZ0ICogaW52ZXJ0TGVmdDtcbiAgICBzdHlsZXMud2lsbENoYW5nZSA9IHNpZGVBICsgJywgJyArIHNpZGVCO1xuICB9XG5cbiAgLy8gQXR0cmlidXRlc1xuICB2YXIgYXR0cmlidXRlcyA9IHtcbiAgICAneC1wbGFjZW1lbnQnOiBkYXRhLnBsYWNlbWVudFxuICB9O1xuXG4gIC8vIFVwZGF0ZSBgZGF0YWAgYXR0cmlidXRlcywgc3R5bGVzIGFuZCBhcnJvd1N0eWxlc1xuICBkYXRhLmF0dHJpYnV0ZXMgPSBfZXh0ZW5kcyh7fSwgYXR0cmlidXRlcywgZGF0YS5hdHRyaWJ1dGVzKTtcbiAgZGF0YS5zdHlsZXMgPSBfZXh0ZW5kcyh7fSwgc3R5bGVzLCBkYXRhLnN0eWxlcyk7XG4gIGRhdGEuYXJyb3dTdHlsZXMgPSBfZXh0ZW5kcyh7fSwgZGF0YS5vZmZzZXRzLmFycm93LCBkYXRhLmFycm93U3R5bGVzKTtcblxuICByZXR1cm4gZGF0YTtcbn1cblxuLyoqXG4gKiBIZWxwZXIgdXNlZCB0byBrbm93IGlmIHRoZSBnaXZlbiBtb2RpZmllciBkZXBlbmRzIGZyb20gYW5vdGhlciBvbmUuPGJyIC8+XG4gKiBJdCBjaGVja3MgaWYgdGhlIG5lZWRlZCBtb2RpZmllciBpcyBsaXN0ZWQgYW5kIGVuYWJsZWQuXG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAcGFyYW0ge0FycmF5fSBtb2RpZmllcnMgLSBsaXN0IG9mIG1vZGlmaWVyc1xuICogQHBhcmFtIHtTdHJpbmd9IHJlcXVlc3RpbmdOYW1lIC0gbmFtZSBvZiByZXF1ZXN0aW5nIG1vZGlmaWVyXG4gKiBAcGFyYW0ge1N0cmluZ30gcmVxdWVzdGVkTmFtZSAtIG5hbWUgb2YgcmVxdWVzdGVkIG1vZGlmaWVyXG4gKiBAcmV0dXJucyB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gaXNNb2RpZmllclJlcXVpcmVkKG1vZGlmaWVycywgcmVxdWVzdGluZ05hbWUsIHJlcXVlc3RlZE5hbWUpIHtcbiAgdmFyIHJlcXVlc3RpbmcgPSBmaW5kKG1vZGlmaWVycywgZnVuY3Rpb24gKF9yZWYpIHtcbiAgICB2YXIgbmFtZSA9IF9yZWYubmFtZTtcbiAgICByZXR1cm4gbmFtZSA9PT0gcmVxdWVzdGluZ05hbWU7XG4gIH0pO1xuXG4gIHZhciBpc1JlcXVpcmVkID0gISFyZXF1ZXN0aW5nICYmIG1vZGlmaWVycy5zb21lKGZ1bmN0aW9uIChtb2RpZmllcikge1xuICAgIHJldHVybiBtb2RpZmllci5uYW1lID09PSByZXF1ZXN0ZWROYW1lICYmIG1vZGlmaWVyLmVuYWJsZWQgJiYgbW9kaWZpZXIub3JkZXIgPCByZXF1ZXN0aW5nLm9yZGVyO1xuICB9KTtcblxuICBpZiAoIWlzUmVxdWlyZWQpIHtcbiAgICB2YXIgX3JlcXVlc3RpbmcgPSAnYCcgKyByZXF1ZXN0aW5nTmFtZSArICdgJztcbiAgICB2YXIgcmVxdWVzdGVkID0gJ2AnICsgcmVxdWVzdGVkTmFtZSArICdgJztcbiAgICBjb25zb2xlLndhcm4ocmVxdWVzdGVkICsgJyBtb2RpZmllciBpcyByZXF1aXJlZCBieSAnICsgX3JlcXVlc3RpbmcgKyAnIG1vZGlmaWVyIGluIG9yZGVyIHRvIHdvcmssIGJlIHN1cmUgdG8gaW5jbHVkZSBpdCBiZWZvcmUgJyArIF9yZXF1ZXN0aW5nICsgJyEnKTtcbiAgfVxuICByZXR1cm4gaXNSZXF1aXJlZDtcbn1cblxuLyoqXG4gKiBAZnVuY3Rpb25cbiAqIEBtZW1iZXJvZiBNb2RpZmllcnNcbiAqIEBhcmd1bWVudCB7T2JqZWN0fSBkYXRhIC0gVGhlIGRhdGEgb2JqZWN0IGdlbmVyYXRlZCBieSB1cGRhdGUgbWV0aG9kXG4gKiBAYXJndW1lbnQge09iamVjdH0gb3B0aW9ucyAtIE1vZGlmaWVycyBjb25maWd1cmF0aW9uIGFuZCBvcHRpb25zXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgZGF0YSBvYmplY3QsIHByb3Blcmx5IG1vZGlmaWVkXG4gKi9cbmZ1bmN0aW9uIGFycm93KGRhdGEsIG9wdGlvbnMpIHtcbiAgdmFyIF9kYXRhJG9mZnNldHMkYXJyb3c7XG5cbiAgLy8gYXJyb3cgZGVwZW5kcyBvbiBrZWVwVG9nZXRoZXIgaW4gb3JkZXIgdG8gd29ya1xuICBpZiAoIWlzTW9kaWZpZXJSZXF1aXJlZChkYXRhLmluc3RhbmNlLm1vZGlmaWVycywgJ2Fycm93JywgJ2tlZXBUb2dldGhlcicpKSB7XG4gICAgcmV0dXJuIGRhdGE7XG4gIH1cblxuICB2YXIgYXJyb3dFbGVtZW50ID0gb3B0aW9ucy5lbGVtZW50O1xuXG4gIC8vIGlmIGFycm93RWxlbWVudCBpcyBhIHN0cmluZywgc3VwcG9zZSBpdCdzIGEgQ1NTIHNlbGVjdG9yXG4gIGlmICh0eXBlb2YgYXJyb3dFbGVtZW50ID09PSAnc3RyaW5nJykge1xuICAgIGFycm93RWxlbWVudCA9IGRhdGEuaW5zdGFuY2UucG9wcGVyLnF1ZXJ5U2VsZWN0b3IoYXJyb3dFbGVtZW50KTtcblxuICAgIC8vIGlmIGFycm93RWxlbWVudCBpcyBub3QgZm91bmQsIGRvbid0IHJ1biB0aGUgbW9kaWZpZXJcbiAgICBpZiAoIWFycm93RWxlbWVudCkge1xuICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIC8vIGlmIHRoZSBhcnJvd0VsZW1lbnQgaXNuJ3QgYSBxdWVyeSBzZWxlY3RvciB3ZSBtdXN0IGNoZWNrIHRoYXQgdGhlXG4gICAgLy8gcHJvdmlkZWQgRE9NIG5vZGUgaXMgY2hpbGQgb2YgaXRzIHBvcHBlciBub2RlXG4gICAgaWYgKCFkYXRhLmluc3RhbmNlLnBvcHBlci5jb250YWlucyhhcnJvd0VsZW1lbnQpKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ1dBUk5JTkc6IGBhcnJvdy5lbGVtZW50YCBtdXN0IGJlIGNoaWxkIG9mIGl0cyBwb3BwZXIgZWxlbWVudCEnKTtcbiAgICAgIHJldHVybiBkYXRhO1xuICAgIH1cbiAgfVxuXG4gIHZhciBwbGFjZW1lbnQgPSBkYXRhLnBsYWNlbWVudC5zcGxpdCgnLScpWzBdO1xuICB2YXIgX2RhdGEkb2Zmc2V0cyA9IGRhdGEub2Zmc2V0cyxcbiAgICAgIHBvcHBlciA9IF9kYXRhJG9mZnNldHMucG9wcGVyLFxuICAgICAgcmVmZXJlbmNlID0gX2RhdGEkb2Zmc2V0cy5yZWZlcmVuY2U7XG5cbiAgdmFyIGlzVmVydGljYWwgPSBbJ2xlZnQnLCAncmlnaHQnXS5pbmRleE9mKHBsYWNlbWVudCkgIT09IC0xO1xuXG4gIHZhciBsZW4gPSBpc1ZlcnRpY2FsID8gJ2hlaWdodCcgOiAnd2lkdGgnO1xuICB2YXIgc2lkZUNhcGl0YWxpemVkID0gaXNWZXJ0aWNhbCA/ICdUb3AnIDogJ0xlZnQnO1xuICB2YXIgc2lkZSA9IHNpZGVDYXBpdGFsaXplZC50b0xvd2VyQ2FzZSgpO1xuICB2YXIgYWx0U2lkZSA9IGlzVmVydGljYWwgPyAnbGVmdCcgOiAndG9wJztcbiAgdmFyIG9wU2lkZSA9IGlzVmVydGljYWwgPyAnYm90dG9tJyA6ICdyaWdodCc7XG4gIHZhciBhcnJvd0VsZW1lbnRTaXplID0gZ2V0T3V0ZXJTaXplcyhhcnJvd0VsZW1lbnQpW2xlbl07XG5cbiAgLy9cbiAgLy8gZXh0ZW5kcyBrZWVwVG9nZXRoZXIgYmVoYXZpb3IgbWFraW5nIHN1cmUgdGhlIHBvcHBlciBhbmQgaXRzXG4gIC8vIHJlZmVyZW5jZSBoYXZlIGVub3VnaCBwaXhlbHMgaW4gY29uanVuY3Rpb25cbiAgLy9cblxuICAvLyB0b3AvbGVmdCBzaWRlXG4gIGlmIChyZWZlcmVuY2Vbb3BTaWRlXSAtIGFycm93RWxlbWVudFNpemUgPCBwb3BwZXJbc2lkZV0pIHtcbiAgICBkYXRhLm9mZnNldHMucG9wcGVyW3NpZGVdIC09IHBvcHBlcltzaWRlXSAtIChyZWZlcmVuY2Vbb3BTaWRlXSAtIGFycm93RWxlbWVudFNpemUpO1xuICB9XG4gIC8vIGJvdHRvbS9yaWdodCBzaWRlXG4gIGlmIChyZWZlcmVuY2Vbc2lkZV0gKyBhcnJvd0VsZW1lbnRTaXplID4gcG9wcGVyW29wU2lkZV0pIHtcbiAgICBkYXRhLm9mZnNldHMucG9wcGVyW3NpZGVdICs9IHJlZmVyZW5jZVtzaWRlXSArIGFycm93RWxlbWVudFNpemUgLSBwb3BwZXJbb3BTaWRlXTtcbiAgfVxuICBkYXRhLm9mZnNldHMucG9wcGVyID0gZ2V0Q2xpZW50UmVjdChkYXRhLm9mZnNldHMucG9wcGVyKTtcblxuICAvLyBjb21wdXRlIGNlbnRlciBvZiB0aGUgcG9wcGVyXG4gIHZhciBjZW50ZXIgPSByZWZlcmVuY2Vbc2lkZV0gKyByZWZlcmVuY2VbbGVuXSAvIDIgLSBhcnJvd0VsZW1lbnRTaXplIC8gMjtcblxuICAvLyBDb21wdXRlIHRoZSBzaWRlVmFsdWUgdXNpbmcgdGhlIHVwZGF0ZWQgcG9wcGVyIG9mZnNldHNcbiAgLy8gdGFrZSBwb3BwZXIgbWFyZ2luIGluIGFjY291bnQgYmVjYXVzZSB3ZSBkb24ndCBoYXZlIHRoaXMgaW5mbyBhdmFpbGFibGVcbiAgdmFyIGNzcyA9IGdldFN0eWxlQ29tcHV0ZWRQcm9wZXJ0eShkYXRhLmluc3RhbmNlLnBvcHBlcik7XG4gIHZhciBwb3BwZXJNYXJnaW5TaWRlID0gcGFyc2VGbG9hdChjc3NbJ21hcmdpbicgKyBzaWRlQ2FwaXRhbGl6ZWRdKTtcbiAgdmFyIHBvcHBlckJvcmRlclNpZGUgPSBwYXJzZUZsb2F0KGNzc1snYm9yZGVyJyArIHNpZGVDYXBpdGFsaXplZCArICdXaWR0aCddKTtcbiAgdmFyIHNpZGVWYWx1ZSA9IGNlbnRlciAtIGRhdGEub2Zmc2V0cy5wb3BwZXJbc2lkZV0gLSBwb3BwZXJNYXJnaW5TaWRlIC0gcG9wcGVyQm9yZGVyU2lkZTtcblxuICAvLyBwcmV2ZW50IGFycm93RWxlbWVudCBmcm9tIGJlaW5nIHBsYWNlZCBub3QgY29udGlndW91c2x5IHRvIGl0cyBwb3BwZXJcbiAgc2lkZVZhbHVlID0gTWF0aC5tYXgoTWF0aC5taW4ocG9wcGVyW2xlbl0gLSBhcnJvd0VsZW1lbnRTaXplLCBzaWRlVmFsdWUpLCAwKTtcblxuICBkYXRhLmFycm93RWxlbWVudCA9IGFycm93RWxlbWVudDtcbiAgZGF0YS5vZmZzZXRzLmFycm93ID0gKF9kYXRhJG9mZnNldHMkYXJyb3cgPSB7fSwgZGVmaW5lUHJvcGVydHkoX2RhdGEkb2Zmc2V0cyRhcnJvdywgc2lkZSwgTWF0aC5yb3VuZChzaWRlVmFsdWUpKSwgZGVmaW5lUHJvcGVydHkoX2RhdGEkb2Zmc2V0cyRhcnJvdywgYWx0U2lkZSwgJycpLCBfZGF0YSRvZmZzZXRzJGFycm93KTtcblxuICByZXR1cm4gZGF0YTtcbn1cblxuLyoqXG4gKiBHZXQgdGhlIG9wcG9zaXRlIHBsYWNlbWVudCB2YXJpYXRpb24gb2YgdGhlIGdpdmVuIG9uZVxuICogQG1ldGhvZFxuICogQG1lbWJlcm9mIFBvcHBlci5VdGlsc1xuICogQGFyZ3VtZW50IHtTdHJpbmd9IHBsYWNlbWVudCB2YXJpYXRpb25cbiAqIEByZXR1cm5zIHtTdHJpbmd9IGZsaXBwZWQgcGxhY2VtZW50IHZhcmlhdGlvblxuICovXG5mdW5jdGlvbiBnZXRPcHBvc2l0ZVZhcmlhdGlvbih2YXJpYXRpb24pIHtcbiAgaWYgKHZhcmlhdGlvbiA9PT0gJ2VuZCcpIHtcbiAgICByZXR1cm4gJ3N0YXJ0JztcbiAgfSBlbHNlIGlmICh2YXJpYXRpb24gPT09ICdzdGFydCcpIHtcbiAgICByZXR1cm4gJ2VuZCc7XG4gIH1cbiAgcmV0dXJuIHZhcmlhdGlvbjtcbn1cblxuLyoqXG4gKiBMaXN0IG9mIGFjY2VwdGVkIHBsYWNlbWVudHMgdG8gdXNlIGFzIHZhbHVlcyBvZiB0aGUgYHBsYWNlbWVudGAgb3B0aW9uLjxiciAvPlxuICogVmFsaWQgcGxhY2VtZW50cyBhcmU6XG4gKiAtIGBhdXRvYFxuICogLSBgdG9wYFxuICogLSBgcmlnaHRgXG4gKiAtIGBib3R0b21gXG4gKiAtIGBsZWZ0YFxuICpcbiAqIEVhY2ggcGxhY2VtZW50IGNhbiBoYXZlIGEgdmFyaWF0aW9uIGZyb20gdGhpcyBsaXN0OlxuICogLSBgLXN0YXJ0YFxuICogLSBgLWVuZGBcbiAqXG4gKiBWYXJpYXRpb25zIGFyZSBpbnRlcnByZXRlZCBlYXNpbHkgaWYgeW91IHRoaW5rIG9mIHRoZW0gYXMgdGhlIGxlZnQgdG8gcmlnaHRcbiAqIHdyaXR0ZW4gbGFuZ3VhZ2VzLiBIb3Jpem9udGFsbHkgKGB0b3BgIGFuZCBgYm90dG9tYCksIGBzdGFydGAgaXMgbGVmdCBhbmQgYGVuZGBcbiAqIGlzIHJpZ2h0LjxiciAvPlxuICogVmVydGljYWxseSAoYGxlZnRgIGFuZCBgcmlnaHRgKSwgYHN0YXJ0YCBpcyB0b3AgYW5kIGBlbmRgIGlzIGJvdHRvbS5cbiAqXG4gKiBTb21lIHZhbGlkIGV4YW1wbGVzIGFyZTpcbiAqIC0gYHRvcC1lbmRgIChvbiB0b3Agb2YgcmVmZXJlbmNlLCByaWdodCBhbGlnbmVkKVxuICogLSBgcmlnaHQtc3RhcnRgIChvbiByaWdodCBvZiByZWZlcmVuY2UsIHRvcCBhbGlnbmVkKVxuICogLSBgYm90dG9tYCAob24gYm90dG9tLCBjZW50ZXJlZClcbiAqIC0gYGF1dG8tZW5kYCAob24gdGhlIHNpZGUgd2l0aCBtb3JlIHNwYWNlIGF2YWlsYWJsZSwgYWxpZ25tZW50IGRlcGVuZHMgYnkgcGxhY2VtZW50KVxuICpcbiAqIEBzdGF0aWNcbiAqIEB0eXBlIHtBcnJheX1cbiAqIEBlbnVtIHtTdHJpbmd9XG4gKiBAcmVhZG9ubHlcbiAqIEBtZXRob2QgcGxhY2VtZW50c1xuICogQG1lbWJlcm9mIFBvcHBlclxuICovXG52YXIgcGxhY2VtZW50cyA9IFsnYXV0by1zdGFydCcsICdhdXRvJywgJ2F1dG8tZW5kJywgJ3RvcC1zdGFydCcsICd0b3AnLCAndG9wLWVuZCcsICdyaWdodC1zdGFydCcsICdyaWdodCcsICdyaWdodC1lbmQnLCAnYm90dG9tLWVuZCcsICdib3R0b20nLCAnYm90dG9tLXN0YXJ0JywgJ2xlZnQtZW5kJywgJ2xlZnQnLCAnbGVmdC1zdGFydCddO1xuXG4vLyBHZXQgcmlkIG9mIGBhdXRvYCBgYXV0by1zdGFydGAgYW5kIGBhdXRvLWVuZGBcbnZhciB2YWxpZFBsYWNlbWVudHMgPSBwbGFjZW1lbnRzLnNsaWNlKDMpO1xuXG4vKipcbiAqIEdpdmVuIGFuIGluaXRpYWwgcGxhY2VtZW50LCByZXR1cm5zIGFsbCB0aGUgc3Vic2VxdWVudCBwbGFjZW1lbnRzXG4gKiBjbG9ja3dpc2UgKG9yIGNvdW50ZXItY2xvY2t3aXNlKS5cbiAqXG4gKiBAbWV0aG9kXG4gKiBAbWVtYmVyb2YgUG9wcGVyLlV0aWxzXG4gKiBAYXJndW1lbnQge1N0cmluZ30gcGxhY2VtZW50IC0gQSB2YWxpZCBwbGFjZW1lbnQgKGl0IGFjY2VwdHMgdmFyaWF0aW9ucylcbiAqIEBhcmd1bWVudCB7Qm9vbGVhbn0gY291bnRlciAtIFNldCB0byB0cnVlIHRvIHdhbGsgdGhlIHBsYWNlbWVudHMgY291bnRlcmNsb2Nrd2lzZVxuICogQHJldHVybnMge0FycmF5fSBwbGFjZW1lbnRzIGluY2x1ZGluZyB0aGVpciB2YXJpYXRpb25zXG4gKi9cbmZ1bmN0aW9uIGNsb2Nrd2lzZShwbGFjZW1lbnQpIHtcbiAgdmFyIGNvdW50ZXIgPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiBhcmd1bWVudHNbMV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1sxXSA6IGZhbHNlO1xuXG4gIHZhciBpbmRleCA9IHZhbGlkUGxhY2VtZW50cy5pbmRleE9mKHBsYWNlbWVudCk7XG4gIHZhciBhcnIgPSB2YWxpZFBsYWNlbWVudHMuc2xpY2UoaW5kZXggKyAxKS5jb25jYXQodmFsaWRQbGFjZW1lbnRzLnNsaWNlKDAsIGluZGV4KSk7XG4gIHJldHVybiBjb3VudGVyID8gYXJyLnJldmVyc2UoKSA6IGFycjtcbn1cblxudmFyIEJFSEFWSU9SUyA9IHtcbiAgRkxJUDogJ2ZsaXAnLFxuICBDTE9DS1dJU0U6ICdjbG9ja3dpc2UnLFxuICBDT1VOVEVSQ0xPQ0tXSVNFOiAnY291bnRlcmNsb2Nrd2lzZSdcbn07XG5cbi8qKlxuICogQGZ1bmN0aW9uXG4gKiBAbWVtYmVyb2YgTW9kaWZpZXJzXG4gKiBAYXJndW1lbnQge09iamVjdH0gZGF0YSAtIFRoZSBkYXRhIG9iamVjdCBnZW5lcmF0ZWQgYnkgdXBkYXRlIG1ldGhvZFxuICogQGFyZ3VtZW50IHtPYmplY3R9IG9wdGlvbnMgLSBNb2RpZmllcnMgY29uZmlndXJhdGlvbiBhbmQgb3B0aW9uc1xuICogQHJldHVybnMge09iamVjdH0gVGhlIGRhdGEgb2JqZWN0LCBwcm9wZXJseSBtb2RpZmllZFxuICovXG5mdW5jdGlvbiBmbGlwKGRhdGEsIG9wdGlvbnMpIHtcbiAgLy8gaWYgYGlubmVyYCBtb2RpZmllciBpcyBlbmFibGVkLCB3ZSBjYW4ndCB1c2UgdGhlIGBmbGlwYCBtb2RpZmllclxuICBpZiAoaXNNb2RpZmllckVuYWJsZWQoZGF0YS5pbnN0YW5jZS5tb2RpZmllcnMsICdpbm5lcicpKSB7XG4gICAgcmV0dXJuIGRhdGE7XG4gIH1cblxuICBpZiAoZGF0YS5mbGlwcGVkICYmIGRhdGEucGxhY2VtZW50ID09PSBkYXRhLm9yaWdpbmFsUGxhY2VtZW50KSB7XG4gICAgLy8gc2VlbXMgbGlrZSBmbGlwIGlzIHRyeWluZyB0byBsb29wLCBwcm9iYWJseSB0aGVyZSdzIG5vdCBlbm91Z2ggc3BhY2Ugb24gYW55IG9mIHRoZSBmbGlwcGFibGUgc2lkZXNcbiAgICByZXR1cm4gZGF0YTtcbiAgfVxuXG4gIHZhciBib3VuZGFyaWVzID0gZ2V0Qm91bmRhcmllcyhkYXRhLmluc3RhbmNlLnBvcHBlciwgZGF0YS5pbnN0YW5jZS5yZWZlcmVuY2UsIG9wdGlvbnMucGFkZGluZywgb3B0aW9ucy5ib3VuZGFyaWVzRWxlbWVudCwgZGF0YS5wb3NpdGlvbkZpeGVkKTtcblxuICB2YXIgcGxhY2VtZW50ID0gZGF0YS5wbGFjZW1lbnQuc3BsaXQoJy0nKVswXTtcbiAgdmFyIHBsYWNlbWVudE9wcG9zaXRlID0gZ2V0T3Bwb3NpdGVQbGFjZW1lbnQocGxhY2VtZW50KTtcbiAgdmFyIHZhcmlhdGlvbiA9IGRhdGEucGxhY2VtZW50LnNwbGl0KCctJylbMV0gfHwgJyc7XG5cbiAgdmFyIGZsaXBPcmRlciA9IFtdO1xuXG4gIHN3aXRjaCAob3B0aW9ucy5iZWhhdmlvcikge1xuICAgIGNhc2UgQkVIQVZJT1JTLkZMSVA6XG4gICAgICBmbGlwT3JkZXIgPSBbcGxhY2VtZW50LCBwbGFjZW1lbnRPcHBvc2l0ZV07XG4gICAgICBicmVhaztcbiAgICBjYXNlIEJFSEFWSU9SUy5DTE9DS1dJU0U6XG4gICAgICBmbGlwT3JkZXIgPSBjbG9ja3dpc2UocGxhY2VtZW50KTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgQkVIQVZJT1JTLkNPVU5URVJDTE9DS1dJU0U6XG4gICAgICBmbGlwT3JkZXIgPSBjbG9ja3dpc2UocGxhY2VtZW50LCB0cnVlKTtcbiAgICAgIGJyZWFrO1xuICAgIGRlZmF1bHQ6XG4gICAgICBmbGlwT3JkZXIgPSBvcHRpb25zLmJlaGF2aW9yO1xuICB9XG5cbiAgZmxpcE9yZGVyLmZvckVhY2goZnVuY3Rpb24gKHN0ZXAsIGluZGV4KSB7XG4gICAgaWYgKHBsYWNlbWVudCAhPT0gc3RlcCB8fCBmbGlwT3JkZXIubGVuZ3RoID09PSBpbmRleCArIDEpIHtcbiAgICAgIHJldHVybiBkYXRhO1xuICAgIH1cblxuICAgIHBsYWNlbWVudCA9IGRhdGEucGxhY2VtZW50LnNwbGl0KCctJylbMF07XG4gICAgcGxhY2VtZW50T3Bwb3NpdGUgPSBnZXRPcHBvc2l0ZVBsYWNlbWVudChwbGFjZW1lbnQpO1xuXG4gICAgdmFyIHBvcHBlck9mZnNldHMgPSBkYXRhLm9mZnNldHMucG9wcGVyO1xuICAgIHZhciByZWZPZmZzZXRzID0gZGF0YS5vZmZzZXRzLnJlZmVyZW5jZTtcblxuICAgIC8vIHVzaW5nIGZsb29yIGJlY2F1c2UgdGhlIHJlZmVyZW5jZSBvZmZzZXRzIG1heSBjb250YWluIGRlY2ltYWxzIHdlIGFyZSBub3QgZ29pbmcgdG8gY29uc2lkZXIgaGVyZVxuICAgIHZhciBmbG9vciA9IE1hdGguZmxvb3I7XG4gICAgdmFyIG92ZXJsYXBzUmVmID0gcGxhY2VtZW50ID09PSAnbGVmdCcgJiYgZmxvb3IocG9wcGVyT2Zmc2V0cy5yaWdodCkgPiBmbG9vcihyZWZPZmZzZXRzLmxlZnQpIHx8IHBsYWNlbWVudCA9PT0gJ3JpZ2h0JyAmJiBmbG9vcihwb3BwZXJPZmZzZXRzLmxlZnQpIDwgZmxvb3IocmVmT2Zmc2V0cy5yaWdodCkgfHwgcGxhY2VtZW50ID09PSAndG9wJyAmJiBmbG9vcihwb3BwZXJPZmZzZXRzLmJvdHRvbSkgPiBmbG9vcihyZWZPZmZzZXRzLnRvcCkgfHwgcGxhY2VtZW50ID09PSAnYm90dG9tJyAmJiBmbG9vcihwb3BwZXJPZmZzZXRzLnRvcCkgPCBmbG9vcihyZWZPZmZzZXRzLmJvdHRvbSk7XG5cbiAgICB2YXIgb3ZlcmZsb3dzTGVmdCA9IGZsb29yKHBvcHBlck9mZnNldHMubGVmdCkgPCBmbG9vcihib3VuZGFyaWVzLmxlZnQpO1xuICAgIHZhciBvdmVyZmxvd3NSaWdodCA9IGZsb29yKHBvcHBlck9mZnNldHMucmlnaHQpID4gZmxvb3IoYm91bmRhcmllcy5yaWdodCk7XG4gICAgdmFyIG92ZXJmbG93c1RvcCA9IGZsb29yKHBvcHBlck9mZnNldHMudG9wKSA8IGZsb29yKGJvdW5kYXJpZXMudG9wKTtcbiAgICB2YXIgb3ZlcmZsb3dzQm90dG9tID0gZmxvb3IocG9wcGVyT2Zmc2V0cy5ib3R0b20pID4gZmxvb3IoYm91bmRhcmllcy5ib3R0b20pO1xuXG4gICAgdmFyIG92ZXJmbG93c0JvdW5kYXJpZXMgPSBwbGFjZW1lbnQgPT09ICdsZWZ0JyAmJiBvdmVyZmxvd3NMZWZ0IHx8IHBsYWNlbWVudCA9PT0gJ3JpZ2h0JyAmJiBvdmVyZmxvd3NSaWdodCB8fCBwbGFjZW1lbnQgPT09ICd0b3AnICYmIG92ZXJmbG93c1RvcCB8fCBwbGFjZW1lbnQgPT09ICdib3R0b20nICYmIG92ZXJmbG93c0JvdHRvbTtcblxuICAgIC8vIGZsaXAgdGhlIHZhcmlhdGlvbiBpZiByZXF1aXJlZFxuICAgIHZhciBpc1ZlcnRpY2FsID0gWyd0b3AnLCAnYm90dG9tJ10uaW5kZXhPZihwbGFjZW1lbnQpICE9PSAtMTtcblxuICAgIC8vIGZsaXBzIHZhcmlhdGlvbiBpZiByZWZlcmVuY2UgZWxlbWVudCBvdmVyZmxvd3MgYm91bmRhcmllc1xuICAgIHZhciBmbGlwcGVkVmFyaWF0aW9uQnlSZWYgPSAhIW9wdGlvbnMuZmxpcFZhcmlhdGlvbnMgJiYgKGlzVmVydGljYWwgJiYgdmFyaWF0aW9uID09PSAnc3RhcnQnICYmIG92ZXJmbG93c0xlZnQgfHwgaXNWZXJ0aWNhbCAmJiB2YXJpYXRpb24gPT09ICdlbmQnICYmIG92ZXJmbG93c1JpZ2h0IHx8ICFpc1ZlcnRpY2FsICYmIHZhcmlhdGlvbiA9PT0gJ3N0YXJ0JyAmJiBvdmVyZmxvd3NUb3AgfHwgIWlzVmVydGljYWwgJiYgdmFyaWF0aW9uID09PSAnZW5kJyAmJiBvdmVyZmxvd3NCb3R0b20pO1xuXG4gICAgLy8gZmxpcHMgdmFyaWF0aW9uIGlmIHBvcHBlciBjb250ZW50IG92ZXJmbG93cyBib3VuZGFyaWVzXG4gICAgdmFyIGZsaXBwZWRWYXJpYXRpb25CeUNvbnRlbnQgPSAhIW9wdGlvbnMuZmxpcFZhcmlhdGlvbnNCeUNvbnRlbnQgJiYgKGlzVmVydGljYWwgJiYgdmFyaWF0aW9uID09PSAnc3RhcnQnICYmIG92ZXJmbG93c1JpZ2h0IHx8IGlzVmVydGljYWwgJiYgdmFyaWF0aW9uID09PSAnZW5kJyAmJiBvdmVyZmxvd3NMZWZ0IHx8ICFpc1ZlcnRpY2FsICYmIHZhcmlhdGlvbiA9PT0gJ3N0YXJ0JyAmJiBvdmVyZmxvd3NCb3R0b20gfHwgIWlzVmVydGljYWwgJiYgdmFyaWF0aW9uID09PSAnZW5kJyAmJiBvdmVyZmxvd3NUb3ApO1xuXG4gICAgdmFyIGZsaXBwZWRWYXJpYXRpb24gPSBmbGlwcGVkVmFyaWF0aW9uQnlSZWYgfHwgZmxpcHBlZFZhcmlhdGlvbkJ5Q29udGVudDtcblxuICAgIGlmIChvdmVybGFwc1JlZiB8fCBvdmVyZmxvd3NCb3VuZGFyaWVzIHx8IGZsaXBwZWRWYXJpYXRpb24pIHtcbiAgICAgIC8vIHRoaXMgYm9vbGVhbiB0byBkZXRlY3QgYW55IGZsaXAgbG9vcFxuICAgICAgZGF0YS5mbGlwcGVkID0gdHJ1ZTtcblxuICAgICAgaWYgKG92ZXJsYXBzUmVmIHx8IG92ZXJmbG93c0JvdW5kYXJpZXMpIHtcbiAgICAgICAgcGxhY2VtZW50ID0gZmxpcE9yZGVyW2luZGV4ICsgMV07XG4gICAgICB9XG5cbiAgICAgIGlmIChmbGlwcGVkVmFyaWF0aW9uKSB7XG4gICAgICAgIHZhcmlhdGlvbiA9IGdldE9wcG9zaXRlVmFyaWF0aW9uKHZhcmlhdGlvbik7XG4gICAgICB9XG5cbiAgICAgIGRhdGEucGxhY2VtZW50ID0gcGxhY2VtZW50ICsgKHZhcmlhdGlvbiA/ICctJyArIHZhcmlhdGlvbiA6ICcnKTtcblxuICAgICAgLy8gdGhpcyBvYmplY3QgY29udGFpbnMgYHBvc2l0aW9uYCwgd2Ugd2FudCB0byBwcmVzZXJ2ZSBpdCBhbG9uZyB3aXRoXG4gICAgICAvLyBhbnkgYWRkaXRpb25hbCBwcm9wZXJ0eSB3ZSBtYXkgYWRkIGluIHRoZSBmdXR1cmVcbiAgICAgIGRhdGEub2Zmc2V0cy5wb3BwZXIgPSBfZXh0ZW5kcyh7fSwgZGF0YS5vZmZzZXRzLnBvcHBlciwgZ2V0UG9wcGVyT2Zmc2V0cyhkYXRhLmluc3RhbmNlLnBvcHBlciwgZGF0YS5vZmZzZXRzLnJlZmVyZW5jZSwgZGF0YS5wbGFjZW1lbnQpKTtcblxuICAgICAgZGF0YSA9IHJ1bk1vZGlmaWVycyhkYXRhLmluc3RhbmNlLm1vZGlmaWVycywgZGF0YSwgJ2ZsaXAnKTtcbiAgICB9XG4gIH0pO1xuICByZXR1cm4gZGF0YTtcbn1cblxuLyoqXG4gKiBAZnVuY3Rpb25cbiAqIEBtZW1iZXJvZiBNb2RpZmllcnNcbiAqIEBhcmd1bWVudCB7T2JqZWN0fSBkYXRhIC0gVGhlIGRhdGEgb2JqZWN0IGdlbmVyYXRlZCBieSB1cGRhdGUgbWV0aG9kXG4gKiBAYXJndW1lbnQge09iamVjdH0gb3B0aW9ucyAtIE1vZGlmaWVycyBjb25maWd1cmF0aW9uIGFuZCBvcHRpb25zXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgZGF0YSBvYmplY3QsIHByb3Blcmx5IG1vZGlmaWVkXG4gKi9cbmZ1bmN0aW9uIGtlZXBUb2dldGhlcihkYXRhKSB7XG4gIHZhciBfZGF0YSRvZmZzZXRzID0gZGF0YS5vZmZzZXRzLFxuICAgICAgcG9wcGVyID0gX2RhdGEkb2Zmc2V0cy5wb3BwZXIsXG4gICAgICByZWZlcmVuY2UgPSBfZGF0YSRvZmZzZXRzLnJlZmVyZW5jZTtcblxuICB2YXIgcGxhY2VtZW50ID0gZGF0YS5wbGFjZW1lbnQuc3BsaXQoJy0nKVswXTtcbiAgdmFyIGZsb29yID0gTWF0aC5mbG9vcjtcbiAgdmFyIGlzVmVydGljYWwgPSBbJ3RvcCcsICdib3R0b20nXS5pbmRleE9mKHBsYWNlbWVudCkgIT09IC0xO1xuICB2YXIgc2lkZSA9IGlzVmVydGljYWwgPyAncmlnaHQnIDogJ2JvdHRvbSc7XG4gIHZhciBvcFNpZGUgPSBpc1ZlcnRpY2FsID8gJ2xlZnQnIDogJ3RvcCc7XG4gIHZhciBtZWFzdXJlbWVudCA9IGlzVmVydGljYWwgPyAnd2lkdGgnIDogJ2hlaWdodCc7XG5cbiAgaWYgKHBvcHBlcltzaWRlXSA8IGZsb29yKHJlZmVyZW5jZVtvcFNpZGVdKSkge1xuICAgIGRhdGEub2Zmc2V0cy5wb3BwZXJbb3BTaWRlXSA9IGZsb29yKHJlZmVyZW5jZVtvcFNpZGVdKSAtIHBvcHBlclttZWFzdXJlbWVudF07XG4gIH1cbiAgaWYgKHBvcHBlcltvcFNpZGVdID4gZmxvb3IocmVmZXJlbmNlW3NpZGVdKSkge1xuICAgIGRhdGEub2Zmc2V0cy5wb3BwZXJbb3BTaWRlXSA9IGZsb29yKHJlZmVyZW5jZVtzaWRlXSk7XG4gIH1cblxuICByZXR1cm4gZGF0YTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBhIHN0cmluZyBjb250YWluaW5nIHZhbHVlICsgdW5pdCBpbnRvIGEgcHggdmFsdWUgbnVtYmVyXG4gKiBAZnVuY3Rpb25cbiAqIEBtZW1iZXJvZiB7bW9kaWZpZXJzfm9mZnNldH1cbiAqIEBwcml2YXRlXG4gKiBAYXJndW1lbnQge1N0cmluZ30gc3RyIC0gVmFsdWUgKyB1bml0IHN0cmluZ1xuICogQGFyZ3VtZW50IHtTdHJpbmd9IG1lYXN1cmVtZW50IC0gYGhlaWdodGAgb3IgYHdpZHRoYFxuICogQGFyZ3VtZW50IHtPYmplY3R9IHBvcHBlck9mZnNldHNcbiAqIEBhcmd1bWVudCB7T2JqZWN0fSByZWZlcmVuY2VPZmZzZXRzXG4gKiBAcmV0dXJucyB7TnVtYmVyfFN0cmluZ31cbiAqIFZhbHVlIGluIHBpeGVscywgb3Igb3JpZ2luYWwgc3RyaW5nIGlmIG5vIHZhbHVlcyB3ZXJlIGV4dHJhY3RlZFxuICovXG5mdW5jdGlvbiB0b1ZhbHVlKHN0ciwgbWVhc3VyZW1lbnQsIHBvcHBlck9mZnNldHMsIHJlZmVyZW5jZU9mZnNldHMpIHtcbiAgLy8gc2VwYXJhdGUgdmFsdWUgZnJvbSB1bml0XG4gIHZhciBzcGxpdCA9IHN0ci5tYXRjaCgvKCg/OlxcLXxcXCspP1xcZCpcXC4/XFxkKikoLiopLyk7XG4gIHZhciB2YWx1ZSA9ICtzcGxpdFsxXTtcbiAgdmFyIHVuaXQgPSBzcGxpdFsyXTtcblxuICAvLyBJZiBpdCdzIG5vdCBhIG51bWJlciBpdCdzIGFuIG9wZXJhdG9yLCBJIGd1ZXNzXG4gIGlmICghdmFsdWUpIHtcbiAgICByZXR1cm4gc3RyO1xuICB9XG5cbiAgaWYgKHVuaXQuaW5kZXhPZignJScpID09PSAwKSB7XG4gICAgdmFyIGVsZW1lbnQgPSB2b2lkIDA7XG4gICAgc3dpdGNoICh1bml0KSB7XG4gICAgICBjYXNlICclcCc6XG4gICAgICAgIGVsZW1lbnQgPSBwb3BwZXJPZmZzZXRzO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJyUnOlxuICAgICAgY2FzZSAnJXInOlxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgZWxlbWVudCA9IHJlZmVyZW5jZU9mZnNldHM7XG4gICAgfVxuXG4gICAgdmFyIHJlY3QgPSBnZXRDbGllbnRSZWN0KGVsZW1lbnQpO1xuICAgIHJldHVybiByZWN0W21lYXN1cmVtZW50XSAvIDEwMCAqIHZhbHVlO1xuICB9IGVsc2UgaWYgKHVuaXQgPT09ICd2aCcgfHwgdW5pdCA9PT0gJ3Z3Jykge1xuICAgIC8vIGlmIGlzIGEgdmggb3IgdncsIHdlIGNhbGN1bGF0ZSB0aGUgc2l6ZSBiYXNlZCBvbiB0aGUgdmlld3BvcnRcbiAgICB2YXIgc2l6ZSA9IHZvaWQgMDtcbiAgICBpZiAodW5pdCA9PT0gJ3ZoJykge1xuICAgICAgc2l6ZSA9IE1hdGgubWF4KGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRIZWlnaHQsIHdpbmRvdy5pbm5lckhlaWdodCB8fCAwKTtcbiAgICB9IGVsc2Uge1xuICAgICAgc2l6ZSA9IE1hdGgubWF4KGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRXaWR0aCwgd2luZG93LmlubmVyV2lkdGggfHwgMCk7XG4gICAgfVxuICAgIHJldHVybiBzaXplIC8gMTAwICogdmFsdWU7XG4gIH0gZWxzZSB7XG4gICAgLy8gaWYgaXMgYW4gZXhwbGljaXQgcGl4ZWwgdW5pdCwgd2UgZ2V0IHJpZCBvZiB0aGUgdW5pdCBhbmQga2VlcCB0aGUgdmFsdWVcbiAgICAvLyBpZiBpcyBhbiBpbXBsaWNpdCB1bml0LCBpdCdzIHB4LCBhbmQgd2UgcmV0dXJuIGp1c3QgdGhlIHZhbHVlXG4gICAgcmV0dXJuIHZhbHVlO1xuICB9XG59XG5cbi8qKlxuICogUGFyc2UgYW4gYG9mZnNldGAgc3RyaW5nIHRvIGV4dHJhcG9sYXRlIGB4YCBhbmQgYHlgIG51bWVyaWMgb2Zmc2V0cy5cbiAqIEBmdW5jdGlvblxuICogQG1lbWJlcm9mIHttb2RpZmllcnN+b2Zmc2V0fVxuICogQHByaXZhdGVcbiAqIEBhcmd1bWVudCB7U3RyaW5nfSBvZmZzZXRcbiAqIEBhcmd1bWVudCB7T2JqZWN0fSBwb3BwZXJPZmZzZXRzXG4gKiBAYXJndW1lbnQge09iamVjdH0gcmVmZXJlbmNlT2Zmc2V0c1xuICogQGFyZ3VtZW50IHtTdHJpbmd9IGJhc2VQbGFjZW1lbnRcbiAqIEByZXR1cm5zIHtBcnJheX0gYSB0d28gY2VsbHMgYXJyYXkgd2l0aCB4IGFuZCB5IG9mZnNldHMgaW4gbnVtYmVyc1xuICovXG5mdW5jdGlvbiBwYXJzZU9mZnNldChvZmZzZXQsIHBvcHBlck9mZnNldHMsIHJlZmVyZW5jZU9mZnNldHMsIGJhc2VQbGFjZW1lbnQpIHtcbiAgdmFyIG9mZnNldHMgPSBbMCwgMF07XG5cbiAgLy8gVXNlIGhlaWdodCBpZiBwbGFjZW1lbnQgaXMgbGVmdCBvciByaWdodCBhbmQgaW5kZXggaXMgMCBvdGhlcndpc2UgdXNlIHdpZHRoXG4gIC8vIGluIHRoaXMgd2F5IHRoZSBmaXJzdCBvZmZzZXQgd2lsbCB1c2UgYW4gYXhpcyBhbmQgdGhlIHNlY29uZCBvbmVcbiAgLy8gd2lsbCB1c2UgdGhlIG90aGVyIG9uZVxuICB2YXIgdXNlSGVpZ2h0ID0gWydyaWdodCcsICdsZWZ0J10uaW5kZXhPZihiYXNlUGxhY2VtZW50KSAhPT0gLTE7XG5cbiAgLy8gU3BsaXQgdGhlIG9mZnNldCBzdHJpbmcgdG8gb2J0YWluIGEgbGlzdCBvZiB2YWx1ZXMgYW5kIG9wZXJhbmRzXG4gIC8vIFRoZSByZWdleCBhZGRyZXNzZXMgdmFsdWVzIHdpdGggdGhlIHBsdXMgb3IgbWludXMgc2lnbiBpbiBmcm9udCAoKzEwLCAtMjAsIGV0YylcbiAgdmFyIGZyYWdtZW50cyA9IG9mZnNldC5zcGxpdCgvKFxcK3xcXC0pLykubWFwKGZ1bmN0aW9uIChmcmFnKSB7XG4gICAgcmV0dXJuIGZyYWcudHJpbSgpO1xuICB9KTtcblxuICAvLyBEZXRlY3QgaWYgdGhlIG9mZnNldCBzdHJpbmcgY29udGFpbnMgYSBwYWlyIG9mIHZhbHVlcyBvciBhIHNpbmdsZSBvbmVcbiAgLy8gdGhleSBjb3VsZCBiZSBzZXBhcmF0ZWQgYnkgY29tbWEgb3Igc3BhY2VcbiAgdmFyIGRpdmlkZXIgPSBmcmFnbWVudHMuaW5kZXhPZihmaW5kKGZyYWdtZW50cywgZnVuY3Rpb24gKGZyYWcpIHtcbiAgICByZXR1cm4gZnJhZy5zZWFyY2goLyx8XFxzLykgIT09IC0xO1xuICB9KSk7XG5cbiAgaWYgKGZyYWdtZW50c1tkaXZpZGVyXSAmJiBmcmFnbWVudHNbZGl2aWRlcl0uaW5kZXhPZignLCcpID09PSAtMSkge1xuICAgIGNvbnNvbGUud2FybignT2Zmc2V0cyBzZXBhcmF0ZWQgYnkgd2hpdGUgc3BhY2UocykgYXJlIGRlcHJlY2F0ZWQsIHVzZSBhIGNvbW1hICgsKSBpbnN0ZWFkLicpO1xuICB9XG5cbiAgLy8gSWYgZGl2aWRlciBpcyBmb3VuZCwgd2UgZGl2aWRlIHRoZSBsaXN0IG9mIHZhbHVlcyBhbmQgb3BlcmFuZHMgdG8gZGl2aWRlXG4gIC8vIHRoZW0gYnkgb2ZzZXQgWCBhbmQgWS5cbiAgdmFyIHNwbGl0UmVnZXggPSAvXFxzKixcXHMqfFxccysvO1xuICB2YXIgb3BzID0gZGl2aWRlciAhPT0gLTEgPyBbZnJhZ21lbnRzLnNsaWNlKDAsIGRpdmlkZXIpLmNvbmNhdChbZnJhZ21lbnRzW2RpdmlkZXJdLnNwbGl0KHNwbGl0UmVnZXgpWzBdXSksIFtmcmFnbWVudHNbZGl2aWRlcl0uc3BsaXQoc3BsaXRSZWdleClbMV1dLmNvbmNhdChmcmFnbWVudHMuc2xpY2UoZGl2aWRlciArIDEpKV0gOiBbZnJhZ21lbnRzXTtcblxuICAvLyBDb252ZXJ0IHRoZSB2YWx1ZXMgd2l0aCB1bml0cyB0byBhYnNvbHV0ZSBwaXhlbHMgdG8gYWxsb3cgb3VyIGNvbXB1dGF0aW9uc1xuICBvcHMgPSBvcHMubWFwKGZ1bmN0aW9uIChvcCwgaW5kZXgpIHtcbiAgICAvLyBNb3N0IG9mIHRoZSB1bml0cyByZWx5IG9uIHRoZSBvcmllbnRhdGlvbiBvZiB0aGUgcG9wcGVyXG4gICAgdmFyIG1lYXN1cmVtZW50ID0gKGluZGV4ID09PSAxID8gIXVzZUhlaWdodCA6IHVzZUhlaWdodCkgPyAnaGVpZ2h0JyA6ICd3aWR0aCc7XG4gICAgdmFyIG1lcmdlV2l0aFByZXZpb3VzID0gZmFsc2U7XG4gICAgcmV0dXJuIG9wXG4gICAgLy8gVGhpcyBhZ2dyZWdhdGVzIGFueSBgK2Agb3IgYC1gIHNpZ24gdGhhdCBhcmVuJ3QgY29uc2lkZXJlZCBvcGVyYXRvcnNcbiAgICAvLyBlLmcuOiAxMCArICs1ID0+IFsxMCwgKywgKzVdXG4gICAgLnJlZHVjZShmdW5jdGlvbiAoYSwgYikge1xuICAgICAgaWYgKGFbYS5sZW5ndGggLSAxXSA9PT0gJycgJiYgWycrJywgJy0nXS5pbmRleE9mKGIpICE9PSAtMSkge1xuICAgICAgICBhW2EubGVuZ3RoIC0gMV0gPSBiO1xuICAgICAgICBtZXJnZVdpdGhQcmV2aW91cyA9IHRydWU7XG4gICAgICAgIHJldHVybiBhO1xuICAgICAgfSBlbHNlIGlmIChtZXJnZVdpdGhQcmV2aW91cykge1xuICAgICAgICBhW2EubGVuZ3RoIC0gMV0gKz0gYjtcbiAgICAgICAgbWVyZ2VXaXRoUHJldmlvdXMgPSBmYWxzZTtcbiAgICAgICAgcmV0dXJuIGE7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gYS5jb25jYXQoYik7XG4gICAgICB9XG4gICAgfSwgW10pXG4gICAgLy8gSGVyZSB3ZSBjb252ZXJ0IHRoZSBzdHJpbmcgdmFsdWVzIGludG8gbnVtYmVyIHZhbHVlcyAoaW4gcHgpXG4gICAgLm1hcChmdW5jdGlvbiAoc3RyKSB7XG4gICAgICByZXR1cm4gdG9WYWx1ZShzdHIsIG1lYXN1cmVtZW50LCBwb3BwZXJPZmZzZXRzLCByZWZlcmVuY2VPZmZzZXRzKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgLy8gTG9vcCB0cm91Z2ggdGhlIG9mZnNldHMgYXJyYXlzIGFuZCBleGVjdXRlIHRoZSBvcGVyYXRpb25zXG4gIG9wcy5mb3JFYWNoKGZ1bmN0aW9uIChvcCwgaW5kZXgpIHtcbiAgICBvcC5mb3JFYWNoKGZ1bmN0aW9uIChmcmFnLCBpbmRleDIpIHtcbiAgICAgIGlmIChpc051bWVyaWMoZnJhZykpIHtcbiAgICAgICAgb2Zmc2V0c1tpbmRleF0gKz0gZnJhZyAqIChvcFtpbmRleDIgLSAxXSA9PT0gJy0nID8gLTEgOiAxKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfSk7XG4gIHJldHVybiBvZmZzZXRzO1xufVxuXG4vKipcbiAqIEBmdW5jdGlvblxuICogQG1lbWJlcm9mIE1vZGlmaWVyc1xuICogQGFyZ3VtZW50IHtPYmplY3R9IGRhdGEgLSBUaGUgZGF0YSBvYmplY3QgZ2VuZXJhdGVkIGJ5IHVwZGF0ZSBtZXRob2RcbiAqIEBhcmd1bWVudCB7T2JqZWN0fSBvcHRpb25zIC0gTW9kaWZpZXJzIGNvbmZpZ3VyYXRpb24gYW5kIG9wdGlvbnNcbiAqIEBhcmd1bWVudCB7TnVtYmVyfFN0cmluZ30gb3B0aW9ucy5vZmZzZXQ9MFxuICogVGhlIG9mZnNldCB2YWx1ZSBhcyBkZXNjcmliZWQgaW4gdGhlIG1vZGlmaWVyIGRlc2NyaXB0aW9uXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgZGF0YSBvYmplY3QsIHByb3Blcmx5IG1vZGlmaWVkXG4gKi9cbmZ1bmN0aW9uIG9mZnNldChkYXRhLCBfcmVmKSB7XG4gIHZhciBvZmZzZXQgPSBfcmVmLm9mZnNldDtcbiAgdmFyIHBsYWNlbWVudCA9IGRhdGEucGxhY2VtZW50LFxuICAgICAgX2RhdGEkb2Zmc2V0cyA9IGRhdGEub2Zmc2V0cyxcbiAgICAgIHBvcHBlciA9IF9kYXRhJG9mZnNldHMucG9wcGVyLFxuICAgICAgcmVmZXJlbmNlID0gX2RhdGEkb2Zmc2V0cy5yZWZlcmVuY2U7XG5cbiAgdmFyIGJhc2VQbGFjZW1lbnQgPSBwbGFjZW1lbnQuc3BsaXQoJy0nKVswXTtcblxuICB2YXIgb2Zmc2V0cyA9IHZvaWQgMDtcbiAgaWYgKGlzTnVtZXJpYygrb2Zmc2V0KSkge1xuICAgIG9mZnNldHMgPSBbK29mZnNldCwgMF07XG4gIH0gZWxzZSB7XG4gICAgb2Zmc2V0cyA9IHBhcnNlT2Zmc2V0KG9mZnNldCwgcG9wcGVyLCByZWZlcmVuY2UsIGJhc2VQbGFjZW1lbnQpO1xuICB9XG5cbiAgaWYgKGJhc2VQbGFjZW1lbnQgPT09ICdsZWZ0Jykge1xuICAgIHBvcHBlci50b3AgKz0gb2Zmc2V0c1swXTtcbiAgICBwb3BwZXIubGVmdCAtPSBvZmZzZXRzWzFdO1xuICB9IGVsc2UgaWYgKGJhc2VQbGFjZW1lbnQgPT09ICdyaWdodCcpIHtcbiAgICBwb3BwZXIudG9wICs9IG9mZnNldHNbMF07XG4gICAgcG9wcGVyLmxlZnQgKz0gb2Zmc2V0c1sxXTtcbiAgfSBlbHNlIGlmIChiYXNlUGxhY2VtZW50ID09PSAndG9wJykge1xuICAgIHBvcHBlci5sZWZ0ICs9IG9mZnNldHNbMF07XG4gICAgcG9wcGVyLnRvcCAtPSBvZmZzZXRzWzFdO1xuICB9IGVsc2UgaWYgKGJhc2VQbGFjZW1lbnQgPT09ICdib3R0b20nKSB7XG4gICAgcG9wcGVyLmxlZnQgKz0gb2Zmc2V0c1swXTtcbiAgICBwb3BwZXIudG9wICs9IG9mZnNldHNbMV07XG4gIH1cblxuICBkYXRhLnBvcHBlciA9IHBvcHBlcjtcbiAgcmV0dXJuIGRhdGE7XG59XG5cbi8qKlxuICogQGZ1bmN0aW9uXG4gKiBAbWVtYmVyb2YgTW9kaWZpZXJzXG4gKiBAYXJndW1lbnQge09iamVjdH0gZGF0YSAtIFRoZSBkYXRhIG9iamVjdCBnZW5lcmF0ZWQgYnkgYHVwZGF0ZWAgbWV0aG9kXG4gKiBAYXJndW1lbnQge09iamVjdH0gb3B0aW9ucyAtIE1vZGlmaWVycyBjb25maWd1cmF0aW9uIGFuZCBvcHRpb25zXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgZGF0YSBvYmplY3QsIHByb3Blcmx5IG1vZGlmaWVkXG4gKi9cbmZ1bmN0aW9uIHByZXZlbnRPdmVyZmxvdyhkYXRhLCBvcHRpb25zKSB7XG4gIHZhciBib3VuZGFyaWVzRWxlbWVudCA9IG9wdGlvbnMuYm91bmRhcmllc0VsZW1lbnQgfHwgZ2V0T2Zmc2V0UGFyZW50KGRhdGEuaW5zdGFuY2UucG9wcGVyKTtcblxuICAvLyBJZiBvZmZzZXRQYXJlbnQgaXMgdGhlIHJlZmVyZW5jZSBlbGVtZW50LCB3ZSByZWFsbHkgd2FudCB0b1xuICAvLyBnbyBvbmUgc3RlcCB1cCBhbmQgdXNlIHRoZSBuZXh0IG9mZnNldFBhcmVudCBhcyByZWZlcmVuY2UgdG9cbiAgLy8gYXZvaWQgdG8gbWFrZSB0aGlzIG1vZGlmaWVyIGNvbXBsZXRlbHkgdXNlbGVzcyBhbmQgbG9vayBsaWtlIGJyb2tlblxuICBpZiAoZGF0YS5pbnN0YW5jZS5yZWZlcmVuY2UgPT09IGJvdW5kYXJpZXNFbGVtZW50KSB7XG4gICAgYm91bmRhcmllc0VsZW1lbnQgPSBnZXRPZmZzZXRQYXJlbnQoYm91bmRhcmllc0VsZW1lbnQpO1xuICB9XG5cbiAgLy8gTk9URTogRE9NIGFjY2VzcyBoZXJlXG4gIC8vIHJlc2V0cyB0aGUgcG9wcGVyJ3MgcG9zaXRpb24gc28gdGhhdCB0aGUgZG9jdW1lbnQgc2l6ZSBjYW4gYmUgY2FsY3VsYXRlZCBleGNsdWRpbmdcbiAgLy8gdGhlIHNpemUgb2YgdGhlIHBvcHBlciBlbGVtZW50IGl0c2VsZlxuICB2YXIgdHJhbnNmb3JtUHJvcCA9IGdldFN1cHBvcnRlZFByb3BlcnR5TmFtZSgndHJhbnNmb3JtJyk7XG4gIHZhciBwb3BwZXJTdHlsZXMgPSBkYXRhLmluc3RhbmNlLnBvcHBlci5zdHlsZTsgLy8gYXNzaWdubWVudCB0byBoZWxwIG1pbmlmaWNhdGlvblxuICB2YXIgdG9wID0gcG9wcGVyU3R5bGVzLnRvcCxcbiAgICAgIGxlZnQgPSBwb3BwZXJTdHlsZXMubGVmdCxcbiAgICAgIHRyYW5zZm9ybSA9IHBvcHBlclN0eWxlc1t0cmFuc2Zvcm1Qcm9wXTtcblxuICBwb3BwZXJTdHlsZXMudG9wID0gJyc7XG4gIHBvcHBlclN0eWxlcy5sZWZ0ID0gJyc7XG4gIHBvcHBlclN0eWxlc1t0cmFuc2Zvcm1Qcm9wXSA9ICcnO1xuXG4gIHZhciBib3VuZGFyaWVzID0gZ2V0Qm91bmRhcmllcyhkYXRhLmluc3RhbmNlLnBvcHBlciwgZGF0YS5pbnN0YW5jZS5yZWZlcmVuY2UsIG9wdGlvbnMucGFkZGluZywgYm91bmRhcmllc0VsZW1lbnQsIGRhdGEucG9zaXRpb25GaXhlZCk7XG5cbiAgLy8gTk9URTogRE9NIGFjY2VzcyBoZXJlXG4gIC8vIHJlc3RvcmVzIHRoZSBvcmlnaW5hbCBzdHlsZSBwcm9wZXJ0aWVzIGFmdGVyIHRoZSBvZmZzZXRzIGhhdmUgYmVlbiBjb21wdXRlZFxuICBwb3BwZXJTdHlsZXMudG9wID0gdG9wO1xuICBwb3BwZXJTdHlsZXMubGVmdCA9IGxlZnQ7XG4gIHBvcHBlclN0eWxlc1t0cmFuc2Zvcm1Qcm9wXSA9IHRyYW5zZm9ybTtcblxuICBvcHRpb25zLmJvdW5kYXJpZXMgPSBib3VuZGFyaWVzO1xuXG4gIHZhciBvcmRlciA9IG9wdGlvbnMucHJpb3JpdHk7XG4gIHZhciBwb3BwZXIgPSBkYXRhLm9mZnNldHMucG9wcGVyO1xuXG4gIHZhciBjaGVjayA9IHtcbiAgICBwcmltYXJ5OiBmdW5jdGlvbiBwcmltYXJ5KHBsYWNlbWVudCkge1xuICAgICAgdmFyIHZhbHVlID0gcG9wcGVyW3BsYWNlbWVudF07XG4gICAgICBpZiAocG9wcGVyW3BsYWNlbWVudF0gPCBib3VuZGFyaWVzW3BsYWNlbWVudF0gJiYgIW9wdGlvbnMuZXNjYXBlV2l0aFJlZmVyZW5jZSkge1xuICAgICAgICB2YWx1ZSA9IE1hdGgubWF4KHBvcHBlcltwbGFjZW1lbnRdLCBib3VuZGFyaWVzW3BsYWNlbWVudF0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGRlZmluZVByb3BlcnR5KHt9LCBwbGFjZW1lbnQsIHZhbHVlKTtcbiAgICB9LFxuICAgIHNlY29uZGFyeTogZnVuY3Rpb24gc2Vjb25kYXJ5KHBsYWNlbWVudCkge1xuICAgICAgdmFyIG1haW5TaWRlID0gcGxhY2VtZW50ID09PSAncmlnaHQnID8gJ2xlZnQnIDogJ3RvcCc7XG4gICAgICB2YXIgdmFsdWUgPSBwb3BwZXJbbWFpblNpZGVdO1xuICAgICAgaWYgKHBvcHBlcltwbGFjZW1lbnRdID4gYm91bmRhcmllc1twbGFjZW1lbnRdICYmICFvcHRpb25zLmVzY2FwZVdpdGhSZWZlcmVuY2UpIHtcbiAgICAgICAgdmFsdWUgPSBNYXRoLm1pbihwb3BwZXJbbWFpblNpZGVdLCBib3VuZGFyaWVzW3BsYWNlbWVudF0gLSAocGxhY2VtZW50ID09PSAncmlnaHQnID8gcG9wcGVyLndpZHRoIDogcG9wcGVyLmhlaWdodCkpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGRlZmluZVByb3BlcnR5KHt9LCBtYWluU2lkZSwgdmFsdWUpO1xuICAgIH1cbiAgfTtcblxuICBvcmRlci5mb3JFYWNoKGZ1bmN0aW9uIChwbGFjZW1lbnQpIHtcbiAgICB2YXIgc2lkZSA9IFsnbGVmdCcsICd0b3AnXS5pbmRleE9mKHBsYWNlbWVudCkgIT09IC0xID8gJ3ByaW1hcnknIDogJ3NlY29uZGFyeSc7XG4gICAgcG9wcGVyID0gX2V4dGVuZHMoe30sIHBvcHBlciwgY2hlY2tbc2lkZV0ocGxhY2VtZW50KSk7XG4gIH0pO1xuXG4gIGRhdGEub2Zmc2V0cy5wb3BwZXIgPSBwb3BwZXI7XG5cbiAgcmV0dXJuIGRhdGE7XG59XG5cbi8qKlxuICogQGZ1bmN0aW9uXG4gKiBAbWVtYmVyb2YgTW9kaWZpZXJzXG4gKiBAYXJndW1lbnQge09iamVjdH0gZGF0YSAtIFRoZSBkYXRhIG9iamVjdCBnZW5lcmF0ZWQgYnkgYHVwZGF0ZWAgbWV0aG9kXG4gKiBAYXJndW1lbnQge09iamVjdH0gb3B0aW9ucyAtIE1vZGlmaWVycyBjb25maWd1cmF0aW9uIGFuZCBvcHRpb25zXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgZGF0YSBvYmplY3QsIHByb3Blcmx5IG1vZGlmaWVkXG4gKi9cbmZ1bmN0aW9uIHNoaWZ0KGRhdGEpIHtcbiAgdmFyIHBsYWNlbWVudCA9IGRhdGEucGxhY2VtZW50O1xuICB2YXIgYmFzZVBsYWNlbWVudCA9IHBsYWNlbWVudC5zcGxpdCgnLScpWzBdO1xuICB2YXIgc2hpZnR2YXJpYXRpb24gPSBwbGFjZW1lbnQuc3BsaXQoJy0nKVsxXTtcblxuICAvLyBpZiBzaGlmdCBzaGlmdHZhcmlhdGlvbiBpcyBzcGVjaWZpZWQsIHJ1biB0aGUgbW9kaWZpZXJcbiAgaWYgKHNoaWZ0dmFyaWF0aW9uKSB7XG4gICAgdmFyIF9kYXRhJG9mZnNldHMgPSBkYXRhLm9mZnNldHMsXG4gICAgICAgIHJlZmVyZW5jZSA9IF9kYXRhJG9mZnNldHMucmVmZXJlbmNlLFxuICAgICAgICBwb3BwZXIgPSBfZGF0YSRvZmZzZXRzLnBvcHBlcjtcblxuICAgIHZhciBpc1ZlcnRpY2FsID0gWydib3R0b20nLCAndG9wJ10uaW5kZXhPZihiYXNlUGxhY2VtZW50KSAhPT0gLTE7XG4gICAgdmFyIHNpZGUgPSBpc1ZlcnRpY2FsID8gJ2xlZnQnIDogJ3RvcCc7XG4gICAgdmFyIG1lYXN1cmVtZW50ID0gaXNWZXJ0aWNhbCA/ICd3aWR0aCcgOiAnaGVpZ2h0JztcblxuICAgIHZhciBzaGlmdE9mZnNldHMgPSB7XG4gICAgICBzdGFydDogZGVmaW5lUHJvcGVydHkoe30sIHNpZGUsIHJlZmVyZW5jZVtzaWRlXSksXG4gICAgICBlbmQ6IGRlZmluZVByb3BlcnR5KHt9LCBzaWRlLCByZWZlcmVuY2Vbc2lkZV0gKyByZWZlcmVuY2VbbWVhc3VyZW1lbnRdIC0gcG9wcGVyW21lYXN1cmVtZW50XSlcbiAgICB9O1xuXG4gICAgZGF0YS5vZmZzZXRzLnBvcHBlciA9IF9leHRlbmRzKHt9LCBwb3BwZXIsIHNoaWZ0T2Zmc2V0c1tzaGlmdHZhcmlhdGlvbl0pO1xuICB9XG5cbiAgcmV0dXJuIGRhdGE7XG59XG5cbi8qKlxuICogQGZ1bmN0aW9uXG4gKiBAbWVtYmVyb2YgTW9kaWZpZXJzXG4gKiBAYXJndW1lbnQge09iamVjdH0gZGF0YSAtIFRoZSBkYXRhIG9iamVjdCBnZW5lcmF0ZWQgYnkgdXBkYXRlIG1ldGhvZFxuICogQGFyZ3VtZW50IHtPYmplY3R9IG9wdGlvbnMgLSBNb2RpZmllcnMgY29uZmlndXJhdGlvbiBhbmQgb3B0aW9uc1xuICogQHJldHVybnMge09iamVjdH0gVGhlIGRhdGEgb2JqZWN0LCBwcm9wZXJseSBtb2RpZmllZFxuICovXG5mdW5jdGlvbiBoaWRlKGRhdGEpIHtcbiAgaWYgKCFpc01vZGlmaWVyUmVxdWlyZWQoZGF0YS5pbnN0YW5jZS5tb2RpZmllcnMsICdoaWRlJywgJ3ByZXZlbnRPdmVyZmxvdycpKSB7XG4gICAgcmV0dXJuIGRhdGE7XG4gIH1cblxuICB2YXIgcmVmUmVjdCA9IGRhdGEub2Zmc2V0cy5yZWZlcmVuY2U7XG4gIHZhciBib3VuZCA9IGZpbmQoZGF0YS5pbnN0YW5jZS5tb2RpZmllcnMsIGZ1bmN0aW9uIChtb2RpZmllcikge1xuICAgIHJldHVybiBtb2RpZmllci5uYW1lID09PSAncHJldmVudE92ZXJmbG93JztcbiAgfSkuYm91bmRhcmllcztcblxuICBpZiAocmVmUmVjdC5ib3R0b20gPCBib3VuZC50b3AgfHwgcmVmUmVjdC5sZWZ0ID4gYm91bmQucmlnaHQgfHwgcmVmUmVjdC50b3AgPiBib3VuZC5ib3R0b20gfHwgcmVmUmVjdC5yaWdodCA8IGJvdW5kLmxlZnQpIHtcbiAgICAvLyBBdm9pZCB1bm5lY2Vzc2FyeSBET00gYWNjZXNzIGlmIHZpc2liaWxpdHkgaGFzbid0IGNoYW5nZWRcbiAgICBpZiAoZGF0YS5oaWRlID09PSB0cnVlKSB7XG4gICAgICByZXR1cm4gZGF0YTtcbiAgICB9XG5cbiAgICBkYXRhLmhpZGUgPSB0cnVlO1xuICAgIGRhdGEuYXR0cmlidXRlc1sneC1vdXQtb2YtYm91bmRhcmllcyddID0gJyc7XG4gIH0gZWxzZSB7XG4gICAgLy8gQXZvaWQgdW5uZWNlc3NhcnkgRE9NIGFjY2VzcyBpZiB2aXNpYmlsaXR5IGhhc24ndCBjaGFuZ2VkXG4gICAgaWYgKGRhdGEuaGlkZSA9PT0gZmFsc2UpIHtcbiAgICAgIHJldHVybiBkYXRhO1xuICAgIH1cblxuICAgIGRhdGEuaGlkZSA9IGZhbHNlO1xuICAgIGRhdGEuYXR0cmlidXRlc1sneC1vdXQtb2YtYm91bmRhcmllcyddID0gZmFsc2U7XG4gIH1cblxuICByZXR1cm4gZGF0YTtcbn1cblxuLyoqXG4gKiBAZnVuY3Rpb25cbiAqIEBtZW1iZXJvZiBNb2RpZmllcnNcbiAqIEBhcmd1bWVudCB7T2JqZWN0fSBkYXRhIC0gVGhlIGRhdGEgb2JqZWN0IGdlbmVyYXRlZCBieSBgdXBkYXRlYCBtZXRob2RcbiAqIEBhcmd1bWVudCB7T2JqZWN0fSBvcHRpb25zIC0gTW9kaWZpZXJzIGNvbmZpZ3VyYXRpb24gYW5kIG9wdGlvbnNcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBkYXRhIG9iamVjdCwgcHJvcGVybHkgbW9kaWZpZWRcbiAqL1xuZnVuY3Rpb24gaW5uZXIoZGF0YSkge1xuICB2YXIgcGxhY2VtZW50ID0gZGF0YS5wbGFjZW1lbnQ7XG4gIHZhciBiYXNlUGxhY2VtZW50ID0gcGxhY2VtZW50LnNwbGl0KCctJylbMF07XG4gIHZhciBfZGF0YSRvZmZzZXRzID0gZGF0YS5vZmZzZXRzLFxuICAgICAgcG9wcGVyID0gX2RhdGEkb2Zmc2V0cy5wb3BwZXIsXG4gICAgICByZWZlcmVuY2UgPSBfZGF0YSRvZmZzZXRzLnJlZmVyZW5jZTtcblxuICB2YXIgaXNIb3JpeiA9IFsnbGVmdCcsICdyaWdodCddLmluZGV4T2YoYmFzZVBsYWNlbWVudCkgIT09IC0xO1xuXG4gIHZhciBzdWJ0cmFjdExlbmd0aCA9IFsndG9wJywgJ2xlZnQnXS5pbmRleE9mKGJhc2VQbGFjZW1lbnQpID09PSAtMTtcblxuICBwb3BwZXJbaXNIb3JpeiA/ICdsZWZ0JyA6ICd0b3AnXSA9IHJlZmVyZW5jZVtiYXNlUGxhY2VtZW50XSAtIChzdWJ0cmFjdExlbmd0aCA/IHBvcHBlcltpc0hvcml6ID8gJ3dpZHRoJyA6ICdoZWlnaHQnXSA6IDApO1xuXG4gIGRhdGEucGxhY2VtZW50ID0gZ2V0T3Bwb3NpdGVQbGFjZW1lbnQocGxhY2VtZW50KTtcbiAgZGF0YS5vZmZzZXRzLnBvcHBlciA9IGdldENsaWVudFJlY3QocG9wcGVyKTtcblxuICByZXR1cm4gZGF0YTtcbn1cblxuLyoqXG4gKiBNb2RpZmllciBmdW5jdGlvbiwgZWFjaCBtb2RpZmllciBjYW4gaGF2ZSBhIGZ1bmN0aW9uIG9mIHRoaXMgdHlwZSBhc3NpZ25lZFxuICogdG8gaXRzIGBmbmAgcHJvcGVydHkuPGJyIC8+XG4gKiBUaGVzZSBmdW5jdGlvbnMgd2lsbCBiZSBjYWxsZWQgb24gZWFjaCB1cGRhdGUsIHRoaXMgbWVhbnMgdGhhdCB5b3UgbXVzdFxuICogbWFrZSBzdXJlIHRoZXkgYXJlIHBlcmZvcm1hbnQgZW5vdWdoIHRvIGF2b2lkIHBlcmZvcm1hbmNlIGJvdHRsZW5lY2tzLlxuICpcbiAqIEBmdW5jdGlvbiBNb2RpZmllckZuXG4gKiBAYXJndW1lbnQge2RhdGFPYmplY3R9IGRhdGEgLSBUaGUgZGF0YSBvYmplY3QgZ2VuZXJhdGVkIGJ5IGB1cGRhdGVgIG1ldGhvZFxuICogQGFyZ3VtZW50IHtPYmplY3R9IG9wdGlvbnMgLSBNb2RpZmllcnMgY29uZmlndXJhdGlvbiBhbmQgb3B0aW9uc1xuICogQHJldHVybnMge2RhdGFPYmplY3R9IFRoZSBkYXRhIG9iamVjdCwgcHJvcGVybHkgbW9kaWZpZWRcbiAqL1xuXG4vKipcbiAqIE1vZGlmaWVycyBhcmUgcGx1Z2lucyB1c2VkIHRvIGFsdGVyIHRoZSBiZWhhdmlvciBvZiB5b3VyIHBvcHBlcnMuPGJyIC8+XG4gKiBQb3BwZXIuanMgdXNlcyBhIHNldCBvZiA5IG1vZGlmaWVycyB0byBwcm92aWRlIGFsbCB0aGUgYmFzaWMgZnVuY3Rpb25hbGl0aWVzXG4gKiBuZWVkZWQgYnkgdGhlIGxpYnJhcnkuXG4gKlxuICogVXN1YWxseSB5b3UgZG9uJ3Qgd2FudCB0byBvdmVycmlkZSB0aGUgYG9yZGVyYCwgYGZuYCBhbmQgYG9uTG9hZGAgcHJvcHMuXG4gKiBBbGwgdGhlIG90aGVyIHByb3BlcnRpZXMgYXJlIGNvbmZpZ3VyYXRpb25zIHRoYXQgY291bGQgYmUgdHdlYWtlZC5cbiAqIEBuYW1lc3BhY2UgbW9kaWZpZXJzXG4gKi9cbnZhciBtb2RpZmllcnMgPSB7XG4gIC8qKlxuICAgKiBNb2RpZmllciB1c2VkIHRvIHNoaWZ0IHRoZSBwb3BwZXIgb24gdGhlIHN0YXJ0IG9yIGVuZCBvZiBpdHMgcmVmZXJlbmNlXG4gICAqIGVsZW1lbnQuPGJyIC8+XG4gICAqIEl0IHdpbGwgcmVhZCB0aGUgdmFyaWF0aW9uIG9mIHRoZSBgcGxhY2VtZW50YCBwcm9wZXJ0eS48YnIgLz5cbiAgICogSXQgY2FuIGJlIG9uZSBlaXRoZXIgYC1lbmRgIG9yIGAtc3RhcnRgLlxuICAgKiBAbWVtYmVyb2YgbW9kaWZpZXJzXG4gICAqIEBpbm5lclxuICAgKi9cbiAgc2hpZnQ6IHtcbiAgICAvKiogQHByb3Age251bWJlcn0gb3JkZXI9MTAwIC0gSW5kZXggdXNlZCB0byBkZWZpbmUgdGhlIG9yZGVyIG9mIGV4ZWN1dGlvbiAqL1xuICAgIG9yZGVyOiAxMDAsXG4gICAgLyoqIEBwcm9wIHtCb29sZWFufSBlbmFibGVkPXRydWUgLSBXaGV0aGVyIHRoZSBtb2RpZmllciBpcyBlbmFibGVkIG9yIG5vdCAqL1xuICAgIGVuYWJsZWQ6IHRydWUsXG4gICAgLyoqIEBwcm9wIHtNb2RpZmllckZufSAqL1xuICAgIGZuOiBzaGlmdFxuICB9LFxuXG4gIC8qKlxuICAgKiBUaGUgYG9mZnNldGAgbW9kaWZpZXIgY2FuIHNoaWZ0IHlvdXIgcG9wcGVyIG9uIGJvdGggaXRzIGF4aXMuXG4gICAqXG4gICAqIEl0IGFjY2VwdHMgdGhlIGZvbGxvd2luZyB1bml0czpcbiAgICogLSBgcHhgIG9yIHVuaXQtbGVzcywgaW50ZXJwcmV0ZWQgYXMgcGl4ZWxzXG4gICAqIC0gYCVgIG9yIGAlcmAsIHBlcmNlbnRhZ2UgcmVsYXRpdmUgdG8gdGhlIGxlbmd0aCBvZiB0aGUgcmVmZXJlbmNlIGVsZW1lbnRcbiAgICogLSBgJXBgLCBwZXJjZW50YWdlIHJlbGF0aXZlIHRvIHRoZSBsZW5ndGggb2YgdGhlIHBvcHBlciBlbGVtZW50XG4gICAqIC0gYHZ3YCwgQ1NTIHZpZXdwb3J0IHdpZHRoIHVuaXRcbiAgICogLSBgdmhgLCBDU1Mgdmlld3BvcnQgaGVpZ2h0IHVuaXRcbiAgICpcbiAgICogRm9yIGxlbmd0aCBpcyBpbnRlbmRlZCB0aGUgbWFpbiBheGlzIHJlbGF0aXZlIHRvIHRoZSBwbGFjZW1lbnQgb2YgdGhlIHBvcHBlci48YnIgLz5cbiAgICogVGhpcyBtZWFucyB0aGF0IGlmIHRoZSBwbGFjZW1lbnQgaXMgYHRvcGAgb3IgYGJvdHRvbWAsIHRoZSBsZW5ndGggd2lsbCBiZSB0aGVcbiAgICogYHdpZHRoYC4gSW4gY2FzZSBvZiBgbGVmdGAgb3IgYHJpZ2h0YCwgaXQgd2lsbCBiZSB0aGUgYGhlaWdodGAuXG4gICAqXG4gICAqIFlvdSBjYW4gcHJvdmlkZSBhIHNpbmdsZSB2YWx1ZSAoYXMgYE51bWJlcmAgb3IgYFN0cmluZ2ApLCBvciBhIHBhaXIgb2YgdmFsdWVzXG4gICAqIGFzIGBTdHJpbmdgIGRpdmlkZWQgYnkgYSBjb21tYSBvciBvbmUgKG9yIG1vcmUpIHdoaXRlIHNwYWNlcy48YnIgLz5cbiAgICogVGhlIGxhdHRlciBpcyBhIGRlcHJlY2F0ZWQgbWV0aG9kIGJlY2F1c2UgaXQgbGVhZHMgdG8gY29uZnVzaW9uIGFuZCB3aWxsIGJlXG4gICAqIHJlbW92ZWQgaW4gdjIuPGJyIC8+XG4gICAqIEFkZGl0aW9uYWxseSwgaXQgYWNjZXB0cyBhZGRpdGlvbnMgYW5kIHN1YnRyYWN0aW9ucyBiZXR3ZWVuIGRpZmZlcmVudCB1bml0cy5cbiAgICogTm90ZSB0aGF0IG11bHRpcGxpY2F0aW9ucyBhbmQgZGl2aXNpb25zIGFyZW4ndCBzdXBwb3J0ZWQuXG4gICAqXG4gICAqIFZhbGlkIGV4YW1wbGVzIGFyZTpcbiAgICogYGBgXG4gICAqIDEwXG4gICAqICcxMCUnXG4gICAqICcxMCwgMTAnXG4gICAqICcxMCUsIDEwJ1xuICAgKiAnMTAgKyAxMCUnXG4gICAqICcxMCAtIDV2aCArIDMlJ1xuICAgKiAnLTEwcHggKyA1dmgsIDVweCAtIDYlJ1xuICAgKiBgYGBcbiAgICogPiAqKk5CKio6IElmIHlvdSBkZXNpcmUgdG8gYXBwbHkgb2Zmc2V0cyB0byB5b3VyIHBvcHBlcnMgaW4gYSB3YXkgdGhhdCBtYXkgbWFrZSB0aGVtIG92ZXJsYXBcbiAgICogPiB3aXRoIHRoZWlyIHJlZmVyZW5jZSBlbGVtZW50LCB1bmZvcnR1bmF0ZWx5LCB5b3Ugd2lsbCBoYXZlIHRvIGRpc2FibGUgdGhlIGBmbGlwYCBtb2RpZmllci5cbiAgICogPiBZb3UgY2FuIHJlYWQgbW9yZSBvbiB0aGlzIGF0IHRoaXMgW2lzc3VlXShodHRwczovL2dpdGh1Yi5jb20vRmV6VnJhc3RhL3BvcHBlci5qcy9pc3N1ZXMvMzczKS5cbiAgICpcbiAgICogQG1lbWJlcm9mIG1vZGlmaWVyc1xuICAgKiBAaW5uZXJcbiAgICovXG4gIG9mZnNldDoge1xuICAgIC8qKiBAcHJvcCB7bnVtYmVyfSBvcmRlcj0yMDAgLSBJbmRleCB1c2VkIHRvIGRlZmluZSB0aGUgb3JkZXIgb2YgZXhlY3V0aW9uICovXG4gICAgb3JkZXI6IDIwMCxcbiAgICAvKiogQHByb3Age0Jvb2xlYW59IGVuYWJsZWQ9dHJ1ZSAtIFdoZXRoZXIgdGhlIG1vZGlmaWVyIGlzIGVuYWJsZWQgb3Igbm90ICovXG4gICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAvKiogQHByb3Age01vZGlmaWVyRm59ICovXG4gICAgZm46IG9mZnNldCxcbiAgICAvKiogQHByb3Age051bWJlcnxTdHJpbmd9IG9mZnNldD0wXG4gICAgICogVGhlIG9mZnNldCB2YWx1ZSBhcyBkZXNjcmliZWQgaW4gdGhlIG1vZGlmaWVyIGRlc2NyaXB0aW9uXG4gICAgICovXG4gICAgb2Zmc2V0OiAwXG4gIH0sXG5cbiAgLyoqXG4gICAqIE1vZGlmaWVyIHVzZWQgdG8gcHJldmVudCB0aGUgcG9wcGVyIGZyb20gYmVpbmcgcG9zaXRpb25lZCBvdXRzaWRlIHRoZSBib3VuZGFyeS5cbiAgICpcbiAgICogQSBzY2VuYXJpbyBleGlzdHMgd2hlcmUgdGhlIHJlZmVyZW5jZSBpdHNlbGYgaXMgbm90IHdpdGhpbiB0aGUgYm91bmRhcmllcy48YnIgLz5cbiAgICogV2UgY2FuIHNheSBpdCBoYXMgXCJlc2NhcGVkIHRoZSBib3VuZGFyaWVzXCIg4oCUIG9yIGp1c3QgXCJlc2NhcGVkXCIuPGJyIC8+XG4gICAqIEluIHRoaXMgY2FzZSB3ZSBuZWVkIHRvIGRlY2lkZSB3aGV0aGVyIHRoZSBwb3BwZXIgc2hvdWxkIGVpdGhlcjpcbiAgICpcbiAgICogLSBkZXRhY2ggZnJvbSB0aGUgcmVmZXJlbmNlIGFuZCByZW1haW4gXCJ0cmFwcGVkXCIgaW4gdGhlIGJvdW5kYXJpZXMsIG9yXG4gICAqIC0gaWYgaXQgc2hvdWxkIGlnbm9yZSB0aGUgYm91bmRhcnkgYW5kIFwiZXNjYXBlIHdpdGggaXRzIHJlZmVyZW5jZVwiXG4gICAqXG4gICAqIFdoZW4gYGVzY2FwZVdpdGhSZWZlcmVuY2VgIGlzIHNldCB0b2B0cnVlYCBhbmQgcmVmZXJlbmNlIGlzIGNvbXBsZXRlbHlcbiAgICogb3V0c2lkZSBpdHMgYm91bmRhcmllcywgdGhlIHBvcHBlciB3aWxsIG92ZXJmbG93IChvciBjb21wbGV0ZWx5IGxlYXZlKVxuICAgKiB0aGUgYm91bmRhcmllcyBpbiBvcmRlciB0byByZW1haW4gYXR0YWNoZWQgdG8gdGhlIGVkZ2Ugb2YgdGhlIHJlZmVyZW5jZS5cbiAgICpcbiAgICogQG1lbWJlcm9mIG1vZGlmaWVyc1xuICAgKiBAaW5uZXJcbiAgICovXG4gIHByZXZlbnRPdmVyZmxvdzoge1xuICAgIC8qKiBAcHJvcCB7bnVtYmVyfSBvcmRlcj0zMDAgLSBJbmRleCB1c2VkIHRvIGRlZmluZSB0aGUgb3JkZXIgb2YgZXhlY3V0aW9uICovXG4gICAgb3JkZXI6IDMwMCxcbiAgICAvKiogQHByb3Age0Jvb2xlYW59IGVuYWJsZWQ9dHJ1ZSAtIFdoZXRoZXIgdGhlIG1vZGlmaWVyIGlzIGVuYWJsZWQgb3Igbm90ICovXG4gICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAvKiogQHByb3Age01vZGlmaWVyRm59ICovXG4gICAgZm46IHByZXZlbnRPdmVyZmxvdyxcbiAgICAvKipcbiAgICAgKiBAcHJvcCB7QXJyYXl9IFtwcmlvcml0eT1bJ2xlZnQnLCdyaWdodCcsJ3RvcCcsJ2JvdHRvbSddXVxuICAgICAqIFBvcHBlciB3aWxsIHRyeSB0byBwcmV2ZW50IG92ZXJmbG93IGZvbGxvd2luZyB0aGVzZSBwcmlvcml0aWVzIGJ5IGRlZmF1bHQsXG4gICAgICogdGhlbiwgaXQgY291bGQgb3ZlcmZsb3cgb24gdGhlIGxlZnQgYW5kIG9uIHRvcCBvZiB0aGUgYGJvdW5kYXJpZXNFbGVtZW50YFxuICAgICAqL1xuICAgIHByaW9yaXR5OiBbJ2xlZnQnLCAncmlnaHQnLCAndG9wJywgJ2JvdHRvbSddLFxuICAgIC8qKlxuICAgICAqIEBwcm9wIHtudW1iZXJ9IHBhZGRpbmc9NVxuICAgICAqIEFtb3VudCBvZiBwaXhlbCB1c2VkIHRvIGRlZmluZSBhIG1pbmltdW0gZGlzdGFuY2UgYmV0d2VlbiB0aGUgYm91bmRhcmllc1xuICAgICAqIGFuZCB0aGUgcG9wcGVyLiBUaGlzIG1ha2VzIHN1cmUgdGhlIHBvcHBlciBhbHdheXMgaGFzIGEgbGl0dGxlIHBhZGRpbmdcbiAgICAgKiBiZXR3ZWVuIHRoZSBlZGdlcyBvZiBpdHMgY29udGFpbmVyXG4gICAgICovXG4gICAgcGFkZGluZzogNSxcbiAgICAvKipcbiAgICAgKiBAcHJvcCB7U3RyaW5nfEhUTUxFbGVtZW50fSBib3VuZGFyaWVzRWxlbWVudD0nc2Nyb2xsUGFyZW50J1xuICAgICAqIEJvdW5kYXJpZXMgdXNlZCBieSB0aGUgbW9kaWZpZXIuIENhbiBiZSBgc2Nyb2xsUGFyZW50YCwgYHdpbmRvd2AsXG4gICAgICogYHZpZXdwb3J0YCBvciBhbnkgRE9NIGVsZW1lbnQuXG4gICAgICovXG4gICAgYm91bmRhcmllc0VsZW1lbnQ6ICdzY3JvbGxQYXJlbnQnXG4gIH0sXG5cbiAgLyoqXG4gICAqIE1vZGlmaWVyIHVzZWQgdG8gbWFrZSBzdXJlIHRoZSByZWZlcmVuY2UgYW5kIGl0cyBwb3BwZXIgc3RheSBuZWFyIGVhY2ggb3RoZXJcbiAgICogd2l0aG91dCBsZWF2aW5nIGFueSBnYXAgYmV0d2VlbiB0aGUgdHdvLiBFc3BlY2lhbGx5IHVzZWZ1bCB3aGVuIHRoZSBhcnJvdyBpc1xuICAgKiBlbmFibGVkIGFuZCB5b3Ugd2FudCB0byBlbnN1cmUgdGhhdCBpdCBwb2ludHMgdG8gaXRzIHJlZmVyZW5jZSBlbGVtZW50LlxuICAgKiBJdCBjYXJlcyBvbmx5IGFib3V0IHRoZSBmaXJzdCBheGlzLiBZb3UgY2FuIHN0aWxsIGhhdmUgcG9wcGVycyB3aXRoIG1hcmdpblxuICAgKiBiZXR3ZWVuIHRoZSBwb3BwZXIgYW5kIGl0cyByZWZlcmVuY2UgZWxlbWVudC5cbiAgICogQG1lbWJlcm9mIG1vZGlmaWVyc1xuICAgKiBAaW5uZXJcbiAgICovXG4gIGtlZXBUb2dldGhlcjoge1xuICAgIC8qKiBAcHJvcCB7bnVtYmVyfSBvcmRlcj00MDAgLSBJbmRleCB1c2VkIHRvIGRlZmluZSB0aGUgb3JkZXIgb2YgZXhlY3V0aW9uICovXG4gICAgb3JkZXI6IDQwMCxcbiAgICAvKiogQHByb3Age0Jvb2xlYW59IGVuYWJsZWQ9dHJ1ZSAtIFdoZXRoZXIgdGhlIG1vZGlmaWVyIGlzIGVuYWJsZWQgb3Igbm90ICovXG4gICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAvKiogQHByb3Age01vZGlmaWVyRm59ICovXG4gICAgZm46IGtlZXBUb2dldGhlclxuICB9LFxuXG4gIC8qKlxuICAgKiBUaGlzIG1vZGlmaWVyIGlzIHVzZWQgdG8gbW92ZSB0aGUgYGFycm93RWxlbWVudGAgb2YgdGhlIHBvcHBlciB0byBtYWtlXG4gICAqIHN1cmUgaXQgaXMgcG9zaXRpb25lZCBiZXR3ZWVuIHRoZSByZWZlcmVuY2UgZWxlbWVudCBhbmQgaXRzIHBvcHBlciBlbGVtZW50LlxuICAgKiBJdCB3aWxsIHJlYWQgdGhlIG91dGVyIHNpemUgb2YgdGhlIGBhcnJvd0VsZW1lbnRgIG5vZGUgdG8gZGV0ZWN0IGhvdyBtYW55XG4gICAqIHBpeGVscyBvZiBjb25qdW5jdGlvbiBhcmUgbmVlZGVkLlxuICAgKlxuICAgKiBJdCBoYXMgbm8gZWZmZWN0IGlmIG5vIGBhcnJvd0VsZW1lbnRgIGlzIHByb3ZpZGVkLlxuICAgKiBAbWVtYmVyb2YgbW9kaWZpZXJzXG4gICAqIEBpbm5lclxuICAgKi9cbiAgYXJyb3c6IHtcbiAgICAvKiogQHByb3Age251bWJlcn0gb3JkZXI9NTAwIC0gSW5kZXggdXNlZCB0byBkZWZpbmUgdGhlIG9yZGVyIG9mIGV4ZWN1dGlvbiAqL1xuICAgIG9yZGVyOiA1MDAsXG4gICAgLyoqIEBwcm9wIHtCb29sZWFufSBlbmFibGVkPXRydWUgLSBXaGV0aGVyIHRoZSBtb2RpZmllciBpcyBlbmFibGVkIG9yIG5vdCAqL1xuICAgIGVuYWJsZWQ6IHRydWUsXG4gICAgLyoqIEBwcm9wIHtNb2RpZmllckZufSAqL1xuICAgIGZuOiBhcnJvdyxcbiAgICAvKiogQHByb3Age1N0cmluZ3xIVE1MRWxlbWVudH0gZWxlbWVudD0nW3gtYXJyb3ddJyAtIFNlbGVjdG9yIG9yIG5vZGUgdXNlZCBhcyBhcnJvdyAqL1xuICAgIGVsZW1lbnQ6ICdbeC1hcnJvd10nXG4gIH0sXG5cbiAgLyoqXG4gICAqIE1vZGlmaWVyIHVzZWQgdG8gZmxpcCB0aGUgcG9wcGVyJ3MgcGxhY2VtZW50IHdoZW4gaXQgc3RhcnRzIHRvIG92ZXJsYXAgaXRzXG4gICAqIHJlZmVyZW5jZSBlbGVtZW50LlxuICAgKlxuICAgKiBSZXF1aXJlcyB0aGUgYHByZXZlbnRPdmVyZmxvd2AgbW9kaWZpZXIgYmVmb3JlIGl0IGluIG9yZGVyIHRvIHdvcmsuXG4gICAqXG4gICAqICoqTk9URToqKiB0aGlzIG1vZGlmaWVyIHdpbGwgaW50ZXJydXB0IHRoZSBjdXJyZW50IHVwZGF0ZSBjeWNsZSBhbmQgd2lsbFxuICAgKiByZXN0YXJ0IGl0IGlmIGl0IGRldGVjdHMgdGhlIG5lZWQgdG8gZmxpcCB0aGUgcGxhY2VtZW50LlxuICAgKiBAbWVtYmVyb2YgbW9kaWZpZXJzXG4gICAqIEBpbm5lclxuICAgKi9cbiAgZmxpcDoge1xuICAgIC8qKiBAcHJvcCB7bnVtYmVyfSBvcmRlcj02MDAgLSBJbmRleCB1c2VkIHRvIGRlZmluZSB0aGUgb3JkZXIgb2YgZXhlY3V0aW9uICovXG4gICAgb3JkZXI6IDYwMCxcbiAgICAvKiogQHByb3Age0Jvb2xlYW59IGVuYWJsZWQ9dHJ1ZSAtIFdoZXRoZXIgdGhlIG1vZGlmaWVyIGlzIGVuYWJsZWQgb3Igbm90ICovXG4gICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAvKiogQHByb3Age01vZGlmaWVyRm59ICovXG4gICAgZm46IGZsaXAsXG4gICAgLyoqXG4gICAgICogQHByb3Age1N0cmluZ3xBcnJheX0gYmVoYXZpb3I9J2ZsaXAnXG4gICAgICogVGhlIGJlaGF2aW9yIHVzZWQgdG8gY2hhbmdlIHRoZSBwb3BwZXIncyBwbGFjZW1lbnQuIEl0IGNhbiBiZSBvbmUgb2ZcbiAgICAgKiBgZmxpcGAsIGBjbG9ja3dpc2VgLCBgY291bnRlcmNsb2Nrd2lzZWAgb3IgYW4gYXJyYXkgd2l0aCBhIGxpc3Qgb2YgdmFsaWRcbiAgICAgKiBwbGFjZW1lbnRzICh3aXRoIG9wdGlvbmFsIHZhcmlhdGlvbnMpXG4gICAgICovXG4gICAgYmVoYXZpb3I6ICdmbGlwJyxcbiAgICAvKipcbiAgICAgKiBAcHJvcCB7bnVtYmVyfSBwYWRkaW5nPTVcbiAgICAgKiBUaGUgcG9wcGVyIHdpbGwgZmxpcCBpZiBpdCBoaXRzIHRoZSBlZGdlcyBvZiB0aGUgYGJvdW5kYXJpZXNFbGVtZW50YFxuICAgICAqL1xuICAgIHBhZGRpbmc6IDUsXG4gICAgLyoqXG4gICAgICogQHByb3Age1N0cmluZ3xIVE1MRWxlbWVudH0gYm91bmRhcmllc0VsZW1lbnQ9J3ZpZXdwb3J0J1xuICAgICAqIFRoZSBlbGVtZW50IHdoaWNoIHdpbGwgZGVmaW5lIHRoZSBib3VuZGFyaWVzIG9mIHRoZSBwb3BwZXIgcG9zaXRpb24uXG4gICAgICogVGhlIHBvcHBlciB3aWxsIG5ldmVyIGJlIHBsYWNlZCBvdXRzaWRlIG9mIHRoZSBkZWZpbmVkIGJvdW5kYXJpZXNcbiAgICAgKiAoZXhjZXB0IGlmIGBrZWVwVG9nZXRoZXJgIGlzIGVuYWJsZWQpXG4gICAgICovXG4gICAgYm91bmRhcmllc0VsZW1lbnQ6ICd2aWV3cG9ydCcsXG4gICAgLyoqXG4gICAgICogQHByb3Age0Jvb2xlYW59IGZsaXBWYXJpYXRpb25zPWZhbHNlXG4gICAgICogVGhlIHBvcHBlciB3aWxsIHN3aXRjaCBwbGFjZW1lbnQgdmFyaWF0aW9uIGJldHdlZW4gYC1zdGFydGAgYW5kIGAtZW5kYCB3aGVuXG4gICAgICogdGhlIHJlZmVyZW5jZSBlbGVtZW50IG92ZXJsYXBzIGl0cyBib3VuZGFyaWVzLlxuICAgICAqXG4gICAgICogVGhlIG9yaWdpbmFsIHBsYWNlbWVudCBzaG91bGQgaGF2ZSBhIHNldCB2YXJpYXRpb24uXG4gICAgICovXG4gICAgZmxpcFZhcmlhdGlvbnM6IGZhbHNlLFxuICAgIC8qKlxuICAgICAqIEBwcm9wIHtCb29sZWFufSBmbGlwVmFyaWF0aW9uc0J5Q29udGVudD1mYWxzZVxuICAgICAqIFRoZSBwb3BwZXIgd2lsbCBzd2l0Y2ggcGxhY2VtZW50IHZhcmlhdGlvbiBiZXR3ZWVuIGAtc3RhcnRgIGFuZCBgLWVuZGAgd2hlblxuICAgICAqIHRoZSBwb3BwZXIgZWxlbWVudCBvdmVybGFwcyBpdHMgcmVmZXJlbmNlIGJvdW5kYXJpZXMuXG4gICAgICpcbiAgICAgKiBUaGUgb3JpZ2luYWwgcGxhY2VtZW50IHNob3VsZCBoYXZlIGEgc2V0IHZhcmlhdGlvbi5cbiAgICAgKi9cbiAgICBmbGlwVmFyaWF0aW9uc0J5Q29udGVudDogZmFsc2VcbiAgfSxcblxuICAvKipcbiAgICogTW9kaWZpZXIgdXNlZCB0byBtYWtlIHRoZSBwb3BwZXIgZmxvdyB0b3dhcmQgdGhlIGlubmVyIG9mIHRoZSByZWZlcmVuY2UgZWxlbWVudC5cbiAgICogQnkgZGVmYXVsdCwgd2hlbiB0aGlzIG1vZGlmaWVyIGlzIGRpc2FibGVkLCB0aGUgcG9wcGVyIHdpbGwgYmUgcGxhY2VkIG91dHNpZGVcbiAgICogdGhlIHJlZmVyZW5jZSBlbGVtZW50LlxuICAgKiBAbWVtYmVyb2YgbW9kaWZpZXJzXG4gICAqIEBpbm5lclxuICAgKi9cbiAgaW5uZXI6IHtcbiAgICAvKiogQHByb3Age251bWJlcn0gb3JkZXI9NzAwIC0gSW5kZXggdXNlZCB0byBkZWZpbmUgdGhlIG9yZGVyIG9mIGV4ZWN1dGlvbiAqL1xuICAgIG9yZGVyOiA3MDAsXG4gICAgLyoqIEBwcm9wIHtCb29sZWFufSBlbmFibGVkPWZhbHNlIC0gV2hldGhlciB0aGUgbW9kaWZpZXIgaXMgZW5hYmxlZCBvciBub3QgKi9cbiAgICBlbmFibGVkOiBmYWxzZSxcbiAgICAvKiogQHByb3Age01vZGlmaWVyRm59ICovXG4gICAgZm46IGlubmVyXG4gIH0sXG5cbiAgLyoqXG4gICAqIE1vZGlmaWVyIHVzZWQgdG8gaGlkZSB0aGUgcG9wcGVyIHdoZW4gaXRzIHJlZmVyZW5jZSBlbGVtZW50IGlzIG91dHNpZGUgb2YgdGhlXG4gICAqIHBvcHBlciBib3VuZGFyaWVzLiBJdCB3aWxsIHNldCBhIGB4LW91dC1vZi1ib3VuZGFyaWVzYCBhdHRyaWJ1dGUgd2hpY2ggY2FuXG4gICAqIGJlIHVzZWQgdG8gaGlkZSB3aXRoIGEgQ1NTIHNlbGVjdG9yIHRoZSBwb3BwZXIgd2hlbiBpdHMgcmVmZXJlbmNlIGlzXG4gICAqIG91dCBvZiBib3VuZGFyaWVzLlxuICAgKlxuICAgKiBSZXF1aXJlcyB0aGUgYHByZXZlbnRPdmVyZmxvd2AgbW9kaWZpZXIgYmVmb3JlIGl0IGluIG9yZGVyIHRvIHdvcmsuXG4gICAqIEBtZW1iZXJvZiBtb2RpZmllcnNcbiAgICogQGlubmVyXG4gICAqL1xuICBoaWRlOiB7XG4gICAgLyoqIEBwcm9wIHtudW1iZXJ9IG9yZGVyPTgwMCAtIEluZGV4IHVzZWQgdG8gZGVmaW5lIHRoZSBvcmRlciBvZiBleGVjdXRpb24gKi9cbiAgICBvcmRlcjogODAwLFxuICAgIC8qKiBAcHJvcCB7Qm9vbGVhbn0gZW5hYmxlZD10cnVlIC0gV2hldGhlciB0aGUgbW9kaWZpZXIgaXMgZW5hYmxlZCBvciBub3QgKi9cbiAgICBlbmFibGVkOiB0cnVlLFxuICAgIC8qKiBAcHJvcCB7TW9kaWZpZXJGbn0gKi9cbiAgICBmbjogaGlkZVxuICB9LFxuXG4gIC8qKlxuICAgKiBDb21wdXRlcyB0aGUgc3R5bGUgdGhhdCB3aWxsIGJlIGFwcGxpZWQgdG8gdGhlIHBvcHBlciBlbGVtZW50IHRvIGdldHNcbiAgICogcHJvcGVybHkgcG9zaXRpb25lZC5cbiAgICpcbiAgICogTm90ZSB0aGF0IHRoaXMgbW9kaWZpZXIgd2lsbCBub3QgdG91Y2ggdGhlIERPTSwgaXQganVzdCBwcmVwYXJlcyB0aGUgc3R5bGVzXG4gICAqIHNvIHRoYXQgYGFwcGx5U3R5bGVgIG1vZGlmaWVyIGNhbiBhcHBseSBpdC4gVGhpcyBzZXBhcmF0aW9uIGlzIHVzZWZ1bFxuICAgKiBpbiBjYXNlIHlvdSBuZWVkIHRvIHJlcGxhY2UgYGFwcGx5U3R5bGVgIHdpdGggYSBjdXN0b20gaW1wbGVtZW50YXRpb24uXG4gICAqXG4gICAqIFRoaXMgbW9kaWZpZXIgaGFzIGA4NTBgIGFzIGBvcmRlcmAgdmFsdWUgdG8gbWFpbnRhaW4gYmFja3dhcmQgY29tcGF0aWJpbGl0eVxuICAgKiB3aXRoIHByZXZpb3VzIHZlcnNpb25zIG9mIFBvcHBlci5qcy4gRXhwZWN0IHRoZSBtb2RpZmllcnMgb3JkZXJpbmcgbWV0aG9kXG4gICAqIHRvIGNoYW5nZSBpbiBmdXR1cmUgbWFqb3IgdmVyc2lvbnMgb2YgdGhlIGxpYnJhcnkuXG4gICAqXG4gICAqIEBtZW1iZXJvZiBtb2RpZmllcnNcbiAgICogQGlubmVyXG4gICAqL1xuICBjb21wdXRlU3R5bGU6IHtcbiAgICAvKiogQHByb3Age251bWJlcn0gb3JkZXI9ODUwIC0gSW5kZXggdXNlZCB0byBkZWZpbmUgdGhlIG9yZGVyIG9mIGV4ZWN1dGlvbiAqL1xuICAgIG9yZGVyOiA4NTAsXG4gICAgLyoqIEBwcm9wIHtCb29sZWFufSBlbmFibGVkPXRydWUgLSBXaGV0aGVyIHRoZSBtb2RpZmllciBpcyBlbmFibGVkIG9yIG5vdCAqL1xuICAgIGVuYWJsZWQ6IHRydWUsXG4gICAgLyoqIEBwcm9wIHtNb2RpZmllckZufSAqL1xuICAgIGZuOiBjb21wdXRlU3R5bGUsXG4gICAgLyoqXG4gICAgICogQHByb3Age0Jvb2xlYW59IGdwdUFjY2VsZXJhdGlvbj10cnVlXG4gICAgICogSWYgdHJ1ZSwgaXQgdXNlcyB0aGUgQ1NTIDNEIHRyYW5zZm9ybWF0aW9uIHRvIHBvc2l0aW9uIHRoZSBwb3BwZXIuXG4gICAgICogT3RoZXJ3aXNlLCBpdCB3aWxsIHVzZSB0aGUgYHRvcGAgYW5kIGBsZWZ0YCBwcm9wZXJ0aWVzXG4gICAgICovXG4gICAgZ3B1QWNjZWxlcmF0aW9uOiB0cnVlLFxuICAgIC8qKlxuICAgICAqIEBwcm9wIHtzdHJpbmd9IFt4PSdib3R0b20nXVxuICAgICAqIFdoZXJlIHRvIGFuY2hvciB0aGUgWCBheGlzIChgYm90dG9tYCBvciBgdG9wYCkuIEFLQSBYIG9mZnNldCBvcmlnaW4uXG4gICAgICogQ2hhbmdlIHRoaXMgaWYgeW91ciBwb3BwZXIgc2hvdWxkIGdyb3cgaW4gYSBkaXJlY3Rpb24gZGlmZmVyZW50IGZyb20gYGJvdHRvbWBcbiAgICAgKi9cbiAgICB4OiAnYm90dG9tJyxcbiAgICAvKipcbiAgICAgKiBAcHJvcCB7c3RyaW5nfSBbeD0nbGVmdCddXG4gICAgICogV2hlcmUgdG8gYW5jaG9yIHRoZSBZIGF4aXMgKGBsZWZ0YCBvciBgcmlnaHRgKS4gQUtBIFkgb2Zmc2V0IG9yaWdpbi5cbiAgICAgKiBDaGFuZ2UgdGhpcyBpZiB5b3VyIHBvcHBlciBzaG91bGQgZ3JvdyBpbiBhIGRpcmVjdGlvbiBkaWZmZXJlbnQgZnJvbSBgcmlnaHRgXG4gICAgICovXG4gICAgeTogJ3JpZ2h0J1xuICB9LFxuXG4gIC8qKlxuICAgKiBBcHBsaWVzIHRoZSBjb21wdXRlZCBzdHlsZXMgdG8gdGhlIHBvcHBlciBlbGVtZW50LlxuICAgKlxuICAgKiBBbGwgdGhlIERPTSBtYW5pcHVsYXRpb25zIGFyZSBsaW1pdGVkIHRvIHRoaXMgbW9kaWZpZXIuIFRoaXMgaXMgdXNlZnVsIGluIGNhc2VcbiAgICogeW91IHdhbnQgdG8gaW50ZWdyYXRlIFBvcHBlci5qcyBpbnNpZGUgYSBmcmFtZXdvcmsgb3IgdmlldyBsaWJyYXJ5IGFuZCB5b3VcbiAgICogd2FudCB0byBkZWxlZ2F0ZSBhbGwgdGhlIERPTSBtYW5pcHVsYXRpb25zIHRvIGl0LlxuICAgKlxuICAgKiBOb3RlIHRoYXQgaWYgeW91IGRpc2FibGUgdGhpcyBtb2RpZmllciwgeW91IG11c3QgbWFrZSBzdXJlIHRoZSBwb3BwZXIgZWxlbWVudFxuICAgKiBoYXMgaXRzIHBvc2l0aW9uIHNldCB0byBgYWJzb2x1dGVgIGJlZm9yZSBQb3BwZXIuanMgY2FuIGRvIGl0cyB3b3JrIVxuICAgKlxuICAgKiBKdXN0IGRpc2FibGUgdGhpcyBtb2RpZmllciBhbmQgZGVmaW5lIHlvdXIgb3duIHRvIGFjaGlldmUgdGhlIGRlc2lyZWQgZWZmZWN0LlxuICAgKlxuICAgKiBAbWVtYmVyb2YgbW9kaWZpZXJzXG4gICAqIEBpbm5lclxuICAgKi9cbiAgYXBwbHlTdHlsZToge1xuICAgIC8qKiBAcHJvcCB7bnVtYmVyfSBvcmRlcj05MDAgLSBJbmRleCB1c2VkIHRvIGRlZmluZSB0aGUgb3JkZXIgb2YgZXhlY3V0aW9uICovXG4gICAgb3JkZXI6IDkwMCxcbiAgICAvKiogQHByb3Age0Jvb2xlYW59IGVuYWJsZWQ9dHJ1ZSAtIFdoZXRoZXIgdGhlIG1vZGlmaWVyIGlzIGVuYWJsZWQgb3Igbm90ICovXG4gICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAvKiogQHByb3Age01vZGlmaWVyRm59ICovXG4gICAgZm46IGFwcGx5U3R5bGUsXG4gICAgLyoqIEBwcm9wIHtGdW5jdGlvbn0gKi9cbiAgICBvbkxvYWQ6IGFwcGx5U3R5bGVPbkxvYWQsXG4gICAgLyoqXG4gICAgICogQGRlcHJlY2F0ZWQgc2luY2UgdmVyc2lvbiAxLjEwLjAsIHRoZSBwcm9wZXJ0eSBtb3ZlZCB0byBgY29tcHV0ZVN0eWxlYCBtb2RpZmllclxuICAgICAqIEBwcm9wIHtCb29sZWFufSBncHVBY2NlbGVyYXRpb249dHJ1ZVxuICAgICAqIElmIHRydWUsIGl0IHVzZXMgdGhlIENTUyAzRCB0cmFuc2Zvcm1hdGlvbiB0byBwb3NpdGlvbiB0aGUgcG9wcGVyLlxuICAgICAqIE90aGVyd2lzZSwgaXQgd2lsbCB1c2UgdGhlIGB0b3BgIGFuZCBgbGVmdGAgcHJvcGVydGllc1xuICAgICAqL1xuICAgIGdwdUFjY2VsZXJhdGlvbjogdW5kZWZpbmVkXG4gIH1cbn07XG5cbi8qKlxuICogVGhlIGBkYXRhT2JqZWN0YCBpcyBhbiBvYmplY3QgY29udGFpbmluZyBhbGwgdGhlIGluZm9ybWF0aW9uIHVzZWQgYnkgUG9wcGVyLmpzLlxuICogVGhpcyBvYmplY3QgaXMgcGFzc2VkIHRvIG1vZGlmaWVycyBhbmQgdG8gdGhlIGBvbkNyZWF0ZWAgYW5kIGBvblVwZGF0ZWAgY2FsbGJhY2tzLlxuICogQG5hbWUgZGF0YU9iamVjdFxuICogQHByb3BlcnR5IHtPYmplY3R9IGRhdGEuaW5zdGFuY2UgVGhlIFBvcHBlci5qcyBpbnN0YW5jZVxuICogQHByb3BlcnR5IHtTdHJpbmd9IGRhdGEucGxhY2VtZW50IFBsYWNlbWVudCBhcHBsaWVkIHRvIHBvcHBlclxuICogQHByb3BlcnR5IHtTdHJpbmd9IGRhdGEub3JpZ2luYWxQbGFjZW1lbnQgUGxhY2VtZW50IG9yaWdpbmFsbHkgZGVmaW5lZCBvbiBpbml0XG4gKiBAcHJvcGVydHkge0Jvb2xlYW59IGRhdGEuZmxpcHBlZCBUcnVlIGlmIHBvcHBlciBoYXMgYmVlbiBmbGlwcGVkIGJ5IGZsaXAgbW9kaWZpZXJcbiAqIEBwcm9wZXJ0eSB7Qm9vbGVhbn0gZGF0YS5oaWRlIFRydWUgaWYgdGhlIHJlZmVyZW5jZSBlbGVtZW50IGlzIG91dCBvZiBib3VuZGFyaWVzLCB1c2VmdWwgdG8ga25vdyB3aGVuIHRvIGhpZGUgdGhlIHBvcHBlclxuICogQHByb3BlcnR5IHtIVE1MRWxlbWVudH0gZGF0YS5hcnJvd0VsZW1lbnQgTm9kZSB1c2VkIGFzIGFycm93IGJ5IGFycm93IG1vZGlmaWVyXG4gKiBAcHJvcGVydHkge09iamVjdH0gZGF0YS5zdHlsZXMgQW55IENTUyBwcm9wZXJ0eSBkZWZpbmVkIGhlcmUgd2lsbCBiZSBhcHBsaWVkIHRvIHRoZSBwb3BwZXIuIEl0IGV4cGVjdHMgdGhlIEphdmFTY3JpcHQgbm9tZW5jbGF0dXJlIChlZy4gYG1hcmdpbkJvdHRvbWApXG4gKiBAcHJvcGVydHkge09iamVjdH0gZGF0YS5hcnJvd1N0eWxlcyBBbnkgQ1NTIHByb3BlcnR5IGRlZmluZWQgaGVyZSB3aWxsIGJlIGFwcGxpZWQgdG8gdGhlIHBvcHBlciBhcnJvdy4gSXQgZXhwZWN0cyB0aGUgSmF2YVNjcmlwdCBub21lbmNsYXR1cmUgKGVnLiBgbWFyZ2luQm90dG9tYClcbiAqIEBwcm9wZXJ0eSB7T2JqZWN0fSBkYXRhLmJvdW5kYXJpZXMgT2Zmc2V0cyBvZiB0aGUgcG9wcGVyIGJvdW5kYXJpZXNcbiAqIEBwcm9wZXJ0eSB7T2JqZWN0fSBkYXRhLm9mZnNldHMgVGhlIG1lYXN1cmVtZW50cyBvZiBwb3BwZXIsIHJlZmVyZW5jZSBhbmQgYXJyb3cgZWxlbWVudHNcbiAqIEBwcm9wZXJ0eSB7T2JqZWN0fSBkYXRhLm9mZnNldHMucG9wcGVyIGB0b3BgLCBgbGVmdGAsIGB3aWR0aGAsIGBoZWlnaHRgIHZhbHVlc1xuICogQHByb3BlcnR5IHtPYmplY3R9IGRhdGEub2Zmc2V0cy5yZWZlcmVuY2UgYHRvcGAsIGBsZWZ0YCwgYHdpZHRoYCwgYGhlaWdodGAgdmFsdWVzXG4gKiBAcHJvcGVydHkge09iamVjdH0gZGF0YS5vZmZzZXRzLmFycm93XSBgdG9wYCBhbmQgYGxlZnRgIG9mZnNldHMsIG9ubHkgb25lIG9mIHRoZW0gd2lsbCBiZSBkaWZmZXJlbnQgZnJvbSAwXG4gKi9cblxuLyoqXG4gKiBEZWZhdWx0IG9wdGlvbnMgcHJvdmlkZWQgdG8gUG9wcGVyLmpzIGNvbnN0cnVjdG9yLjxiciAvPlxuICogVGhlc2UgY2FuIGJlIG92ZXJyaWRkZW4gdXNpbmcgdGhlIGBvcHRpb25zYCBhcmd1bWVudCBvZiBQb3BwZXIuanMuPGJyIC8+XG4gKiBUbyBvdmVycmlkZSBhbiBvcHRpb24sIHNpbXBseSBwYXNzIGFuIG9iamVjdCB3aXRoIHRoZSBzYW1lXG4gKiBzdHJ1Y3R1cmUgb2YgdGhlIGBvcHRpb25zYCBvYmplY3QsIGFzIHRoZSAzcmQgYXJndW1lbnQuIEZvciBleGFtcGxlOlxuICogYGBgXG4gKiBuZXcgUG9wcGVyKHJlZiwgcG9wLCB7XG4gKiAgIG1vZGlmaWVyczoge1xuICogICAgIHByZXZlbnRPdmVyZmxvdzogeyBlbmFibGVkOiBmYWxzZSB9XG4gKiAgIH1cbiAqIH0pXG4gKiBgYGBcbiAqIEB0eXBlIHtPYmplY3R9XG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyb2YgUG9wcGVyXG4gKi9cbnZhciBEZWZhdWx0cyA9IHtcbiAgLyoqXG4gICAqIFBvcHBlcidzIHBsYWNlbWVudC5cbiAgICogQHByb3Age1BvcHBlci5wbGFjZW1lbnRzfSBwbGFjZW1lbnQ9J2JvdHRvbSdcbiAgICovXG4gIHBsYWNlbWVudDogJ2JvdHRvbScsXG5cbiAgLyoqXG4gICAqIFNldCB0aGlzIHRvIHRydWUgaWYgeW91IHdhbnQgcG9wcGVyIHRvIHBvc2l0aW9uIGl0IHNlbGYgaW4gJ2ZpeGVkJyBtb2RlXG4gICAqIEBwcm9wIHtCb29sZWFufSBwb3NpdGlvbkZpeGVkPWZhbHNlXG4gICAqL1xuICBwb3NpdGlvbkZpeGVkOiBmYWxzZSxcblxuICAvKipcbiAgICogV2hldGhlciBldmVudHMgKHJlc2l6ZSwgc2Nyb2xsKSBhcmUgaW5pdGlhbGx5IGVuYWJsZWQuXG4gICAqIEBwcm9wIHtCb29sZWFufSBldmVudHNFbmFibGVkPXRydWVcbiAgICovXG4gIGV2ZW50c0VuYWJsZWQ6IHRydWUsXG5cbiAgLyoqXG4gICAqIFNldCB0byB0cnVlIGlmIHlvdSB3YW50IHRvIGF1dG9tYXRpY2FsbHkgcmVtb3ZlIHRoZSBwb3BwZXIgd2hlblxuICAgKiB5b3UgY2FsbCB0aGUgYGRlc3Ryb3lgIG1ldGhvZC5cbiAgICogQHByb3Age0Jvb2xlYW59IHJlbW92ZU9uRGVzdHJveT1mYWxzZVxuICAgKi9cbiAgcmVtb3ZlT25EZXN0cm95OiBmYWxzZSxcblxuICAvKipcbiAgICogQ2FsbGJhY2sgY2FsbGVkIHdoZW4gdGhlIHBvcHBlciBpcyBjcmVhdGVkLjxiciAvPlxuICAgKiBCeSBkZWZhdWx0LCBpdCBpcyBzZXQgdG8gbm8tb3AuPGJyIC8+XG4gICAqIEFjY2VzcyBQb3BwZXIuanMgaW5zdGFuY2Ugd2l0aCBgZGF0YS5pbnN0YW5jZWAuXG4gICAqIEBwcm9wIHtvbkNyZWF0ZX1cbiAgICovXG4gIG9uQ3JlYXRlOiBmdW5jdGlvbiBvbkNyZWF0ZSgpIHt9LFxuXG4gIC8qKlxuICAgKiBDYWxsYmFjayBjYWxsZWQgd2hlbiB0aGUgcG9wcGVyIGlzIHVwZGF0ZWQuIFRoaXMgY2FsbGJhY2sgaXMgbm90IGNhbGxlZFxuICAgKiBvbiB0aGUgaW5pdGlhbGl6YXRpb24vY3JlYXRpb24gb2YgdGhlIHBvcHBlciwgYnV0IG9ubHkgb24gc3Vic2VxdWVudFxuICAgKiB1cGRhdGVzLjxiciAvPlxuICAgKiBCeSBkZWZhdWx0LCBpdCBpcyBzZXQgdG8gbm8tb3AuPGJyIC8+XG4gICAqIEFjY2VzcyBQb3BwZXIuanMgaW5zdGFuY2Ugd2l0aCBgZGF0YS5pbnN0YW5jZWAuXG4gICAqIEBwcm9wIHtvblVwZGF0ZX1cbiAgICovXG4gIG9uVXBkYXRlOiBmdW5jdGlvbiBvblVwZGF0ZSgpIHt9LFxuXG4gIC8qKlxuICAgKiBMaXN0IG9mIG1vZGlmaWVycyB1c2VkIHRvIG1vZGlmeSB0aGUgb2Zmc2V0cyBiZWZvcmUgdGhleSBhcmUgYXBwbGllZCB0byB0aGUgcG9wcGVyLlxuICAgKiBUaGV5IHByb3ZpZGUgbW9zdCBvZiB0aGUgZnVuY3Rpb25hbGl0aWVzIG9mIFBvcHBlci5qcy5cbiAgICogQHByb3Age21vZGlmaWVyc31cbiAgICovXG4gIG1vZGlmaWVyczogbW9kaWZpZXJzXG59O1xuXG4vKipcbiAqIEBjYWxsYmFjayBvbkNyZWF0ZVxuICogQHBhcmFtIHtkYXRhT2JqZWN0fSBkYXRhXG4gKi9cblxuLyoqXG4gKiBAY2FsbGJhY2sgb25VcGRhdGVcbiAqIEBwYXJhbSB7ZGF0YU9iamVjdH0gZGF0YVxuICovXG5cbi8vIFV0aWxzXG4vLyBNZXRob2RzXG52YXIgUG9wcGVyID0gZnVuY3Rpb24gKCkge1xuICAvKipcbiAgICogQ3JlYXRlcyBhIG5ldyBQb3BwZXIuanMgaW5zdGFuY2UuXG4gICAqIEBjbGFzcyBQb3BwZXJcbiAgICogQHBhcmFtIHtFbGVtZW50fHJlZmVyZW5jZU9iamVjdH0gcmVmZXJlbmNlIC0gVGhlIHJlZmVyZW5jZSBlbGVtZW50IHVzZWQgdG8gcG9zaXRpb24gdGhlIHBvcHBlclxuICAgKiBAcGFyYW0ge0VsZW1lbnR9IHBvcHBlciAtIFRoZSBIVE1MIC8gWE1MIGVsZW1lbnQgdXNlZCBhcyB0aGUgcG9wcGVyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gWW91ciBjdXN0b20gb3B0aW9ucyB0byBvdmVycmlkZSB0aGUgb25lcyBkZWZpbmVkIGluIFtEZWZhdWx0c10oI2RlZmF1bHRzKVxuICAgKiBAcmV0dXJuIHtPYmplY3R9IGluc3RhbmNlIC0gVGhlIGdlbmVyYXRlZCBQb3BwZXIuanMgaW5zdGFuY2VcbiAgICovXG4gIGZ1bmN0aW9uIFBvcHBlcihyZWZlcmVuY2UsIHBvcHBlcikge1xuICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICB2YXIgb3B0aW9ucyA9IGFyZ3VtZW50cy5sZW5ndGggPiAyICYmIGFyZ3VtZW50c1syXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzJdIDoge307XG4gICAgY2xhc3NDYWxsQ2hlY2sodGhpcywgUG9wcGVyKTtcblxuICAgIHRoaXMuc2NoZWR1bGVVcGRhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKF90aGlzLnVwZGF0ZSk7XG4gICAgfTtcblxuICAgIC8vIG1ha2UgdXBkYXRlKCkgZGVib3VuY2VkLCBzbyB0aGF0IGl0IG9ubHkgcnVucyBhdCBtb3N0IG9uY2UtcGVyLXRpY2tcbiAgICB0aGlzLnVwZGF0ZSA9IGRlYm91bmNlKHRoaXMudXBkYXRlLmJpbmQodGhpcykpO1xuXG4gICAgLy8gd2l0aCB7fSB3ZSBjcmVhdGUgYSBuZXcgb2JqZWN0IHdpdGggdGhlIG9wdGlvbnMgaW5zaWRlIGl0XG4gICAgdGhpcy5vcHRpb25zID0gX2V4dGVuZHMoe30sIFBvcHBlci5EZWZhdWx0cywgb3B0aW9ucyk7XG5cbiAgICAvLyBpbml0IHN0YXRlXG4gICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgIGlzRGVzdHJveWVkOiBmYWxzZSxcbiAgICAgIGlzQ3JlYXRlZDogZmFsc2UsXG4gICAgICBzY3JvbGxQYXJlbnRzOiBbXVxuICAgIH07XG5cbiAgICAvLyBnZXQgcmVmZXJlbmNlIGFuZCBwb3BwZXIgZWxlbWVudHMgKGFsbG93IGpRdWVyeSB3cmFwcGVycylcbiAgICB0aGlzLnJlZmVyZW5jZSA9IHJlZmVyZW5jZSAmJiByZWZlcmVuY2UuanF1ZXJ5ID8gcmVmZXJlbmNlWzBdIDogcmVmZXJlbmNlO1xuICAgIHRoaXMucG9wcGVyID0gcG9wcGVyICYmIHBvcHBlci5qcXVlcnkgPyBwb3BwZXJbMF0gOiBwb3BwZXI7XG5cbiAgICAvLyBEZWVwIG1lcmdlIG1vZGlmaWVycyBvcHRpb25zXG4gICAgdGhpcy5vcHRpb25zLm1vZGlmaWVycyA9IHt9O1xuICAgIE9iamVjdC5rZXlzKF9leHRlbmRzKHt9LCBQb3BwZXIuRGVmYXVsdHMubW9kaWZpZXJzLCBvcHRpb25zLm1vZGlmaWVycykpLmZvckVhY2goZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgIF90aGlzLm9wdGlvbnMubW9kaWZpZXJzW25hbWVdID0gX2V4dGVuZHMoe30sIFBvcHBlci5EZWZhdWx0cy5tb2RpZmllcnNbbmFtZV0gfHwge30sIG9wdGlvbnMubW9kaWZpZXJzID8gb3B0aW9ucy5tb2RpZmllcnNbbmFtZV0gOiB7fSk7XG4gICAgfSk7XG5cbiAgICAvLyBSZWZhY3RvcmluZyBtb2RpZmllcnMnIGxpc3QgKE9iamVjdCA9PiBBcnJheSlcbiAgICB0aGlzLm1vZGlmaWVycyA9IE9iamVjdC5rZXlzKHRoaXMub3B0aW9ucy5tb2RpZmllcnMpLm1hcChmdW5jdGlvbiAobmFtZSkge1xuICAgICAgcmV0dXJuIF9leHRlbmRzKHtcbiAgICAgICAgbmFtZTogbmFtZVxuICAgICAgfSwgX3RoaXMub3B0aW9ucy5tb2RpZmllcnNbbmFtZV0pO1xuICAgIH0pXG4gICAgLy8gc29ydCB0aGUgbW9kaWZpZXJzIGJ5IG9yZGVyXG4gICAgLnNvcnQoZnVuY3Rpb24gKGEsIGIpIHtcbiAgICAgIHJldHVybiBhLm9yZGVyIC0gYi5vcmRlcjtcbiAgICB9KTtcblxuICAgIC8vIG1vZGlmaWVycyBoYXZlIHRoZSBhYmlsaXR5IHRvIGV4ZWN1dGUgYXJiaXRyYXJ5IGNvZGUgd2hlbiBQb3BwZXIuanMgZ2V0IGluaXRlZFxuICAgIC8vIHN1Y2ggY29kZSBpcyBleGVjdXRlZCBpbiB0aGUgc2FtZSBvcmRlciBvZiBpdHMgbW9kaWZpZXJcbiAgICAvLyB0aGV5IGNvdWxkIGFkZCBuZXcgcHJvcGVydGllcyB0byB0aGVpciBvcHRpb25zIGNvbmZpZ3VyYXRpb25cbiAgICAvLyBCRSBBV0FSRTogZG9uJ3QgYWRkIG9wdGlvbnMgdG8gYG9wdGlvbnMubW9kaWZpZXJzLm5hbWVgIGJ1dCB0byBgbW9kaWZpZXJPcHRpb25zYCFcbiAgICB0aGlzLm1vZGlmaWVycy5mb3JFYWNoKGZ1bmN0aW9uIChtb2RpZmllck9wdGlvbnMpIHtcbiAgICAgIGlmIChtb2RpZmllck9wdGlvbnMuZW5hYmxlZCAmJiBpc0Z1bmN0aW9uKG1vZGlmaWVyT3B0aW9ucy5vbkxvYWQpKSB7XG4gICAgICAgIG1vZGlmaWVyT3B0aW9ucy5vbkxvYWQoX3RoaXMucmVmZXJlbmNlLCBfdGhpcy5wb3BwZXIsIF90aGlzLm9wdGlvbnMsIG1vZGlmaWVyT3B0aW9ucywgX3RoaXMuc3RhdGUpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy8gZmlyZSB0aGUgZmlyc3QgdXBkYXRlIHRvIHBvc2l0aW9uIHRoZSBwb3BwZXIgaW4gdGhlIHJpZ2h0IHBsYWNlXG4gICAgdGhpcy51cGRhdGUoKTtcblxuICAgIHZhciBldmVudHNFbmFibGVkID0gdGhpcy5vcHRpb25zLmV2ZW50c0VuYWJsZWQ7XG4gICAgaWYgKGV2ZW50c0VuYWJsZWQpIHtcbiAgICAgIC8vIHNldHVwIGV2ZW50IGxpc3RlbmVycywgdGhleSB3aWxsIHRha2UgY2FyZSBvZiB1cGRhdGUgdGhlIHBvc2l0aW9uIGluIHNwZWNpZmljIHNpdHVhdGlvbnNcbiAgICAgIHRoaXMuZW5hYmxlRXZlbnRMaXN0ZW5lcnMoKTtcbiAgICB9XG5cbiAgICB0aGlzLnN0YXRlLmV2ZW50c0VuYWJsZWQgPSBldmVudHNFbmFibGVkO1xuICB9XG5cbiAgLy8gV2UgY2FuJ3QgdXNlIGNsYXNzIHByb3BlcnRpZXMgYmVjYXVzZSB0aGV5IGRvbid0IGdldCBsaXN0ZWQgaW4gdGhlXG4gIC8vIGNsYXNzIHByb3RvdHlwZSBhbmQgYnJlYWsgc3R1ZmYgbGlrZSBTaW5vbiBzdHVic1xuXG5cbiAgY3JlYXRlQ2xhc3MoUG9wcGVyLCBbe1xuICAgIGtleTogJ3VwZGF0ZScsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIHVwZGF0ZSQkMSgpIHtcbiAgICAgIHJldHVybiB1cGRhdGUuY2FsbCh0aGlzKTtcbiAgICB9XG4gIH0sIHtcbiAgICBrZXk6ICdkZXN0cm95JyxcbiAgICB2YWx1ZTogZnVuY3Rpb24gZGVzdHJveSQkMSgpIHtcbiAgICAgIHJldHVybiBkZXN0cm95LmNhbGwodGhpcyk7XG4gICAgfVxuICB9LCB7XG4gICAga2V5OiAnZW5hYmxlRXZlbnRMaXN0ZW5lcnMnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiBlbmFibGVFdmVudExpc3RlbmVycyQkMSgpIHtcbiAgICAgIHJldHVybiBlbmFibGVFdmVudExpc3RlbmVycy5jYWxsKHRoaXMpO1xuICAgIH1cbiAgfSwge1xuICAgIGtleTogJ2Rpc2FibGVFdmVudExpc3RlbmVycycsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIGRpc2FibGVFdmVudExpc3RlbmVycyQkMSgpIHtcbiAgICAgIHJldHVybiBkaXNhYmxlRXZlbnRMaXN0ZW5lcnMuY2FsbCh0aGlzKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTY2hlZHVsZXMgYW4gdXBkYXRlLiBJdCB3aWxsIHJ1biBvbiB0aGUgbmV4dCBVSSB1cGRhdGUgYXZhaWxhYmxlLlxuICAgICAqIEBtZXRob2Qgc2NoZWR1bGVVcGRhdGVcbiAgICAgKiBAbWVtYmVyb2YgUG9wcGVyXG4gICAgICovXG5cblxuICAgIC8qKlxuICAgICAqIENvbGxlY3Rpb24gb2YgdXRpbGl0aWVzIHVzZWZ1bCB3aGVuIHdyaXRpbmcgY3VzdG9tIG1vZGlmaWVycy5cbiAgICAgKiBTdGFydGluZyBmcm9tIHZlcnNpb24gMS43LCB0aGlzIG1ldGhvZCBpcyBhdmFpbGFibGUgb25seSBpZiB5b3VcbiAgICAgKiBpbmNsdWRlIGBwb3BwZXItdXRpbHMuanNgIGJlZm9yZSBgcG9wcGVyLmpzYC5cbiAgICAgKlxuICAgICAqICoqREVQUkVDQVRJT04qKjogVGhpcyB3YXkgdG8gYWNjZXNzIFBvcHBlclV0aWxzIGlzIGRlcHJlY2F0ZWRcbiAgICAgKiBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHYyISBVc2UgdGhlIFBvcHBlclV0aWxzIG1vZHVsZSBkaXJlY3RseSBpbnN0ZWFkLlxuICAgICAqIER1ZSB0byB0aGUgaGlnaCBpbnN0YWJpbGl0eSBvZiB0aGUgbWV0aG9kcyBjb250YWluZWQgaW4gVXRpbHMsIHdlIGNhbid0XG4gICAgICogZ3VhcmFudGVlIHRoZW0gdG8gZm9sbG93IHNlbXZlci4gVXNlIHRoZW0gYXQgeW91ciBvd24gcmlzayFcbiAgICAgKiBAc3RhdGljXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAqIEBkZXByZWNhdGVkIHNpbmNlIHZlcnNpb24gMS44XG4gICAgICogQG1lbWJlciBVdGlsc1xuICAgICAqIEBtZW1iZXJvZiBQb3BwZXJcbiAgICAgKi9cblxuICB9XSk7XG4gIHJldHVybiBQb3BwZXI7XG59KCk7XG5cbi8qKlxuICogVGhlIGByZWZlcmVuY2VPYmplY3RgIGlzIGFuIG9iamVjdCB0aGF0IHByb3ZpZGVzIGFuIGludGVyZmFjZSBjb21wYXRpYmxlIHdpdGggUG9wcGVyLmpzXG4gKiBhbmQgbGV0cyB5b3UgdXNlIGl0IGFzIHJlcGxhY2VtZW50IG9mIGEgcmVhbCBET00gbm9kZS48YnIgLz5cbiAqIFlvdSBjYW4gdXNlIHRoaXMgbWV0aG9kIHRvIHBvc2l0aW9uIGEgcG9wcGVyIHJlbGF0aXZlbHkgdG8gYSBzZXQgb2YgY29vcmRpbmF0ZXNcbiAqIGluIGNhc2UgeW91IGRvbid0IGhhdmUgYSBET00gbm9kZSB0byB1c2UgYXMgcmVmZXJlbmNlLlxuICpcbiAqIGBgYFxuICogbmV3IFBvcHBlcihyZWZlcmVuY2VPYmplY3QsIHBvcHBlck5vZGUpO1xuICogYGBgXG4gKlxuICogTkI6IFRoaXMgZmVhdHVyZSBpc24ndCBzdXBwb3J0ZWQgaW4gSW50ZXJuZXQgRXhwbG9yZXIgMTAuXG4gKiBAbmFtZSByZWZlcmVuY2VPYmplY3RcbiAqIEBwcm9wZXJ0eSB7RnVuY3Rpb259IGRhdGEuZ2V0Qm91bmRpbmdDbGllbnRSZWN0XG4gKiBBIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhIHNldCBvZiBjb29yZGluYXRlcyBjb21wYXRpYmxlIHdpdGggdGhlIG5hdGl2ZSBgZ2V0Qm91bmRpbmdDbGllbnRSZWN0YCBtZXRob2QuXG4gKiBAcHJvcGVydHkge251bWJlcn0gZGF0YS5jbGllbnRXaWR0aFxuICogQW4gRVM2IGdldHRlciB0aGF0IHdpbGwgcmV0dXJuIHRoZSB3aWR0aCBvZiB0aGUgdmlydHVhbCByZWZlcmVuY2UgZWxlbWVudC5cbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBkYXRhLmNsaWVudEhlaWdodFxuICogQW4gRVM2IGdldHRlciB0aGF0IHdpbGwgcmV0dXJuIHRoZSBoZWlnaHQgb2YgdGhlIHZpcnR1YWwgcmVmZXJlbmNlIGVsZW1lbnQuXG4gKi9cblxuXG5Qb3BwZXIuVXRpbHMgPSAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgPyB3aW5kb3cgOiBnbG9iYWwpLlBvcHBlclV0aWxzO1xuUG9wcGVyLnBsYWNlbWVudHMgPSBwbGFjZW1lbnRzO1xuUG9wcGVyLkRlZmF1bHRzID0gRGVmYXVsdHM7XG5cbmV4cG9ydCBkZWZhdWx0IFBvcHBlcjtcbi8vIyBzb3VyY2VNYXBwaW5nVVJMPXBvcHBlci5qcy5tYXBcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./node_modules/popper.js/dist/esm/popper.js\n");
|
|
|
|
/***/ })
|
|
|
|
/******/ });
|
|
/************************************************************************/
|
|
/******/ // The module cache
|
|
/******/ var __webpack_module_cache__ = {};
|
|
/******/
|
|
/******/ // The require function
|
|
/******/ function __webpack_require__(moduleId) {
|
|
/******/ // Check if module is in cache
|
|
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
|
/******/ if (cachedModule !== undefined) {
|
|
/******/ return cachedModule.exports;
|
|
/******/ }
|
|
/******/ // Create a new module (and put it into the cache)
|
|
/******/ var module = __webpack_module_cache__[moduleId] = {
|
|
/******/ // no module.id needed
|
|
/******/ // no module.loaded needed
|
|
/******/ exports: {}
|
|
/******/ };
|
|
/******/
|
|
/******/ // Execute the module function
|
|
/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
|
/******/
|
|
/******/ // Return the exports of the module
|
|
/******/ return module.exports;
|
|
/******/ }
|
|
/******/
|
|
/******/ // expose the modules object (__webpack_modules__)
|
|
/******/ __webpack_require__.m = __webpack_modules__;
|
|
/******/
|
|
/************************************************************************/
|
|
/******/ /* webpack/runtime/chunk loaded */
|
|
/******/ (() => {
|
|
/******/ var deferred = [];
|
|
/******/ __webpack_require__.O = (result, chunkIds, fn, priority) => {
|
|
/******/ if(chunkIds) {
|
|
/******/ priority = priority || 0;
|
|
/******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
|
|
/******/ deferred[i] = [chunkIds, fn, priority];
|
|
/******/ return;
|
|
/******/ }
|
|
/******/ var notFulfilled = Infinity;
|
|
/******/ for (var i = 0; i < deferred.length; i++) {
|
|
/******/ var [chunkIds, fn, priority] = deferred[i];
|
|
/******/ var fulfilled = true;
|
|
/******/ for (var j = 0; j < chunkIds.length; j++) {
|
|
/******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {
|
|
/******/ chunkIds.splice(j--, 1);
|
|
/******/ } else {
|
|
/******/ fulfilled = false;
|
|
/******/ if(priority < notFulfilled) notFulfilled = priority;
|
|
/******/ }
|
|
/******/ }
|
|
/******/ if(fulfilled) {
|
|
/******/ deferred.splice(i--, 1)
|
|
/******/ var r = fn();
|
|
/******/ if (r !== undefined) result = r;
|
|
/******/ }
|
|
/******/ }
|
|
/******/ return result;
|
|
/******/ };
|
|
/******/ })();
|
|
/******/
|
|
/******/ /* webpack/runtime/define property getters */
|
|
/******/ (() => {
|
|
/******/ // define getter functions for harmony exports
|
|
/******/ __webpack_require__.d = (exports, definition) => {
|
|
/******/ for(var key in definition) {
|
|
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
|
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
|
/******/ }
|
|
/******/ }
|
|
/******/ };
|
|
/******/ })();
|
|
/******/
|
|
/******/ /* webpack/runtime/global */
|
|
/******/ (() => {
|
|
/******/ __webpack_require__.g = (function() {
|
|
/******/ if (typeof globalThis === 'object') return globalThis;
|
|
/******/ try {
|
|
/******/ return this || new Function('return this')();
|
|
/******/ } catch (e) {
|
|
/******/ if (typeof window === 'object') return window;
|
|
/******/ }
|
|
/******/ })();
|
|
/******/ })();
|
|
/******/
|
|
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
|
/******/ (() => {
|
|
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
|
/******/ })();
|
|
/******/
|
|
/******/ /* webpack/runtime/make namespace object */
|
|
/******/ (() => {
|
|
/******/ // define __esModule on exports
|
|
/******/ __webpack_require__.r = (exports) => {
|
|
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
|
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
/******/ }
|
|
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
|
/******/ };
|
|
/******/ })();
|
|
/******/
|
|
/******/ /* webpack/runtime/jsonp chunk loading */
|
|
/******/ (() => {
|
|
/******/ // no baseURI
|
|
/******/
|
|
/******/ // object to store loaded and loading chunks
|
|
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
|
|
/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
|
|
/******/ var installedChunks = {
|
|
/******/ "/js/app": 0,
|
|
/******/ "css/app": 0
|
|
/******/ };
|
|
/******/
|
|
/******/ // no chunk on demand loading
|
|
/******/
|
|
/******/ // no prefetching
|
|
/******/
|
|
/******/ // no preloaded
|
|
/******/
|
|
/******/ // no HMR
|
|
/******/
|
|
/******/ // no HMR manifest
|
|
/******/
|
|
/******/ __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
|
|
/******/
|
|
/******/ // install a JSONP callback for chunk loading
|
|
/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
|
|
/******/ var [chunkIds, moreModules, runtime] = data;
|
|
/******/ // add "moreModules" to the modules object,
|
|
/******/ // then flag all "chunkIds" as loaded and fire callback
|
|
/******/ var moduleId, chunkId, i = 0;
|
|
/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
|
|
/******/ for(moduleId in moreModules) {
|
|
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
|
|
/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
|
|
/******/ }
|
|
/******/ }
|
|
/******/ if(runtime) var result = runtime(__webpack_require__);
|
|
/******/ }
|
|
/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
|
|
/******/ for(;i < chunkIds.length; i++) {
|
|
/******/ chunkId = chunkIds[i];
|
|
/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
|
|
/******/ installedChunks[chunkId][0]();
|
|
/******/ }
|
|
/******/ installedChunks[chunkIds[i]] = 0;
|
|
/******/ }
|
|
/******/ return __webpack_require__.O(result);
|
|
/******/ }
|
|
/******/
|
|
/******/ var chunkLoadingGlobal = self["webpackChunk"] = self["webpackChunk"] || [];
|
|
/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
|
|
/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
|
|
/******/ })();
|
|
/******/
|
|
/************************************************************************/
|
|
/******/
|
|
/******/ // startup
|
|
/******/ // Load entry module and return exports
|
|
/******/ // This entry module depends on other loaded chunks and execution need to be delayed
|
|
/******/ __webpack_require__.O(undefined, ["css/app"], () => (__webpack_require__("./resources/js/app.js")))
|
|
/******/ var __webpack_exports__ = __webpack_require__.O(undefined, ["css/app"], () => (__webpack_require__("./resources/sass/app.scss")))
|
|
/******/ __webpack_exports__ = __webpack_require__.O(__webpack_exports__);
|
|
/******/
|
|
/******/ })()
|
|
; |